summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/cell
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/cell')
-rw-r--r--arch/powerpc/platforms/cell/celleb_scc_pciex.c5
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c6
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.h6
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c44
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c1
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c21
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c21
7 files changed, 65 insertions, 39 deletions
diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
index 31da84c458d2..0e04f8fb152a 100644
--- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c
+++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
@@ -217,7 +217,7 @@ static u##size scc_pciex_in##name(unsigned long port) \
static void scc_pciex_ins##name(unsigned long p, void *b, unsigned long c) \
{ \
struct iowa_bus *bus = iowa_pio_find_bus(p); \
- u##size *dst = b; \
+ __le##size *dst = b; \
for (; c != 0; c--, dst++) \
*dst = cpu_to_le##size(__scc_pciex_in##name(bus->phb, p)); \
scc_pciex_io_flush(bus); \
@@ -231,10 +231,11 @@ static void scc_pciex_outs##name(unsigned long p, const void *b, \
unsigned long c) \
{ \
struct iowa_bus *bus = iowa_pio_find_bus(p); \
- const u##size *src = b; \
+ const __le##size *src = b; \
for (; c != 0; c--, src++) \
__scc_pciex_out##name(bus->phb, le##size##_to_cpu(*src), p); \
}
+#define __le8 u8
#define cpu_to_le8(x) (x)
#define le8_to_cpu(x) (x)
PCIEX_PIO_FUNC(8, b)
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 3b84e8be314c..b5f84e8f0899 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -118,7 +118,7 @@ static void iowa_##name at \
#undef DEF_PCI_AC_RET
#undef DEF_PCI_AC_NORET
-static struct ppc_pci_io __initdata iowa_pci_io = {
+static const struct ppc_pci_io __devinitconst iowa_pci_io = {
#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name,
#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name,
@@ -146,7 +146,7 @@ static void __iomem *iowa_ioremap(unsigned long addr, unsigned long size,
}
/* Regist new bus to support workaround */
-void __init iowa_register_bus(struct pci_controller *phb,
+void __devinit iowa_register_bus(struct pci_controller *phb,
struct ppc_pci_io *ops,
int (*initfunc)(struct iowa_bus *, void *), void *data)
{
@@ -173,7 +173,7 @@ void __init iowa_register_bus(struct pci_controller *phb,
}
/* enable IO workaround */
-void __init io_workaround_init(void)
+void __devinit io_workaround_init(void)
{
static int io_workaround_inited;
diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/platforms/cell/io-workarounds.h
index 79d8ed3d510f..6efc7782ebf2 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.h
+++ b/arch/powerpc/platforms/cell/io-workarounds.h
@@ -31,9 +31,9 @@ struct iowa_bus {
void *private;
};
-void __init io_workaround_init(void);
-void __init iowa_register_bus(struct pci_controller *, struct ppc_pci_io *,
- int (*)(struct iowa_bus *, void *), void *);
+void __devinit io_workaround_init(void);
+void __devinit iowa_register_bus(struct pci_controller *, struct ppc_pci_io *,
+ int (*)(struct iowa_bus *, void *), void *);
struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR);
struct iowa_bus *iowa_pio_find_bus(unsigned long);
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 70c660121ec4..78f905bc6a42 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -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;
@@ -324,17 +334,13 @@ spu_irq_class_0(int irq, void *data)
stat = spu_int_stat_get(spu, 0) & mask;
spu->class_0_pending |= stat;
- spu->class_0_dsisr = spu_mfc_dsisr_get(spu);
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_dsisr = 0;
spu->class_0_dar = 0;
spu_int_stat_clear(spu, 0, stat);
+ spin_unlock(&spu->register_lock);
return IRQ_HANDLED;
}
@@ -357,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);
@@ -376,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;
}
@@ -394,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);
@@ -421,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;
}
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 80911a373400..c81341ff75b5 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -32,6 +32,7 @@
#include <linux/marker.h>
#include <asm/io.h>
+#include <asm/time.h>
#include <asm/spu.h>
#include <asm/spu_info.h>
#include <asm/uaccess.h>
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index b7493b865812..f7edba6cb795 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -27,7 +27,6 @@ void spufs_stop_callback(struct spu *spu, int irq)
switch(irq) {
case 0 :
ctx->csa.class_0_pending = spu->class_0_pending;
- ctx->csa.class_0_dsisr = spu->class_0_dsisr;
ctx->csa.class_0_dar = spu->class_0_dar;
break;
case 1 :
@@ -51,18 +50,22 @@ int spu_stopped(struct spu_context *ctx, u32 *stat)
u64 dsisr;
u32 stopped;
- *stat = ctx->ops->status_read(ctx);
-
- if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
- return 1;
-
stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP |
SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
- if (!(*stat & SPU_STATUS_RUNNING) && (*stat & stopped))
+
+top:
+ *stat = ctx->ops->status_read(ctx);
+ if (*stat & stopped) {
+ /*
+ * If the spu hasn't finished stopping, we need to
+ * re-read the register to get the stopped value.
+ */
+ if (*stat & SPU_STATUS_RUNNING)
+ goto top;
return 1;
+ }
- dsisr = ctx->csa.class_0_dsisr;
- if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
+ if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
return 1;
dsisr = ctx->csa.class_1_dsisr;
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 2e411f23462b..e929e70a84e3 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -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;
@@ -403,6 +407,8 @@ static int has_affinity(struct spu_context *ctx)
*/
static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
{
+ u32 status;
+
spu_context_trace(spu_unbind_context__enter, ctx, spu);
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
@@ -423,18 +429,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);
@@ -444,6 +454,9 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
/* This maps the underlying spu state to idle */
spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
ctx->spu = NULL;
+
+ if (spu_stopped(ctx, &status))
+ wake_up_all(&ctx->stop_wq);
}
/**
@@ -659,7 +672,7 @@ static struct spu *find_victim(struct spu_context *ctx)
victim->stats.invol_ctx_switch++;
spu->stats.invol_ctx_switch++;
- if (test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags))
+ if (test_bit(SPU_SCHED_SPU_RUN, &victim->sched_flags))
spu_add_to_rq(victim);
mutex_unlock(&victim->state_mutex);