diff options
-rw-r--r-- | arch/powerpc/platforms/cell/spu_syscalls.c | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/gang.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 132 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 16 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/syscalls.c | 32 | ||||
-rw-r--r-- | include/asm-powerpc/spu.h | 8 | ||||
-rw-r--r-- | include/linux/syscalls.h | 2 |
8 files changed, 195 insertions, 17 deletions
diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index 261b507a901a..dd2c6688c8aa 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c | |||
@@ -34,14 +34,27 @@ struct spufs_calls spufs_calls = { | |||
34 | * this file is not used and the syscalls directly enter the fs code */ | 34 | * this file is not used and the syscalls directly enter the fs code */ |
35 | 35 | ||
36 | asmlinkage long sys_spu_create(const char __user *name, | 36 | asmlinkage long sys_spu_create(const char __user *name, |
37 | unsigned int flags, mode_t mode) | 37 | unsigned int flags, mode_t mode, int neighbor_fd) |
38 | { | 38 | { |
39 | long ret; | 39 | long ret; |
40 | struct module *owner = spufs_calls.owner; | 40 | struct module *owner = spufs_calls.owner; |
41 | struct file *neighbor; | ||
42 | int fput_needed; | ||
41 | 43 | ||
42 | ret = -ENOSYS; | 44 | ret = -ENOSYS; |
43 | if (owner && try_module_get(owner)) { | 45 | if (owner && try_module_get(owner)) { |
44 | ret = spufs_calls.create_thread(name, flags, mode); | 46 | if (flags & SPU_CREATE_AFFINITY_SPU) { |
47 | neighbor = fget_light(neighbor_fd, &fput_needed); | ||
48 | if (neighbor) { | ||
49 | ret = spufs_calls.create_thread(name, flags, | ||
50 | mode, neighbor); | ||
51 | fput_light(neighbor, fput_needed); | ||
52 | } | ||
53 | } | ||
54 | else { | ||
55 | ret = spufs_calls.create_thread(name, flags, | ||
56 | mode, NULL); | ||
57 | } | ||
45 | module_put(owner); | 58 | module_put(owner); |
46 | } | 59 | } |
47 | return ret; | 60 | return ret; |
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 6b091ea1d192..a7efb999d65e 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -55,6 +55,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
55 | ctx->ops = &spu_backing_ops; | 55 | ctx->ops = &spu_backing_ops; |
56 | ctx->owner = get_task_mm(current); | 56 | ctx->owner = get_task_mm(current); |
57 | INIT_LIST_HEAD(&ctx->rq); | 57 | INIT_LIST_HEAD(&ctx->rq); |
58 | INIT_LIST_HEAD(&ctx->aff_list); | ||
58 | if (gang) | 59 | if (gang) |
59 | spu_gang_add_ctx(gang, ctx); | 60 | spu_gang_add_ctx(gang, ctx); |
60 | ctx->cpus_allowed = current->cpus_allowed; | 61 | ctx->cpus_allowed = current->cpus_allowed; |
diff --git a/arch/powerpc/platforms/cell/spufs/gang.c b/arch/powerpc/platforms/cell/spufs/gang.c index 212ea78f9051..0a752ce67c8a 100644 --- a/arch/powerpc/platforms/cell/spufs/gang.c +++ b/arch/powerpc/platforms/cell/spufs/gang.c | |||
@@ -35,7 +35,9 @@ struct spu_gang *alloc_spu_gang(void) | |||
35 | 35 | ||
36 | kref_init(&gang->kref); | 36 | kref_init(&gang->kref); |
37 | mutex_init(&gang->mutex); | 37 | mutex_init(&gang->mutex); |
38 | mutex_init(&gang->aff_mutex); | ||
38 | INIT_LIST_HEAD(&gang->list); | 39 | INIT_LIST_HEAD(&gang->list); |
40 | INIT_LIST_HEAD(&gang->aff_list_head); | ||
39 | 41 | ||
40 | out: | 42 | out: |
41 | return gang; | 43 | return gang; |
@@ -73,6 +75,8 @@ void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx) | |||
73 | { | 75 | { |
74 | mutex_lock(&gang->mutex); | 76 | mutex_lock(&gang->mutex); |
75 | WARN_ON(ctx->gang != gang); | 77 | WARN_ON(ctx->gang != gang); |
78 | if (!list_empty(&ctx->aff_list)) | ||
79 | list_del_init(&ctx->aff_list); | ||
76 | list_del_init(&ctx->gang_list); | 80 | list_del_init(&ctx->gang_list); |
77 | gang->contexts--; | 81 | gang->contexts--; |
78 | mutex_unlock(&gang->mutex); | 82 | mutex_unlock(&gang->mutex); |
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 7eb4d6cbcb74..b3d0dd118dd0 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -316,11 +316,107 @@ out: | |||
316 | return ret; | 316 | return ret; |
317 | } | 317 | } |
318 | 318 | ||
319 | static int spufs_create_context(struct inode *inode, | 319 | static struct spu_context * |
320 | struct dentry *dentry, | 320 | spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, |
321 | struct vfsmount *mnt, int flags, int mode) | 321 | struct file *filp) |
322 | { | ||
323 | struct spu_context *tmp, *neighbor; | ||
324 | int count, node; | ||
325 | int aff_supp; | ||
326 | |||
327 | aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next, | ||
328 | struct spu, cbe_list))->aff_list); | ||
329 | |||
330 | if (!aff_supp) | ||
331 | return ERR_PTR(-EINVAL); | ||
332 | |||
333 | if (flags & SPU_CREATE_GANG) | ||
334 | return ERR_PTR(-EINVAL); | ||
335 | |||
336 | if (flags & SPU_CREATE_AFFINITY_MEM && | ||
337 | gang->aff_ref_ctx && | ||
338 | gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM) | ||
339 | return ERR_PTR(-EEXIST); | ||
340 | |||
341 | if (gang->aff_flags & AFF_MERGED) | ||
342 | return ERR_PTR(-EBUSY); | ||
343 | |||
344 | neighbor = NULL; | ||
345 | if (flags & SPU_CREATE_AFFINITY_SPU) { | ||
346 | if (!filp || filp->f_op != &spufs_context_fops) | ||
347 | return ERR_PTR(-EINVAL); | ||
348 | |||
349 | neighbor = get_spu_context( | ||
350 | SPUFS_I(filp->f_dentry->d_inode)->i_ctx); | ||
351 | |||
352 | if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) && | ||
353 | !list_is_last(&neighbor->aff_list, &gang->aff_list_head) && | ||
354 | !list_entry(neighbor->aff_list.next, struct spu_context, | ||
355 | aff_list)->aff_head) | ||
356 | return ERR_PTR(-EEXIST); | ||
357 | |||
358 | if (gang != neighbor->gang) | ||
359 | return ERR_PTR(-EINVAL); | ||
360 | |||
361 | count = 1; | ||
362 | list_for_each_entry(tmp, &gang->aff_list_head, aff_list) | ||
363 | count++; | ||
364 | if (list_empty(&neighbor->aff_list)) | ||
365 | count++; | ||
366 | |||
367 | for (node = 0; node < MAX_NUMNODES; node++) { | ||
368 | if ((cbe_spu_info[node].n_spus - atomic_read( | ||
369 | &cbe_spu_info[node].reserved_spus)) >= count) | ||
370 | break; | ||
371 | } | ||
372 | |||
373 | if (node == MAX_NUMNODES) | ||
374 | return ERR_PTR(-EEXIST); | ||
375 | } | ||
376 | |||
377 | return neighbor; | ||
378 | } | ||
379 | |||
380 | static void | ||
381 | spufs_set_affinity(unsigned int flags, struct spu_context *ctx, | ||
382 | struct spu_context *neighbor) | ||
383 | { | ||
384 | if (flags & SPU_CREATE_AFFINITY_MEM) | ||
385 | ctx->gang->aff_ref_ctx = ctx; | ||
386 | |||
387 | if (flags & SPU_CREATE_AFFINITY_SPU) { | ||
388 | if (list_empty(&neighbor->aff_list)) { | ||
389 | list_add_tail(&neighbor->aff_list, | ||
390 | &ctx->gang->aff_list_head); | ||
391 | neighbor->aff_head = 1; | ||
392 | } | ||
393 | |||
394 | if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head) | ||
395 | || list_entry(neighbor->aff_list.next, struct spu_context, | ||
396 | aff_list)->aff_head) { | ||
397 | list_add(&ctx->aff_list, &neighbor->aff_list); | ||
398 | } else { | ||
399 | list_add_tail(&ctx->aff_list, &neighbor->aff_list); | ||
400 | if (neighbor->aff_head) { | ||
401 | neighbor->aff_head = 0; | ||
402 | ctx->aff_head = 1; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | if (!ctx->gang->aff_ref_ctx) | ||
407 | ctx->gang->aff_ref_ctx = ctx; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | static int | ||
412 | spufs_create_context(struct inode *inode, struct dentry *dentry, | ||
413 | struct vfsmount *mnt, int flags, int mode, | ||
414 | struct file *aff_filp) | ||
322 | { | 415 | { |
323 | int ret; | 416 | int ret; |
417 | int affinity; | ||
418 | struct spu_gang *gang; | ||
419 | struct spu_context *neighbor; | ||
324 | 420 | ||
325 | ret = -EPERM; | 421 | ret = -EPERM; |
326 | if ((flags & SPU_CREATE_NOSCHED) && | 422 | if ((flags & SPU_CREATE_NOSCHED) && |
@@ -336,9 +432,29 @@ static int spufs_create_context(struct inode *inode, | |||
336 | if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader) | 432 | if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader) |
337 | goto out_unlock; | 433 | goto out_unlock; |
338 | 434 | ||
435 | gang = NULL; | ||
436 | neighbor = NULL; | ||
437 | affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU); | ||
438 | if (affinity) { | ||
439 | gang = SPUFS_I(inode)->i_gang; | ||
440 | ret = -EINVAL; | ||
441 | if (!gang) | ||
442 | goto out_unlock; | ||
443 | mutex_lock(&gang->aff_mutex); | ||
444 | neighbor = spufs_assert_affinity(flags, gang, aff_filp); | ||
445 | if (IS_ERR(neighbor)) { | ||
446 | ret = PTR_ERR(neighbor); | ||
447 | goto out_aff_unlock; | ||
448 | } | ||
449 | } | ||
450 | |||
339 | ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); | 451 | ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); |
340 | if (ret) | 452 | if (ret) |
341 | goto out_unlock; | 453 | goto out_aff_unlock; |
454 | |||
455 | if (affinity) | ||
456 | spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx, | ||
457 | neighbor); | ||
342 | 458 | ||
343 | /* | 459 | /* |
344 | * get references for dget and mntget, will be released | 460 | * get references for dget and mntget, will be released |
@@ -352,6 +468,9 @@ static int spufs_create_context(struct inode *inode, | |||
352 | goto out; | 468 | goto out; |
353 | } | 469 | } |
354 | 470 | ||
471 | out_aff_unlock: | ||
472 | if (affinity) | ||
473 | mutex_unlock(&gang->aff_mutex); | ||
355 | out_unlock: | 474 | out_unlock: |
356 | mutex_unlock(&inode->i_mutex); | 475 | mutex_unlock(&inode->i_mutex); |
357 | out: | 476 | out: |
@@ -450,7 +569,8 @@ out: | |||
450 | 569 | ||
451 | static struct file_system_type spufs_type; | 570 | static struct file_system_type spufs_type; |
452 | 571 | ||
453 | long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) | 572 | long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, |
573 | struct file *filp) | ||
454 | { | 574 | { |
455 | struct dentry *dentry; | 575 | struct dentry *dentry; |
456 | int ret; | 576 | int ret; |
@@ -487,7 +607,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) | |||
487 | dentry, nd->mnt, mode); | 607 | dentry, nd->mnt, mode); |
488 | else | 608 | else |
489 | return spufs_create_context(nd->dentry->d_inode, | 609 | return spufs_create_context(nd->dentry->d_inode, |
490 | dentry, nd->mnt, flags, mode); | 610 | dentry, nd->mnt, flags, mode, filp); |
491 | 611 | ||
492 | out_dput: | 612 | out_dput: |
493 | dput(dentry); | 613 | dput(dentry); |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 03e8315f6f9e..36da17987e9c 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -109,6 +109,9 @@ struct spu_context { | |||
109 | unsigned long long class2_intr_base; /* # at last ctx switch */ | 109 | unsigned long long class2_intr_base; /* # at last ctx switch */ |
110 | unsigned long long libassist; | 110 | unsigned long long libassist; |
111 | } stats; | 111 | } stats; |
112 | |||
113 | struct list_head aff_list; | ||
114 | int aff_head; | ||
112 | }; | 115 | }; |
113 | 116 | ||
114 | struct spu_gang { | 117 | struct spu_gang { |
@@ -116,8 +119,17 @@ struct spu_gang { | |||
116 | struct mutex mutex; | 119 | struct mutex mutex; |
117 | struct kref kref; | 120 | struct kref kref; |
118 | int contexts; | 121 | int contexts; |
122 | |||
123 | struct spu_context *aff_ref_ctx; | ||
124 | struct list_head aff_list_head; | ||
125 | struct mutex aff_mutex; | ||
126 | int aff_flags; | ||
119 | }; | 127 | }; |
120 | 128 | ||
129 | /* Flag bits for spu_gang aff_flags */ | ||
130 | #define AFF_OFFSETS_SET 1 | ||
131 | #define AFF_MERGED 2 | ||
132 | |||
121 | struct mfc_dma_command { | 133 | struct mfc_dma_command { |
122 | int32_t pad; /* reserved */ | 134 | int32_t pad; /* reserved */ |
123 | uint32_t lsa; /* local storage address */ | 135 | uint32_t lsa; /* local storage address */ |
@@ -182,8 +194,8 @@ extern struct tree_descr spufs_dir_nosched_contents[]; | |||
182 | 194 | ||
183 | /* system call implementation */ | 195 | /* system call implementation */ |
184 | long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); | 196 | long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); |
185 | long spufs_create(struct nameidata *nd, | 197 | long spufs_create(struct nameidata *nd, unsigned int flags, |
186 | unsigned int flags, mode_t mode); | 198 | mode_t mode, struct file *filp); |
187 | extern const struct file_operations spufs_context_fops; | 199 | extern const struct file_operations spufs_context_fops; |
188 | 200 | ||
189 | /* gang management */ | 201 | /* gang management */ |
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 13a383c67cae..43f0fb88abbc 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c | |||
@@ -76,8 +76,8 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) | |||
76 | } | 76 | } |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | asmlinkage long sys_spu_create(const char __user *pathname, | 79 | asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags, |
80 | unsigned int flags, mode_t mode) | 80 | mode_t mode, struct file *neighbor) |
81 | { | 81 | { |
82 | char *tmp; | 82 | char *tmp; |
83 | int ret; | 83 | int ret; |
@@ -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(&nd, flags, mode); | 93 | ret = spufs_create(&nd, flags, mode, neighbor); |
94 | path_release(&nd); | 94 | path_release(&nd); |
95 | } | 95 | } |
96 | putname(tmp); | 96 | putname(tmp); |
@@ -99,8 +99,32 @@ asmlinkage long sys_spu_create(const char __user *pathname, | |||
99 | return ret; | 99 | return ret; |
100 | } | 100 | } |
101 | 101 | ||
102 | #ifndef MODULE | ||
103 | asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags, | ||
104 | mode_t mode, int neighbor_fd) | ||
105 | { | ||
106 | int fput_needed; | ||
107 | struct file *neighbor; | ||
108 | long ret; | ||
109 | |||
110 | if (flags & SPU_CREATE_AFFINITY_SPU) { | ||
111 | ret = -EBADF; | ||
112 | neighbor = fget_light(neighbor_fd, &fput_needed); | ||
113 | if (neighbor) { | ||
114 | ret = do_spu_create(pathname, flags, mode, neighbor); | ||
115 | fput_light(neighbor, fput_needed); | ||
116 | } | ||
117 | } | ||
118 | else { | ||
119 | ret = do_spu_create(pathname, flags, mode, NULL); | ||
120 | } | ||
121 | |||
122 | return ret; | ||
123 | } | ||
124 | #endif | ||
125 | |||
102 | struct spufs_calls spufs_calls = { | 126 | struct spufs_calls spufs_calls = { |
103 | .create_thread = sys_spu_create, | 127 | .create_thread = do_spu_create, |
104 | .spu_run = do_spu_run, | 128 | .spu_run = do_spu_run, |
105 | .owner = THIS_MODULE, | 129 | .owner = THIS_MODULE, |
106 | }; | 130 | }; |
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 18e558bef98e..24f352da2869 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h | |||
@@ -196,6 +196,7 @@ extern struct cbe_spu_info cbe_spu_info[]; | |||
196 | 196 | ||
197 | struct spu *spu_alloc(void); | 197 | struct spu *spu_alloc(void); |
198 | struct spu *spu_alloc_node(int node); | 198 | struct spu *spu_alloc_node(int node); |
199 | struct spu *spu_alloc_spu(struct spu *spu); | ||
199 | void spu_free(struct spu *spu); | 200 | void spu_free(struct spu *spu); |
200 | int spu_irq_class_0_bottom(struct spu *spu); | 201 | int spu_irq_class_0_bottom(struct spu *spu); |
201 | int spu_irq_class_1_bottom(struct spu *spu); | 202 | int spu_irq_class_1_bottom(struct spu *spu); |
@@ -227,7 +228,8 @@ extern long spu_sys_callback(struct spu_syscall_block *s); | |||
227 | struct file; | 228 | struct file; |
228 | extern struct spufs_calls { | 229 | extern struct spufs_calls { |
229 | asmlinkage long (*create_thread)(const char __user *name, | 230 | asmlinkage long (*create_thread)(const char __user *name, |
230 | unsigned int flags, mode_t mode); | 231 | unsigned int flags, mode_t mode, |
232 | struct file *neighbor); | ||
231 | asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, | 233 | asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, |
232 | __u32 __user *ustatus); | 234 | __u32 __user *ustatus); |
233 | struct module *owner; | 235 | struct module *owner; |
@@ -254,8 +256,10 @@ struct spu_coredump_calls { | |||
254 | #define SPU_CREATE_GANG 0x0002 | 256 | #define SPU_CREATE_GANG 0x0002 |
255 | #define SPU_CREATE_NOSCHED 0x0004 | 257 | #define SPU_CREATE_NOSCHED 0x0004 |
256 | #define SPU_CREATE_ISOLATE 0x0008 | 258 | #define SPU_CREATE_ISOLATE 0x0008 |
259 | #define SPU_CREATE_AFFINITY_SPU 0x0010 | ||
260 | #define SPU_CREATE_AFFINITY_MEM 0x0020 | ||
257 | 261 | ||
258 | #define SPU_CREATE_FLAG_ALL 0x000f /* mask of all valid flags */ | 262 | #define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */ |
259 | 263 | ||
260 | 264 | ||
261 | #ifdef CONFIG_SPU_FS_MODULE | 265 | #ifdef CONFIG_SPU_FS_MODULE |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 7a8b1e3322e0..61def7c8fbb3 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -549,7 +549,7 @@ asmlinkage long sys_inotify_rm_watch(int fd, u32 wd); | |||
549 | asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, | 549 | asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, |
550 | __u32 __user *ustatus); | 550 | __u32 __user *ustatus); |
551 | asmlinkage long sys_spu_create(const char __user *name, | 551 | asmlinkage long sys_spu_create(const char __user *name, |
552 | unsigned int flags, mode_t mode); | 552 | unsigned int flags, mode_t mode, int fd); |
553 | 553 | ||
554 | asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode, | 554 | asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode, |
555 | unsigned dev); | 555 | unsigned dev); |