powerpc/spufs: synchronize interaction between spu exception handling and time slicing

Time slicing can occur at the same time as spu exception handling
resulting in the wakeup of the wrong thread.

This change uses the the spu's register_lock to enforce synchronization
between bind/unbind and spu exception handling so that they are
mutually exclusive.

Signed-off-by: Luke Browning <lukebrowning@us.ibm.com>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
This commit is contained in:
Luke Browning 2008-06-13 14:17:35 +10:00 committed by Jeremy Kerr
parent 1f64643aa5
commit 2c911a14b7
2 changed files with 37 additions and 19 deletions

View file

@ -219,15 +219,25 @@ 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)
{
int ret;
pr_debug("%s, %lx, %lx\n", __func__, dsisr, ea);
/* Handle kernel space hash faults immediately.
User hash faults need to be deferred to process context. */
if ((dsisr & MFC_DSISR_PTE_NOT_FOUND)
&& REGION_ID(ea) != USER_REGION_ID
&& hash_page(ea, _PAGE_PRESENT, 0x300) == 0) {
spu_restart_dma(spu);
return 0;
/*
* Handle kernel space hash faults immediately. User hash
* faults need to be deferred to process context.
*/
if ((dsisr & MFC_DSISR_PTE_NOT_FOUND) &&
(REGION_ID(ea) != USER_REGION_ID)) {
spin_unlock(&spu->register_lock);
ret = hash_page(ea, _PAGE_PRESENT, 0x300);
spin_lock(&spu->register_lock);
if (!ret) {
spu_restart_dma(spu);
return 0;
}
}
spu->class_1_dar = ea;
@ -325,14 +335,12 @@ spu_irq_class_0(int irq, void *data)
spu->class_0_pending |= stat;
spu->class_0_dar = spu_mfc_dar_get(spu);
spin_unlock(&spu->register_lock);
spu->stop_callback(spu, 0);
spu->class_0_pending = 0;
spu->class_0_dar = 0;
spu_int_stat_clear(spu, 0, stat);
spin_unlock(&spu->register_lock);
return IRQ_HANDLED;
}
@ -355,13 +363,12 @@ spu_irq_class_1(int irq, void *data)
spu_mfc_dsisr_set(spu, 0ul);
spu_int_stat_clear(spu, 1, stat);
if (stat & CLASS1_SEGMENT_FAULT_INTR)
__spu_trap_data_seg(spu, dar);
spin_unlock(&spu->register_lock);
pr_debug("%s: %lx %lx %lx %lx\n", __func__, mask, stat,
dar, dsisr);
if (stat & CLASS1_SEGMENT_FAULT_INTR)
__spu_trap_data_seg(spu, dar);
if (stat & CLASS1_STORAGE_FAULT_INTR)
__spu_trap_data_map(spu, dar, dsisr);
@ -374,6 +381,8 @@ spu_irq_class_1(int irq, void *data)
spu->class_1_dsisr = 0;
spu->class_1_dar = 0;
spin_unlock(&spu->register_lock);
return stat ? IRQ_HANDLED : IRQ_NONE;
}
@ -392,14 +401,12 @@ spu_irq_class_2(int irq, void *data)
mask = spu_int_mask_get(spu, 2);
/* ignore interrupts we're not waiting for */
stat &= mask;
/* mailbox interrupts are level triggered. mask them now before
* acknowledging */
if (stat & mailbox_intrs)
spu_int_mask_and(spu, 2, ~(stat & mailbox_intrs));
/* acknowledge all interrupts before the callbacks */
spu_int_stat_clear(spu, 2, stat);
spin_unlock(&spu->register_lock);
pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
@ -419,6 +426,9 @@ spu_irq_class_2(int irq, void *data)
spu->wbox_callback(spu);
spu->stats.class2_intr++;
spin_unlock(&spu->register_lock);
return stat ? IRQ_HANDLED : IRQ_NONE;
}

View file

@ -230,19 +230,23 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
ctx->stats.slb_flt_base = spu->stats.slb_flt;
ctx->stats.class2_intr_base = spu->stats.class2_intr;
spu_associate_mm(spu, ctx->owner);
spin_lock_irq(&spu->register_lock);
spu->ctx = ctx;
spu->flags = 0;
ctx->spu = spu;
ctx->ops = &spu_hw_ops;
spu->pid = current->pid;
spu->tgid = current->tgid;
spu_associate_mm(spu, ctx->owner);
spu->ibox_callback = spufs_ibox_callback;
spu->wbox_callback = spufs_wbox_callback;
spu->stop_callback = spufs_stop_callback;
spu->mfc_callback = spufs_mfc_callback;
mb();
spin_unlock_irq(&spu->register_lock);
spu_unmap_mappings(ctx);
spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0);
spu_restore(&ctx->csa, spu);
spu->timestamp = jiffies;
@ -423,18 +427,22 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
spu_unmap_mappings(ctx);
spu_save(&ctx->csa, spu);
spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0);
spin_lock_irq(&spu->register_lock);
spu->timestamp = jiffies;
ctx->state = SPU_STATE_SAVED;
spu->ibox_callback = NULL;
spu->wbox_callback = NULL;
spu->stop_callback = NULL;
spu->mfc_callback = NULL;
spu_associate_mm(spu, NULL);
spu->pid = 0;
spu->tgid = 0;
ctx->ops = &spu_backing_ops;
spu->flags = 0;
spu->ctx = NULL;
spin_unlock_irq(&spu->register_lock);
spu_associate_mm(spu, NULL);
ctx->stats.slb_flt +=
(spu->stats.slb_flt - ctx->stats.slb_flt_base);