summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/cell/spu_base.c
diff options
context:
space:
mode:
authorMark Nutter <mnutter@us.ibm.com>2005-11-15 23:53:49 +0300
committerPaul Mackerras <paulus@samba.org>2006-01-09 06:49:16 +0300
commit5473af049d8b3556874174e61ce1986c9b5e8fa6 (patch)
tree53da74c13eb9125b85e85f9fc44981d3d1b41b49 /arch/powerpc/platforms/cell/spu_base.c
parent67207b9664a8d603138ef1556141e6d0a102bea7 (diff)
downloadlinux-5473af049d8b3556874174e61ce1986c9b5e8fa6.tar.xz
[PATCH] spufs: switchable spu contexts
Add some infrastructure for saving and restoring the context of an SPE. This patch creates a new structure that can hold the whole state of a physical SPE in memory. It also contains code that avoids races during the context switch and the binary code that is loaded to the SPU in order to access its registers. The actual PPE- and SPE-side context switch code are two separate patches. Signed-off-by: Arnd Bergmann <arndb@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/cell/spu_base.c')
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 9e9096590a07..44492d87cdf7 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -62,7 +62,9 @@ static int __spu_trap_error(struct spu *spu)
static void spu_restart_dma(struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+
+ if (!test_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags))
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
}
static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
@@ -72,6 +74,11 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
pr_debug("%s\n", __FUNCTION__);
+ if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+ printk("%s: invalid access during switch!\n", __func__);
+ return 1;
+ }
+
if (REGION_ID(ea) != USER_REGION_ID) {
pr_debug("invalid region access at %016lx\n", ea);
return 1;
@@ -98,6 +105,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
return 0;
}
+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)
{
unsigned long dsisr;
@@ -107,8 +115,21 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea)
priv1 = spu->priv1;
dsisr = in_be64(&priv1->mfc_dsisr_RW);
- wake_up(&spu->stop_wq);
+ /* 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;
+ }
+
+ if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+ printk("%s: invalid access during switch!\n", __func__);
+ return 1;
+ }
+ wake_up(&spu->stop_wq);
return 0;
}
@@ -382,7 +403,6 @@ void spu_free(struct spu *spu)
}
EXPORT_SYMBOL(spu_free);
-extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
static int spu_handle_mm_fault(struct spu *spu)
{
struct spu_priv1 __iomem *priv1;
@@ -650,6 +670,7 @@ static int __init create_spu(struct device_node *spe)
spu->slb_replace = 0;
spu->mm = NULL;
spu->class_0_pending = 0;
+ spu->flags = 0UL;
spin_lock_init(&spu->register_lock);
out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));