aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/cell
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/cell')
-rw-r--r--arch/powerpc/platforms/cell/setup.c75
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c138
-rw-r--r--arch/powerpc/platforms/cell/spufs/Makefile2
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c252
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c114
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c599
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c206
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c62
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c419
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h55
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c51
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c10
12 files changed, 1667 insertions, 316 deletions
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index d45dc18855a..25e0f68d053 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -68,6 +68,77 @@ void cell_show_cpuinfo(struct seq_file *m)
68 of_node_put(root); 68 of_node_put(root);
69} 69}
70 70
71#ifdef CONFIG_SPARSEMEM
72static int __init find_spu_node_id(struct device_node *spe)
73{
74 unsigned int *id;
75#ifdef CONFIG_NUMA
76 struct device_node *cpu;
77 cpu = spe->parent->parent;
78 id = (unsigned int *)get_property(cpu, "node-id", NULL);
79#else
80 id = NULL;
81#endif
82 return id ? *id : 0;
83}
84
85static void __init cell_spuprop_present(struct device_node *spe,
86 const char *prop, int early)
87{
88 struct address_prop {
89 unsigned long address;
90 unsigned int len;
91 } __attribute__((packed)) *p;
92 int proplen;
93
94 unsigned long start_pfn, end_pfn, pfn;
95 int node_id;
96
97 p = (void*)get_property(spe, prop, &proplen);
98 WARN_ON(proplen != sizeof (*p));
99
100 node_id = find_spu_node_id(spe);
101
102 start_pfn = p->address >> PAGE_SHIFT;
103 end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
104
105 /* We need to call memory_present *before* the call to sparse_init,
106 but we can initialize the page structs only *after* that call.
107 Thus, we're being called twice. */
108 if (early)
109 memory_present(node_id, start_pfn, end_pfn);
110 else {
111 /* As the pages backing SPU LS and I/O are outside the range
112 of regular memory, their page structs were not initialized
113 by free_area_init. Do it here instead. */
114 for (pfn = start_pfn; pfn < end_pfn; pfn++) {
115 struct page *page = pfn_to_page(pfn);
116 set_page_links(page, ZONE_DMA, node_id, pfn);
117 set_page_count(page, 0);
118 reset_page_mapcount(page);
119 SetPageReserved(page);
120 INIT_LIST_HEAD(&page->lru);
121 }
122 }
123}
124
125static void __init cell_spumem_init(int early)
126{
127 struct device_node *node;
128 for (node = of_find_node_by_type(NULL, "spe");
129 node; node = of_find_node_by_type(node, "spe")) {
130 cell_spuprop_present(node, "local-store", early);
131 cell_spuprop_present(node, "problem", early);
132 cell_spuprop_present(node, "priv1", early);
133 cell_spuprop_present(node, "priv2", early);
134 }
135}
136#else
137static void __init cell_spumem_init(int early)
138{
139}
140#endif
141
71static void cell_progress(char *s, unsigned short hex) 142static void cell_progress(char *s, unsigned short hex)
72{ 143{
73 printk("*** %04x : %s\n", hex, s ? s : ""); 144 printk("*** %04x : %s\n", hex, s ? s : "");
@@ -99,6 +170,8 @@ static void __init cell_setup_arch(void)
99#endif 170#endif
100 171
101 mmio_nvram_init(); 172 mmio_nvram_init();
173
174 cell_spumem_init(0);
102} 175}
103 176
104/* 177/*
@@ -114,6 +187,8 @@ static void __init cell_init_early(void)
114 187
115 ppc64_interrupt_controller = IC_CELL_PIC; 188 ppc64_interrupt_controller = IC_CELL_PIC;
116 189
190 cell_spumem_init(1);
191
117 DBG(" <- cell_init_early()\n"); 192 DBG(" <- cell_init_early()\n");
118} 193}
119 194
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 44492d87cdf..408c455cff0 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -69,51 +69,49 @@ static void spu_restart_dma(struct spu *spu)
69 69
70static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) 70static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
71{ 71{
72 struct spu_priv2 __iomem *priv2; 72 struct spu_priv2 __iomem *priv2 = spu->priv2;
73 struct mm_struct *mm; 73 struct mm_struct *mm = spu->mm;
74 u64 esid, vsid;
74 75
75 pr_debug("%s\n", __FUNCTION__); 76 pr_debug("%s\n", __FUNCTION__);
76 77
77 if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) { 78 if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
79 /* SLBs are pre-loaded for context switch, so
80 * we should never get here!
81 */
78 printk("%s: invalid access during switch!\n", __func__); 82 printk("%s: invalid access during switch!\n", __func__);
79 return 1; 83 return 1;
80 } 84 }
81 85 if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
82 if (REGION_ID(ea) != USER_REGION_ID) { 86 /* Future: support kernel segments so that drivers
87 * can use SPUs.
88 */
83 pr_debug("invalid region access at %016lx\n", ea); 89 pr_debug("invalid region access at %016lx\n", ea);
84 return 1; 90 return 1;
85 } 91 }
86 92
87 priv2 = spu->priv2; 93 esid = (ea & ESID_MASK) | SLB_ESID_V;
88 mm = spu->mm; 94 vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER;
95 if (in_hugepage_area(mm->context, ea))
96 vsid |= SLB_VSID_L;
89 97
98 out_be64(&priv2->slb_index_W, spu->slb_replace);
99 out_be64(&priv2->slb_vsid_RW, vsid);
100 out_be64(&priv2->slb_esid_RW, esid);
101
102 spu->slb_replace++;
90 if (spu->slb_replace >= 8) 103 if (spu->slb_replace >= 8)
91 spu->slb_replace = 0; 104 spu->slb_replace = 0;
92 105
93 out_be64(&priv2->slb_index_W, spu->slb_replace);
94 out_be64(&priv2->slb_vsid_RW,
95 (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT)
96 | SLB_VSID_USER);
97 out_be64(&priv2->slb_esid_RW, (ea & ESID_MASK) | SLB_ESID_V);
98
99 spu_restart_dma(spu); 106 spu_restart_dma(spu);
100 107
101 pr_debug("set slb %d context %lx, ea %016lx, vsid %016lx, esid %016lx\n",
102 spu->slb_replace, mm->context.id, ea,
103 (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT)| SLB_VSID_USER,
104 (ea & ESID_MASK) | SLB_ESID_V);
105 return 0; 108 return 0;
106} 109}
107 110
108extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX 111extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
109static int __spu_trap_data_map(struct spu *spu, unsigned long ea) 112static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
110{ 113{
111 unsigned long dsisr;
112 struct spu_priv1 __iomem *priv1;
113
114 pr_debug("%s\n", __FUNCTION__); 114 pr_debug("%s\n", __FUNCTION__);
115 priv1 = spu->priv1;
116 dsisr = in_be64(&priv1->mfc_dsisr_RW);
117 115
118 /* Handle kernel space hash faults immediately. 116 /* Handle kernel space hash faults immediately.
119 User hash faults need to be deferred to process context. */ 117 User hash faults need to be deferred to process context. */
@@ -129,14 +127,17 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea)
129 return 1; 127 return 1;
130 } 128 }
131 129
130 spu->dar = ea;
131 spu->dsisr = dsisr;
132 mb();
132 wake_up(&spu->stop_wq); 133 wake_up(&spu->stop_wq);
133 return 0; 134 return 0;
134} 135}
135 136
136static int __spu_trap_mailbox(struct spu *spu) 137static int __spu_trap_mailbox(struct spu *spu)
137{ 138{
138 wake_up_all(&spu->ibox_wq); 139 if (spu->ibox_callback)
139 kill_fasync(&spu->ibox_fasync, SIGIO, POLLIN); 140 spu->ibox_callback(spu);
140 141
141 /* atomically disable SPU mailbox interrupts */ 142 /* atomically disable SPU mailbox interrupts */
142 spin_lock(&spu->register_lock); 143 spin_lock(&spu->register_lock);
@@ -171,8 +172,8 @@ static int __spu_trap_tag_group(struct spu *spu)
171 172
172static int __spu_trap_spubox(struct spu *spu) 173static int __spu_trap_spubox(struct spu *spu)
173{ 174{
174 wake_up_all(&spu->wbox_wq); 175 if (spu->wbox_callback)
175 kill_fasync(&spu->wbox_fasync, SIGIO, POLLOUT); 176 spu->wbox_callback(spu);
176 177
177 /* atomically disable SPU mailbox interrupts */ 178 /* atomically disable SPU mailbox interrupts */
178 spin_lock(&spu->register_lock); 179 spin_lock(&spu->register_lock);
@@ -220,17 +221,25 @@ static irqreturn_t
220spu_irq_class_1(int irq, void *data, struct pt_regs *regs) 221spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
221{ 222{
222 struct spu *spu; 223 struct spu *spu;
223 unsigned long stat, dar; 224 unsigned long stat, mask, dar, dsisr;
224 225
225 spu = data; 226 spu = data;
226 stat = in_be64(&spu->priv1->int_stat_class1_RW); 227
228 /* atomically read & clear class1 status. */
229 spin_lock(&spu->register_lock);
230 mask = in_be64(&spu->priv1->int_mask_class1_RW);
231 stat = in_be64(&spu->priv1->int_stat_class1_RW) & mask;
227 dar = in_be64(&spu->priv1->mfc_dar_RW); 232 dar = in_be64(&spu->priv1->mfc_dar_RW);
233 dsisr = in_be64(&spu->priv1->mfc_dsisr_RW);
234 out_be64(&spu->priv1->mfc_dsisr_RW, 0UL);
235 out_be64(&spu->priv1->int_stat_class1_RW, stat);
236 spin_unlock(&spu->register_lock);
228 237
229 if (stat & 1) /* segment fault */ 238 if (stat & 1) /* segment fault */
230 __spu_trap_data_seg(spu, dar); 239 __spu_trap_data_seg(spu, dar);
231 240
232 if (stat & 2) { /* mapping fault */ 241 if (stat & 2) { /* mapping fault */
233 __spu_trap_data_map(spu, dar); 242 __spu_trap_data_map(spu, dar, dsisr);
234 } 243 }
235 244
236 if (stat & 4) /* ls compare & suspend on get */ 245 if (stat & 4) /* ls compare & suspend on get */
@@ -239,7 +248,6 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
239 if (stat & 8) /* ls compare & suspend on put */ 248 if (stat & 8) /* ls compare & suspend on put */
240 ; 249 ;
241 250
242 out_be64(&spu->priv1->int_stat_class1_RW, stat);
243 return stat ? IRQ_HANDLED : IRQ_NONE; 251 return stat ? IRQ_HANDLED : IRQ_NONE;
244} 252}
245 253
@@ -396,8 +404,6 @@ EXPORT_SYMBOL(spu_alloc);
396void spu_free(struct spu *spu) 404void spu_free(struct spu *spu)
397{ 405{
398 down(&spu_mutex); 406 down(&spu_mutex);
399 spu->ibox_fasync = NULL;
400 spu->wbox_fasync = NULL;
401 list_add_tail(&spu->list, &spu_list); 407 list_add_tail(&spu->list, &spu_list);
402 up(&spu_mutex); 408 up(&spu_mutex);
403} 409}
@@ -405,15 +411,13 @@ EXPORT_SYMBOL(spu_free);
405 411
406static int spu_handle_mm_fault(struct spu *spu) 412static int spu_handle_mm_fault(struct spu *spu)
407{ 413{
408 struct spu_priv1 __iomem *priv1;
409 struct mm_struct *mm = spu->mm; 414 struct mm_struct *mm = spu->mm;
410 struct vm_area_struct *vma; 415 struct vm_area_struct *vma;
411 u64 ea, dsisr, is_write; 416 u64 ea, dsisr, is_write;
412 int ret; 417 int ret;
413 418
414 priv1 = spu->priv1; 419 ea = spu->dar;
415 ea = in_be64(&priv1->mfc_dar_RW); 420 dsisr = spu->dsisr;
416 dsisr = in_be64(&priv1->mfc_dsisr_RW);
417#if 0 421#if 0
418 if (!IS_VALID_EA(ea)) { 422 if (!IS_VALID_EA(ea)) {
419 return -EFAULT; 423 return -EFAULT;
@@ -476,15 +480,14 @@ bad_area:
476 480
477static int spu_handle_pte_fault(struct spu *spu) 481static int spu_handle_pte_fault(struct spu *spu)
478{ 482{
479 struct spu_priv1 __iomem *priv1;
480 u64 ea, dsisr, access, error = 0UL; 483 u64 ea, dsisr, access, error = 0UL;
481 int ret = 0; 484 int ret = 0;
482 485
483 priv1 = spu->priv1; 486 ea = spu->dar;
484 ea = in_be64(&priv1->mfc_dar_RW); 487 dsisr = spu->dsisr;
485 dsisr = in_be64(&priv1->mfc_dsisr_RW);
486 access = (_PAGE_PRESENT | _PAGE_USER);
487 if (dsisr & MFC_DSISR_PTE_NOT_FOUND) { 488 if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
489 access = (_PAGE_PRESENT | _PAGE_USER);
490 access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
488 if (hash_page(ea, access, 0x300) != 0) 491 if (hash_page(ea, access, 0x300) != 0)
489 error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; 492 error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
490 } 493 }
@@ -495,18 +498,33 @@ static int spu_handle_pte_fault(struct spu *spu)
495 else 498 else
496 error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR; 499 error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
497 } 500 }
498 if (!error) 501 spu->dar = 0UL;
502 spu->dsisr = 0UL;
503 if (!error) {
499 spu_restart_dma(spu); 504 spu_restart_dma(spu);
500 505 } else {
506 __spu_trap_invalid_dma(spu);
507 }
501 return ret; 508 return ret;
502} 509}
503 510
511static inline int spu_pending(struct spu *spu, u32 * stat)
512{
513 struct spu_problem __iomem *prob = spu->problem;
514 u64 pte_fault;
515
516 *stat = in_be32(&prob->spu_status_R);
517 pte_fault = spu->dsisr &
518 (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
519 return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
520}
521
504int spu_run(struct spu *spu) 522int spu_run(struct spu *spu)
505{ 523{
506 struct spu_problem __iomem *prob; 524 struct spu_problem __iomem *prob;
507 struct spu_priv1 __iomem *priv1; 525 struct spu_priv1 __iomem *priv1;
508 struct spu_priv2 __iomem *priv2; 526 struct spu_priv2 __iomem *priv2;
509 unsigned long status; 527 u32 status;
510 int ret; 528 int ret;
511 529
512 prob = spu->problem; 530 prob = spu->problem;
@@ -514,21 +532,15 @@ int spu_run(struct spu *spu)
514 priv2 = spu->priv2; 532 priv2 = spu->priv2;
515 533
516 /* Let SPU run. */ 534 /* Let SPU run. */
517 spu->mm = current->mm;
518 eieio(); 535 eieio();
519 out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); 536 out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
520 537
521 do { 538 do {
522 ret = wait_event_interruptible(spu->stop_wq, 539 ret = wait_event_interruptible(spu->stop_wq,
523 (!((status = in_be32(&prob->spu_status_R)) & 0x1)) 540 spu_pending(spu, &status));
524 || (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND) 541
525 || spu->class_0_pending); 542 if (spu->dsisr &
526 543 (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
527 if (status & SPU_STATUS_STOPPED_BY_STOP)
528 ret = -EAGAIN;
529 else if (status & SPU_STATUS_STOPPED_BY_HALT)
530 ret = -EIO;
531 else if (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND)
532 ret = spu_handle_pte_fault(spu); 544 ret = spu_handle_pte_fault(spu);
533 545
534 if (spu->class_0_pending) 546 if (spu->class_0_pending)
@@ -537,7 +549,9 @@ int spu_run(struct spu *spu)
537 if (!ret && signal_pending(current)) 549 if (!ret && signal_pending(current))
538 ret = -ERESTARTSYS; 550 ret = -ERESTARTSYS;
539 551
540 } while (!ret); 552 } while (!ret && !(status &
553 (SPU_STATUS_STOPPED_BY_STOP |
554 SPU_STATUS_STOPPED_BY_HALT)));
541 555
542 /* Ensure SPU is stopped. */ 556 /* Ensure SPU is stopped. */
543 out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); 557 out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
@@ -549,8 +563,6 @@ int spu_run(struct spu *spu)
549 out_be64(&priv1->tlb_invalidate_entry_W, 0UL); 563 out_be64(&priv1->tlb_invalidate_entry_W, 0UL);
550 eieio(); 564 eieio();
551 565
552 spu->mm = NULL;
553
554 /* Check for SPU breakpoint. */ 566 /* Check for SPU breakpoint. */
555 if (unlikely(current->ptrace & PT_PTRACED)) { 567 if (unlikely(current->ptrace & PT_PTRACED)) {
556 status = in_be32(&prob->spu_status_R); 568 status = in_be32(&prob->spu_status_R);
@@ -669,19 +681,21 @@ static int __init create_spu(struct device_node *spe)
669 spu->stop_code = 0; 681 spu->stop_code = 0;
670 spu->slb_replace = 0; 682 spu->slb_replace = 0;
671 spu->mm = NULL; 683 spu->mm = NULL;
684 spu->ctx = NULL;
685 spu->rq = NULL;
686 spu->pid = 0;
672 spu->class_0_pending = 0; 687 spu->class_0_pending = 0;
673 spu->flags = 0UL; 688 spu->flags = 0UL;
689 spu->dar = 0UL;
690 spu->dsisr = 0UL;
674 spin_lock_init(&spu->register_lock); 691 spin_lock_init(&spu->register_lock);
675 692
676 out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); 693 out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
677 out_be64(&spu->priv1->mfc_sr1_RW, 0x33); 694 out_be64(&spu->priv1->mfc_sr1_RW, 0x33);
678 695
679 init_waitqueue_head(&spu->stop_wq); 696 init_waitqueue_head(&spu->stop_wq);
680 init_waitqueue_head(&spu->wbox_wq); 697 spu->ibox_callback = NULL;
681 init_waitqueue_head(&spu->ibox_wq); 698 spu->wbox_callback = NULL;
682
683 spu->ibox_fasync = NULL;
684 spu->wbox_fasync = NULL;
685 699
686 down(&spu_mutex); 700 down(&spu_mutex);
687 spu->number = number++; 701 spu->number = number++;
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index b38ab747efd..ac86b2596d0 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,6 +1,6 @@
1obj-$(CONFIG_SPU_FS) += spufs.o 1obj-$(CONFIG_SPU_FS) += spufs.o
2
3spufs-y += inode.o file.o context.o switch.o syscalls.o 2spufs-y += inode.o file.o context.o switch.o syscalls.o
3spufs-y += sched.o backing_ops.o hw_ops.o
4 4
5# Rules to build switch.o with the help of SPU tool chain 5# Rules to build switch.o with the help of SPU tool chain
6SPU_CROSS := spu- 6SPU_CROSS := spu-
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
new file mode 100644
index 00000000000..caf0984064e
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -0,0 +1,252 @@
1/* backing_ops.c - query/set operations on saved SPU context.
2 *
3 * Copyright (C) IBM 2005
4 * Author: Mark Nutter <mnutter@us.ibm.com>
5 *
6 * These register operations allow SPUFS to operate on saved
7 * SPU contexts rather than hardware.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/config.h>
25#include <linux/module.h>
26#include <linux/errno.h>
27#include <linux/sched.h>
28#include <linux/kernel.h>
29#include <linux/mm.h>
30#include <linux/vmalloc.h>
31#include <linux/smp.h>
32#include <linux/smp_lock.h>
33#include <linux/stddef.h>
34#include <linux/unistd.h>
35
36#include <asm/io.h>
37#include <asm/spu.h>
38#include <asm/spu_csa.h>
39#include <asm/mmu_context.h>
40#include "spufs.h"
41
42/*
43 * Reads/writes to various problem and priv2 registers require
44 * state changes, i.e. generate SPU events, modify channel
45 * counts, etc.
46 */
47
48static void gen_spu_event(struct spu_context *ctx, u32 event)
49{
50 u64 ch0_cnt;
51 u64 ch0_data;
52 u64 ch1_data;
53
54 ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
55 ch0_data = ctx->csa.spu_chnldata_RW[0];
56 ch1_data = ctx->csa.spu_chnldata_RW[1];
57 ctx->csa.spu_chnldata_RW[0] |= event;
58 if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
59 ctx->csa.spu_chnlcnt_RW[0] = 1;
60 }
61}
62
63static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
64{
65 u32 mbox_stat;
66 int ret = 0;
67
68 spin_lock(&ctx->csa.register_lock);
69 mbox_stat = ctx->csa.prob.mb_stat_R;
70 if (mbox_stat & 0x0000ff) {
71 /* Read the first available word.
72 * Implementation note: the depth
73 * of pu_mb_R is currently 1.
74 */
75 *data = ctx->csa.prob.pu_mb_R;
76 ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
77 ctx->csa.spu_chnlcnt_RW[28] = 1;
78 gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
79 ret = 4;
80 }
81 spin_unlock(&ctx->csa.register_lock);
82 return ret;
83}
84
85static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
86{
87 return ctx->csa.prob.mb_stat_R;
88}
89
90static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
91{
92 int ret;
93
94 spin_lock(&ctx->csa.register_lock);
95 if (ctx->csa.prob.mb_stat_R & 0xff0000) {
96 /* Read the first available word.
97 * Implementation note: the depth
98 * of puint_mb_R is currently 1.
99 */
100 *data = ctx->csa.priv2.puint_mb_R;
101 ctx->csa.prob.mb_stat_R &= ~(0xff0000);
102 ctx->csa.spu_chnlcnt_RW[30] = 1;
103 gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
104 ret = 4;
105 } else {
106 /* make sure we get woken up by the interrupt */
107 ctx->csa.priv1.int_mask_class2_RW |= 0x1UL;
108 ret = 0;
109 }
110 spin_unlock(&ctx->csa.register_lock);
111 return ret;
112}
113
114static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
115{
116 int ret;
117
118 spin_lock(&ctx->csa.register_lock);
119 if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
120 int slot = ctx->csa.spu_chnlcnt_RW[29];
121 int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
122
123 /* We have space to write wbox_data.
124 * Implementation note: the depth
125 * of spu_mb_W is currently 4.
126 */
127 BUG_ON(avail != (4 - slot));
128 ctx->csa.spu_mailbox_data[slot] = data;
129 ctx->csa.spu_chnlcnt_RW[29] = ++slot;
130 ctx->csa.prob.mb_stat_R = (((4 - slot) & 0xff) << 8);
131 gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
132 ret = 4;
133 } else {
134 /* make sure we get woken up by the interrupt when space
135 becomes available */
136 ctx->csa.priv1.int_mask_class2_RW |= 0x10;
137 ret = 0;
138 }
139 spin_unlock(&ctx->csa.register_lock);
140 return ret;
141}
142
143static u32 spu_backing_signal1_read(struct spu_context *ctx)
144{
145 return ctx->csa.spu_chnldata_RW[3];
146}
147
148static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
149{
150 spin_lock(&ctx->csa.register_lock);
151 if (ctx->csa.priv2.spu_cfg_RW & 0x1)
152 ctx->csa.spu_chnldata_RW[3] |= data;
153 else
154 ctx->csa.spu_chnldata_RW[3] = data;
155 ctx->csa.spu_chnlcnt_RW[3] = 1;
156 gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
157 spin_unlock(&ctx->csa.register_lock);
158}
159
160static u32 spu_backing_signal2_read(struct spu_context *ctx)
161{
162 return ctx->csa.spu_chnldata_RW[4];
163}
164
165static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
166{
167 spin_lock(&ctx->csa.register_lock);
168 if (ctx->csa.priv2.spu_cfg_RW & 0x2)
169 ctx->csa.spu_chnldata_RW[4] |= data;
170 else
171 ctx->csa.spu_chnldata_RW[4] = data;
172 ctx->csa.spu_chnlcnt_RW[4] = 1;
173 gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
174 spin_unlock(&ctx->csa.register_lock);
175}
176
177static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
178{
179 u64 tmp;
180
181 spin_lock(&ctx->csa.register_lock);
182 tmp = ctx->csa.priv2.spu_cfg_RW;
183 if (val)
184 tmp |= 1;
185 else
186 tmp &= ~1;
187 ctx->csa.priv2.spu_cfg_RW = tmp;
188 spin_unlock(&ctx->csa.register_lock);
189}
190
191static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
192{
193 return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
194}
195
196static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
197{
198 u64 tmp;
199
200 spin_lock(&ctx->csa.register_lock);
201 tmp = ctx->csa.priv2.spu_cfg_RW;
202 if (val)
203 tmp |= 2;
204 else
205 tmp &= ~2;
206 ctx->csa.priv2.spu_cfg_RW = tmp;
207 spin_unlock(&ctx->csa.register_lock);
208}
209
210static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
211{
212 return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
213}
214
215static u32 spu_backing_npc_read(struct spu_context *ctx)
216{
217 return ctx->csa.prob.spu_npc_RW;
218}
219
220static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
221{
222 ctx->csa.prob.spu_npc_RW = val;
223}
224
225static u32 spu_backing_status_read(struct spu_context *ctx)
226{
227 return ctx->csa.prob.spu_status_R;
228}
229
230static char *spu_backing_get_ls(struct spu_context *ctx)
231{
232 return ctx->csa.lscsa->ls;
233}
234
235struct spu_context_ops spu_backing_ops = {
236 .mbox_read = spu_backing_mbox_read,
237 .mbox_stat_read = spu_backing_mbox_stat_read,
238 .ibox_read = spu_backing_ibox_read,
239 .wbox_write = spu_backing_wbox_write,
240 .signal1_read = spu_backing_signal1_read,
241 .signal1_write = spu_backing_signal1_write,
242 .signal2_read = spu_backing_signal2_read,
243 .signal2_write = spu_backing_signal2_write,
244 .signal1_type_set = spu_backing_signal1_type_set,
245 .signal1_type_get = spu_backing_signal1_type_get,
246 .signal2_type_set = spu_backing_signal2_type_set,
247 .signal2_type_get = spu_backing_signal2_type_get,
248 .npc_read = spu_backing_npc_read,
249 .npc_write = spu_backing_npc_write,
250 .status_read = spu_backing_status_read,
251 .get_ls = spu_backing_get_ls,
252};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 41eea4576b6..5d6195fc107 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -20,39 +20,38 @@
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */ 21 */
22 22
23#include <linux/fs.h>
24#include <linux/mm.h>
23#include <linux/slab.h> 25#include <linux/slab.h>
24#include <asm/spu.h> 26#include <asm/spu.h>
25#include <asm/spu_csa.h> 27#include <asm/spu_csa.h>
26#include "spufs.h" 28#include "spufs.h"
27 29
28struct spu_context *alloc_spu_context(void) 30struct spu_context *alloc_spu_context(struct address_space *local_store)
29{ 31{
30 struct spu_context *ctx; 32 struct spu_context *ctx;
31 ctx = kmalloc(sizeof *ctx, GFP_KERNEL); 33 ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
32 if (!ctx) 34 if (!ctx)
33 goto out; 35 goto out;
34 /* Future enhancement: do not call spu_alloc() 36 /* Binding to physical processor deferred
35 * here. This step should be deferred until 37 * until spu_activate().
36 * spu_run()!!
37 *
38 * More work needs to be done to read(),
39 * write(), mmap(), etc., so that operations
40 * are performed on CSA when the context is
41 * not currently being run. In this way we
42 * can support arbitrarily large number of
43 * entries in /spu, allow state queries, etc.
44 */ 38 */
45 ctx->spu = spu_alloc();
46 if (!ctx->spu)
47 goto out_free;
48 spu_init_csa(&ctx->csa); 39 spu_init_csa(&ctx->csa);
49 if (!ctx->csa.lscsa) { 40 if (!ctx->csa.lscsa) {
50 spu_free(ctx->spu);
51 goto out_free; 41 goto out_free;
52 } 42 }
53 init_rwsem(&ctx->backing_sema);
54 spin_lock_init(&ctx->mmio_lock); 43 spin_lock_init(&ctx->mmio_lock);
55 kref_init(&ctx->kref); 44 kref_init(&ctx->kref);
45 init_rwsem(&ctx->state_sema);
46 init_waitqueue_head(&ctx->ibox_wq);
47 init_waitqueue_head(&ctx->wbox_wq);
48 ctx->ibox_fasync = NULL;
49 ctx->wbox_fasync = NULL;
50 ctx->state = SPU_STATE_SAVED;
51 ctx->local_store = local_store;
52 ctx->spu = NULL;
53 ctx->ops = &spu_backing_ops;
54 ctx->owner = get_task_mm(current);
56 goto out; 55 goto out;
57out_free: 56out_free:
58 kfree(ctx); 57 kfree(ctx);
@@ -65,8 +64,11 @@ void destroy_spu_context(struct kref *kref)
65{ 64{
66 struct spu_context *ctx; 65 struct spu_context *ctx;
67 ctx = container_of(kref, struct spu_context, kref); 66 ctx = container_of(kref, struct spu_context, kref);
68 if (ctx->spu) 67 down_write(&ctx->state_sema);
69 spu_free(ctx->spu); 68 spu_deactivate(ctx);
69 ctx->ibox_fasync = NULL;
70 ctx->wbox_fasync = NULL;
71 up_write(&ctx->state_sema);
70 spu_fini_csa(&ctx->csa); 72 spu_fini_csa(&ctx->csa);
71 kfree(ctx); 73 kfree(ctx);
72} 74}
@@ -82,4 +84,80 @@ int put_spu_context(struct spu_context *ctx)
82 return kref_put(&ctx->kref, &destroy_spu_context); 84 return kref_put(&ctx->kref, &destroy_spu_context);
83} 85}
84 86
87/* give up the mm reference when the context is about to be destroyed */
88void spu_forget(struct spu_context *ctx)
89{
90 struct mm_struct *mm;
91 spu_acquire_saved(ctx);
92 mm = ctx->owner;
93 ctx->owner = NULL;
94 mmput(mm);
95 spu_release(ctx);
96}
97
98void spu_acquire(struct spu_context *ctx)
99{
100 down_read(&ctx->state_sema);
101}
102
103void spu_release(struct spu_context *ctx)
104{
105 up_read(&ctx->state_sema);
106}
107
108static void spu_unmap_mappings(struct spu_context *ctx)
109{
110 unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
111}
112
113int spu_acquire_runnable(struct spu_context *ctx)
114{
115 int ret = 0;
85 116
117 down_read(&ctx->state_sema);
118 if (ctx->state == SPU_STATE_RUNNABLE)
119 return 0;
120 /* ctx is about to be freed, can't acquire any more */
121 if (!ctx->owner) {
122 ret = -EINVAL;
123 goto out;
124 }
125 up_read(&ctx->state_sema);
126
127 down_write(&ctx->state_sema);
128 if (ctx->state == SPU_STATE_SAVED) {
129 spu_unmap_mappings(ctx);
130 ret = spu_activate(ctx, 0);
131 ctx->state = SPU_STATE_RUNNABLE;
132 }
133 downgrade_write(&ctx->state_sema);
134 if (ret)
135 goto out;
136
137 /* On success, we return holding the lock */
138 return ret;
139out:
140 /* Release here, to simplify calling code. */
141 up_read(&ctx->state_sema);
142
143 return ret;
144}
145
146void spu_acquire_saved(struct spu_context *ctx)
147{
148 down_read(&ctx->state_sema);
149
150 if (ctx->state == SPU_STATE_SAVED)
151 return;
152
153 up_read(&ctx->state_sema);
154 down_write(&ctx->state_sema);
155
156 if (ctx->state == SPU_STATE_RUNNABLE) {
157 spu_unmap_mappings(ctx);
158 spu_deactivate(ctx);
159 ctx->state = SPU_STATE_SAVED;
160 }
161
162 downgrade_write(&ctx->state_sema);
163}
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index c1e64331049..786fdb1a1cc 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -32,11 +32,13 @@
32 32
33#include "spufs.h" 33#include "spufs.h"
34 34
35
35static int 36static int
36spufs_mem_open(struct inode *inode, struct file *file) 37spufs_mem_open(struct inode *inode, struct file *file)
37{ 38{
38 struct spufs_inode_info *i = SPUFS_I(inode); 39 struct spufs_inode_info *i = SPUFS_I(inode);
39 file->private_data = i->i_ctx; 40 file->private_data = i->i_ctx;
41 file->f_mapping = i->i_ctx->local_store;
40 return 0; 42 return 0;
41} 43}
42 44
@@ -44,23 +46,16 @@ static ssize_t
44spufs_mem_read(struct file *file, char __user *buffer, 46spufs_mem_read(struct file *file, char __user *buffer,
45 size_t size, loff_t *pos) 47 size_t size, loff_t *pos)
46{ 48{
47 struct spu *spu; 49 struct spu_context *ctx = file->private_data;
48 struct spu_context *ctx; 50 char *local_store;
49 int ret; 51 int ret;
50 52
51 ctx = file->private_data; 53 spu_acquire(ctx);
52 spu = ctx->spu;
53 54
54 down_read(&ctx->backing_sema); 55 local_store = ctx->ops->get_ls(ctx);
55 if (spu->number & 0/*1*/) { 56 ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
56 ret = generic_file_read(file, buffer, size, pos);
57 goto out;
58 }
59 57
60 ret = simple_read_from_buffer(buffer, size, pos, 58 spu_release(ctx);
61 spu->local_store, LS_SIZE);
62out:
63 up_read(&ctx->backing_sema);
64 return ret; 59 return ret;
65} 60}
66 61
@@ -69,50 +64,181 @@ spufs_mem_write(struct file *file, const char __user *buffer,
69 size_t size, loff_t *pos) 64 size_t size, loff_t *pos)
70{ 65{
71 struct spu_context *ctx = file->private_data; 66 struct spu_context *ctx = file->private_data;
72 struct spu *spu = ctx->spu; 67 char *local_store;
73 68 int ret;
74 if (spu->number & 0) //1)
75 return generic_file_write(file, buffer, size, pos);
76 69
77 size = min_t(ssize_t, LS_SIZE - *pos, size); 70 size = min_t(ssize_t, LS_SIZE - *pos, size);
78 if (size <= 0) 71 if (size <= 0)
79 return -EFBIG; 72 return -EFBIG;
80 *pos += size; 73 *pos += size;
81 return copy_from_user(spu->local_store + *pos - size, 74
82 buffer, size) ? -EFAULT : size; 75 spu_acquire(ctx);
76
77 local_store = ctx->ops->get_ls(ctx);
78 ret = copy_from_user(local_store + *pos - size,
79 buffer, size) ? -EFAULT : size;
80
81 spu_release(ctx);
82 return ret;
83} 83}
84 84
85#ifdef CONFIG_SPARSEMEM
86static struct page *
87spufs_mem_mmap_nopage(struct vm_area_struct *vma,
88 unsigned long address, int *type)
89{
90 struct page *page = NOPAGE_SIGBUS;
91
92 struct spu_context *ctx = vma->vm_file->private_data;
93 unsigned long offset = address - vma->vm_start;
94 offset += vma->vm_pgoff << PAGE_SHIFT;
95
96 spu_acquire(ctx);
97
98 if (ctx->state == SPU_STATE_SAVED)
99 page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
100 else
101 page = pfn_to_page((ctx->spu->local_store_phys + offset)
102 >> PAGE_SHIFT);
103
104 spu_release(ctx);
105
106 if (type)
107 *type = VM_FAULT_MINOR;
108
109 return page;
110}
111
112static struct vm_operations_struct spufs_mem_mmap_vmops = {
113 .nopage = spufs_mem_mmap_nopage,
114};
115
85static int 116static int
86spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) 117spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
87{ 118{
88 struct spu_context *ctx = file->private_data; 119 if (!(vma->vm_flags & VM_SHARED))
89 struct spu *spu = ctx->spu; 120 return -EINVAL;
90 unsigned long pfn;
91
92 if (spu->number & 0) //1)
93 return generic_file_mmap(file, vma);
94 121
122 /* FIXME: */
95 vma->vm_flags |= VM_RESERVED; 123 vma->vm_flags |= VM_RESERVED;
96 vma->vm_page_prot = __pgprot(pgprot_val (vma->vm_page_prot) 124 vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
97 | _PAGE_NO_CACHE); 125 | _PAGE_NO_CACHE);
98 pfn = spu->local_store_phys >> PAGE_SHIFT; 126
99 /* 127 vma->vm_ops = &spufs_mem_mmap_vmops;
100 * This will work for actual SPUs, but not for vmalloc memory:
101 */
102 if (remap_pfn_range(vma, vma->vm_start, pfn,
103 vma->vm_end-vma->vm_start, vma->vm_page_prot))
104 return -EAGAIN;
105 return 0; 128 return 0;
106} 129}
130#endif
107 131
108static struct file_operations spufs_mem_fops = { 132static struct file_operations spufs_mem_fops = {
109 .open = spufs_mem_open, 133 .open = spufs_mem_open,
110 .read = spufs_mem_read, 134 .read = spufs_mem_read,
111 .write = spufs_mem_write, 135 .write = spufs_mem_write,
136 .llseek = generic_file_llseek,
137#ifdef CONFIG_SPARSEMEM
112 .mmap = spufs_mem_mmap, 138 .mmap = spufs_mem_mmap,
139#endif
140};
141
142static int
143spufs_regs_open(struct inode *inode, struct file *file)
144{
145 struct spufs_inode_info *i = SPUFS_I(inode);
146 file->private_data = i->i_ctx;
147 return 0;
148}
149
150static ssize_t
151spufs_regs_read(struct file *file, char __user *buffer,
152 size_t size, loff_t *pos)
153{
154 struct spu_context *ctx = file->private_data;
155 struct spu_lscsa *lscsa = ctx->csa.lscsa;
156 int ret;
157
158 spu_acquire_saved(ctx);
159
160 ret = simple_read_from_buffer(buffer, size, pos,
161 lscsa->gprs, sizeof lscsa->gprs);
162
163 spu_release(ctx);
164 return ret;
165}
166
167static ssize_t
168spufs_regs_write(struct file *file, const char __user *buffer,
169 size_t size, loff_t *pos)
170{
171 struct spu_context *ctx = file->private_data;
172 struct spu_lscsa *lscsa = ctx->csa.lscsa;
173 int ret;
174
175 size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
176 if (size <= 0)
177 return -EFBIG;
178 *pos += size;
179
180 spu_acquire_saved(ctx);
181
182 ret = copy_from_user(lscsa->gprs + *pos - size,
183 buffer, size) ? -EFAULT : size;
184
185 spu_release(ctx);
186 return ret;
187}
188
189static struct file_operations spufs_regs_fops = {
190 .open = spufs_regs_open,
191 .read = spufs_regs_read,
192 .write = spufs_regs_write,
113 .llseek = generic_file_llseek, 193 .llseek = generic_file_llseek,
114}; 194};
115 195
196static ssize_t
197spufs_fpcr_read(struct file *file, char __user * buffer,
198 size_t size, loff_t * pos)
199{
200 struct spu_context *ctx = file->private_data;
201 struct spu_lscsa *lscsa = ctx->csa.lscsa;
202 int ret;
203
204 spu_acquire_saved(ctx);
205
206 ret = simple_read_from_buffer(buffer, size, pos,
207 &lscsa->fpcr, sizeof(lscsa->fpcr));
208
209 spu_release(ctx);
210 return ret;
211}
212
213static ssize_t
214spufs_fpcr_write(struct file *file, const char __user * buffer,
215 size_t size, loff_t * pos)
216{
217 struct spu_context *ctx = file->private_data;
218 struct spu_lscsa *lscsa = ctx->csa.lscsa;
219 int ret;
220
221 size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
222 if (size <= 0)
223 return -EFBIG;
224 *pos += size;
225
226 spu_acquire_saved(ctx);
227
228 ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
229 buffer, size) ? -EFAULT : size;
230
231 spu_release(ctx);
232 return ret;
233}
234
235static struct file_operations spufs_fpcr_fops = {
236 .open = spufs_regs_open,
237 .read = spufs_fpcr_read,
238 .write = spufs_fpcr_write,
239 .llseek = generic_file_llseek,
240};
241
116/* generic open function for all pipe-like files */ 242/* generic open function for all pipe-like files */
117static int spufs_pipe_open(struct inode *inode, struct file *file) 243static int spufs_pipe_open(struct inode *inode, struct file *file)
118{ 244{
@@ -125,21 +251,19 @@ static int spufs_pipe_open(struct inode *inode, struct file *file)
125static ssize_t spufs_mbox_read(struct file *file, char __user *buf, 251static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
126 size_t len, loff_t *pos) 252 size_t len, loff_t *pos)
127{ 253{
128 struct spu_context *ctx; 254 struct spu_context *ctx = file->private_data;
129 struct spu_problem __iomem *prob;
130 u32 mbox_stat;
131 u32 mbox_data; 255 u32 mbox_data;
256 int ret;
132 257
133 if (len < 4) 258 if (len < 4)
134 return -EINVAL; 259 return -EINVAL;
135 260
136 ctx = file->private_data; 261 spu_acquire(ctx);
137 prob = ctx->spu->problem; 262 ret = ctx->ops->mbox_read(ctx, &mbox_data);
138 mbox_stat = in_be32(&prob->mb_stat_R); 263 spu_release(ctx);
139 if (!(mbox_stat & 0x0000ff))
140 return -EAGAIN;
141 264
142 mbox_data = in_be32(&prob->pu_mb_R); 265 if (!ret)
266 return -EAGAIN;
143 267
144 if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) 268 if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
145 return -EFAULT; 269 return -EFAULT;
@@ -155,14 +279,17 @@ static struct file_operations spufs_mbox_fops = {
155static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, 279static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
156 size_t len, loff_t *pos) 280 size_t len, loff_t *pos)
157{ 281{
158 struct spu_context *ctx; 282 struct spu_context *ctx = file->private_data;
159 u32 mbox_stat; 283 u32 mbox_stat;
160 284
161 if (len < 4) 285 if (len < 4)
162 return -EINVAL; 286 return -EINVAL;
163 287
164 ctx = file->private_data; 288 spu_acquire(ctx);
165 mbox_stat = in_be32(&ctx->spu->problem->mb_stat_R) & 0xff; 289
290 mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
291
292 spu_release(ctx);
166 293
167 if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) 294 if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
168 return -EFAULT; 295 return -EFAULT;
@@ -175,57 +302,78 @@ static struct file_operations spufs_mbox_stat_fops = {
175 .read = spufs_mbox_stat_read, 302 .read = spufs_mbox_stat_read,
176}; 303};
177 304
305/*
306 * spufs_wait
307 * Same as wait_event_interruptible(), except that here
308 * we need to call spu_release(ctx) before sleeping, and
309 * then spu_acquire(ctx) when awoken.
310 */
311
312#define spufs_wait(wq, condition) \
313({ \
314 int __ret = 0; \
315 DEFINE_WAIT(__wait); \
316 for (;;) { \
317 prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \
318 if (condition) \
319 break; \
320 if (!signal_pending(current)) { \
321 spu_release(ctx); \
322 schedule(); \
323 spu_acquire(ctx); \
324 continue; \
325 } \
326 __ret = -ERESTARTSYS; \
327 break; \
328 } \
329 finish_wait(&(wq), &__wait); \
330 __ret; \
331})
332
178/* low-level ibox access function */ 333/* low-level ibox access function */
179size_t spu_ibox_read(struct spu *spu, u32 *data) 334size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
180{ 335{
181 int ret; 336 return ctx->ops->ibox_read(ctx, data);
182 337}
183 spin_lock_irq(&spu->register_lock);
184 338
185 if (in_be32(&spu->problem->mb_stat_R) & 0xff0000) { 339static int spufs_ibox_fasync(int fd, struct file *file, int on)
186 /* read the first available word */ 340{
187 *data = in_be64(&spu->priv2->puint_mb_R); 341 struct spu_context *ctx = file->private_data;
188 ret = 4;
189 } else {
190 /* make sure we get woken up by the interrupt */
191 out_be64(&spu->priv1->int_mask_class2_RW,
192 in_be64(&spu->priv1->int_mask_class2_RW) | 0x1);
193 ret = 0;
194 }
195 342
196 spin_unlock_irq(&spu->register_lock); 343 return fasync_helper(fd, file, on, &ctx->ibox_fasync);
197 return ret;
198} 344}
199EXPORT_SYMBOL(spu_ibox_read);
200 345
201static int spufs_ibox_fasync(int fd, struct file *file, int on) 346/* interrupt-level ibox callback function. */
347void spufs_ibox_callback(struct spu *spu)
202{ 348{
203 struct spu_context *ctx; 349 struct spu_context *ctx = spu->ctx;
204 ctx = file->private_data; 350
205 return fasync_helper(fd, file, on, &ctx->spu->ibox_fasync); 351 wake_up_all(&ctx->ibox_wq);
352 kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
206} 353}
207 354
208static ssize_t spufs_ibox_read(struct file *file, char __user *buf, 355static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
209 size_t len, loff_t *pos) 356 size_t len, loff_t *pos)
210{ 357{
211 struct spu_context *ctx; 358 struct spu_context *ctx = file->private_data;
212 u32 ibox_data; 359 u32 ibox_data;
213 ssize_t ret; 360 ssize_t ret;
214 361
215 if (len < 4) 362 if (len < 4)
216 return -EINVAL; 363 return -EINVAL;
217 364
218 ctx = file->private_data; 365 spu_acquire(ctx);
219 366
220 ret = 0; 367 ret = 0;
221 if (file->f_flags & O_NONBLOCK) { 368 if (file->f_flags & O_NONBLOCK) {
222 if (!spu_ibox_read(ctx->spu, &ibox_data)) 369 if (!spu_ibox_read(ctx, &ibox_data))
223 ret = -EAGAIN; 370 ret = -EAGAIN;
224 } else { 371 } else {
225 ret = wait_event_interruptible(ctx->spu->ibox_wq, 372 ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
226 spu_ibox_read(ctx->spu, &ibox_data));
227 } 373 }
228 374
375 spu_release(ctx);
376
229 if (ret) 377 if (ret)
230 return ret; 378 return ret;
231 379
@@ -238,16 +386,17 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
238 386
239static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) 387static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
240{ 388{
241 struct spu_context *ctx; 389 struct spu_context *ctx = file->private_data;
242 struct spu_problem __iomem *prob;
243 u32 mbox_stat; 390 u32 mbox_stat;
244 unsigned int mask; 391 unsigned int mask;
245 392
246 ctx = file->private_data; 393 spu_acquire(ctx);
247 prob = ctx->spu->problem; 394
248 mbox_stat = in_be32(&prob->mb_stat_R); 395 mbox_stat = ctx->ops->mbox_stat_read(ctx);
396
397 spu_release(ctx);
249 398
250 poll_wait(file, &ctx->spu->ibox_wq, wait); 399 poll_wait(file, &ctx->ibox_wq, wait);
251 400
252 mask = 0; 401 mask = 0;
253 if (mbox_stat & 0xff0000) 402 if (mbox_stat & 0xff0000)
@@ -266,14 +415,15 @@ static struct file_operations spufs_ibox_fops = {
266static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, 415static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
267 size_t len, loff_t *pos) 416 size_t len, loff_t *pos)
268{ 417{
269 struct spu_context *ctx; 418 struct spu_context *ctx = file->private_data;
270 u32 ibox_stat; 419 u32 ibox_stat;
271 420
272 if (len < 4) 421 if (len < 4)
273 return -EINVAL; 422 return -EINVAL;
274 423
275 ctx = file->private_data; 424 spu_acquire(ctx);
276 ibox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 16) & 0xff; 425 ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
426 spu_release(ctx);
277 427
278 if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) 428 if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
279 return -EFAULT; 429 return -EFAULT;
@@ -287,75 +437,69 @@ static struct file_operations spufs_ibox_stat_fops = {
287}; 437};
288 438
289/* low-level mailbox write */ 439/* low-level mailbox write */
290size_t spu_wbox_write(struct spu *spu, u32 data) 440size_t spu_wbox_write(struct spu_context *ctx, u32 data)
291{ 441{
292 int ret; 442 return ctx->ops->wbox_write(ctx, data);
443}
293 444
294 spin_lock_irq(&spu->register_lock); 445static int spufs_wbox_fasync(int fd, struct file *file, int on)
446{
447 struct spu_context *ctx = file->private_data;
448 int ret;
295 449
296 if (in_be32(&spu->problem->mb_stat_R) & 0x00ff00) { 450 ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
297 /* we have space to write wbox_data to */
298 out_be32(&spu->problem->spu_mb_W, data);
299 ret = 4;
300 } else {
301 /* make sure we get woken up by the interrupt when space
302 becomes available */
303 out_be64(&spu->priv1->int_mask_class2_RW,
304 in_be64(&spu->priv1->int_mask_class2_RW) | 0x10);
305 ret = 0;
306 }
307 451
308 spin_unlock_irq(&spu->register_lock);
309 return ret; 452 return ret;
310} 453}
311EXPORT_SYMBOL(spu_wbox_write);
312 454
313static int spufs_wbox_fasync(int fd, struct file *file, int on) 455/* interrupt-level wbox callback function. */
456void spufs_wbox_callback(struct spu *spu)
314{ 457{
315 struct spu_context *ctx; 458 struct spu_context *ctx = spu->ctx;
316 ctx = file->private_data; 459
317 return fasync_helper(fd, file, on, &ctx->spu->wbox_fasync); 460 wake_up_all(&ctx->wbox_wq);
461 kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
318} 462}
319 463
320static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, 464static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
321 size_t len, loff_t *pos) 465 size_t len, loff_t *pos)
322{ 466{
323 struct spu_context *ctx; 467 struct spu_context *ctx = file->private_data;
324 u32 wbox_data; 468 u32 wbox_data;
325 int ret; 469 int ret;
326 470
327 if (len < 4) 471 if (len < 4)
328 return -EINVAL; 472 return -EINVAL;
329 473
330 ctx = file->private_data;
331
332 if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) 474 if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
333 return -EFAULT; 475 return -EFAULT;
334 476
477 spu_acquire(ctx);
478
335 ret = 0; 479 ret = 0;
336 if (file->f_flags & O_NONBLOCK) { 480 if (file->f_flags & O_NONBLOCK) {
337 if (!spu_wbox_write(ctx->spu, wbox_data)) 481 if (!spu_wbox_write(ctx, wbox_data))
338 ret = -EAGAIN; 482 ret = -EAGAIN;
339 } else { 483 } else {
340 ret = wait_event_interruptible(ctx->spu->wbox_wq, 484 ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
341 spu_wbox_write(ctx->spu, wbox_data));
342 } 485 }
343 486
487 spu_release(ctx);
488
344 return ret ? ret : sizeof wbox_data; 489 return ret ? ret : sizeof wbox_data;
345} 490}
346 491
347static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) 492static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
348{ 493{
349 struct spu_context *ctx; 494 struct spu_context *ctx = file->private_data;
350 struct spu_problem __iomem *prob;
351 u32 mbox_stat; 495 u32 mbox_stat;
352 unsigned int mask; 496 unsigned int mask;
353 497
354 ctx = file->private_data; 498 spu_acquire(ctx);
355 prob = ctx->spu->problem; 499 mbox_stat = ctx->ops->mbox_stat_read(ctx);
356 mbox_stat = in_be32(&prob->mb_stat_R); 500 spu_release(ctx);
357 501
358 poll_wait(file, &ctx->spu->wbox_wq, wait); 502 poll_wait(file, &ctx->wbox_wq, wait);
359 503
360 mask = 0; 504 mask = 0;
361 if (mbox_stat & 0x00ff00) 505 if (mbox_stat & 0x00ff00)
@@ -374,14 +518,15 @@ static struct file_operations spufs_wbox_fops = {
374static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, 518static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
375 size_t len, loff_t *pos) 519 size_t len, loff_t *pos)
376{ 520{
377 struct spu_context *ctx; 521 struct spu_context *ctx = file->private_data;
378 u32 wbox_stat; 522 u32 wbox_stat;
379 523
380 if (len < 4) 524 if (len < 4)
381 return -EINVAL; 525 return -EINVAL;
382 526
383 ctx = file->private_data; 527 spu_acquire(ctx);
384 wbox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 8) & 0xff; 528 wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
529 spu_release(ctx);
385 530
386 if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) 531 if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
387 return -EFAULT; 532 return -EFAULT;
@@ -395,47 +540,41 @@ static struct file_operations spufs_wbox_stat_fops = {
395}; 540};
396 541
397long spufs_run_spu(struct file *file, struct spu_context *ctx, 542long spufs_run_spu(struct file *file, struct spu_context *ctx,
398 u32 *npc, u32 *status) 543 u32 *npc, u32 *status)
399{ 544{
400 struct spu_problem __iomem *prob;
401 int ret; 545 int ret;
402 546
403 if (file->f_flags & O_NONBLOCK) { 547 ret = spu_acquire_runnable(ctx);
404 ret = -EAGAIN; 548 if (ret)
405 if (!down_write_trylock(&ctx->backing_sema)) 549 return ret;
406 goto out;
407 } else {
408 down_write(&ctx->backing_sema);
409 }
410 550
411 prob = ctx->spu->problem; 551 ctx->ops->npc_write(ctx, *npc);
412 out_be32(&prob->spu_npc_RW, *npc);
413 552
414 ret = spu_run(ctx->spu); 553 ret = spu_run(ctx->spu);
415 554
416 *status = in_be32(&prob->spu_status_R); 555 if (!ret)
417 *npc = in_be32(&prob->spu_npc_RW); 556 ret = ctx->ops->status_read(ctx);
418 557
419 up_write(&ctx->backing_sema); 558 *npc = ctx->ops->npc_read(ctx);
420 559
421out: 560 spu_release(ctx);
561 spu_yield(ctx);
422 return ret; 562 return ret;
423} 563}
424 564
425static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 565static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
426 size_t len, loff_t *pos) 566 size_t len, loff_t *pos)
427{ 567{
428 struct spu_context *ctx; 568 struct spu_context *ctx = file->private_data;
429 struct spu_problem *prob;
430 u32 data; 569 u32 data;
431 570
432 ctx = file->private_data;
433 prob = ctx->spu->problem;
434
435 if (len < 4) 571 if (len < 4)
436 return -EINVAL; 572 return -EINVAL;
437 573
438 data = in_be32(&prob->signal_notify1); 574 spu_acquire(ctx);
575 data = ctx->ops->signal1_read(ctx);
576 spu_release(ctx);
577
439 if (copy_to_user(buf, &data, 4)) 578 if (copy_to_user(buf, &data, 4))
440 return -EFAULT; 579 return -EFAULT;
441 580
@@ -446,11 +585,9 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
446 size_t len, loff_t *pos) 585 size_t len, loff_t *pos)
447{ 586{
448 struct spu_context *ctx; 587 struct spu_context *ctx;
449 struct spu_problem *prob;
450 u32 data; 588 u32 data;
451 589
452 ctx = file->private_data; 590 ctx = file->private_data;
453 prob = ctx->spu->problem;
454 591
455 if (len < 4) 592 if (len < 4)
456 return -EINVAL; 593 return -EINVAL;
@@ -458,7 +595,9 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
458 if (copy_from_user(&data, buf, 4)) 595 if (copy_from_user(&data, buf, 4))
459 return -EFAULT; 596 return -EFAULT;
460 597
461 out_be32(&prob->signal_notify1, data); 598 spu_acquire(ctx);
599 ctx->ops->signal1_write(ctx, data);
600 spu_release(ctx);
462 601
463 return 4; 602 return 4;
464} 603}
@@ -473,16 +612,17 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
473 size_t len, loff_t *pos) 612 size_t len, loff_t *pos)
474{ 613{
475 struct spu_context *ctx; 614 struct spu_context *ctx;
476 struct spu_problem *prob;
477 u32 data; 615 u32 data;
478 616
479 ctx = file->private_data; 617 ctx = file->private_data;
480 prob = ctx->spu->problem;
481 618
482 if (len < 4) 619 if (len < 4)
483 return -EINVAL; 620 return -EINVAL;
484 621
485 data = in_be32(&prob->signal_notify2); 622 spu_acquire(ctx);
623 data = ctx->ops->signal2_read(ctx);
624 spu_release(ctx);
625
486 if (copy_to_user(buf, &data, 4)) 626 if (copy_to_user(buf, &data, 4))
487 return -EFAULT; 627 return -EFAULT;
488 628
@@ -493,11 +633,9 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
493 size_t len, loff_t *pos) 633 size_t len, loff_t *pos)
494{ 634{
495 struct spu_context *ctx; 635 struct spu_context *ctx;
496 struct spu_problem *prob;
497 u32 data; 636 u32 data;
498 637
499 ctx = file->private_data; 638 ctx = file->private_data;
500 prob = ctx->spu->problem;
501 639
502 if (len < 4) 640 if (len < 4)
503 return -EINVAL; 641 return -EINVAL;
@@ -505,7 +643,9 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
505 if (copy_from_user(&data, buf, 4)) 643 if (copy_from_user(&data, buf, 4))
506 return -EFAULT; 644 return -EFAULT;
507 645
508 out_be32(&prob->signal_notify2, data); 646 spu_acquire(ctx);
647 ctx->ops->signal2_write(ctx, data);
648 spu_release(ctx);
509 649
510 return 4; 650 return 4;
511} 651}
@@ -519,23 +659,22 @@ static struct file_operations spufs_signal2_fops = {
519static void spufs_signal1_type_set(void *data, u64 val) 659static void spufs_signal1_type_set(void *data, u64 val)
520{ 660{
521 struct spu_context *ctx = data; 661 struct spu_context *ctx = data;
522 struct spu_priv2 *priv2 = ctx->spu->priv2;
523 u64 tmp;
524 662
525 spin_lock_irq(&ctx->spu->register_lock); 663 spu_acquire(ctx);
526 tmp = in_be64(&priv2->spu_cfg_RW); 664 ctx->ops->signal1_type_set(ctx, val);
527 if (val) 665 spu_release(ctx);
528 tmp |= 1;
529 else
530 tmp &= ~1;
531 out_be64(&priv2->spu_cfg_RW, tmp);
532 spin_unlock_irq(&ctx->spu->register_lock);
533} 666}
534 667
535static u64 spufs_signal1_type_get(void *data) 668static u64 spufs_signal1_type_get(void *data)
536{ 669{
537 struct spu_context *ctx = data; 670 struct spu_context *ctx = data;
538 return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0; 671 u64 ret;
672
673 spu_acquire(ctx);
674 ret = ctx->ops->signal1_type_get(ctx);
675 spu_release(ctx);
676
677 return ret;
539} 678}
540DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, 679DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
541 spufs_signal1_type_set, "%llu"); 680 spufs_signal1_type_set, "%llu");
@@ -543,23 +682,22 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
543static void spufs_signal2_type_set(void *data, u64 val) 682static void spufs_signal2_type_set(void *data, u64 val)
544{ 683{
545 struct spu_context *ctx = data; 684 struct spu_context *ctx = data;
546 struct spu_priv2 *priv2 = ctx->spu->priv2;
547 u64 tmp;
548 685
549 spin_lock_irq(&ctx->spu->register_lock); 686 spu_acquire(ctx);
550 tmp = in_be64(&priv2->spu_cfg_RW); 687 ctx->ops->signal2_type_set(ctx, val);
551 if (val) 688 spu_release(ctx);
552 tmp |= 2;
553 else
554 tmp &= ~2;
555 out_be64(&priv2->spu_cfg_RW, tmp);
556 spin_unlock_irq(&ctx->spu->register_lock);
557} 689}
558 690
559static u64 spufs_signal2_type_get(void *data) 691static u64 spufs_signal2_type_get(void *data)
560{ 692{
561 struct spu_context *ctx = data; 693 struct spu_context *ctx = data;
562 return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0; 694 u64 ret;
695
696 spu_acquire(ctx);
697 ret = ctx->ops->signal2_type_get(ctx);
698 spu_release(ctx);
699
700 return ret;
563} 701}
564DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 702DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
565 spufs_signal2_type_set, "%llu"); 703 spufs_signal2_type_set, "%llu");
@@ -567,20 +705,135 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
567static void spufs_npc_set(void *data, u64 val) 705static void spufs_npc_set(void *data, u64 val)
568{ 706{
569 struct spu_context *ctx = data; 707 struct spu_context *ctx = data;
570 out_be32(&ctx->spu->problem->spu_npc_RW, val); 708 spu_acquire(ctx);
709 ctx->ops->npc_write(ctx, val);
710 spu_release(ctx);
571} 711}
572 712
573static u64 spufs_npc_get(void *data) 713static u64 spufs_npc_get(void *data)
574{ 714{
575 struct spu_context *ctx = data; 715 struct spu_context *ctx = data;
576 u64 ret; 716 u64 ret;
577 ret = in_be32(&ctx->spu->problem->spu_npc_RW); 717 spu_acquire(ctx);
718 ret = ctx->ops->npc_read(ctx);
719 spu_release(ctx);
578 return ret; 720 return ret;
579} 721}
580DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") 722DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
581 723
724static void spufs_decr_set(void *data, u64 val)
725{
726 struct spu_context *ctx = data;
727 struct spu_lscsa *lscsa = ctx->csa.lscsa;
728 spu_acquire_saved(ctx);
729 lscsa->decr.slot[0] = (u32) val;
730 spu_release(ctx);
731}
732
733static u64 spufs_decr_get(void *data)
734{
735 struct spu_context *ctx = data;
736 struct spu_lscsa *lscsa = ctx->csa.lscsa;
737 u64 ret;
738 spu_acquire_saved(ctx);
739 ret = lscsa->decr.slot[0];
740 spu_release(ctx);
741 return ret;
742}
743DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
744 "%llx\n")
745
746static void spufs_decr_status_set(void *data, u64 val)
747{
748 struct spu_context *ctx = data;
749 struct spu_lscsa *lscsa = ctx->csa.lscsa;
750 spu_acquire_saved(ctx);
751 lscsa->decr_status.slot[0] = (u32) val;
752 spu_release(ctx);
753}
754
755static u64 spufs_decr_status_get(void *data)
756{
757 struct spu_context *ctx = data;
758 struct spu_lscsa *lscsa = ctx->csa.lscsa;
759 u64 ret;
760 spu_acquire_saved(ctx);
761 ret = lscsa->decr_status.slot[0];
762 spu_release(ctx);
763 return ret;
764}
765DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
766 spufs_decr_status_set, "%llx\n")
767
768static void spufs_spu_tag_mask_set(void *data, u64 val)
769{
770 struct spu_context *ctx = data;
771 struct spu_lscsa *lscsa = ctx->csa.lscsa;
772 spu_acquire_saved(ctx);
773 lscsa->tag_mask.slot[0] = (u32) val;
774 spu_release(ctx);
775}
776
777static u64 spufs_spu_tag_mask_get(void *data)
778{
779 struct spu_context *ctx = data;
780 struct spu_lscsa *lscsa = ctx->csa.lscsa;
781 u64 ret;
782 spu_acquire_saved(ctx);
783 ret = lscsa->tag_mask.slot[0];
784 spu_release(ctx);
785 return ret;
786}
787DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
788 spufs_spu_tag_mask_set, "%llx\n")
789
790static void spufs_event_mask_set(void *data, u64 val)
791{
792 struct spu_context *ctx = data;
793 struct spu_lscsa *lscsa = ctx->csa.lscsa;
794 spu_acquire_saved(ctx);
795 lscsa->event_mask.slot[0] = (u32) val;
796 spu_release(ctx);
797}
798
799static u64 spufs_event_mask_get(void *data)
800{
801 struct spu_context *ctx = data;
802 struct spu_lscsa *lscsa = ctx->csa.lscsa;
803 u64 ret;
804 spu_acquire_saved(ctx);
805 ret = lscsa->event_mask.slot[0];
806 spu_release(ctx);
807 return ret;
808}
809DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
810 spufs_event_mask_set, "%llx\n")
811
812static void spufs_srr0_set(void *data, u64 val)
813{
814 struct spu_context *ctx = data;
815 struct spu_lscsa *lscsa = ctx->csa.lscsa;
816 spu_acquire_saved(ctx);
817 lscsa->srr0.slot[0] = (u32) val;
818 spu_release(ctx);
819}
820
821static u64 spufs_srr0_get(void *data)
822{
823 struct spu_context *ctx = data;
824 struct spu_lscsa *lscsa = ctx->csa.lscsa;
825 u64 ret;
826 spu_acquire_saved(ctx);
827 ret = lscsa->srr0.slot[0];
828 spu_release(ctx);
829 return ret;
830}
831DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
832 "%llx\n")
833
582struct tree_descr spufs_dir_contents[] = { 834struct tree_descr spufs_dir_contents[] = {
583 { "mem", &spufs_mem_fops, 0666, }, 835 { "mem", &spufs_mem_fops, 0666, },
836 { "regs", &spufs_regs_fops, 0666, },
584 { "mbox", &spufs_mbox_fops, 0444, }, 837 { "mbox", &spufs_mbox_fops, 0444, },
585 { "ibox", &spufs_ibox_fops, 0444, }, 838 { "ibox", &spufs_ibox_fops, 0444, },
586 { "wbox", &spufs_wbox_fops, 0222, }, 839 { "wbox", &spufs_wbox_fops, 0222, },
@@ -592,5 +845,11 @@ struct tree_descr spufs_dir_contents[] = {
592 { "signal1_type", &spufs_signal1_type, 0666, }, 845 { "signal1_type", &spufs_signal1_type, 0666, },
593 { "signal2_type", &spufs_signal2_type, 0666, }, 846 { "signal2_type", &spufs_signal2_type, 0666, },
594 { "npc", &spufs_npc_ops, 0666, }, 847 { "npc", &spufs_npc_ops, 0666, },
848 { "fpcr", &spufs_fpcr_fops, 0666, },
849 { "decr", &spufs_decr_ops, 0666, },
850 { "decr_status", &spufs_decr_status_ops, 0666, },
851 { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
852 { "event_mask", &spufs_event_mask_ops, 0666, },
853 { "srr0", &spufs_srr0_ops, 0666, },
595 {}, 854 {},
596}; 855};
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
new file mode 100644
index 00000000000..2e90cae98a8
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -0,0 +1,206 @@
1/* hw_ops.c - query/set operations on active SPU context.
2 *
3 * Copyright (C) IBM 2005
4 * Author: Mark Nutter <mnutter@us.ibm.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/config.h>
22#include <linux/module.h>
23#include <linux/errno.h>
24#include <linux/sched.h>
25#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/vmalloc.h>
28#include <linux/smp.h>
29#include <linux/smp_lock.h>
30#include <linux/stddef.h>
31#include <linux/unistd.h>
32
33#include <asm/io.h>
34#include <asm/spu.h>
35#include <asm/spu_csa.h>
36#include <asm/mmu_context.h>
37#include "spufs.h"
38
39static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
40{
41 struct spu *spu = ctx->spu;
42 struct spu_problem __iomem *prob = spu->problem;
43 u32 mbox_stat;
44 int ret = 0;
45
46 spin_lock_irq(&spu->register_lock);
47 mbox_stat = in_be32(&prob->mb_stat_R);
48 if (mbox_stat & 0x0000ff) {
49 *data = in_be32(&prob->pu_mb_R);
50 ret = 4;
51 }
52 spin_unlock_irq(&spu->register_lock);
53 return ret;
54}
55
56static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
57{
58 return in_be32(&ctx->spu->problem->mb_stat_R);
59}
60
61static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
62{
63 struct spu *spu = ctx->spu;
64 struct spu_problem __iomem *prob = spu->problem;
65 struct spu_priv1 __iomem *priv1 = spu->priv1;
66 struct spu_priv2 __iomem *priv2 = spu->priv2;
67 int ret;
68
69 spin_lock_irq(&spu->register_lock);
70 if (in_be32(&prob->mb_stat_R) & 0xff0000) {
71 /* read the first available word */
72 *data = in_be64(&priv2->puint_mb_R);
73 ret = 4;
74 } else {
75 /* make sure we get woken up by the interrupt */
76 out_be64(&priv1->int_mask_class2_RW,
77 in_be64(&priv1->int_mask_class2_RW) | 0x1);
78 ret = 0;
79 }
80 spin_unlock_irq(&spu->register_lock);
81 return ret;
82}
83
84static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
85{
86 struct spu *spu = ctx->spu;
87 struct spu_problem __iomem *prob = spu->problem;
88 struct spu_priv1 __iomem *priv1 = spu->priv1;
89 int ret;
90
91 spin_lock_irq(&spu->register_lock);
92 if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
93 /* we have space to write wbox_data to */
94 out_be32(&prob->spu_mb_W, data);
95 ret = 4;
96 } else {
97 /* make sure we get woken up by the interrupt when space
98 becomes available */
99 out_be64(&priv1->int_mask_class2_RW,
100 in_be64(&priv1->int_mask_class2_RW) | 0x10);
101 ret = 0;
102 }
103 spin_unlock_irq(&spu->register_lock);
104 return ret;
105}
106
107static u32 spu_hw_signal1_read(struct spu_context *ctx)
108{
109 return in_be32(&ctx->spu->problem->signal_notify1);
110}
111
112static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
113{
114 out_be32(&ctx->spu->problem->signal_notify1, data);
115}
116
117static u32 spu_hw_signal2_read(struct spu_context *ctx)
118{
119 return in_be32(&ctx->spu->problem->signal_notify1);
120}
121
122static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
123{
124 out_be32(&ctx->spu->problem->signal_notify2, data);
125}
126
127static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
128{
129 struct spu *spu = ctx->spu;
130 struct spu_priv2 __iomem *priv2 = spu->priv2;
131 u64 tmp;
132
133 spin_lock_irq(&spu->register_lock);
134 tmp = in_be64(&priv2->spu_cfg_RW);
135 if (val)
136 tmp |= 1;
137 else
138 tmp &= ~1;
139 out_be64(&priv2->spu_cfg_RW, tmp);
140 spin_unlock_irq(&spu->register_lock);
141}
142
143static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
144{
145 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
146}
147
148static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
149{
150 struct spu *spu = ctx->spu;
151 struct spu_priv2 __iomem *priv2 = spu->priv2;
152 u64 tmp;
153
154 spin_lock_irq(&spu->register_lock);
155 tmp = in_be64(&priv2->spu_cfg_RW);
156 if (val)
157 tmp |= 2;
158 else
159 tmp &= ~2;
160 out_be64(&priv2->spu_cfg_RW, tmp);
161 spin_unlock_irq(&spu->register_lock);
162}
163
164static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
165{
166 return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
167}
168
169static u32 spu_hw_npc_read(struct spu_context *ctx)
170{
171 return in_be32(&ctx->spu->problem->spu_npc_RW);
172}
173
174static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
175{
176 out_be32(&ctx->spu->problem->spu_npc_RW, val);
177}
178
179static u32 spu_hw_status_read(struct spu_context *ctx)
180{
181 return in_be32(&ctx->spu->problem->spu_status_R);
182}
183
184static char *spu_hw_get_ls(struct spu_context *ctx)
185{
186 return ctx->spu->local_store;
187}
188
189struct spu_context_ops spu_hw_ops = {
190 .mbox_read = spu_hw_mbox_read,
191 .mbox_stat_read = spu_hw_mbox_stat_read,
192 .ibox_read = spu_hw_ibox_read,
193 .wbox_write = spu_hw_wbox_write,
194 .signal1_read = spu_hw_signal1_read,
195 .signal1_write = spu_hw_signal1_write,
196 .signal2_read = spu_hw_signal2_read,
197 .signal2_write = spu_hw_signal2_write,
198 .signal1_type_set = spu_hw_signal1_type_set,
199 .signal1_type_get = spu_hw_signal1_type_get,
200 .signal2_type_set = spu_hw_signal2_type_set,
201 .signal2_type_get = spu_hw_signal2_type_get,
202 .npc_read = spu_hw_npc_read,
203 .npc_write = spu_hw_npc_write,
204 .status_read = spu_hw_status_read,
205 .get_ls = spu_hw_get_ls,
206};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index f7aa0a6b1ce..2c3ba4eb41c 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -41,24 +41,6 @@
41 41
42static kmem_cache_t *spufs_inode_cache; 42static kmem_cache_t *spufs_inode_cache;
43 43
44/* Information about the backing dev, same as ramfs */
45#if 0
46static struct backing_dev_info spufs_backing_dev_info = {
47 .ra_pages = 0, /* No readahead */
48 .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK |
49 BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | BDI_CAP_READ_MAP |
50 BDI_CAP_WRITE_MAP,
51};
52
53static struct address_space_operations spufs_aops = {
54 .readpage = simple_readpage,
55 .prepare_write = simple_prepare_write,
56 .commit_write = simple_commit_write,
57};
58#endif
59
60/* Inode operations */
61
62static struct inode * 44static struct inode *
63spufs_alloc_inode(struct super_block *sb) 45spufs_alloc_inode(struct super_block *sb)
64{ 46{
@@ -111,9 +93,6 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr)
111{ 93{
112 struct inode *inode = dentry->d_inode; 94 struct inode *inode = dentry->d_inode;
113 95
114/* dump_stack();
115 pr_debug("ia_size %lld, i_size:%lld\n", attr->ia_size, inode->i_size);
116*/
117 if ((attr->ia_valid & ATTR_SIZE) && 96 if ((attr->ia_valid & ATTR_SIZE) &&
118 (attr->ia_size != inode->i_size)) 97 (attr->ia_size != inode->i_size))
119 return -EINVAL; 98 return -EINVAL;
@@ -127,9 +106,7 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry,
127 struct spu_context *ctx) 106 struct spu_context *ctx)
128{ 107{
129 static struct inode_operations spufs_file_iops = { 108 static struct inode_operations spufs_file_iops = {
130 .getattr = simple_getattr,
131 .setattr = spufs_setattr, 109 .setattr = spufs_setattr,
132 .unlink = simple_unlink,
133 }; 110 };
134 struct inode *inode; 111 struct inode *inode;
135 int ret; 112 int ret;
@@ -183,21 +160,32 @@ out:
183 160
184static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) 161static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
185{ 162{
186 struct dentry *dentry; 163 struct dentry *dentry, *tmp;
164 struct spu_context *ctx;
187 int err; 165 int err;
188 166
189 spin_lock(&dcache_lock);
190 /* remove all entries */ 167 /* remove all entries */
191 err = 0; 168 err = 0;
192 list_for_each_entry(dentry, &dir_dentry->d_subdirs, d_child) { 169 list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) {
193 if (d_unhashed(dentry) || !dentry->d_inode) 170 spin_lock(&dcache_lock);
194 continue;
195 atomic_dec(&dentry->d_count);
196 spin_lock(&dentry->d_lock); 171 spin_lock(&dentry->d_lock);
197 __d_drop(dentry); 172 if (!(d_unhashed(dentry)) && dentry->d_inode) {
198 spin_unlock(&dentry->d_lock); 173 dget_locked(dentry);
174 __d_drop(dentry);
175 spin_unlock(&dentry->d_lock);
176 simple_unlink(dir_dentry->d_inode, dentry);
177 spin_unlock(&dcache_lock);
178 dput(dentry);
179 } else {
180 spin_unlock(&dentry->d_lock);
181 spin_unlock(&dcache_lock);
182 }
199 } 183 }
200 spin_unlock(&dcache_lock); 184
185 /* We have to give up the mm_struct */
186 ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
187 spu_forget(ctx);
188
201 if (!err) { 189 if (!err) {
202 shrink_dcache_parent(dir_dentry); 190 shrink_dcache_parent(dir_dentry);
203 err = simple_rmdir(root, dir_dentry); 191 err = simple_rmdir(root, dir_dentry);
@@ -249,7 +237,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
249 inode->i_gid = dir->i_gid; 237 inode->i_gid = dir->i_gid;
250 inode->i_mode &= S_ISGID; 238 inode->i_mode &= S_ISGID;
251 } 239 }
252 ctx = alloc_spu_context(); 240 ctx = alloc_spu_context(inode->i_mapping);
253 SPUFS_I(inode)->i_ctx = ctx; 241 SPUFS_I(inode)->i_ctx = ctx;
254 if (!ctx) 242 if (!ctx)
255 goto out_iput; 243 goto out_iput;
@@ -368,7 +356,8 @@ spufs_parse_options(char *options, struct inode *root)
368} 356}
369 357
370static int 358static int
371spufs_create_root(struct super_block *sb, void *data) { 359spufs_create_root(struct super_block *sb, void *data)
360{
372 struct inode *inode; 361 struct inode *inode;
373 int ret; 362 int ret;
374 363
@@ -441,6 +430,10 @@ static int spufs_init(void)
441 430
442 if (!spufs_inode_cache) 431 if (!spufs_inode_cache)
443 goto out; 432 goto out;
433 if (spu_sched_init() != 0) {
434 kmem_cache_destroy(spufs_inode_cache);
435 goto out;
436 }
444 ret = register_filesystem(&spufs_type); 437 ret = register_filesystem(&spufs_type);
445 if (ret) 438 if (ret)
446 goto out_cache; 439 goto out_cache;
@@ -459,6 +452,7 @@ module_init(spufs_init);
459 452
460static void spufs_exit(void) 453static void spufs_exit(void)
461{ 454{
455 spu_sched_exit();
462 unregister_spu_syscalls(&spufs_calls); 456 unregister_spu_syscalls(&spufs_calls);
463 unregister_filesystem(&spufs_type); 457 unregister_filesystem(&spufs_type);
464 kmem_cache_destroy(spufs_inode_cache); 458 kmem_cache_destroy(spufs_inode_cache);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
new file mode 100644
index 00000000000..c0d9d83a9ac
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -0,0 +1,419 @@
1/* sched.c - SPU scheduler.
2 *
3 * Copyright (C) IBM 2005
4 * Author: Mark Nutter <mnutter@us.ibm.com>
5 *
6 * SPU scheduler, based on Linux thread priority. For now use
7 * a simple "cooperative" yield model with no preemption. SPU
8 * scheduling will eventually be preemptive: When a thread with
9 * a higher static priority gets ready to run, then an active SPU
10 * context will be preempted and returned to the waitq.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#define DEBUG 1
28#include <linux/config.h>
29#include <linux/module.h>
30#include <linux/errno.h>
31#include <linux/sched.h>
32#include <linux/kernel.h>
33#include <linux/mm.h>
34#include <linux/completion.h>
35#include <linux/vmalloc.h>
36#include <linux/smp.h>
37#include <linux/smp_lock.h>
38#include <linux/stddef.h>
39#include <linux/unistd.h>
40
41#include <asm/io.h>
42#include <asm/mmu_context.h>
43#include <asm/spu.h>
44#include <asm/spu_csa.h>
45#include "spufs.h"
46
47#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
48struct spu_prio_array {
49 atomic_t nr_blocked;
50 unsigned long bitmap[SPU_BITMAP_SIZE];
51 wait_queue_head_t waitq[MAX_PRIO];
52};
53
54/* spu_runqueue - This is the main runqueue data structure for SPUs. */
55struct spu_runqueue {
56 struct semaphore sem;
57 unsigned long nr_active;
58 unsigned long nr_idle;
59 unsigned long nr_switches;
60 struct list_head active_list;
61 struct list_head idle_list;
62 struct spu_prio_array prio;
63};
64
65static struct spu_runqueue *spu_runqueues = NULL;
66
67static inline struct spu_runqueue *spu_rq(void)
68{
69 /* Future: make this a per-NODE array,
70 * and use cpu_to_node(smp_processor_id())
71 */
72 return spu_runqueues;
73}
74
75static inline struct spu *del_idle(struct spu_runqueue *rq)
76{
77 struct spu *spu;
78
79 BUG_ON(rq->nr_idle <= 0);
80 BUG_ON(list_empty(&rq->idle_list));
81 /* Future: Move SPU out of low-power SRI state. */
82 spu = list_entry(rq->idle_list.next, struct spu, sched_list);
83 list_del_init(&spu->sched_list);
84 rq->nr_idle--;
85 return spu;
86}
87
88static inline void del_active(struct spu_runqueue *rq, struct spu *spu)
89{
90 BUG_ON(rq->nr_active <= 0);
91 BUG_ON(list_empty(&rq->active_list));
92 list_del_init(&spu->sched_list);
93 rq->nr_active--;
94}
95
96static inline void add_idle(struct spu_runqueue *rq, struct spu *spu)
97{
98 /* Future: Put SPU into low-power SRI state. */
99 list_add_tail(&spu->sched_list, &rq->idle_list);
100 rq->nr_idle++;
101}
102
103static inline void add_active(struct spu_runqueue *rq, struct spu *spu)
104{
105 rq->nr_active++;
106 rq->nr_switches++;
107 list_add_tail(&spu->sched_list, &rq->active_list);
108}
109
110static void prio_wakeup(struct spu_runqueue *rq)
111{
112 if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) {
113 int best = sched_find_first_bit(rq->prio.bitmap);
114 if (best < MAX_PRIO) {
115 wait_queue_head_t *wq = &rq->prio.waitq[best];
116 wake_up_interruptible_nr(wq, 1);
117 }
118 }
119}
120
121static void prio_wait(struct spu_runqueue *rq, u64 flags)
122{
123 int prio = current->prio;
124 wait_queue_head_t *wq = &rq->prio.waitq[prio];
125 DEFINE_WAIT(wait);
126
127 __set_bit(prio, rq->prio.bitmap);
128 atomic_inc(&rq->prio.nr_blocked);
129 prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE);
130 if (!signal_pending(current)) {
131 up(&rq->sem);
132 pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
133 current->pid, current->prio);
134 schedule();
135 down(&rq->sem);
136 }
137 finish_wait(wq, &wait);
138 atomic_dec(&rq->prio.nr_blocked);
139 if (!waitqueue_active(wq))
140 __clear_bit(prio, rq->prio.bitmap);
141}
142
143static inline int is_best_prio(struct spu_runqueue *rq)
144{
145 int best_prio;
146
147 best_prio = sched_find_first_bit(rq->prio.bitmap);
148 return (current->prio < best_prio) ? 1 : 0;
149}
150
151static inline void mm_needs_global_tlbie(struct mm_struct *mm)
152{
153 /* Global TLBIE broadcast required with SPEs. */
154#if (NR_CPUS > 1)
155 __cpus_setall(&mm->cpu_vm_mask, NR_CPUS);
156#else
157 __cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */
158#endif
159}
160
161static inline void bind_context(struct spu *spu, struct spu_context *ctx)
162{
163 pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid,
164 spu->number);
165 spu->ctx = ctx;
166 spu->flags = 0;
167 ctx->spu = spu;
168 ctx->ops = &spu_hw_ops;
169 spu->pid = current->pid;
170 spu->prio = current->prio;
171 spu->mm = ctx->owner;
172 mm_needs_global_tlbie(spu->mm);
173 spu->ibox_callback = spufs_ibox_callback;
174 spu->wbox_callback = spufs_wbox_callback;
175 mb();
176 spu_restore(&ctx->csa, spu);
177}
178
179static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
180{
181 pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__,
182 spu->pid, spu->number);
183 spu_save(&ctx->csa, spu);
184 ctx->state = SPU_STATE_SAVED;
185 spu->ibox_callback = NULL;
186 spu->wbox_callback = NULL;
187 spu->mm = NULL;
188 spu->pid = 0;
189 spu->prio = MAX_PRIO;
190 ctx->ops = &spu_backing_ops;
191 ctx->spu = NULL;
192 spu->ctx = NULL;
193}
194
195static struct spu *preempt_active(struct spu_runqueue *rq)
196{
197 struct list_head *p;
198 struct spu_context *ctx;
199 struct spu *spu;
200
201 /* Future: implement real preemption. For now just
202 * boot a lower priority ctx that is in "detached"
203 * state, i.e. on a processor but not currently in
204 * spu_run().
205 */
206 list_for_each(p, &rq->active_list) {
207 spu = list_entry(p, struct spu, sched_list);
208 if (current->prio < spu->prio) {
209 ctx = spu->ctx;
210 if (down_write_trylock(&ctx->state_sema)) {
211 if (ctx->state != SPU_STATE_RUNNABLE) {
212 up_write(&ctx->state_sema);
213 continue;
214 }
215 pr_debug("%s: booting pid=%d from SPU %d\n",
216 __FUNCTION__, spu->pid, spu->number);
217 del_active(rq, spu);
218 up(&rq->sem);
219 unbind_context(spu, ctx);
220 up_write(&ctx->state_sema);
221 return spu;
222 }
223 }
224 }
225 return NULL;
226}
227
228static struct spu *get_idle_spu(u64 flags)
229{
230 struct spu_runqueue *rq;
231 struct spu *spu = NULL;
232
233 rq = spu_rq();
234 down(&rq->sem);
235 for (;;) {
236 if (rq->nr_idle > 0) {
237 if (is_best_prio(rq)) {
238 /* Fall through. */
239 spu = del_idle(rq);
240 break;
241 } else {
242 prio_wakeup(rq);
243 up(&rq->sem);
244 yield();
245 if (signal_pending(current)) {
246 return NULL;
247 }
248 rq = spu_rq();
249 down(&rq->sem);
250 continue;
251 }
252 } else {
253 if (is_best_prio(rq)) {
254 if ((spu = preempt_active(rq)) != NULL)
255 return spu;
256 }
257 prio_wait(rq, flags);
258 if (signal_pending(current)) {
259 prio_wakeup(rq);
260 spu = NULL;
261 break;
262 }
263 continue;
264 }
265 }
266 up(&rq->sem);
267 return spu;
268}
269
270static void put_idle_spu(struct spu *spu)
271{
272 struct spu_runqueue *rq = spu->rq;
273
274 down(&rq->sem);
275 add_idle(rq, spu);
276 prio_wakeup(rq);
277 up(&rq->sem);
278}
279
280static int get_active_spu(struct spu *spu)
281{
282 struct spu_runqueue *rq = spu->rq;
283 struct list_head *p;
284 struct spu *tmp;
285 int rc = 0;
286
287 down(&rq->sem);
288 list_for_each(p, &rq->active_list) {
289 tmp = list_entry(p, struct spu, sched_list);
290 if (tmp == spu) {
291 del_active(rq, spu);
292 rc = 1;
293 break;
294 }
295 }
296 up(&rq->sem);
297 return rc;
298}
299
300static void put_active_spu(struct spu *spu)
301{
302 struct spu_runqueue *rq = spu->rq;
303
304 down(&rq->sem);
305 add_active(rq, spu);
306 up(&rq->sem);
307}
308
309/* Lock order:
310 * spu_activate() & spu_deactivate() require the
311 * caller to have down_write(&ctx->state_sema).
312 *
313 * The rq->sem is breifly held (inside or outside a
314 * given ctx lock) for list management, but is never
315 * held during save/restore.
316 */
317
318int spu_activate(struct spu_context *ctx, u64 flags)
319{
320 struct spu *spu;
321
322 if (ctx->spu)
323 return 0;
324 spu = get_idle_spu(flags);
325 if (!spu)
326 return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
327 bind_context(spu, ctx);
328 put_active_spu(spu);
329 return 0;
330}
331
332void spu_deactivate(struct spu_context *ctx)
333{
334 struct spu *spu;
335 int needs_idle;
336
337 spu = ctx->spu;
338 if (!spu)
339 return;
340 needs_idle = get_active_spu(spu);
341 unbind_context(spu, ctx);
342 if (needs_idle)
343 put_idle_spu(spu);
344}
345
346void spu_yield(struct spu_context *ctx)
347{
348 struct spu *spu;
349
350 if (!down_write_trylock(&ctx->state_sema))
351 return;
352 spu = ctx->spu;
353 if ((ctx->state == SPU_STATE_RUNNABLE) &&
354 (sched_find_first_bit(spu->rq->prio.bitmap) <= current->prio)) {
355 pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number);
356 spu_deactivate(ctx);
357 ctx->state = SPU_STATE_SAVED;
358 }
359 up_write(&ctx->state_sema);
360}
361
362int __init spu_sched_init(void)
363{
364 struct spu_runqueue *rq;
365 struct spu *spu;
366 int i;
367
368 rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL);
369 if (!rq) {
370 printk(KERN_WARNING "%s: Unable to allocate runqueues.\n",
371 __FUNCTION__);
372 return 1;
373 }
374 memset(rq, 0, sizeof(struct spu_runqueue));
375 init_MUTEX(&rq->sem);
376 INIT_LIST_HEAD(&rq->active_list);
377 INIT_LIST_HEAD(&rq->idle_list);
378 rq->nr_active = 0;
379 rq->nr_idle = 0;
380 rq->nr_switches = 0;
381 atomic_set(&rq->prio.nr_blocked, 0);
382 for (i = 0; i < MAX_PRIO; i++) {
383 init_waitqueue_head(&rq->prio.waitq[i]);
384 __clear_bit(i, rq->prio.bitmap);
385 }
386 __set_bit(MAX_PRIO, rq->prio.bitmap);
387 for (;;) {
388 spu = spu_alloc();
389 if (!spu)
390 break;
391 pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number);
392 add_idle(rq, spu);
393 spu->rq = rq;
394 }
395 if (!rq->nr_idle) {
396 printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__);
397 kfree(rq);
398 return 1;
399 }
400 return 0;
401}
402
403void __exit spu_sched_exit(void)
404{
405 struct spu_runqueue *rq = spu_rq();
406 struct spu *spu;
407
408 if (!rq) {
409 printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__);
410 return;
411 }
412 while (rq->nr_idle > 0) {
413 spu = del_idle(rq);
414 if (!spu)
415 break;
416 spu_free(spu);
417 }
418 kfree(rq);
419}
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 67aff57faf6..93c6a053756 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -35,15 +35,50 @@ enum {
35 SPUFS_MAGIC = 0x23c9b64e, 35 SPUFS_MAGIC = 0x23c9b64e,
36}; 36};
37 37
38struct spu_context_ops;
39
38struct spu_context { 40struct spu_context {
39 struct spu *spu; /* pointer to a physical SPU */ 41 struct spu *spu; /* pointer to a physical SPU */
40 struct spu_state csa; /* SPU context save area. */ 42 struct spu_state csa; /* SPU context save area. */
41 struct rw_semaphore backing_sema; /* protects the above */
42 spinlock_t mmio_lock; /* protects mmio access */ 43 spinlock_t mmio_lock; /* protects mmio access */
44 struct address_space *local_store;/* local store backing store */
45
46 enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
47 struct rw_semaphore state_sema;
48
49 struct mm_struct *owner;
43 50
44 struct kref kref; 51 struct kref kref;
52 wait_queue_head_t ibox_wq;
53 wait_queue_head_t wbox_wq;
54 struct fasync_struct *ibox_fasync;
55 struct fasync_struct *wbox_fasync;
56 struct spu_context_ops *ops;
57};
58
59/* SPU context query/set operations. */
60struct spu_context_ops {
61 int (*mbox_read) (struct spu_context * ctx, u32 * data);
62 u32(*mbox_stat_read) (struct spu_context * ctx);
63 int (*ibox_read) (struct spu_context * ctx, u32 * data);
64 int (*wbox_write) (struct spu_context * ctx, u32 data);
65 u32(*signal1_read) (struct spu_context * ctx);
66 void (*signal1_write) (struct spu_context * ctx, u32 data);
67 u32(*signal2_read) (struct spu_context * ctx);
68 void (*signal2_write) (struct spu_context * ctx, u32 data);
69 void (*signal1_type_set) (struct spu_context * ctx, u64 val);
70 u64(*signal1_type_get) (struct spu_context * ctx);
71 void (*signal2_type_set) (struct spu_context * ctx, u64 val);
72 u64(*signal2_type_get) (struct spu_context * ctx);
73 u32(*npc_read) (struct spu_context * ctx);
74 void (*npc_write) (struct spu_context * ctx, u32 data);
75 u32(*status_read) (struct spu_context * ctx);
76 char*(*get_ls) (struct spu_context * ctx);
45}; 77};
46 78
79extern struct spu_context_ops spu_hw_ops;
80extern struct spu_context_ops spu_backing_ops;
81
47struct spufs_inode_info { 82struct spufs_inode_info {
48 struct spu_context *i_ctx; 83 struct spu_context *i_ctx;
49 struct inode vfs_inode; 84 struct inode vfs_inode;
@@ -60,14 +95,28 @@ long spufs_create_thread(struct nameidata *nd, const char *name,
60 unsigned int flags, mode_t mode); 95 unsigned int flags, mode_t mode);
61 96
62/* context management */ 97/* context management */
63struct spu_context * alloc_spu_context(void); 98struct spu_context * alloc_spu_context(struct address_space *local_store);
64void destroy_spu_context(struct kref *kref); 99void destroy_spu_context(struct kref *kref);
65struct spu_context * get_spu_context(struct spu_context *ctx); 100struct spu_context * get_spu_context(struct spu_context *ctx);
66int put_spu_context(struct spu_context *ctx); 101int put_spu_context(struct spu_context *ctx);
67 102
103void spu_forget(struct spu_context *ctx);
68void spu_acquire(struct spu_context *ctx); 104void spu_acquire(struct spu_context *ctx);
69void spu_release(struct spu_context *ctx); 105void spu_release(struct spu_context *ctx);
70void spu_acquire_runnable(struct spu_context *ctx); 106int spu_acquire_runnable(struct spu_context *ctx);
71void spu_acquire_saved(struct spu_context *ctx); 107void spu_acquire_saved(struct spu_context *ctx);
72 108
109int spu_activate(struct spu_context *ctx, u64 flags);
110void spu_deactivate(struct spu_context *ctx);
111void spu_yield(struct spu_context *ctx);
112int __init spu_sched_init(void);
113void __exit spu_sched_exit(void);
114
115size_t spu_wbox_write(struct spu_context *ctx, u32 data);
116size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
117
118/* irq callback funcs. */
119void spufs_ibox_callback(struct spu *spu);
120void spufs_wbox_callback(struct spu *spu);
121
73#endif 122#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 70345b0524f..51266257b0a 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -646,7 +646,7 @@ static inline void save_spu_mb(struct spu_state *csa, struct spu *spu)
646 eieio(); 646 eieio();
647 csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW); 647 csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW);
648 for (i = 0; i < 4; i++) { 648 for (i = 0; i < 4; i++) {
649 csa->pu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW); 649 csa->spu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW);
650 } 650 }
651 out_be64(&priv2->spu_chnlcnt_RW, 0UL); 651 out_be64(&priv2->spu_chnlcnt_RW, 0UL);
652 eieio(); 652 eieio();
@@ -1667,7 +1667,7 @@ static inline void restore_spu_mb(struct spu_state *csa, struct spu *spu)
1667 eieio(); 1667 eieio();
1668 out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]); 1668 out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]);
1669 for (i = 0; i < 4; i++) { 1669 for (i = 0; i < 4; i++) {
1670 out_be64(&priv2->spu_chnldata_RW, csa->pu_mailbox_data[i]); 1670 out_be64(&priv2->spu_chnldata_RW, csa->spu_mailbox_data[i]);
1671 } 1671 }
1672 eieio(); 1672 eieio();
1673} 1673}
@@ -2079,7 +2079,10 @@ int spu_save(struct spu_state *prev, struct spu *spu)
2079 acquire_spu_lock(spu); /* Step 1. */ 2079 acquire_spu_lock(spu); /* Step 1. */
2080 rc = __do_spu_save(prev, spu); /* Steps 2-53. */ 2080 rc = __do_spu_save(prev, spu); /* Steps 2-53. */
2081 release_spu_lock(spu); 2081 release_spu_lock(spu);
2082 2082 if (rc) {
2083 panic("%s failed on SPU[%d], rc=%d.\n",
2084 __func__, spu->number, rc);
2085 }
2083 return rc; 2086 return rc;
2084} 2087}
2085 2088
@@ -2098,34 +2101,31 @@ int spu_restore(struct spu_state *new, struct spu *spu)
2098 2101
2099 acquire_spu_lock(spu); 2102 acquire_spu_lock(spu);
2100 harvest(NULL, spu); 2103 harvest(NULL, spu);
2104 spu->stop_code = 0;
2105 spu->dar = 0;
2106 spu->dsisr = 0;
2107 spu->slb_replace = 0;
2108 spu->class_0_pending = 0;
2101 rc = __do_spu_restore(new, spu); 2109 rc = __do_spu_restore(new, spu);
2102 release_spu_lock(spu); 2110 release_spu_lock(spu);
2103 2111 if (rc) {
2112 panic("%s failed on SPU[%d] rc=%d.\n",
2113 __func__, spu->number, rc);
2114 }
2104 return rc; 2115 return rc;
2105} 2116}
2106 2117
2107/** 2118/**
2108 * spu_switch - SPU context switch (save + restore). 2119 * spu_harvest - SPU harvest (reset) operation
2109 * @prev: pointer to SPU context save area, to be saved.
2110 * @new: pointer to SPU context save area, to be restored.
2111 * @spu: pointer to SPU iomem structure. 2120 * @spu: pointer to SPU iomem structure.
2112 * 2121 *
2113 * Perform save, then restore. Only harvest if the 2122 * Perform SPU harvest (reset) operation.
2114 * save fails, as cleanup is otherwise not needed.
2115 */ 2123 */
2116int spu_switch(struct spu_state *prev, struct spu_state *new, struct spu *spu) 2124void spu_harvest(struct spu *spu)
2117{ 2125{
2118 int rc; 2126 acquire_spu_lock(spu);
2119 2127 harvest(NULL, spu);
2120 acquire_spu_lock(spu); /* Save, Step 1. */
2121 rc = __do_spu_save(prev, spu); /* Save, Steps 2-53. */
2122 if (rc != 0) {
2123 harvest(prev, spu);
2124 }
2125 rc = __do_spu_restore(new, spu);
2126 release_spu_lock(spu); 2128 release_spu_lock(spu);
2127
2128 return rc;
2129} 2129}
2130 2130
2131static void init_prob(struct spu_state *csa) 2131static void init_prob(struct spu_state *csa)
@@ -2181,6 +2181,7 @@ static void init_priv2(struct spu_state *csa)
2181void spu_init_csa(struct spu_state *csa) 2181void spu_init_csa(struct spu_state *csa)
2182{ 2182{
2183 struct spu_lscsa *lscsa; 2183 struct spu_lscsa *lscsa;
2184 unsigned char *p;
2184 2185
2185 if (!csa) 2186 if (!csa)
2186 return; 2187 return;
@@ -2192,6 +2193,11 @@ void spu_init_csa(struct spu_state *csa)
2192 2193
2193 memset(lscsa, 0, sizeof(struct spu_lscsa)); 2194 memset(lscsa, 0, sizeof(struct spu_lscsa));
2194 csa->lscsa = lscsa; 2195 csa->lscsa = lscsa;
2196 csa->register_lock = SPIN_LOCK_UNLOCKED;
2197
2198 /* Set LS pages reserved to allow for user-space mapping. */
2199 for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
2200 SetPageReserved(vmalloc_to_page(p));
2195 2201
2196 init_prob(csa); 2202 init_prob(csa);
2197 init_priv1(csa); 2203 init_priv1(csa);
@@ -2200,5 +2206,10 @@ void spu_init_csa(struct spu_state *csa)
2200 2206
2201void spu_fini_csa(struct spu_state *csa) 2207void spu_fini_csa(struct spu_state *csa)
2202{ 2208{
2209 /* Clear reserved bit before vfree. */
2210 unsigned char *p;
2211 for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
2212 ClearPageReserved(vmalloc_to_page(p));
2213
2203 vfree(csa->lscsa); 2214 vfree(csa->lscsa);
2204} 2215}
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 3f71bb5e9d8..17a2b51c94b 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -36,7 +36,7 @@ long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus)
36 u32 npc, status; 36 u32 npc, status;
37 37
38 ret = -EFAULT; 38 ret = -EFAULT;
39 if (get_user(npc, unpc)) 39 if (get_user(npc, unpc) || get_user(status, ustatus))
40 goto out; 40 goto out;
41 41
42 ret = -EINVAL; 42 ret = -EINVAL;
@@ -46,13 +46,7 @@ long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus)
46 i = SPUFS_I(filp->f_dentry->d_inode); 46 i = SPUFS_I(filp->f_dentry->d_inode);
47 ret = spufs_run_spu(filp, i->i_ctx, &npc, &status); 47 ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
48 48
49 if (ret ==-EAGAIN || ret == -EIO) 49 if (put_user(npc, unpc) || put_user(status, ustatus))
50 ret = status;
51
52 if (put_user(npc, unpc))
53 ret = -EFAULT;
54
55 if (ustatus && put_user(status, ustatus))
56 ret = -EFAULT; 50 ret = -EFAULT;
57out: 51out:
58 return ret; 52 return ret;