aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/cell/spu_syscalls.c17
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c1
-rw-r--r--arch/powerpc/platforms/cell/spufs/gang.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c132
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h16
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c32
-rw-r--r--include/asm-powerpc/spu.h8
-rw-r--r--include/linux/syscalls.h2
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
36asmlinkage long sys_spu_create(const char __user *name, 36asmlinkage 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
40out: 42out:
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
319static int spufs_create_context(struct inode *inode, 319static struct spu_context *
320 struct dentry *dentry, 320spufs_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
380static void
381spufs_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
411static int
412spufs_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
471out_aff_unlock:
472 if (affinity)
473 mutex_unlock(&gang->aff_mutex);
355out_unlock: 474out_unlock:
356 mutex_unlock(&inode->i_mutex); 475 mutex_unlock(&inode->i_mutex);
357out: 476out:
@@ -450,7 +569,8 @@ out:
450 569
451static struct file_system_type spufs_type; 570static struct file_system_type spufs_type;
452 571
453long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) 572long 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
492out_dput: 612out_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
114struct spu_gang { 117struct 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
121struct mfc_dma_command { 133struct 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 */
184long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); 196long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
185long spufs_create(struct nameidata *nd, 197long spufs_create(struct nameidata *nd, unsigned int flags,
186 unsigned int flags, mode_t mode); 198 mode_t mode, struct file *filp);
187extern const struct file_operations spufs_context_fops; 199extern 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
79asmlinkage long sys_spu_create(const char __user *pathname, 79asmlinkage 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
103asmlinkage 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
102struct spufs_calls spufs_calls = { 126struct 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
197struct spu *spu_alloc(void); 197struct spu *spu_alloc(void);
198struct spu *spu_alloc_node(int node); 198struct spu *spu_alloc_node(int node);
199struct spu *spu_alloc_spu(struct spu *spu);
199void spu_free(struct spu *spu); 200void spu_free(struct spu *spu);
200int spu_irq_class_0_bottom(struct spu *spu); 201int spu_irq_class_0_bottom(struct spu *spu);
201int spu_irq_class_1_bottom(struct spu *spu); 202int spu_irq_class_1_bottom(struct spu *spu);
@@ -227,7 +228,8 @@ extern long spu_sys_callback(struct spu_syscall_block *s);
227struct file; 228struct file;
228extern struct spufs_calls { 229extern 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);
549asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, 549asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
550 __u32 __user *ustatus); 550 __u32 __user *ustatus);
551asmlinkage long sys_spu_create(const char __user *name, 551asmlinkage 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
554asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode, 554asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode,
555 unsigned dev); 555 unsigned dev);