[POWERPC] spufs: handle faults while the context switch pending flag is set

Currently, page fault handlers don't issue a mfc restart if the context
switch pending flag is set, which can leave us with a hanging DMA after
a context restore.

This patch introduces fault pending flag that is set by the fault
handler and read by the context switch code, so that the latter can add
the restart bit at the right spot, after it has successfuly saved the
state of the mfc control register.

Signed-off-by: Luke Browning <lukebr@linux.vnet.ibm.com>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
This commit is contained in:
Luke Browning 2008-04-28 17:35:56 +10:00 committed by Jeremy Kerr
parent f3d69e0507
commit de1028927a
3 changed files with 19 additions and 9 deletions

View file

@ -141,6 +141,10 @@ static void spu_restart_dma(struct spu *spu)
if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags)) if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
else {
set_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags);
mb();
}
} }
static inline void spu_load_slb(struct spu *spu, int slbe, struct spu_slb *slb) static inline void spu_load_slb(struct spu *spu, int slbe, struct spu_slb *slb)

View file

@ -139,6 +139,7 @@ static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
* via a simple load. * via a simple load.
*/ */
set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags); set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
clear_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags);
synchronize_irq(spu->irqs[0]); synchronize_irq(spu->irqs[0]);
synchronize_irq(spu->irqs[1]); synchronize_irq(spu->irqs[1]);
synchronize_irq(spu->irqs[2]); synchronize_irq(spu->irqs[2]);
@ -739,10 +740,14 @@ static inline void set_switch_active(struct spu_state *csa, struct spu *spu)
/* Save, Step 48: /* Save, Step 48:
* Restore, Step 23. * Restore, Step 23.
* Change the software context switch pending flag * Change the software context switch pending flag
* to context switch active. * to context switch active. This implementation does
* not uses a switch active flag.
* *
* This implementation does not uses a switch active flag. * Now that we have saved the mfc in the csa, we can add in the
* restart command if an exception occurred.
*/ */
if (test_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags))
csa->priv2.mfc_control_RW |= MFC_CNTL_RESTART_DMA_COMMAND;
clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags); clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
mb(); mb();
} }
@ -1742,15 +1747,15 @@ static inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu)
*/ */
out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW); out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW);
eieio(); eieio();
/* /*
* FIXME: this is to restart a DMA that we were processing * The queue is put back into the same state that was evident prior to
* before the save. better remember the fault information * the context switch. The suspend flag is added to the saved state in
* in the csa instead. * the csa, if the operational state was suspending or suspended. In
* this case, the code that suspended the mfc is responsible for
* continuing it. Note that SPE faults do not change the operational
* state of the spu.
*/ */
if ((csa->priv2.mfc_control_RW & MFC_CNTL_SUSPEND_DMA_QUEUE_MASK)) {
out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
eieio();
}
} }
static inline void enable_user_access(struct spu_state *csa, struct spu *spu) static inline void enable_user_access(struct spu_state *csa, struct spu *spu)

View file

@ -100,6 +100,7 @@
/* Flag indicating progress during context switch. */ /* Flag indicating progress during context switch. */
#define SPU_CONTEXT_SWITCH_PENDING 0UL #define SPU_CONTEXT_SWITCH_PENDING 0UL
#define SPU_CONTEXT_FAULT_PENDING 1UL
struct spu_context; struct spu_context;
struct spu_runqueue; struct spu_runqueue;