Merge branch 'mv-merge'
[sfrench/cifs-2.6.git] / arch / powerpc / platforms / cell / spu_base.c
index b71313ae752666c76e59f62eb70cd340fb22b466..269dda4fd0b4ff23cb2657087cf6bd34adc09739 100644 (file)
@@ -20,7 +20,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define DEBUG 1
+#undef DEBUG
 
 #include <linux/interrupt.h>
 #include <linux/list.h>
@@ -32,7 +32,7 @@
 
 #include <asm/io.h>
 #include <asm/prom.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/spu.h>
 #include <asm/mmu_context.h>
 
@@ -63,7 +63,7 @@ static void spu_restart_dma(struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
 
-       if (!test_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags))
+       if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
                out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
 }
 
@@ -75,7 +75,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
 
        pr_debug("%s\n", __FUNCTION__);
 
-       if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+       if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
                /* SLBs are pre-loaded for context switch, so
                 * we should never get here!
                 */
@@ -111,7 +111,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
 extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
 static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
 {
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea);
 
        /* Handle kernel space hash faults immediately.
           User hash faults need to be deferred to process context. */
@@ -122,7 +122,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
                return 0;
        }
 
-       if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+       if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
                printk("%s: invalid access during switch!\n", __func__);
                return 1;
        }
@@ -130,7 +130,8 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
        spu->dar = ea;
        spu->dsisr = dsisr;
        mb();
-       wake_up(&spu->stop_wq);
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
        return 0;
 }
 
@@ -141,8 +142,7 @@ static int __spu_trap_mailbox(struct spu *spu)
 
        /* atomically disable SPU mailbox interrupts */
        spin_lock(&spu->register_lock);
-       out_be64(&spu->priv1->int_mask_class2_RW,
-               in_be64(&spu->priv1->int_mask_class2_RW) & ~0x1);
+       spu_int_mask_and(spu, 2, ~0x1);
        spin_unlock(&spu->register_lock);
        return 0;
 }
@@ -151,7 +151,8 @@ static int __spu_trap_stop(struct spu *spu)
 {
        pr_debug("%s\n", __FUNCTION__);
        spu->stop_code = in_be32(&spu->problem->spu_status_R);
-       wake_up(&spu->stop_wq);
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
        return 0;
 }
 
@@ -159,14 +160,15 @@ static int __spu_trap_halt(struct spu *spu)
 {
        pr_debug("%s\n", __FUNCTION__);
        spu->stop_code = in_be32(&spu->problem->spu_status_R);
-       wake_up(&spu->stop_wq);
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
        return 0;
 }
 
 static int __spu_trap_tag_group(struct spu *spu)
 {
        pr_debug("%s\n", __FUNCTION__);
-       /* wake_up(&spu->dma_wq); */
+       spu->mfc_callback(spu);
        return 0;
 }
 
@@ -177,8 +179,7 @@ static int __spu_trap_spubox(struct spu *spu)
 
        /* atomically disable SPU mailbox interrupts */
        spin_lock(&spu->register_lock);
-       out_be64(&spu->priv1->int_mask_class2_RW,
-               in_be64(&spu->priv1->int_mask_class2_RW) & ~0x10);
+       spu_int_mask_and(spu, 2, ~0x10);
        spin_unlock(&spu->register_lock);
        return 0;
 }
@@ -190,19 +191,23 @@ spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
 
        spu = data;
        spu->class_0_pending = 1;
-       wake_up(&spu->stop_wq);
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
 
        return IRQ_HANDLED;
 }
 
-static int
+int
 spu_irq_class_0_bottom(struct spu *spu)
 {
-       unsigned long stat;
+       unsigned long stat, mask;
 
        spu->class_0_pending = 0;
 
-       stat = in_be64(&spu->priv1->int_stat_class0_RW);
+       mask = spu_int_mask_get(spu, 0);
+       stat = spu_int_stat_get(spu, 0);
+
+       stat &= mask;
 
        if (stat & 1) /* invalid MFC DMA */
                __spu_trap_invalid_dma(spu);
@@ -213,9 +218,11 @@ spu_irq_class_0_bottom(struct spu *spu)
        if (stat & 4) /* error on SPU */
                __spu_trap_error(spu);
 
-       out_be64(&spu->priv1->int_stat_class0_RW, stat);
-       return 0;
+       spu_int_stat_clear(spu, 0, stat);
+
+       return (stat & 0x7) ? -EIO : 0;
 }
+EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
 
 static irqreturn_t
 spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
@@ -227,13 +234,16 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
 
        /* atomically read & clear class1 status. */
        spin_lock(&spu->register_lock);
