diff options
author | Arnd Bergmann <arnd@arndb.de> | 2006-10-04 11:26:15 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-10-04 19:21:01 -0400 |
commit | 6263203ed6e9ff107129a1ebe613290b342a4465 (patch) | |
tree | dc7d68b783fed2b5ffcb8905c62086ebe078368b /arch | |
parent | 9add11daeee2f6d69f6b86237f197824332a4a3b (diff) |
[POWERPC] spufs: Add infrastructure needed for gang scheduling
Add the concept of a gang to spufs as a new type of object.
So far, this has no impact whatsover on scheduling, but makes
it possible to add that later.
A new type of object in spufs is now a spu_gang. It is created
with the spu_create system call with the flags argument set
to SPU_CREATE_GANG (0x2). Inside of a spu_gang, it
is then possible to create spu_context objects, which until
now was only possible at the root of spufs.
There is a new member in struct spu_context pointing to
the spu_gang it belongs to, if any. The spu_gang maintains
a list of spu_context structures that are its children.
This information can then be used in the scheduler in the
future.
There is still a bug that needs to be resolved in this
basic infrastructure regarding the order in which objects
are removed. When the spu_gang file descriptor is closed
before the spu_context descriptors, we leak the dentry
and inode for the gang. Any ideas how to cleanly solve
this are appreciated.
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/gang.c | 81 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 225 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 24 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/syscalls.c | 2 |
6 files changed, 299 insertions, 41 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index bb5dc634272c..ecdfbb35f82e 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile | |||
@@ -2,7 +2,7 @@ obj-y += switch.o | |||
2 | 2 | ||
3 | obj-$(CONFIG_SPU_FS) += spufs.o | 3 | obj-$(CONFIG_SPU_FS) += spufs.o |
4 | spufs-y += inode.o file.o context.o syscalls.o | 4 | spufs-y += inode.o file.o context.o syscalls.o |
5 | spufs-y += sched.o backing_ops.o hw_ops.o run.o | 5 | spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o |
6 | 6 | ||
7 | # Rules to build switch.o with the help of SPU tool chain | 7 | # Rules to build switch.o with the help of SPU tool chain |
8 | SPU_CROSS := spu- | 8 | SPU_CROSS := spu- |
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 36439c5e9f2d..034cf6af53a2 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <asm/spu_csa.h> | 27 | #include <asm/spu_csa.h> |
28 | #include "spufs.h" | 28 | #include "spufs.h" |
29 | 29 | ||
30 | struct spu_context *alloc_spu_context(void) | 30 | struct spu_context *alloc_spu_context(struct spu_gang *gang) |
31 | { | 31 | { |
32 | struct spu_context *ctx; | 32 | struct spu_context *ctx; |
33 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); | 33 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); |
@@ -51,6 +51,8 @@ struct spu_context *alloc_spu_context(void) | |||
51 | ctx->state = SPU_STATE_SAVED; | 51 | ctx->state = SPU_STATE_SAVED; |
52 | ctx->ops = &spu_backing_ops; | 52 | ctx->ops = &spu_backing_ops; |
53 | ctx->owner = get_task_mm(current); | 53 | ctx->owner = get_task_mm(current); |
54 | if (gang) | ||
55 | spu_gang_add_ctx(gang, ctx); | ||
54 | goto out; | 56 | goto out; |
55 | out_free: | 57 | out_free: |
56 | kfree(ctx); | 58 | kfree(ctx); |
@@ -67,6 +69,8 @@ void destroy_spu_context(struct kref *kref) | |||
67 | spu_deactivate(ctx); | 69 | spu_deactivate(ctx); |
68 | up_write(&ctx->state_sema); | 70 | up_write(&ctx->state_sema); |
69 | spu_fini_csa(&ctx->csa); | 71 | spu_fini_csa(&ctx->csa); |
72 | if (ctx->gang) | ||
73 | spu_gang_remove_ctx(ctx->gang, ctx); | ||
70 | kfree(ctx); | 74 | kfree(ctx); |
71 | } | 75 | } |
72 | 76 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/gang.c b/arch/powerpc/platforms/cell/spufs/gang.c new file mode 100644 index 000000000000..212ea78f9051 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/gang.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * SPU file system | ||
3 | * | ||
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | ||
5 | * | ||
6 | * Author: Arnd Bergmann <arndb@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/list.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include "spufs.h" | ||
27 | |||
28 | struct spu_gang *alloc_spu_gang(void) | ||
29 | { | ||
30 | struct spu_gang *gang; | ||
31 | |||
32 | gang = kzalloc(sizeof *gang, GFP_KERNEL); | ||
33 | if (!gang) | ||
34 | goto out; | ||
35 | |||
36 | kref_init(&gang->kref); | ||
37 | mutex_init(&gang->mutex); | ||
38 | INIT_LIST_HEAD(&gang->list); | ||
39 | |||
40 | out: | ||
41 | return gang; | ||
42 | } | ||
43 | |||
44 | static void destroy_spu_gang(struct kref *kref) | ||
45 | { | ||
46 | struct spu_gang *gang; | ||
47 | gang = container_of(kref, struct spu_gang, kref); | ||
48 | WARN_ON(gang->contexts || !list_empty(&gang->list)); | ||
49 | kfree(gang); | ||
50 | } | ||
51 | |||
52 | struct spu_gang *get_spu_gang(struct spu_gang *gang) | ||
53 | { | ||
54 | kref_get(&gang->kref); | ||
55 | return gang; | ||
56 | } | ||
57 | |||
58 | int put_spu_gang(struct spu_gang *gang) | ||
59 | { | ||
60 | return kref_put(&gang->kref, &destroy_spu_gang); | ||
61 | } | ||
62 | |||
63 | void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx) | ||
64 | { | ||
65 | mutex_lock(&gang->mutex); | ||
66 | ctx->gang = get_spu_gang(gang); | ||
67 | list_add(&ctx->gang_list, &gang->list); | ||
68 | gang->contexts++; | ||
69 | mutex_unlock(&gang->mutex); | ||
70 | } | ||
71 | |||
72 | void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx) | ||
73 | { | ||
74 | mutex_lock(&gang->mutex); | ||
75 | WARN_ON(ctx->gang != gang); | ||
76 | list_del_init(&ctx->gang_list); | ||
77 | gang->contexts--; | ||
78 | mutex_unlock(&gang->mutex); | ||
79 | |||
80 | put_spu_gang(gang); | ||
81 | } | ||
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 8cc615ff3637..427d00a4f6a0 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -50,6 +50,10 @@ spufs_alloc_inode(struct super_block *sb) | |||
50 | ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL); | 50 | ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL); |
51 | if (!ei) | 51 | if (!ei) |
52 | return NULL; | 52 | return NULL; |
53 | |||
54 | ei->i_gang = NULL; | ||
55 | ei->i_ctx = NULL; | ||
56 | |||
53 | return &ei->vfs_inode; | 57 | return &ei->vfs_inode; |
54 | } | 58 | } |
55 | 59 | ||
@@ -128,14 +132,19 @@ out: | |||
128 | static void | 132 | static void |
129 | spufs_delete_inode(struct inode *inode) | 133 | spufs_delete_inode(struct inode *inode) |
130 | { | 134 | { |
131 | if (SPUFS_I(inode)->i_ctx) | 135 | struct spufs_inode_info *ei = SPUFS_I(inode); |
132 | put_spu_context(SPUFS_I(inode)->i_ctx); | 136 | |
137 | if (ei->i_ctx) | ||
138 | put_spu_context(ei->i_ctx); | ||
139 | if (ei->i_gang) | ||
140 | put_spu_gang(ei->i_gang); | ||
133 | clear_inode(inode); | 141 | clear_inode(inode); |
134 | } | 142 | } |
135 | 143 | ||
136 | static void spufs_prune_dir(struct dentry *dir) | 144 | static void spufs_prune_dir(struct dentry *dir) |
137 | { | 145 | { |
138 | struct dentry *dentry, *tmp; | 146 | struct dentry *dentry, *tmp; |
147 | |||
139 | mutex_lock(&dir->d_inode->i_mutex); | 148 | mutex_lock(&dir->d_inode->i_mutex); |
140 | list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { | 149 | list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { |
141 | spin_lock(&dcache_lock); | 150 | spin_lock(&dcache_lock); |
@@ -156,13 +165,13 @@ static void spufs_prune_dir(struct dentry *dir) | |||
156 | mutex_unlock(&dir->d_inode->i_mutex); | 165 | mutex_unlock(&dir->d_inode->i_mutex); |
157 | } | 166 | } |
158 | 167 | ||
159 | /* Caller must hold root->i_mutex */ | 168 | /* Caller must hold parent->i_mutex */ |
160 | static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) | 169 | static int spufs_rmdir(struct inode *parent, struct dentry *dir) |
161 | { | 170 | { |
162 | /* remove all entries */ | 171 | /* remove all entries */ |
163 | spufs_prune_dir(dir_dentry); | 172 | spufs_prune_dir(dir); |
164 | 173 | ||
165 | return simple_rmdir(root, dir_dentry); | 174 | return simple_rmdir(parent, dir); |
166 | } | 175 | } |
167 | 176 | ||
168 | static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, | 177 | static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, |
@@ -191,17 +200,17 @@ out: | |||
191 | static int spufs_dir_close(struct inode *inode, struct file *file) | 200 | static int spufs_dir_close(struct inode *inode, struct file *file) |
192 | { | 201 | { |
193 | struct spu_context *ctx; | 202 | struct spu_context *ctx; |
194 | struct inode *dir; | 203 | struct inode *parent; |
195 | struct dentry *dentry; | 204 | struct dentry *dir; |
196 | int ret; | 205 | int ret; |
197 | 206 | ||
198 | dentry = file->f_dentry; | 207 | dir = file->f_dentry; |
199 | dir = dentry->d_parent->d_inode; | 208 | parent = dir->d_parent->d_inode; |
200 | ctx = SPUFS_I(dentry->d_inode)->i_ctx; | 209 | ctx = SPUFS_I(dir->d_inode)->i_ctx; |
201 | 210 | ||
202 | mutex_lock(&dir->i_mutex); | 211 | mutex_lock(&parent->i_mutex); |
203 | ret = spufs_rmdir(dir, dentry); | 212 | ret = spufs_rmdir(parent, dir); |
204 | mutex_unlock(&dir->i_mutex); | 213 | mutex_unlock(&parent->i_mutex); |
205 | WARN_ON(ret); | 214 | WARN_ON(ret); |
206 | 215 | ||
207 | /* We have to give up the mm_struct */ | 216 | /* We have to give up the mm_struct */ |
@@ -240,7 +249,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, | |||
240 | inode->i_gid = dir->i_gid; | 249 | inode->i_gid = dir->i_gid; |
241 | inode->i_mode &= S_ISGID; | 250 | inode->i_mode &= S_ISGID; |
242 | } | 251 | } |
243 | ctx = alloc_spu_context(); | 252 | ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */ |
244 | SPUFS_I(inode)->i_ctx = ctx; | 253 | SPUFS_I(inode)->i_ctx = ctx; |
245 | if (!ctx) | 254 | if (!ctx) |
246 | goto out_iput; | 255 | goto out_iput; |
@@ -292,24 +301,177 @@ out: | |||
292 | return ret; | 301 | return ret; |
293 | } | 302 | } |
294 | 303 | ||
304 | static int spufs_create_context(struct inode *inode, | ||
305 | struct dentry *dentry, | ||
306 | struct vfsmount *mnt, int flags, int mode) | ||
307 | { | ||
308 | int ret; | ||
309 | |||
310 | ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); | ||
311 | if (ret) | ||
312 | goto out_unlock; | ||
313 | |||
314 | /* | ||
315 | * get references for dget and mntget, will be released | ||
316 | * in error path of *_open(). | ||
317 | */ | ||
318 | ret = spufs_context_open(dget(dentry), mntget(mnt)); | ||
319 | if (ret < 0) { | ||
320 | WARN_ON(spufs_rmdir(inode, dentry)); | ||
321 | mutex_unlock(&inode->i_mutex); | ||
322 | spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | out_unlock: | ||
327 | mutex_unlock(&inode->i_mutex); | ||
328 | out: | ||
329 | dput(dentry); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | static int spufs_rmgang(struct inode *root, struct dentry *dir) | ||
334 | { | ||
335 | /* FIXME: this fails if the dir is not empty, | ||
336 | which causes a leak of gangs. */ | ||
337 | return simple_rmdir(root, dir); | ||
338 | } | ||
339 | |||
340 | static int spufs_gang_close(struct inode *inode, struct file *file) | ||
341 | { | ||
342 | struct inode *parent; | ||
343 | struct dentry *dir; | ||
344 | int ret; | ||
345 | |||
346 | dir = file->f_dentry; | ||
347 | parent = dir->d_parent->d_inode; | ||
348 | |||
349 | ret = spufs_rmgang(parent, dir); | ||
350 | WARN_ON(ret); | ||
351 | |||
352 | return dcache_dir_close(inode, file); | ||
353 | } | ||
354 | |||
355 | struct file_operations spufs_gang_fops = { | ||
356 | .open = dcache_dir_open, | ||
357 | .release = spufs_gang_close, | ||
358 | .llseek = dcache_dir_lseek, | ||
359 | .read = generic_read_dir, | ||
360 | .readdir = dcache_readdir, | ||
361 | .fsync = simple_sync_file, | ||
362 | }; | ||
363 | |||
364 | static int | ||
365 | spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) | ||
366 | { | ||
367 | int ret; | ||
368 | struct inode *inode; | ||
369 | struct spu_gang *gang; | ||
370 | |||
371 | ret = -ENOSPC; | ||
372 | inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); | ||
373 | if (!inode) | ||
374 | goto out; | ||
375 | |||
376 | ret = 0; | ||
377 | if (dir->i_mode & S_ISGID) { | ||
378 | inode->i_gid = dir->i_gid; | ||
379 | inode->i_mode &= S_ISGID; | ||
380 | } | ||
381 | gang = alloc_spu_gang(); | ||
382 | SPUFS_I(inode)->i_ctx = NULL; | ||
383 | SPUFS_I(inode)->i_gang = gang; | ||
384 | if (!gang) | ||
385 | goto out_iput; | ||
386 | |||
387 | inode->i_op = &spufs_dir_inode_operations; | ||
388 | inode->i_fop = &simple_dir_operations; | ||
389 | |||
390 | d_instantiate(dentry, inode); | ||
391 | dget(dentry); | ||
392 | dir->i_nlink++; | ||
393 | dentry->d_inode->i_nlink++; | ||
394 | return ret; | ||
395 | |||
396 | out_iput: | ||
397 | iput(inode); | ||
398 | out: | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt) | ||
403 | { | ||
404 | int ret; | ||
405 | struct file *filp; | ||
406 | |||
407 | ret = get_unused_fd(); | ||
408 | if (ret < 0) { | ||
409 | dput(dentry); | ||
410 | mntput(mnt); | ||
411 | goto out; | ||
412 | } | ||
413 | |||
414 | filp = dentry_open(dentry, mnt, O_RDONLY); | ||
415 | if (IS_ERR(filp)) { | ||
416 | put_unused_fd(ret); | ||
417 | ret = PTR_ERR(filp); | ||
418 | goto out; | ||
419 | } | ||
420 | |||
421 | filp->f_op = &spufs_gang_fops; | ||
422 | fd_install(ret, filp); | ||
423 | out: | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | static int spufs_create_gang(struct inode *inode, | ||
428 | struct dentry *dentry, | ||
429 | struct vfsmount *mnt, int mode) | ||
430 | { | ||
431 | int ret; | ||
432 | |||
433 | ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO); | ||
434 | if (ret) | ||
435 | goto out; | ||
436 | |||
437 | /* | ||
438 | * get references for dget and mntget, will be released | ||
439 | * in error path of *_open(). | ||
440 | */ | ||
441 | ret = spufs_gang_open(dget(dentry), mntget(mnt)); | ||
442 | if (ret < 0) | ||
443 | WARN_ON(spufs_rmgang(inode, dentry)); | ||
444 | |||
445 | out: | ||
446 | mutex_unlock(&inode->i_mutex); | ||
447 | dput(dentry); | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | |||
295 | static struct file_system_type spufs_type; | 452 | static struct file_system_type spufs_type; |
296 | 453 | ||
297 | long spufs_create_thread(struct nameidata *nd, | 454 | long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) |
298 | unsigned int flags, mode_t mode) | ||
299 | { | 455 | { |
300 | struct dentry *dentry; | 456 | struct dentry *dentry; |
301 | int ret; | 457 | int ret; |
302 | 458 | ||
303 | /* need to be at the root of spufs */ | ||
304 | ret = -EINVAL; | 459 | ret = -EINVAL; |
305 | if (nd->dentry->d_sb->s_type != &spufs_type || | 460 | /* check if we are on spufs */ |
306 | nd->dentry != nd->dentry->d_sb->s_root) | 461 | if (nd->dentry->d_sb->s_type != &spufs_type) |
307 | goto out; | 462 | goto out; |
308 | 463 | ||
309 | /* all flags are reserved */ | 464 | /* don't accept undefined flags */ |
310 | if (flags & (~SPU_CREATE_FLAG_ALL)) | 465 | if (flags & (~SPU_CREATE_FLAG_ALL)) |
311 | goto out; | 466 | goto out; |
312 | 467 | ||
468 | /* only threads can be underneath a gang */ | ||
469 | if (nd->dentry != nd->dentry->d_sb->s_root) { | ||
470 | if ((flags & SPU_CREATE_GANG) || | ||
471 | !SPUFS_I(nd->dentry->d_inode)->i_gang) | ||
472 | goto out; | ||
473 | } | ||
474 | |||
313 | dentry = lookup_create(nd, 1); | 475 | dentry = lookup_create(nd, 1); |
314 | ret = PTR_ERR(dentry); | 476 | ret = PTR_ERR(dentry); |
315 | if (IS_ERR(dentry)) | 477 | if (IS_ERR(dentry)) |
@@ -320,22 +482,13 @@ long spufs_create_thread(struct nameidata *nd, | |||
320 | goto out_dput; | 482 | goto out_dput; |
321 | 483 | ||
322 | mode &= ~current->fs->umask; | 484 | mode &= ~current->fs->umask; |
323 | ret = spufs_mkdir(nd->dentry->d_inode, dentry, flags, mode & S_IRWXUGO); | ||
324 | if (ret) | ||
325 | goto out_dput; | ||
326 | 485 | ||
327 | /* | 486 | if (flags & SPU_CREATE_GANG) |
328 | * get references for dget and mntget, will be released | 487 | return spufs_create_gang(nd->dentry->d_inode, |
329 | * in error path of *_open(). | 488 | dentry, nd->mnt, mode); |
330 | */ | 489 | else |
331 | ret = spufs_context_open(dget(dentry), mntget(nd->mnt)); | 490 | return spufs_create_context(nd->dentry->d_inode, |
332 | if (ret < 0) { | 491 | dentry, nd->mnt, flags, mode); |
333 | WARN_ON(spufs_rmdir(nd->dentry->d_inode, dentry)); | ||
334 | mutex_unlock(&nd->dentry->d_inode->i_mutex); | ||
335 | spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); | ||
336 | dput(dentry); | ||
337 | goto out; | ||
338 | } | ||
339 | 492 | ||
340 | out_dput: | 493 | out_dput: |
341 | dput(dentry); | 494 | dput(dentry); |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 2fb6a0099112..f6624ceedf70 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -39,6 +39,8 @@ struct spu_context_ops; | |||
39 | 39 | ||
40 | #define SPU_CONTEXT_PREEMPT 0UL | 40 | #define SPU_CONTEXT_PREEMPT 0UL |
41 | 41 | ||
42 | struct spu_gang; | ||
43 | |||
42 | struct spu_context { | 44 | struct spu_context { |
43 | struct spu *spu; /* pointer to a physical SPU */ | 45 | struct spu *spu; /* pointer to a physical SPU */ |
44 | struct spu_state csa; /* SPU context save area. */ | 46 | struct spu_state csa; /* SPU context save area. */ |
@@ -68,6 +70,16 @@ struct spu_context { | |||
68 | struct work_struct reap_work; | 70 | struct work_struct reap_work; |
69 | unsigned long flags; | 71 | unsigned long flags; |
70 | unsigned long event_return; | 72 | unsigned long event_return; |
73 | |||
74 | struct list_head gang_list; | ||
75 | struct spu_gang *gang; | ||
76 | }; | ||
77 | |||
78 | struct spu_gang { | ||
79 | struct list_head list; | ||
80 | struct mutex mutex; | ||
81 | struct kref kref; | ||
82 | int contexts; | ||
71 | }; | 83 | }; |
72 | 84 | ||
73 | struct mfc_dma_command { | 85 | struct mfc_dma_command { |
@@ -115,6 +127,7 @@ extern struct spu_context_ops spu_backing_ops; | |||
115 | 127 | ||
116 | struct spufs_inode_info { | 128 | struct spufs_inode_info { |
117 | struct spu_context *i_ctx; | 129 | struct spu_context *i_ctx; |
130 | struct spu_gang *i_gang; | ||
118 | struct inode vfs_inode; | 131 | struct inode vfs_inode; |
119 | }; | 132 | }; |
120 | #define SPUFS_I(inode) \ | 133 | #define SPUFS_I(inode) \ |
@@ -125,12 +138,19 @@ extern struct tree_descr spufs_dir_contents[]; | |||
125 | /* system call implementation */ | 138 | /* system call implementation */ |
126 | long spufs_run_spu(struct file *file, | 139 | long spufs_run_spu(struct file *file, |
127 | struct spu_context *ctx, u32 *npc, u32 *status); | 140 | struct spu_context *ctx, u32 *npc, u32 *status); |
128 | long spufs_create_thread(struct nameidata *nd, | 141 | long spufs_create(struct nameidata *nd, |
129 | unsigned int flags, mode_t mode); | 142 | unsigned int flags, mode_t mode); |
130 | extern struct file_operations spufs_context_fops; | 143 | extern struct file_operations spufs_context_fops; |
131 | 144 | ||
145 | /* gang management */ | ||
146 | struct spu_gang *alloc_spu_gang(void); | ||
147 | struct spu_gang *get_spu_gang(struct spu_gang *gang); | ||
148 | int put_spu_gang(struct spu_gang *gang); | ||
149 | void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); | ||
150 | void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); | ||
151 | |||
132 | /* context management */ | 152 | /* context management */ |
133 | struct spu_context * alloc_spu_context(void); | 153 | struct spu_context * alloc_spu_context(struct spu_gang *gang); |
134 | void destroy_spu_context(struct kref *kref); | 154 | void destroy_spu_context(struct kref *kref); |
135 | struct spu_context * get_spu_context(struct spu_context *ctx); | 155 | struct spu_context * get_spu_context(struct spu_context *ctx); |
136 | int put_spu_context(struct spu_context *ctx); | 156 | int put_spu_context(struct spu_context *ctx); |
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index ef33a0ca2036..a6d1ae4dc2a3 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c | |||
@@ -90,7 +90,7 @@ asmlinkage long sys_spu_create(const char __user *pathname, | |||
90 | ret = path_lookup(tmp, LOOKUP_PARENT| | 90 | ret = path_lookup(tmp, LOOKUP_PARENT| |
91 | LOOKUP_OPEN|LOOKUP_CREATE, &nd); | 91 | LOOKUP_OPEN|LOOKUP_CREATE, &nd); |
92 | if (!ret) { | 92 | if (!ret) { |
93 | ret = spufs_create_thread(&nd, flags, mode); | 93 | ret = spufs_create(&nd, flags, mode); |
94 | path_release(&nd); | 94 | path_release(&nd); |
95 | } | 95 | } |
96 | putname(tmp); | 96 | putname(tmp); |