Skip to content

Commit

Permalink
powerpc/spufs: synchronize interaction between spu exception handling…
Browse files Browse the repository at this point in the history
… 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>
  • Loading branch information
Luke Browning authored and Jeremy Kerr committed Jun 16, 2008
1 parent 1f64643 commit 2c911a1
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 19 deletions.
42 changes: 26 additions & 16 deletions arch/powerpc/platforms/cell/spu_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);

Expand All @@ -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;
}

Expand All @@ -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);

Expand All @@ -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;
}

Expand Down
14 changes: 11 additions & 3 deletions arch/powerpc/platforms/cell/spufs/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 2c911a1

Please sign in to comment.