-       mask  = in_be64(&spu->priv1->int_mask_class1_RW);
-       stat  = in_be64(&spu->priv1->int_stat_class1_RW) & mask;
-       dar   = in_be64(&spu->priv1->mfc_dar_RW);
-       dsisr = in_be64(&spu->priv1->mfc_dsisr_RW);
-       out_be64(&spu->priv1->mfc_dsisr_RW, 0UL);
-       out_be64(&spu->priv1->int_stat_class1_RW, stat);
+       mask  = spu_int_mask_get(spu, 1);
+       stat  = spu_int_stat_get(spu, 1) & mask;
+       dar   = spu_mfc_dar_get(spu);
+       dsisr = spu_mfc_dsisr_get(spu);
+       if (stat & 2) /* mapping fault */
+               spu_mfc_dsisr_set(spu, 0ul);
+       spu_int_stat_clear(spu, 1, stat);
        spin_unlock(&spu->register_lock);
+       pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat,
+                       dar, dsisr);
 
        if (stat & 1) /* segment fault */
                __spu_trap_data_seg(spu, dar);
@@ -250,19 +260,22 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
 
        return stat ? IRQ_HANDLED : IRQ_NONE;
 }
+EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
 
 static irqreturn_t
 spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
 {
        struct spu *spu;
        unsigned long stat;
+       unsigned long mask;
 
        spu = data;
-       stat = in_be64(&spu->priv1->int_stat_class2_RW);
+       stat = spu_int_stat_get(spu, 2);
+       mask = spu_int_mask_get(spu, 2);
 
-       pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat,
-               in_be64(&spu->priv1->int_mask_class2_RW));
+       pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
 
+       stat &= mask;
 
        if (stat & 1)  /* PPC core mailbox */
                __spu_trap_mailbox(spu);
@@ -279,7 +292,7 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
        if (stat & 0x10) /* SPU mailbox threshold */
                __spu_trap_spubox(spu);
 
-       out_be64(&spu->priv1->int_stat_class2_RW, stat);
+       spu_int_stat_clear(spu, 2, stat);
        return stat ? IRQ_HANDLED : IRQ_NONE;
 }
 
@@ -296,21 +309,18 @@ spu_request_irqs(struct spu *spu)
                 spu_irq_class_0, 0, spu->irq_c0, spu);
        if (ret)
                goto out;
-       out_be64(&spu->priv1->int_mask_class0_RW, 0x7);
 
        snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
        ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
                 spu_irq_class_1, 0, spu->irq_c1, spu);
        if (ret)
                goto out1;
-       out_be64(&spu->priv1->int_mask_class1_RW, 0x3);
 
        snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
        ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
                 spu_irq_class_2, 0, spu->irq_c2, spu);
        if (ret)
                goto out2;
-       out_be64(&spu->priv1->int_mask_class2_RW, 0xe);
        goto out;
 
 out2:
@@ -334,7 +344,7 @@ spu_free_irqs(struct spu *spu)
 }
 
 static LIST_HEAD(spu_list);
-static DECLARE_MUTEX(spu_mutex);
+static DEFINE_MUTEX(spu_mutex);
 
 static void spu_init_channels(struct spu *spu)
 {
@@ -349,7 +359,7 @@ static void spu_init_channels(struct spu *spu)
                { 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, },
                { 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, },
        };
-       struct spu_priv2 *priv2;
+       struct spu_priv2 __iomem *priv2;
        int i;
 
        priv2 = spu->priv2;
@@ -370,18 +380,11 @@ static void spu_init_channels(struct spu *spu)
        }
 }
 
-static void spu_init_regs(struct spu *spu)
-{
-       out_be64(&spu->priv1->int_mask_class0_RW, 0x7);
-       out_be64(&spu->priv1->int_mask_class1_RW, 0x3);
-       out_be64(&spu->priv1->int_mask_class2_RW, 0xe);
-}
-
 struct spu *spu_alloc(void)
 {
        struct spu *spu;
 
-       down(&spu_mutex);
+       mutex_lock(&spu_mutex);
        if (!list_empty(&spu_list)) {
                spu = list_entry(spu_list.next, struct spu, list);
                list_del_init(&spu->list);
@@ -390,12 +393,10 @@ struct spu *spu_alloc(void)
                pr_debug("No SPU left\n");
                spu = NULL;
        }
-       up(&spu_mutex);
+       mutex_unlock(&spu_mutex);
 
-       if (spu) {
+       if (spu)
                spu_init_channels(spu);
-               spu_init_regs(spu);
-       }
 
        return spu;
 }
@@ -403,9 +404,9 @@ EXPORT_SYMBOL_GPL(spu_alloc);
 
 void spu_free(struct spu *spu)
 {
-       down(&spu_mutex);
+       mutex_lock(&spu_mutex);
        list_add_tail(&spu->list, &spu_list);
-       up(&spu_mutex);
+       mutex_unlock(&spu_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_free);
 
@@ -478,21 +479,20 @@ bad_area:
        return -EFAULT;
 }
 
-static int spu_handle_pte_fault(struct spu *spu)
+int spu_irq_class_1_bottom(struct spu *spu)
 {
        u64 ea, dsisr, access, error = 0UL;
        int ret = 0;
 
        ea = spu->dar;
        dsisr = spu->dsisr;
-       if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
+       if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
                access = (_PAGE_PRESENT | _PAGE_USER);
                access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
                if (hash_page(ea, access, 0x300) != 0)
                        error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
        }
