]> err.no Git - linux-2.6/blobdiff - arch/powerpc/platforms/cell/spufs/switch.c
[POWERPC] spufs: save MFC command channel before purging MFC queue
[linux-2.6] / arch / powerpc / platforms / cell / spufs / switch.c
index de7e5ee451d25b4da2eb7337ad6b02d96713d0e6..d2a1249d36dd2a7bc018727e09c3b7c57b88cf1c 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <linux/hardirq.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -48,6 +49,8 @@
 #include <asm/spu_csa.h>
 #include <asm/mmu_context.h>
 
+#include "spufs.h"
+
 #include "spu_save_dump.h"
 #include "spu_restore_dump.h"
 
@@ -115,6 +118,8 @@ static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
         *     Write INT_MASK_class1 with value of 0.
         *     Save INT_Mask_class2 in CSA.
         *     Write INT_MASK_class2 with value of 0.
+        *     Synchronize all three interrupts to be sure
+        *     we no longer execute a handler on another CPU.
         */
        spin_lock_irq(&spu->register_lock);
        if (csa) {
@@ -127,6 +132,9 @@ static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
        spu_int_mask_set(spu, 2, 0ul);
        eieio();
        spin_unlock_irq(&spu->register_lock);
+       synchronize_irq(spu->irqs[0]);
+       synchronize_irq(spu->irqs[1]);
+       synchronize_irq(spu->irqs[2]);
 }
 
 static inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu)
@@ -691,35 +699,9 @@ static inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu)
        out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE);
 }
 
-static inline void get_kernel_slb(u64 ea, u64 slb[2])
-{
-       u64 llp;
-
-       if (REGION_ID(ea) == KERNEL_REGION_ID)
-               llp = mmu_psize_defs[mmu_linear_psize].sllp;
-       else
-               llp = mmu_psize_defs[mmu_virtual_psize].sllp;
-       slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
-               SLB_VSID_KERNEL | llp;
-       slb[1] = (ea & ESID_MASK) | SLB_ESID_V;
-}
-
-static inline void load_mfc_slb(struct spu *spu, u64 slb[2], int slbe)
-{
-       struct spu_priv2 __iomem *priv2 = spu->priv2;
-
-       out_be64(&priv2->slb_index_W, slbe);
-       eieio();
-       out_be64(&priv2->slb_vsid_RW, slb[0]);
-       out_be64(&priv2->slb_esid_RW, slb[1]);
-       eieio();
-}
-
-static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu)
+static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu,
+               unsigned int *code, int code_size)
 {
-       u64 code_slb[2];
-       u64 lscsa_slb[2];
-
        /* Save, Step 47:
         * Restore, Step 30.
         *     If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All
@@ -735,11 +717,7 @@ static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu)
         *     translation is desired by OS environment).
         */
        spu_invalidate_slbs(spu);
-       get_kernel_slb((unsigned long)&spu_save_code[0], code_slb);
-       get_kernel_slb((unsigned long)csa->lscsa, lscsa_slb);
-       load_mfc_slb(spu, code_slb, 0);
-       if ((lscsa_slb[0] != code_slb[0]) || (lscsa_slb[1] != code_slb[1]))
-               load_mfc_slb(spu, lscsa_slb, 1);
+       spu_setup_kernel_slbs(spu, csa->lscsa, code, code_size);
 }
 
 static inline void set_switch_active(struct spu_state *csa, struct spu *spu)
@@ -748,8 +726,9 @@ static inline void set_switch_active(struct spu_state *csa, struct spu *spu)
         * Restore, Step 23.
         *     Change the software context switch pending flag
         *     to context switch active.
+        *
+        *     This implementation does not uses a switch active flag.
         */
-       set_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
        clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
        mb();
 }
@@ -768,9 +747,9 @@ static inline void enable_interrupts(struct spu_state *csa, struct spu *spu)
         *     (translation) interrupts.
         */
        spin_lock_irq(&spu->register_lock);
-       spu_int_stat_clear(spu, 0, ~0ul);
-       spu_int_stat_clear(spu, 1, ~0ul);
-       spu_int_stat_clear(spu, 2, ~0ul);
+       spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
+       spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK);
+       spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
        spu_int_mask_set(spu, 0, 0ul);
        spu_int_mask_set(spu, 1, class1_mask);
        spu_int_mask_set(spu, 2, 0ul);
@@ -927,8 +906,8 @@ static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu)
        POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask);
 
        local_irq_save(flags);
-       spu_int_stat_clear(spu, 0, ~(0ul));
-       spu_int_stat_clear(spu, 2, ~(0ul));
+       spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
+       spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
        local_irq_restore(flags);
 }
 
@@ -946,8 +925,8 @@ static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu)
        POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
 
        local_irq_save(flags);
