aboutsummaryrefslogtreecommitdiff
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/Kconfig3
-rw-r--r--arch/powerpc/platforms/cell/setup.c78
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c101
-rw-r--r--arch/powerpc/platforms/cell/spu_callbacks.c19
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c2
5 files changed, 97 insertions, 106 deletions
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index c2a3db8edb0..6a02d51086c 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -12,7 +12,8 @@ config SPU_FS
config SPUFS_MMAP
bool
- depends on SPU_FS && SPARSEMEM && !PPC_64K_PAGES
+ depends on SPU_FS && SPARSEMEM
+ select MEMORY_HOTPLUG
default y
endmenu
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index dac5d0365fd..6574b22b3cf 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -29,6 +29,8 @@
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/console.h>
+#include <linux/mutex.h>
+#include <linux/memory_hotplug.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -46,6 +48,7 @@
#include <asm/cputable.h>
#include <asm/ppc-pci.h>
#include <asm/irq.h>
+#include <asm/spu.h>
#include "interrupt.h"
#include "iommu.h"
@@ -69,77 +72,6 @@ static void cell_show_cpuinfo(struct seq_file *m)
of_node_put(root);
}
-#ifdef CONFIG_SPARSEMEM
-static int __init find_spu_node_id(struct device_node *spe)
-{
- unsigned int *id;
-#ifdef CONFIG_NUMA
- struct device_node *cpu;
- cpu = spe->parent->parent;
- id = (unsigned int *)get_property(cpu, "node-id", NULL);
-#else
- id = NULL;
-#endif
- return id ? *id : 0;
-}
-
-static void __init cell_spuprop_present(struct device_node *spe,
- const char *prop, int early)
-{
- struct address_prop {
- unsigned long address;
- unsigned int len;
- } __attribute__((packed)) *p;
- int proplen;
-
- unsigned long start_pfn, end_pfn, pfn;
- int node_id;
-
- p = (void*)get_property(spe, prop, &proplen);
- WARN_ON(proplen != sizeof (*p));
-
- node_id = find_spu_node_id(spe);
-
- start_pfn = p->address >> PAGE_SHIFT;
- end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
- /* We need to call memory_present *before* the call to sparse_init,
- but we can initialize the page structs only *after* that call.
- Thus, we're being called twice. */
- if (early)
- memory_present(node_id, start_pfn, end_pfn);
- else {
- /* As the pages backing SPU LS and I/O are outside the range
- of regular memory, their page structs were not initialized
- by free_area_init. Do it here instead. */
- for (pfn = start_pfn; pfn < end_pfn; pfn++) {
- struct page *page = pfn_to_page(pfn);
- set_page_links(page, ZONE_DMA, node_id, pfn);
- init_page_count(page);
- reset_page_mapcount(page);
- SetPageReserved(page);
- INIT_LIST_HEAD(&page->lru);
- }
- }
-}
-
-static void __init cell_spumem_init(int early)
-{
- struct device_node *node;
- for (node = of_find_node_by_type(NULL, "spe");
- node; node = of_find_node_by_type(node, "spe")) {
- cell_spuprop_present(node, "local-store", early);
- cell_spuprop_present(node, "problem", early);
- cell_spuprop_present(node, "priv1", early);
- cell_spuprop_present(node, "priv2", early);
- }
-}
-#else
-static void __init cell_spumem_init(int early)
-{
-}
-#endif
-
static void cell_progress(char *s, unsigned short hex)
{
printk("*** %04x : %s\n", hex, s ? s : "");
@@ -172,8 +104,6 @@ static void __init cell_setup_arch(void)
#endif
mmio_nvram_init();
-
- cell_spumem_init(0);
}
/*
@@ -189,8 +119,6 @@ static void __init cell_init_early(void)
ppc64_interrupt_controller = IC_CELL_PIC;
- cell_spumem_init(1);
-
DBG(" <- cell_init_early()\n");
}
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 269dda4fd0b..ad141fe8d52 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -306,19 +306,19 @@ spu_request_irqs(struct spu *spu)
snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number);
ret = request_irq(irq_base + spu->isrc,
- spu_irq_class_0, 0, spu->irq_c0, spu);
+ spu_irq_class_0, SA_INTERRUPT, spu->irq_c0, spu);
if (ret)
goto out;
snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
- spu_irq_class_1, 0, spu->irq_c1, spu);
+ spu_irq_class_1, SA_INTERRUPT, spu->irq_c1, spu);
if (ret)
goto out1;
snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
- spu_irq_class_2, 0, spu->irq_c2, spu);
+ spu_irq_class_2, SA_INTERRUPT, spu->irq_c2, spu);
if (ret)
goto out2;
goto out;
@@ -487,10 +487,14 @@ int spu_irq_class_1_bottom(struct spu *spu)
ea = spu->dar;
dsisr = spu->dsisr;
if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
+ u64 flags;
+
access = (_PAGE_PRESENT | _PAGE_USER);
access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+ local_irq_save(flags);
if (hash_page(ea, access, 0x300) != 0)
error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
+ local_irq_restore(flags);
}
if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
if ((ret = spu_handle_mm_fault(spu)) != 0)
@@ -516,8 +520,50 @@ void spu_irq_setaffinity(struct spu *spu, int cpu)
}
EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
-static void __iomem * __init map_spe_prop(struct device_node *n,
- const char *name)
+static int __init find_spu_node_id(struct device_node *spe)
+{
+ unsigned int *id;
+ struct device_node *cpu;
+ cpu = spe->parent->parent;
+ id = (unsigned int *)get_property(cpu, "node-id", NULL);
+ return id ? *id : 0;
+}
+
+static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
+ const char *prop)
+{
+ static DEFINE_MUTEX(add_spumem_mutex);
+
+ struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *p;
+ int proplen;
+
+ unsigned long start_pfn, nr_pages;
+ struct pglist_data *pgdata;
+ struct zone *zone;
+ int ret;
+
+ p = (void*)get_property(spe, prop, &proplen);
+ WARN_ON(proplen != sizeof (*p));
+
+ start_pfn = p->address >> PAGE_SHIFT;
+ nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ pgdata = NODE_DATA(spu->nid);
+ zone = pgdata->node_zones;
+
+ /* XXX rethink locking here */
+ mutex_lock(&add_spumem_mutex);
+ ret = __add_pages(zone, start_pfn, nr_pages);
+ mutex_unlock(&add_spumem_mutex);
+
+ return ret;
+}
+
+static void __iomem * __init map_spe_prop(struct spu *spu,
+ struct device_node *n, const char *name)
{
struct address_prop {
unsigned long address;
@@ -526,6 +572,8 @@ static void __iomem * __init map_spe_prop(struct device_node *n,
void *p;
int proplen;
+ void* ret = NULL;
+ int err = 0;
p = get_property(n, name, &proplen);
if (proplen != sizeof (struct address_prop))
@@ -533,7 +581,14 @@ static void __iomem * __init map_spe_prop(struct device_node *n,
prop = p;
- return ioremap(prop->address, prop->len);
+ err = cell_spuprop_present(spu, n, name);
+ if (err && (err != -EEXIST))
+ goto out;
+
+ ret = ioremap(prop->address, prop->len);
+
+ out:
+ return ret;
}
static void spu_unmap(struct spu *spu)
@@ -544,44 +599,45 @@ static void spu_unmap(struct spu *spu)
iounmap((u8 __iomem *)spu->local_store);
}
-static int __init spu_map_device(struct spu *spu, struct device_node *spe)
+static int __init spu_map_device(struct spu *spu, struct device_node *node)
{
char *prop;
int ret;
ret = -ENODEV;
- prop = get_property(spe, "isrc", NULL);
+ prop = get_property(node, "isrc", NULL);
if (!prop)
goto out;
spu->isrc = *(unsigned int *)prop;
- spu->name = get_property(spe, "name", NULL);
+ spu->name = get_property(node, "name", NULL);
if (!spu->name)
goto out;
- prop = get_property(spe, "local-store", NULL);
+ prop = get_property(node, "local-store", NULL);
if (!prop)
goto out;
spu->local_store_phys = *(unsigned long *)prop;
/* we use local store as ram, not io memory */
- spu->local_store = (void __force *)map_spe_prop(spe, "local-store");
+ spu->local_store = (void __force *)
+ map_spe_prop(spu, node, "local-store");
if (!spu->local_store)
goto out;
- prop = get_property(spe, "problem", NULL);
+ prop = get_property(node, "problem", NULL);
if (!prop)
goto out_unmap;
spu->problem_phys = *(unsigned long *)prop;
- spu->problem= map_spe_prop(spe, "problem");
+ spu->problem= map_spe_prop(spu, node, "problem");
if (!spu->problem)
goto out_unmap;
- spu->priv1= map_spe_prop(spe, "priv1");
+ spu->priv1= map_spe_prop(spu, node, "priv1");
/* priv1 is not available on a hypervisor */
- spu->priv2= map_spe_prop(spe, "priv2");
+ spu->priv2= map_spe_prop(spu, node, "priv2");
if (!spu->priv2)
goto out_unmap;
ret = 0;
@@ -593,17 +649,6 @@ out:
return ret;
}
-static int __init find_spu_node_id(struct device_node *spe)
-{
- unsigned int *id;
- struct device_node *cpu;
-
- cpu = spe->parent->parent;
- id = (unsigned int *)get_property(cpu, "node-id", NULL);
-
- return id ? *id : 0;
-}
-
static int __init create_spu(struct device_node *spe)
{
struct spu *spu;
@@ -620,6 +665,10 @@ static int __init create_spu(struct device_node *spe)
goto out_free;
spu->node = find_spu_node_id(spe);
+ spu->nid = of_node_to_nid(spe);
+ if (spu->nid == -1)
+ spu->nid = 0;
+
spu->stop_code = 0;
spu->slb_replace = 0;
spu->mm = NULL;
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c
index 6594bec7388..95b36430aa0 100644
--- a/arch/powerpc/platforms/cell/spu_callbacks.c
+++ b/arch/powerpc/platforms/cell/spu_callbacks.c
@@ -317,17 +317,30 @@ void *spu_syscall_table[] = {
[__NR_ppoll] sys_ni_syscall, /* sys_ppoll */
[__NR_unshare] sys_unshare,
[__NR_splice] sys_splice,
+ [__NR_tee] sys_tee,
+ [__NR_vmsplice] sys_vmsplice,
+ [__NR_openat] sys_openat,
+ [__NR_mkdirat] sys_mkdirat,
+ [__NR_mknodat] sys_mknodat,
+ [__NR_fchownat] sys_fchownat,
+ [__NR_futimesat] sys_futimesat,
+ [__NR_newfstatat] sys_newfstatat,
+ [__NR_unlinkat] sys_unlinkat,
+ [__NR_renameat] sys_renameat,
+ [__NR_linkat] sys_linkat,
+ [__NR_symlinkat] sys_symlinkat,
+ [__NR_readlinkat] sys_readlinkat,
+ [__NR_fchmodat] sys_fchmodat,
+ [__NR_faccessat] sys_faccessat,
};
long spu_sys_callback(struct spu_syscall_block *s)
{
long (*syscall)(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6);
- BUILD_BUG_ON(ARRAY_SIZE(spu_syscall_table) != __NR_syscalls);
-
syscall = spu_syscall_table[s->nr_ret];
- if (s->nr_ret >= __NR_syscalls) {
+ if (s->nr_ret >= ARRAY_SIZE(spu_syscall_table)) {
pr_debug("%s: invalid syscall #%ld", __FUNCTION__, s->nr_ret);
return -ENOSYS;
}
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 97898d5d34e..1726bfe38ee 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -1297,7 +1297,7 @@ static inline void setup_decr(struct spu_state *csa, struct spu *spu)
cycles_t resume_time = get_cycles();
cycles_t delta_time = resume_time - csa->suspend_time;
- csa->lscsa->decr.slot[0] = delta_time;
+ csa->lscsa->decr.slot[0] -= delta_time;
}
}