-       if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||
-           (dsisr & MFC_DSISR_ACCESS_DENIED)) {
+       if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
                if ((ret = spu_handle_mm_fault(spu)) != 0)
                        error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
                else
@@ -508,75 +508,13 @@ static int spu_handle_pte_fault(struct spu *spu)
        return ret;
 }
 
-static inline int spu_pending(struct spu *spu, u32 * stat)
+void spu_irq_setaffinity(struct spu *spu, int cpu)
 {
-       struct spu_problem __iomem *prob = spu->problem;
-       u64 pte_fault;
-
-       *stat = in_be32(&prob->spu_status_R);
-       pte_fault = spu->dsisr &
-                   (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
-       return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+       u64 target = iic_get_target_id(cpu);
+       u64 route = target << 48 | target << 32 | target << 16;
+       spu_int_route_set(spu, route);
 }
-
-int spu_run(struct spu *spu)
-{
-       struct spu_problem __iomem *prob;
-       struct spu_priv1 __iomem *priv1;
-       struct spu_priv2 __iomem *priv2;
-       u32 status;
-       int ret;
-
-       prob = spu->problem;
-       priv1 = spu->priv1;
-       priv2 = spu->priv2;
-
-       /* Let SPU run.  */
-       eieio();
-       out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
-
-       do {
-               ret = wait_event_interruptible(spu->stop_wq,
-                                              spu_pending(spu, &status));
-
-               if (spu->dsisr &
-                   (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
-                       ret = spu_handle_pte_fault(spu);
-
-               if (spu->class_0_pending)
-                       spu_irq_class_0_bottom(spu);
-
-               if (!ret && signal_pending(current))
-                       ret = -ERESTARTSYS;
-
-       } while (!ret && !(status &
-                          (SPU_STATUS_STOPPED_BY_STOP |
-                           SPU_STATUS_STOPPED_BY_HALT)));
-
-       /* Ensure SPU is stopped.  */
-       out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
-       eieio();
-       while (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)
-               cpu_relax();
-
-       out_be64(&priv2->slb_invalidate_all_W, 0);
-       out_be64(&priv1->tlb_invalidate_entry_W, 0UL);
-       eieio();
-
-       /* Check for SPU breakpoint.  */
-       if (unlikely(current->ptrace & PT_PTRACED)) {
-               status = in_be32(&prob->spu_status_R);
-
-               if ((status & SPU_STATUS_STOPPED_BY_STOP)
-                   && status >> SPU_STOP_STATUS_SHIFT == 0x3fff) {
-                       force_sig(SIGTRAP, current);
-                       ret = -ERESTARTSYS;
-               }
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(spu_run);
+EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
 
 static void __iomem * __init map_spe_prop(struct device_node *n,
                                                 const char *name)
@@ -631,13 +569,17 @@ static int __init spu_map_device(struct spu *spu, struct device_node *spe)
        if (!spu->local_store)
                goto out;
 
+       prop = get_property(spe, "problem", NULL);
+       if (!prop)
+               goto out_unmap;
+       spu->problem_phys = *(unsigned long *)prop;
+
        spu->problem= map_spe_prop(spe, "problem");
        if (!spu->problem)
                goto out_unmap;
 
        spu->priv1= map_spe_prop(spe, "priv1");
-       if (!spu->priv1)
-               goto out_unmap;
+       /* priv1 is not available on a hypervisor */
 
        spu->priv2= map_spe_prop(spe, "priv2");
        if (!spu->priv2)
@@ -690,21 +632,22 @@ static int __init create_spu(struct device_node *spe)
        spu->dsisr = 0UL;
        spin_lock_init(&spu->register_lock);
 
-       out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
-       out_be64(&spu->priv1->mfc_sr1_RW, 0x33);
+       spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+       spu_mfc_sr1_set(spu, 0x33);
 
-       init_waitqueue_head(&spu->stop_wq);
        spu->ibox_callback = NULL;
        spu->wbox_callback = NULL;
+       spu->stop_callback = NULL;
+       spu->mfc_callback = NULL;
 
-       down(&spu_mutex);
+       mutex_lock(&spu_mutex);
        spu->number = number++;
        ret = spu_request_irqs(spu);
        if (ret)
                goto out_unmap;
 
        list_add(&spu->list, &spu_list);
-       up(&spu_mutex);
+       mutex_unlock(&spu_mutex);
 
        pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
                spu->name, spu->isrc, spu->local_store,
@@ -712,7 +655,7 @@ static int __init create_spu(struct device_node *spe)
        goto out;
 
 out_unmap:
-       up(&spu_mutex);
+       mutex_unlock(&spu_mutex);
        spu_unmap(spu);
 out_free:
        kfree(spu);
@@ -732,10 +675,10 @@ static void destroy_spu(struct spu *spu)
 static void cleanup_spu_base(void)
 {
        struct spu *spu, *tmp;
-       down(&spu_mutex);
+       mutex_lock(&spu_mutex);
        list_for_each_entry_safe(spu, tmp, &spu_list, list)
                destroy_spu(spu);
-       up(&spu_mutex);
+       mutex_unlock(&spu_mutex);
 }
 module_exit(cleanup_spu_base);