-       spu_int_stat_clear(spu, 0, ~(0ul));
-       spu_int_stat_clear(spu, 2, ~(0ul));
+       spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
+       spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
        local_irq_restore(flags);
 }
 
@@ -1423,9 +1402,9 @@ static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
        spu_int_mask_set(spu, 0, 0ul);
        spu_int_mask_set(spu, 1, 0ul);
        spu_int_mask_set(spu, 2, 0ul);
-       spu_int_stat_clear(spu, 0, ~0ul);
-       spu_int_stat_clear(spu, 1, ~0ul);
-       spu_int_stat_clear(spu, 2, ~0ul);
+       spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
+       spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK);
+       spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
        spin_unlock_irq(&spu->register_lock);
 }
 
@@ -1767,9 +1746,8 @@ static inline void reset_switch_active(struct spu_state *csa, struct spu *spu)
 {
        /* Restore, Step 74:
         *     Reset the "context switch active" flag.
+        *     Not performed by this implementation.
         */
-       clear_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
-       mb();
 }
 
 static inline void reenable_interrupts(struct spu_state *csa, struct spu *spu)
@@ -1837,6 +1815,7 @@ static void save_csa(struct spu_state *prev, struct spu *spu)
        save_mfc_csr_ato(prev, spu);    /* Step 24. */
        save_mfc_tclass_id(prev, spu);  /* Step 25. */
        set_mfc_tclass_id(prev, spu);   /* Step 26. */
+       save_mfc_cmd(prev, spu);        /* Step 26a - moved from 44. */
        purge_mfc_queue(prev, spu);     /* Step 27. */
        wait_purge_complete(prev, spu); /* Step 28. */
        setup_mfc_sr1(prev, spu);       /* Step 30. */
@@ -1853,7 +1832,6 @@ static void save_csa(struct spu_state *prev, struct spu *spu)
        save_ppuint_mb(prev, spu);      /* Step 41. */
        save_ch_part1(prev, spu);       /* Step 42. */
        save_spu_mb(prev, spu);         /* Step 43. */
-       save_mfc_cmd(prev, spu);        /* Step 44. */
        reset_ch(prev, spu);            /* Step 45. */
 }
 
@@ -1866,7 +1844,8 @@ static void save_lscsa(struct spu_state *prev, struct spu *spu)
         */
 
        resume_mfc_queue(prev, spu);    /* Step 46. */
-       setup_mfc_slbs(prev, spu);      /* Step 47. */
+       /* Step 47. */
+       setup_mfc_slbs(prev, spu, spu_save_code, sizeof(spu_save_code));
        set_switch_active(prev, spu);   /* Step 48. */
        enable_interrupts(prev, spu);   /* Step 49. */
        save_ls_16kb(prev, spu);        /* Step 50. */
@@ -1971,7 +1950,8 @@ static void restore_lscsa(struct spu_state *next, struct spu *spu)
        setup_spu_status_part1(next, spu);      /* Step 27. */
        setup_spu_status_part2(next, spu);      /* Step 28. */
        restore_mfc_rag(next, spu);             /* Step 29. */
-       setup_mfc_slbs(next, spu);              /* Step 30. */
+       /* Step 30. */
+       setup_mfc_slbs(next, spu, spu_restore_code, sizeof(spu_restore_code));
        set_spu_npc(next, spu);                 /* Step 31. */
        set_signot1(next, spu);                 /* Step 32. */
        set_signot2(next, spu);                 /* Step 33. */
@@ -2103,10 +2083,6 @@ int spu_save(struct spu_state *prev, struct spu *spu)
        int rc;
 
        acquire_spu_lock(spu);          /* Step 1.     */
-       prev->dar = spu->dar;
-       prev->dsisr = spu->dsisr;
-       spu->dar = 0;
-       spu->dsisr = 0;
        rc = __do_spu_save(prev, spu);  /* Steps 2-53. */
        release_spu_lock(spu);
        if (rc != 0 && rc != 2 && rc != 6) {
@@ -2133,9 +2109,6 @@ int spu_restore(struct spu_state *new, struct spu *spu)
        acquire_spu_lock(spu);
        harvest(NULL, spu);
        spu->slb_replace = 0;
-       new->dar = 0;
-       new->dsisr = 0;
-       spu->class_0_pending = 0;
        rc = __do_spu_restore(new, spu);
        release_spu_lock(spu);
        if (rc) {
@@ -2215,10 +2188,8 @@ int spu_init_csa(struct spu_state *csa)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(spu_init_csa);
 
 void spu_fini_csa(struct spu_state *csa)
 {
        spu_free_lscsa(csa);
 }
-EXPORT_SYMBOL_GPL(spu_fini_csa);