aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig1
-rw-r--r--arch/powerpc/platforms/cell/Kconfig5
-rw-r--r--arch/powerpc/platforms/cell/Makefile10
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c133
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h2
-rw-r--r--arch/powerpc/platforms/cell/iommu.c16
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c4
-rw-r--r--arch/powerpc/platforms/cell/setup.c11
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c108
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c39
-rw-r--r--arch/powerpc/platforms/cell/spu_callbacks.c345
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c47
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c24
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c523
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c57
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c8
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c91
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h28
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c3
-rw-r--r--arch/powerpc/platforms/chrp/chrp.h2
-rw-r--r--arch/powerpc/platforms/chrp/setup.c77
-rw-r--r--arch/powerpc/platforms/chrp/time.c22
-rw-r--r--arch/powerpc/platforms/iseries/setup.c13
-rw-r--r--arch/powerpc/platforms/maple/setup.c10
-rw-r--r--arch/powerpc/platforms/maple/time.c24
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c6
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c7
-rw-r--r--arch/powerpc/platforms/powermac/feature.c2
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c3
-rw-r--r--arch/powerpc/platforms/powermac/nvram.c14
-rw-r--r--arch/powerpc/platforms/powermac/pci.c5
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c2
-rw-r--r--arch/powerpc/platforms/powermac/setup.c74
-rw-r--r--arch/powerpc/platforms/powermac/time.c4
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c16
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c2
-rw-r--r--arch/powerpc/platforms/pseries/hvconsole.c5
-rw-r--r--arch/powerpc/platforms/pseries/pci.c2
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c11
-rw-r--r--arch/powerpc/platforms/pseries/ras.c2
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c15
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c3
-rw-r--r--arch/powerpc/platforms/pseries/setup.c231
-rw-r--r--arch/powerpc/platforms/pseries/xics.c4
47 files changed, 1630 insertions, 387 deletions
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index d3d0ff745e8..06e371282f5 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -7,6 +7,7 @@ choice
config MPC8540_ADS
bool "Freescale MPC8540 ADS"
+ select DEFAULT_UIMAGE
help
This option enables support for the MPC 8540 ADS board
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 3157071e241..c2a3db8edb0 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -10,4 +10,9 @@ config SPU_FS
Units on machines implementing the Broadband Processor
Architecture.
+config SPUFS_MMAP
+ bool
+ depends on SPU_FS && SPARSEMEM && !PPC_64K_PAGES
+ default y
+
endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 3b998a393e3..e570bad0639 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -6,5 +6,11 @@ obj-$(CONFIG_SPU_FS) += spu-base.o spufs/
spu-base-y += spu_base.o spu_priv1.o
-builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o
-obj-y += $(builtin-spufs-m)
+# needed only when building loadable spufs.ko
+spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
+obj-y += $(spufs-modular-m)
+
+# always needed in kernel
+spufs-builtin-$(CONFIG_SPU_FS) += spu_callbacks.o
+obj-y += $(spufs-builtin-y) $(spufs-builtin-m)
+
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 63aa52acf44..978be1c30c1 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -63,7 +63,24 @@ static DEFINE_PER_CPU(struct iic, iic);
void iic_local_enable(void)
{
- out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
+ struct iic *iic = &__get_cpu_var(iic);
+ u64 tmp;
+
+ /*
+ * There seems to be a bug that is present in DD2.x CPUs
+ * and still only partially fixed in DD3.1.
+ * This bug causes a value written to the priority register
+ * not to make it there, resulting in a system hang unless we
+ * write it again.
+ * Masking with 0xf0 is done because the Cell BE does not
+ * implement the lower four bits of the interrupt priority,
+ * they always read back as zeroes, although future CPUs
+ * might implement different bits.
+ */
+ do {
+ out_be64(&iic->regs->prio, 0xff);
+ tmp = in_be64(&iic->regs->prio);
+ } while ((tmp & 0xf0) != 0xf0);
}
void iic_local_disable(void)
@@ -123,7 +140,7 @@ static int iic_external_get_irq(struct iic_pending_bits pending)
pending.class != 2)
break;
irq = IIC_EXT_OFFSET
- + spider_get_irq(pending.prio + node * IIC_NODE_STRIDE)
+ + spider_get_irq(node)
+ node * IIC_NODE_STRIDE;
break;
case 0x01 ... 0x04:
@@ -174,38 +191,98 @@ int iic_get_irq(struct pt_regs *regs)
return irq;
}
-static int setup_iic(int cpu, struct iic *iic)
+/* hardcoded part to be compatible with older firmware */
+
+static int setup_iic_hardcoded(void)
{
struct device_node *np;
- int nodeid = cpu / 2;
+ int nodeid, cpu;
unsigned long regs;
+ struct iic *iic;
- for (np = of_find_node_by_type(NULL, "cpu");
- np;
- np = of_find_node_by_type(np, "cpu")) {
- if (nodeid == *(int *)get_property(np, "node-id", NULL))
- break;
+ for_each_cpu(cpu) {
+ iic = &per_cpu(iic, cpu);
+ nodeid = cpu/2;
+
+ for (np = of_find_node_by_type(NULL, "cpu");
+ np;
+ np = of_find_node_by_type(np, "cpu")) {
+ if (nodeid == *(int *)get_property(np, "node-id", NULL))
+ break;
+ }
+
+ if (!np) {
+ printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
+ iic->regs = NULL;
+ iic->target_id = 0xff;
+ return -ENODEV;
+ }
+
+ regs = *(long *)get_property(np, "iic", NULL);
+
+ /* hack until we have decided on the devtree info */
+ regs += 0x400;
+ if (cpu & 1)
+ regs += 0x20;
+
+ printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
+ iic->regs = ioremap(regs, sizeof(struct iic_regs));
+ iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
}
- if (!np) {
- printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
- iic->regs = NULL;
- iic->target_id = 0xff;
- return -ENODEV;
- }
+ return 0;
+}
- regs = *(long *)get_property(np, "iic", NULL);
+static int setup_iic(void)
+{
+ struct device_node *dn;
+ unsigned long *regs;
+ char *compatible;
+ unsigned *np, found = 0;
+ struct iic *iic = NULL;
+
+ for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
+ compatible = (char *)get_property(dn, "compatible", NULL);
+
+ if (!compatible) {
+ printk(KERN_WARNING "no compatible property found !\n");
+ continue;
+ }
- /* hack until we have decided on the devtree info */
- regs += 0x400;
- if (cpu & 1)
- regs += 0x20;
+ if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller"))
+ regs = (unsigned long *)get_property(dn,"reg", NULL);
+ else
+ continue;
- printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
- iic->regs = __ioremap(regs, sizeof(struct iic_regs),
- _PAGE_NO_CACHE);
- iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
- return 0;
+ if (!regs)
+ printk(KERN_WARNING "IIC: no reg property\n");
+
+ np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL);
+
+ if (!np) {
+ printk(KERN_WARNING "IIC: CPU association not found\n");
+ iic->regs = NULL;
+ iic->target_id = 0xff;
+ return -ENODEV;
+ }
+
+ iic = &per_cpu(iic, np[0]);
+ iic->regs = ioremap(regs[0], sizeof(struct iic_regs));
+ iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
+ printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
+
+ iic = &per_cpu(iic, np[1]);
+ iic->regs = ioremap(regs[2], sizeof(struct iic_regs));
+ iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
+ printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
+
+ found++;
+ }
+
+ if (found)
+ return 0;
+ else
+ return -ENODEV;
}
#ifdef CONFIG_SMP
@@ -283,10 +360,12 @@ void iic_init_IRQ(void)
int cpu, irq_offset;
struct iic *iic;
+ if (setup_iic() < 0)
+ setup_iic_hardcoded();
+
irq_offset = 0;
- for_each_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
iic = &per_cpu(iic, cpu);
- setup_iic(cpu, iic);
if (iic->regs)
out_be64(&iic->regs->prio, 0xff);
}
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index a14bd38791c..799f77d98f9 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -57,7 +57,7 @@ extern void iic_local_disable(void);
extern u8 iic_get_target_id(int cpu);
extern void spider_init_IRQ(void);
-extern int spider_get_irq(unsigned long int_pending);
+extern int spider_get_irq(int node);
#endif
#endif /* ASM_CELL_PIC_H */
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 46e7cb9c3e6..a49ceb799a8 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -289,7 +289,7 @@ static void cell_do_map_iommu(struct cell_iommu *iommu,
ioc_base = iommu->mapped_base;
ioc_mmio_base = iommu->mapped_mmio_base;
- for (real_address = 0, io_address = 0;
+ for (real_address = 0, io_address = map_start;
io_address <= map_start + map_size;
real_address += io_page_size, io_address += io_page_size) {
ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
@@ -302,7 +302,7 @@ static void cell_do_map_iommu(struct cell_iommu *iommu,
set_iopt_cache(ioc_mmio_base,
get_ioc_hash_1way(ioste, io_address),
get_ioc_tag(ioste, io_address),
- get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW));
+ get_iopt_entry(real_address, ioid, IOPT_PROT_RW));
}
}
@@ -344,8 +344,8 @@ static int cell_map_iommu_hardcoded(int num_nodes)
/* node 0 */
iommu = &cell_iommus[0];
- iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE);
- iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE);
+ iommu->mapped_base = ioremap(0x20000511000, 0x1000);
+ iommu->mapped_mmio_base = ioremap(0x20000510000, 0x1000);
enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
@@ -357,8 +357,8 @@ static int cell_map_iommu_hardcoded(int num_nodes)
/* node 1 */
iommu = &cell_iommus[1];
- iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE);
- iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE);
+ iommu->mapped_base = ioremap(0x30000511000, 0x1000);
+ iommu->mapped_mmio_base = ioremap(0x30000510000, 0x1000);
enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
@@ -407,8 +407,8 @@ static int cell_map_iommu(void)
iommu->base = *base;
iommu->mmio_base = *mmio_base;
- iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE);
- iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE);
+ iommu->mapped_base = ioremap(*base, 0x1000);
+ iommu->mapped_mmio_base = ioremap(*mmio_base, 0x1000);
enable_mapping(iommu->mapped_base,
iommu->mapped_mmio_base);
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index e0e051c675d..7eed8c62451 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -203,7 +203,7 @@ found:
pr_debug("pervasive area for CPU %d at %lx, size %x\n",
cpu, real_address, size);
- p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE);
+ p->regs = ioremap(real_address, size);
p->thread = thread;
return 0;
}
@@ -217,7 +217,7 @@ void __init cell_pervasive_init(void)
if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
return;
- for_each_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
p = &cbe_pervasive[cpu];
ret = cbe_find_pmd_mmio(cpu, p);
if (ret)
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index fec8e65b36e..dac5d0365fd 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -195,9 +195,13 @@ static void __init cell_init_early(void)
}
-static int __init cell_probe(int platform)
+static int __init cell_probe(void)
{
- if (platform != PLATFORM_CELL)
+ /* XXX This is temporary, the Cell maintainer will come up with
+ * more appropriate detection logic
+ */
+ unsigned long root = of_get_flat_dt_root();
+ if (!of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
return 0;
return 1;
@@ -212,7 +216,8 @@ static int cell_check_legacy_ioport(unsigned int baseport)
return -ENODEV;
}
-struct machdep_calls __initdata cell_md = {
+define_machine(cell) {
+ .name = "Cell",
.probe = cell_probe,
.setup_arch = cell_setup_arch,
.init_early = cell_init_early,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index e74132188bd..55cbdd77a62 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -84,10 +84,11 @@ static void __iomem *spider_get_irq_config(int irq)
static void spider_enable_irq(unsigned int irq)
{
+ int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
void __iomem *cfg = spider_get_irq_config(irq);
irq = spider_get_nr(irq);
- out_be32(cfg, in_be32(cfg) | 0x3107000eu);
+ out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
}
@@ -131,61 +132,108 @@ static struct hw_interrupt_type spider_pic = {
.end = spider_end_irq,
};
-
-int spider_get_irq(unsigned long int_pending)
+int spider_get_irq(int node)
{
- void __iomem *regs = spider_get_pic(int_pending);
unsigned long cs;
- int irq;
-
- cs = in_be32(regs + TIR_CS);
+ void __iomem *regs = spider_pics[node];
- irq = cs >> 24;
- if (irq != 63)
- return irq;
+ cs = in_be32(regs + TIR_CS) >> 24;
- return -1;
+ if (cs == 63)
+ return -1;
+ else
+ return cs;
}
-
-void spider_init_IRQ(void)
+
+/* hardcoded part to be compatible with older firmware */
+
+void spider_init_IRQ_hardcoded(void)
{
int node;
- struct device_node *dn;
- unsigned int *property;
long spiderpic;
+ long pics[] = { 0x24000008000, 0x34000008000 };
int n;
-/* FIXME: detect multiple PICs as soon as the device tree has them */
- for (node = 0; node < 1; node++) {
- dn = of_find_node_by_path("/");
- n = prom_n_addr_cells(dn);
- property = (unsigned int *) get_property(dn,
- "platform-spider-pic", NULL);
+ pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
- if (!property)
- continue;
- for (spiderpic = 0; n > 0; --n)
- spiderpic = (spiderpic << 32) + *property++;
+ for (node = 0; node < num_present_cpus()/2; node++) {
+ spiderpic = pics[node];
printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
- spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE);
+ spider_pics[node] = ioremap(spiderpic, 0x800);
for (n = 0; n < IIC_NUM_EXT; n++) {
int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
get_irq_desc(irq)->handler = &spider_pic;
+ }
/* do not mask any interrupts because of level */
out_be32(spider_pics[node] + TIR_MSK, 0x0);
-
+
/* disable edge detection clear */
/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
-
+
/* enable interrupt packets to be output */
out_be32(spider_pics[node] + TIR_PIEN,
in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
-
+
/* Enable the interrupt detection enable bit. Do this last! */
out_be32(spider_pics[node] + TIR_DEN,
- in_be32(spider_pics[node] +TIR_DEN) | 0x1);
+ in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+ }
+}
+
+void spider_init_IRQ(void)
+{
+ long spider_reg;
+ struct device_node *dn;
+ char *compatible;
+ int n, node = 0;
+
+ for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
+ compatible = (char *)get_property(dn, "compatible", NULL);
+ if (!compatible)
+ continue;
+
+ if (strstr(compatible, "CBEA,platform-spider-pic"))
+ spider_reg = *(long *)get_property(dn,"reg", NULL);
+ else if (strstr(compatible, "sti,platform-spider-pic")) {
+ spider_init_IRQ_hardcoded();
+ return;
+ } else
+ continue;
+
+ if (!spider_reg)
+ printk("interrupt controller does not have reg property !\n");
+
+ n = prom_n_addr_cells(dn);
+
+ if ( n != 2)
+ printk("reg property with invalid number of elements \n");
+
+ spider_pics[node] = ioremap(spider_reg, 0x800);
+
+ printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
+ spider_reg, n, spider_pics[node]);
+
+ for (n = 0; n < IIC_NUM_EXT; n++) {
+ int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
+ get_irq_desc(irq)->handler = &spider_pic;
}
+
+ /* do not mask any interrupts because of level */
+ out_be32(spider_pics[node] + TIR_MSK, 0x0);
+
+ /* disable edge detection clear */
+ /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
+
+ /* enable interrupt packets to be output */
+ out_be32(spider_pics[node] + TIR_PIEN,
+ in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
+
+ /* Enable the interrupt detection enable bit. Do this last! */
+ out_be32(spider_pics[node] + TIR_DEN,
+ in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+
+ node++;
}
}
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index d75ae03df68..269dda4fd0b 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -32,7 +32,7 @@
#include <asm/io.h>
#include <asm/prom.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/spu.h>
#include <asm/mmu_context.h>
@@ -111,7 +111,7 @@ 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)
{
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea);
/* Handle kernel space hash faults immediately.
User hash faults need to be deferred to process context. */
@@ -168,7 +168,7 @@ static int __spu_trap_halt(struct spu *spu)
static int __spu_trap_tag_group(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
- /* wake_up(&spu->dma_wq); */
+ spu->mfc_callback(spu);
return 0;
}
@@ -242,6 +242,8 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
spu_mfc_dsisr_set(spu, 0ul);
spu_int_stat_clear(spu, 1, stat);
spin_unlock(&spu->register_lock);
+ pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat,
+ dar, dsisr);
if (stat & 1) /* segment fault */
__spu_trap_data_seg(spu, dar);
@@ -342,7 +344,7 @@ spu_free_irqs(struct spu *spu)
}
static LIST_HEAD(spu_list);
-static DECLARE_MUTEX(spu_mutex);
+static DEFINE_MUTEX(spu_mutex);
static void spu_init_channels(struct spu *spu)
{
@@ -382,7 +384,7 @@ struct spu *spu_alloc(void)
{
struct spu *spu;
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
if (!list_empty(&spu_list)) {
spu = list_entry(spu_list.next, struct spu, list);
list_del_init(&spu->list);
@@ -391,7 +393,7 @@ struct spu *spu_alloc(void)
pr_debug("No SPU left\n");
spu = NULL;
}
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
if (spu)
spu_init_channels(spu);
@@ -402,9 +404,9 @@ EXPORT_SYMBOL_GPL(spu_alloc);
void spu_free(struct spu *spu)
{
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
list_add_tail(&spu->list, &spu_list);
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
}
EXPORT_SYMBOL_GPL(spu_free);
@@ -484,14 +486,13 @@ int spu_irq_class_1_bottom(struct spu *spu)
ea = spu->dar;
dsisr = spu->dsisr;
- if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
+ if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
access = (_PAGE_PRESENT | _PAGE_USER);
access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
if (hash_page(ea, access, 0x300) != 0)
error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
}
- if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||
- (dsisr & MFC_DSISR_ACCESS_DENIED)) {
+ if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
if ((ret = spu_handle_mm_fault(spu)) != 0)
error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
else
@@ -568,6 +569,11 @@ static int __init spu_map_device(struct spu *spu, struct device_node *spe)
if (!spu->local_store)
goto out;
+ prop = get_property(spe, "problem", NULL);
+ if (!prop)
+ goto out_unmap;
+ spu->problem_phys = *(unsigned long *)prop;
+
spu->problem= map_spe_prop(spe, "problem");
if (!spu->problem)
goto out_unmap;
@@ -632,15 +638,16 @@ static int __init create_spu(struct device_node *spe)
spu->ibox_callback = NULL;
spu->wbox_callback = NULL;
spu->stop_callback = NULL;
+ spu->mfc_callback = NULL;
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
spu->number = number++;
ret = spu_request_irqs(spu);
if (ret)
goto out_unmap;
list_add(&spu->list, &spu_list);
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
spu->name, spu->isrc, spu->local_store,
@@ -648,7 +655,7 @@ static int __init create_spu(struct device_node *spe)
goto out;
out_unmap:
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
spu_unmap(spu);
out_free:
kfree(spu);
@@ -668,10 +675,10 @@ static void destroy_spu(struct spu *spu)
static void cleanup_spu_base(void)
{
struct spu *spu, *tmp;
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
list_for_each_entry_safe(spu, tmp, &spu_list, list)
destroy_spu(spu);
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
}
module_exit(cleanup_spu_base);
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c
new file mode 100644
index 00000000000..3a4245c926a
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_callbacks.c
@@ -0,0 +1,345 @@
+/*
+ * System call callback functions for SPUs
+ */
+
+#define DEBUG
+
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+#include <asm/spu.h>
+#include <asm/syscalls.h>
+#include <asm/unistd.h>
+
+/*
+ * This table defines the system calls that an SPU can call.
+ * It is currently a subset of the 64 bit powerpc system calls,
+ * with the exact semantics.
+ *
+ * The reasons for disabling some of the system calls are:
+ * 1. They interact with the way SPU syscalls are handled
+ * and we can't let them execute ever:
+ * restart_syscall, exit, for, execve, ptrace, ...
+ * 2. They are deprecated and replaced by other means:
+ * uselib, pciconfig_*, sysfs, ...
+ * 3. They are somewhat interacting with the system in a way
+ * we don't want an SPU to:
+ * reboot, init_module, mount, kexec_load
+ * 4. They are optional and we can't rely on them being
+ * linked into the kernel. Unfortunately, the cond_syscall
+ * helper does not work here as it does not add the necessary
+ * opd symbols:
+ * mbind, mq_open, ipc, ...
+ */
+
+void *spu_syscall_table[] = {
+ [__NR_restart_syscall] sys_ni_syscall, /* sys_restart_syscall */
+ [__NR_exit] sys_ni_syscall, /* sys_exit */
+ [__NR_fork] sys_ni_syscall, /* ppc_fork */
+ [__NR_read] sys_read,
+ [__NR_write] sys_write,
+ [__NR_open] sys_open,
+ [__NR_close] sys_close,
+ [__NR_waitpid] sys_waitpid,
+ [__NR_creat] sys_creat,
+ [__NR_link] sys_link,
+ [__NR_unlink] sys_unlink,
+ [__NR_execve] sys_ni_syscall, /* sys_execve */
+ [__NR_chdir] sys_chdir,
+ [__NR_time] sys_time,
+ [__NR_mknod] sys_mknod,
+ [__NR_chmod] sys_chmod,
+ [__NR_lchown] sys_lchown,
+ [__NR_break] sys_ni_syscall,
+ [__NR_oldstat] sys_ni_syscall,
+ [__NR_lseek] sys_lseek,
+ [__NR_getpid] sys_getpid,
+ [__NR_mount] sys_ni_syscall, /* sys_mount */
+ [__NR_umount] sys_ni_syscall,
+ [__NR_setuid] sys_setuid,
+ [__NR_getuid] sys_getuid,
+ [__NR_stime] sys_stime,
+ [__NR_ptrace] sys_ni_syscall, /* sys_ptrace */
+ [__NR_alarm] sys_alarm,
+ [__NR_oldfstat] sys_ni_syscall,
+ [__NR_pause] sys_ni_syscall, /* sys_pause */
+ [__NR_utime] sys_ni_syscall, /* sys_utime */
+ [__NR_stty] sys_ni_syscall,
+ [__NR_gtty] sys_ni_syscall,
+ [__NR_access] sys_access,
+ [__NR_nice] sys_nice,
+ [__NR_ftime] sys_ni_syscall,
+ [__NR_sync] sys_sync,
+ [__NR_kill] sys_kill,
+ [__NR_rename] sys_rename,
+ [__NR_mkdir] sys_mkdir,
+ [__NR_rmdir] sys_rmdir,
+ [__NR_dup] sys_dup,
+ [__NR_pipe] sys_pipe,
+ [__NR_times] sys_times,
+ [__NR_prof] sys_ni_syscall,
+ [__NR_brk] sys_brk,
+ [__NR_setgid] sys_setgid,
+ [__NR_getgid] sys_getgid,
+ [__NR_signal] sys_ni_syscall, /* sys_signal */
+ [__NR_geteuid] sys_geteuid,
+ [__NR_getegid] sys_getegid,
+ [__NR_acct] sys_ni_syscall, /* sys_acct */
+ [__NR_umount2] sys_ni_syscall, /* sys_umount */
+ [__NR_lock] sys_ni_syscall,
+ [__NR_ioctl] sys_ioctl,
+ [__NR_fcntl] sys_fcntl,
+ [__NR_mpx] sys_ni_syscall,
+ [__NR_setpgid] sys_setpgid,
+ [__NR_ulimit] sys_ni_syscall,
+ [__NR_oldolduname] sys_ni_syscall,
+ [__NR_umask] sys_umask,
+ [__NR_chroot] sys_chroot,
+ [__NR_ustat] sys_ni_syscall, /* sys_ustat */
+ [__NR_dup2] sys_dup2,
+ [__NR_getppid] sys_getppid,
+ [__NR_getpgrp] sys_getpgrp,
+ [__NR_setsid] sys_setsid,
+ [__NR_sigaction] sys_ni_syscall,
+ [__NR_sgetmask] sys_sgetmask,
+ [__NR_ssetmask] sys_ssetmask,
+ [__NR_setreuid] sys_setreuid,
+ [__NR_setregid] sys_setregid,
+ [__NR_sigsuspend] sys_ni_syscall,
+ [__NR_sigpending] sys_ni_syscall,
+ [__NR_sethostname] sys_sethostname,
+ [__NR_setrlimit] sys_setrlimit,
+ [__NR_getrlimit] sys_ni_syscall,
+ [__NR_getrusage] sys_getrusage,
+ [__NR_gettimeofday] sys_gettimeofday,
+ [__NR_settimeofday] sys_settimeofday,
+ [__NR_getgroups] sys_getgroups,
+ [__NR_setgroups] sys_setgroups,
+ [__NR_select] sys_ni_syscall,
+ [__NR_symlink] sys_symlink,
+ [__NR_oldlstat] sys_ni_syscall,
+ [__NR_readlink] sys_readlink,
+ [__NR_uselib] sys_ni_syscall, /* sys_uselib */
+ [__NR_swapon] sys_ni_syscall, /* sys_swapon */
+ [__NR_reboot] sys_ni_syscall, /* sys_reboot */
+ [__NR_readdir] sys_ni_syscall,
+ [__NR_mmap] sys_mmap,
+ [__NR_munmap] sys_munmap,
+ [__NR_truncate] sys_truncate,
+ [__NR_ftruncate] sys_ftruncate,
+ [__NR_fchmod] sys_fchmod,
+ [__NR_fchown] sys_fchown,
+ [__NR_getpriority] sys_getpriority,
+ [__NR_setpriority] sys_setpriority,
+ [__NR_profil] sys_ni_syscall,
+ [__NR_statfs] sys_ni_syscall, /* sys_statfs */
+ [__NR_fstatfs] sys_ni_syscall, /* sys_fstatfs */
+ [__NR_ioperm] sys_ni_syscall,
+ [__NR_socketcall] sys_socketcall,
+ [__NR_syslog] sys_syslog,
+ [__NR_setitimer] sys_setitimer,
+ [__NR_getitimer] sys_getitimer,
+ [__NR_stat] sys_newstat,
+ [__NR_lstat] sys_newlstat,
+ [__NR_fstat] sys_newfstat,
+ [__NR_olduname] sys_ni_syscall,
+ [__NR_iopl] sys_ni_syscall,
+ [__NR_vhangup] sys_vhangup,
+ [__NR_idle] sys_ni_syscall,
+ [__NR_vm86] sys_ni_syscall,
+ [__NR_wait4] sys_wait4,
+ [__NR_swapoff] sys_ni_syscall, /* sys_swapoff */
+ [__NR_sysinfo] sys_sysinfo,
+ [__NR_ipc] sys_ni_syscall, /* sys_ipc */
+ [__NR_fsync] sys_fsync,
+ [__NR_sigreturn] sys_ni_syscall,
+ [__NR_clone] sys_ni_syscall, /* ppc_clone */
+ [__NR_setdomainname] sys_setdomainname,
+ [__NR_uname] ppc_newuname,
+ [__NR_modify_ldt] sys_ni_syscall,
+ [__NR_adjtimex] sys_adjtimex,
+ [__NR_mprotect] sys_mprotect,
+ [__NR_sigprocmask] sys_ni_syscall,
+ [__NR_create_module] sys_ni_syscall,
+ [__NR_init_module] sys_ni_syscall, /* sys_init_module */
+ [__NR_delete_module] sys_ni_syscall, /* sys_delete_module */
+ [__NR_get_kernel_syms] sys_ni_syscall,
+ [__NR_quotactl] sys_ni_syscall, /* sys_quotactl */
+ [__NR_getpgid] sys_getpgid,
+ [__NR_fchdir] sys_fchdir,
+ [__NR_bdflush] sys_bdflush,
+ [__NR_sysfs] sys_ni_syscall, /* sys_sysfs */
+ [__NR_personality] ppc64_personality,
+ [__NR_afs_syscall] sys_ni_syscall,
+ [__NR_setfsuid] sys_setfsuid,
+ [__NR_setfsgid] sys_setfsgid,
+ [__NR__llseek] sys_llseek,
+ [__NR_getdents] sys_getdents,
+ [__NR__newselect] sys_select,
+ [__NR_flock] sys_flock,
+ [__NR_msync] sys_msync,
+ [__NR_readv] sys_readv,
+ [__NR_writev] sys_writev,
+ [__NR_getsid] sys_getsid,
+ [__NR_fdatasync] sys_fdatasync,
+ [__NR__sysctl] sys_ni_syscall, /* sys_sysctl */
+ [__NR_mlock] sys_mlock,
+ [__NR_munlock] sys_munlock,
+ [__NR_mlockall] sys_mlockall,
+ [__NR_munlockall] sys_munlockall,
+ [__NR_sched_setparam] sys_sched_setparam,
+ [__NR_sched_getparam] sys_sched_getparam,
+ [__NR_sched_setscheduler] sys_sched_setscheduler,
+ [__NR_sched_getscheduler] sys_sched_getscheduler,
+ [__NR_sched_yield] sys_sched_yield,
+ [__NR_sched_get_priority_max] sys_sched_get_priority_max,
+ [__NR_sched_get_priority_min] sys_sched_get_priority_min,
+ [__NR_sched_rr_get_interval] sys_sched_rr_get_interval,
+ [__NR_nanosleep] sys_nanosleep,
+ [__NR_mremap] sys_mremap,
+ [__NR_setresuid] sys_setresuid,
+ [__NR_getresuid] sys_getresuid,
+ [__NR_query_module] sys_ni_syscall,
+ [__NR_poll] sys_poll,
+ [__NR_nfsservctl] sys_ni_syscall, /* sys_nfsservctl */
+ [__NR_setresgid] sys_setresgid,
+ [__NR_getresgid] sys_getresgid,
+ [__NR_prctl] sys_prctl,
+ [__NR_rt_sigreturn] sys_ni_syscall, /* ppc64_rt_sigreturn */
+ [__NR_rt_sigaction] sys_ni_syscall, /* sys_rt_sigaction */
+ [__NR_rt_sigprocmask] sys_ni_syscall, /* sys_rt_sigprocmask */
+ [__NR_rt_sigpending] sys_ni_syscall, /* sys_rt_sigpending */
+ [__NR_rt_sigtimedwait] sys_ni_syscall, /* sys_rt_sigtimedwait */
+ [__NR_rt_sigqueueinfo] sys_ni_syscall, /* sys_rt_sigqueueinfo */
+ [__NR_rt_sigsuspend] sys_ni_syscall, /* sys_rt_sigsuspend */
+ [__NR_pread64] sys_pread64,
+ [__NR_pwrite64] sys_pwrite64,
+ [__NR_chown] sys_chown,
+ [__NR_getcwd] sys_getcwd,
+ [__NR_capget] sys_capget,
+ [__NR_capset] sys_capset,
+ [__NR_sigaltstack] sys_ni_syscall, /* sys_sigaltstack */
+ [__NR_sendfile] sys_sendfile64,
+ [__NR_getpmsg] sys_ni_syscall,
+ [__NR_putpmsg] sys_ni_syscall,
+ [__NR_vfork] sys_ni_syscall, /* ppc_vfork */
+ [__NR_ugetrlimit] sys_getrlimit,
+ [__NR_readahead] sys_readahead,
+ [192] sys_ni_syscall,
+ [193] sys_ni_syscall,
+ [194] sys_ni_syscall,
+ [195] sys_ni_syscall,
+ [196] sys_ni_syscall,
+ [197] sys_ni_syscall,
+ [__NR_pciconfig_read] sys_ni_syscall, /* sys_pciconfig_read */
+ [__NR_pciconfig_write] sys_ni_syscall, /* sys_pciconfig_write */
+ [__NR_pciconfig_iobase] sys_ni_syscall, /* sys_pciconfig_iobase */
+ [__NR_multiplexer] sys_ni_syscall,
+ [__NR_getdents64] sys_getdents64,
+ [__NR_pivot_root] sys_pivot_root,
+ [204] sys_ni_syscall,
+ [__NR_madvise] sys_madvise,
+ [__NR_mincore] sys_mincore,
+ [__NR_gettid] sys_gettid,
+ [__NR_tkill] sys_tkill,
+ [__NR_setxattr] sys_setxattr,
+ [__NR_lsetxattr] sys_lsetxattr,
+ [__NR_fsetxattr] sys_fsetxattr,
+ [__NR_getxattr] sys_getxattr,
+ [__NR_lgetxattr] sys_lgetxattr,
+ [__NR_fgetxattr] sys_fgetxattr,
+ [__NR_listxattr] sys_listxattr,
+ [__NR_llistxattr] sys_llistxattr,
+ [__NR_flistxattr] sys_flistxattr,
+ [__NR_removexattr] sys_removexattr,
+ [__NR_lremovexattr] sys_lremovexattr,
+ [__NR_fremovexattr] sys_fremovexattr,
+ [__NR_futex] sys_futex,
+ [__NR_sched_setaffinity] sys_sched_setaffinity,
+ [__NR_sched_getaffinity] sys_sched_getaffinity,
+ [__NR_tuxcall] sys_ni_syscall,
+ [226] sys_ni_syscall,
+ [__NR_io_setup] sys_io_setup,
+ [__NR_io_destroy] sys_io_destroy,
+ [__NR_io_getevents] sys_io_getevents,
+ [__NR_io_submit] sys_io_submit,
+ [__NR_io_cancel] sys_io_cancel,
+ [__NR_set_tid_address] sys_ni_syscall, /* sys_set_tid_address */
+ [__NR_fadvise64] sys_fadvise64,
+ [__NR_exit_group] sys_ni_syscall, /* sys_exit_group */
+ [__NR_lookup_dcookie] sys_ni_syscall, /* sys_lookup_dcookie */
+ [__NR_epoll_create] sys_epoll_create,
+ [__NR_epoll_ctl] sys_epoll_ctl,
+ [__NR_epoll_wait] sys_epoll_wait,
+ [__NR_remap_file_pages] sys_remap_file_pages,
+ [__NR_timer_create] sys_timer_create,
+ [__NR_timer_settime] sys_timer_settime,
+ [__NR_timer_gettime] sys_timer_gettime,
+ [__NR_timer_getoverrun] sys_timer_getoverrun,
+ [__NR_timer_delete] sys_timer_delete,
+ [__NR_clock_settime] sys_clock_settime,
+ [__NR_clock_gettime] sys_clock_gettime,
+ [__NR_clock_getres] sys_clock_getres,
+ [__NR_clock_nanosleep] sys_clock_nanosleep,
+ [__NR_swapcontext] sys_ni_syscall, /* ppc64_swapcontext */
+ [__NR_tgkill] sys_tgkill,
+ [__NR_utimes] sys_utimes,
+ [__NR_statfs64] sys_statfs64,
+ [__NR_fstatfs64] sys_fstatfs64,
+ [254] sys_ni_syscall,
+ [__NR_rtas] ppc_rtas,
+ [256] sys_ni_syscall,
+ [257] sys_ni_syscall,
+ [258] sys_ni_syscall,
+ [__NR_mbind] sys_ni_syscall, /* sys_mbind */
+ [__NR_get_mempolicy] sys_ni_syscall, /* sys_get_mempolicy */
+ [__NR_set_mempolicy] sys_ni_syscall, /* sys_set_mempolicy */
+ [__NR_mq_open] sys_ni_syscall, /* sys_mq_open */
+ [__NR_mq_unlink] sys_ni_syscall, /* sys_mq_unlink */
+ [__NR_mq_timedsend] sys_ni_syscall, /* sys_mq_timedsend */
+ [__NR_mq_timedreceive] sys_ni_syscall, /* sys_mq_timedreceive */
+ [__NR_mq_notify] sys_ni_syscall, /* sys_mq_notify */
+ [__NR_mq_getsetattr] sys_ni_syscall, /* sys_mq_getsetattr */
+ [__NR_kexec_load] sys_ni_syscall, /* sys_kexec_load */
+ [__NR_add_key] sys_ni_syscall, /* sys_add_key */
+ [__NR_request_key] sys_ni_syscall, /* sys_request_key */
+ [__NR_keyctl] sys_ni_syscall, /* sys_keyctl */
+ [__NR_waitid] sys_ni_syscall, /* sys_waitid */
+ [__NR_ioprio_set] sys_ni_syscall, /* sys_ioprio_set */
+ [__NR_ioprio_get] sys_ni_syscall, /* sys_ioprio_get */
+ [__NR_inotify_init] sys_ni_syscall, /* sys_inotify_init */
+ [__NR_inotify_add_watch] sys_ni_syscall, /* sys_inotify_add_watch */
+ [__NR_inotify_rm_watch] sys_ni_syscall, /* sys_inotify_rm_watch */
+ [__NR_spu_run] sys_ni_syscall, /* sys_spu_run */
+ [__NR_spu_create] sys_ni_syscall, /* sys_spu_create */
+ [__NR_pselect6] sys_ni_syscall, /* sys_pselect */
+ [__NR_ppoll] sys_ni_syscall, /* sys_ppoll */
+ [__NR_unshare] sys_unshare,
+};
+
+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) {
+ pr_debug("%s: invalid syscall #%ld", __FUNCTION__, s->nr_ret);
+ return -ENOSYS;
+ }
+
+#ifdef DEBUG
+ print_symbol(KERN_DEBUG "SPU-syscall %s:", (unsigned long)syscall);
+ printk("syscall%ld(%lx, %lx, %lx, %lx, %lx, %lx)\n",
+ s->nr_ret,
+ s->parm[0], s->parm[1], s->parm[2],
+ s->parm[3], s->parm[4], s->parm[5]);
+#endif
+
+ return syscall(s->parm[0], s->parm[1], s->parm[2],
+ s->parm[3], s->parm[4], s->parm[5]);
+}
+EXPORT_SYMBOL_GPL(spu_sys_callback);
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
index a5c489a53c6..f1d35ddc9df 100644
--- a/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -285,6 +285,49 @@ static void spu_backing_runcntl_stop(struct spu_context *ctx)
spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
}
+static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
+ u32 mode)
+{
+ struct spu_problem_collapsed *prob = &ctx->csa.prob;
+ int ret;
+
+ spin_lock(&ctx->csa.register_lock);
+ ret = -EAGAIN;
+ if (prob->dma_querytype_RW)
+ goto out;
+ ret = 0;
+ /* FIXME: what are the side-effects of this? */
+ prob->dma_querymask_RW = mask;
+ prob->dma_querytype_RW = mode;
+out:
+ spin_unlock(&ctx->csa.register_lock);
+
+ return ret;
+}
+
+static u32 spu_backing_read_mfc_tagstatus(struct spu_context * ctx)
+{
+ return ctx->csa.prob.dma_tagstatus_R;
+}
+
+static u32 spu_backing_get_mfc_free_elements(struct spu_context *ctx)
+{
+ return ctx->csa.prob.dma_qstatus_R;
+}
+
+static int spu_backing_send_mfc_command(struct spu_context *ctx,
+ struct mfc_dma_command *cmd)
+{
+ int ret;
+
+ spin_lock(&ctx->csa.register_lock);
+ ret = -EAGAIN;
+ /* FIXME: set up priv2->puq */
+ spin_unlock(&ctx->csa.register_lock);
+
+ return ret;
+}
+
struct spu_context_ops spu_backing_ops = {
.mbox_read = spu_backing_mbox_read,
.mbox_stat_read = spu_backing_mbox_stat_read,
@@ -305,4 +348,8 @@ struct spu_context_ops spu_backing_ops = {
.get_ls = spu_backing_get_ls,
.runcntl_write = spu_backing_runcntl_write,
.runcntl_stop = spu_backing_runcntl_stop,
+ .set_mfc_query = spu_backing_set_mfc_query,
+ .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
+ .get_mfc_free_elements = spu_backing_get_mfc_free_elements,
+ .send_mfc_command = spu_backing_send_mfc_command,
};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 336f238102f..8bb33abfad1 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -27,7 +27,7 @@
#include <asm/spu_csa.h>
#include "spufs.h"
-struct spu_context *alloc_spu_context(struct address_space *local_store)
+struct spu_context *alloc_spu_context(void)
{
struct spu_context *ctx;
ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
@@ -47,10 +47,17 @@ struct spu_context *alloc_spu_context(struct address_space *local_store)
init_waitqueue_head(&ctx->ibox_wq);
init_waitqueue_head(&ctx->wbox_wq);
init_waitqueue_head(&ctx->stop_wq);
+ init_waitqueue_head(&ctx->mfc_wq);
ctx->ibox_fasync = NULL;
ctx->wbox_fasync = NULL;
+ ctx->mfc_fasync = NULL;
+ ctx->mfc = NULL;
+ ctx->tagwait = 0;
ctx->state = SPU_STATE_SAVED;
- ctx->local_store = local_store;
+ ctx->local_store = NULL;
+ ctx->cntl = NULL;
+ ctx->signal1 = NULL;
+ ctx->signal2 = NULL;
ctx->spu = NULL;
ctx->ops = &spu_backing_ops;
ctx->owner = get_task_mm(current);
@@ -68,8 +75,6 @@ void destroy_spu_context(struct kref *kref)
ctx = container_of(kref, struct spu_context, kref);
down_write(&ctx->state_sema);
spu_deactivate(ctx);
- ctx->ibox_fasync = NULL;
- ctx->wbox_fasync = NULL;
up_write(&ctx->state_sema);
spu_fini_csa(&ctx->csa);
kfree(ctx);
@@ -109,7 +114,16 @@ void spu_release(struct spu_context *ctx)
void spu_unmap_mappings(struct spu_context *ctx)
{
- unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+ if (ctx->local_store)
+ unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+ if (ctx->mfc)
+ unmap_mapping_range(ctx->mfc, 0, 0x4000, 1);
+ if (ctx->cntl)
+ unmap_mapping_range(ctx->cntl, 0, 0x4000, 1);
+ if (ctx->signal1)
+ unmap_mapping_range(ctx->signal1, 0, 0x4000, 1);
+ if (ctx->signal2)
+ unmap_mapping_range(ctx->signal2, 0, 0x4000, 1);
}
int spu_acquire_runnable(struct spu_context *ctx)
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index dfa649c9b95..366185e9266 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#undef DEBUG
+
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/module.h>
@@ -39,8 +41,10 @@ static int
spufs_mem_open(struct inode *inode, struct file *file)
{
struct spufs_inode_info *i = SPUFS_I(inode);
- file->private_data = i->i_ctx;
- file->f_mapping = i->i_ctx->local_store;
+ struct spu_context *ctx = i->i_ctx;
+ file->private_data = ctx;
+ file->f_mapping = inode->i_mapping;
+ ctx->local_store = inode->i_mapping;
return 0;
}
@@ -84,7 +88,7 @@ spufs_mem_write(struct file *file, const char __user *buffer,
return ret;
}
-#ifdef CONFIG_SPARSEMEM
+#ifdef CONFIG_SPUFS_MMAP
static struct page *
spufs_mem_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
@@ -136,11 +140,113 @@ static struct file_operations spufs_mem_fops = {
.read = spufs_mem_read,
.write = spufs_mem_write,
.llseek = generic_file_llseek,
-#ifdef CONFIG_SPARSEMEM
+#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mem_mmap,
#endif
};
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int *type, unsigned long ps_offs)
+{
+ struct page *page = NOPAGE_SIGBUS;
+ int fault_type = VM_FAULT_SIGBUS;
+ struct spu_context *ctx = vma->vm_file->private_data;
+ unsigned long offset = address - vma->vm_start;
+ unsigned long area;
+ int ret;
+
+ offset += vma->vm_pgoff << PAGE_SHIFT;
+ if (offset >= 0x4000)
+ goto out;
+
+ ret = spu_acquire_runnable(ctx);
+ if (ret)
+ goto out;
+
+ area = ctx->spu->problem_phys + ps_offs;
+ page = pfn_to_page((area + offset) >> PAGE_SHIFT);
+ fault_type = VM_FAULT_MINOR;
+ page_cache_get(page);
+
+ spu_release(ctx);
+
+ out:
+ if (type)
+ *type = fault_type;
+
+ return page;
+}
+
+static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return spufs_ps_nopage(vma, address, type, 0x4000);
+}
+
+static struct vm_operations_struct spufs_cntl_mmap_vmops = {
+ .nopage = spufs_cntl_mmap_nopage,
+};
+
+/*
+ * mmap support for problem state control area [0x4000 - 0x4fff].
+ * Mapping this area requires that the application have CAP_SYS_RAWIO,
+ * as these registers require special care when read/writing.
+ */
+static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE);
+
+ vma->vm_ops = &spufs_cntl_mmap_vmops;
+ return 0;
+}
+#endif
+
+static int spufs_cntl_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ file->private_data = ctx;
+ file->f_mapping = inode->i_mapping;
+ ctx->cntl = inode->i_mapping;
+ return 0;
+}
+
+static ssize_t
+spufs_cntl_read(struct file *file, char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ /* FIXME: read from spu status */
+ return -EINVAL;
+}
+
+static ssize_t
+spufs_cntl_write(struct file *file, const char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ /* FIXME: write to runctl bit */
+ return -EINVAL;
+}
+
+static struct file_operations spufs_cntl_fops = {
+ .open = spufs_cntl_open,
+ .read = spufs_cntl_read,
+ .write = spufs_cntl_write,
+#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_cntl_mmap,
+#endif
+};
+
static int
spufs_regs_open(struct inode *inode, struct file *file)
{
@@ -501,6 +607,16 @@ static struct file_operations spufs_wbox_stat_fops = {
.read = spufs_wbox_stat_read,
};
+static int spufs_signal1_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+ file->private_data = ctx;
+ file->f_mapping = inode->i_mapping;
+ ctx->signal1 = inode->i_mapping;
+ return nonseekable_open(inode, file);
+}
+
static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
@@ -541,12 +657,50 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
return 4;
}
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return spufs_ps_nopage(vma, address, type, 0x14000);
+}
+
+static struct vm_operations_struct spufs_signal1_mmap_vmops = {
+ .nopage = spufs_signal1_mmap_nopage,
+};
+
+static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE);
+
+ vma->vm_ops = &spufs_signal1_mmap_vmops;
+ return 0;
+}
+#endif
+
static struct file_operations spufs_signal1_fops = {
- .open = spufs_pipe_open,
+ .open = spufs_signal1_open,
.read = spufs_signal1_read,
.write = spufs_signal1_write,
+#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_signal1_mmap,
+#endif
};
+static int spufs_signal2_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+ file->private_data = ctx;
+ file->f_mapping = inode->i_mapping;
+ ctx->signal2 = inode->i_mapping;
+ return nonseekable_open(inode, file);
+}
+
static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
@@ -589,10 +743,39 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
return 4;
}
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return spufs_ps_nopage(vma, address, type, 0x1c000);
+}
+
+static struct vm_operations_struct spufs_signal2_mmap_vmops = {
+ .nopage = spufs_signal2_mmap_nopage,
+};
+
+static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ /* FIXME: */
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE);
+
+ vma->vm_ops = &spufs_signal2_mmap_vmops;
+ return 0;
+}
+#endif
+
static struct file_operations spufs_signal2_fops = {
- .open = spufs_pipe_open,
+ .open = spufs_signal2_open,
.read = spufs_signal2_read,
.write = spufs_signal2_write,
+#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_signal2_mmap,
+#endif
};
static void spufs_signal1_type_set(void *data, u64 val)
@@ -641,6 +824,332 @@ static u64 spufs_signal2_type_get(void *data)
DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
spufs_signal2_type_set, "%llu");
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return spufs_ps_nopage(vma, address, type, 0x3000);
+}
+
+static struct vm_operations_struct spufs_mfc_mmap_vmops = {
+ .nopage = spufs_mfc_mmap_nopage,
+};
+
+/*
+ * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
+ * Mapping this area requires that the application have CAP_SYS_RAWIO,
+ * as these registers require special care when read/writing.
+ */
+static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE);
+
+ vma->vm_ops = &spufs_mfc_mmap_vmops;
+ return 0;
+}
+#endif
+
+static int spufs_mfc_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ /* we don't want to deal with DMA into other processes */
+ if (ctx->owner != current->mm)
+ return -EINVAL;
+
+ if (atomic_read(&inode->i_count) != 1)
+ return -EBUSY;
+
+ file->private_data = ctx;
+ return nonseekable_open(inode, file);
+}
+
+/* interrupt-level mfc callback function. */
+void spufs_mfc_callback(struct spu *spu)
+{
+ struct spu_context *ctx = spu->ctx;
+
+ wake_up_all(&ctx->mfc_wq);
+
+ pr_debug("%s %s\n", __FUNCTION__, spu->name);
+ if (ctx->mfc_fasync) {
+ u32 free_elements, tagstatus;
+ unsigned int mask;
+
+ /* no need for spu_acquire in interrupt context */
+ free_elements = ctx->ops->get_mfc_free_elements(ctx);
+ tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
+
+ mask = 0;
+ if (free_elements & 0xffff)
+ mask |= POLLOUT;
+ if (tagstatus & ctx->tagwait)
+ mask |= POLLIN;
+
+ kill_fasync(&ctx->mfc_fasync, SIGIO, mask);
+ }
+}
+
+static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status)
+{
+ /* See if there is one tag group is complete */
+ /* FIXME we need locking around tagwait */
+ *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;
+ ctx->tagwait &= ~*status;
+ if (*status)
+ return 1;
+
+ /* enable interrupt waiting for any tag group,
+ may silently fail if interrupts are already enabled */
+ ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
+ return 0;
+}
+
+static ssize_t spufs_mfc_read(struct file *file, char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ int ret = -EINVAL;
+ u32 status;
+
+ if (size != 4)
+ goto out;
+
+ spu_acquire(ctx);
+ if (file->f_flags & O_NONBLOCK) {
+ status = ctx->ops->read_mfc_tagstatus(ctx);
+ if (!(status & ctx->tagwait))
+ ret = -EAGAIN;
+ else
+ ctx->tagwait &= ~status;
+ } else {
+ ret = spufs_wait(ctx->mfc_wq,
+ spufs_read_mfc_tagstatus(ctx, &status));
+ }
+ spu_release(ctx);
+
+ if (ret)
+ goto out;
+
+ ret = 4;
+ if (copy_to_user(buffer, &status, 4))
+ ret = -EFAULT;
+
+out:
+ return ret;
+}
+
+static int spufs_check_valid_dma(struct mfc_dma_command *cmd)
+{
+ pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa,
+ cmd->ea, cmd->size, cmd->tag, cmd->cmd);
+
+ switch (cmd->cmd) {
+ case MFC_PUT_CMD:
+ case MFC_PUTF_CMD:
+ case MFC_PUTB_CMD:
+ case MFC_GET_CMD:
+ case MFC_GETF_CMD:
+ case MFC_GETB_CMD:
+ break;
+ default:
+ pr_debug("invalid DMA opcode %x\n", cmd->cmd);
+ return -EIO;
+ }
+
+ if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {
+ pr_debug("invalid DMA alignment, ea %lx lsa %x\n",
+ cmd->ea, cmd->lsa);
+ return -EIO;
+ }
+
+ switch (cmd->size & 0xf) {
+ case 1:
+ break;
+ case 2:
+ if (cmd->lsa & 1)
+ goto error;
+ break;
+ case 4:
+ if (cmd->lsa & 3)
+ goto error;
+ break;
+ case 8:
+ if (cmd->lsa & 7)
+ goto error;
+ break;
+ case 0:
+ if (cmd->lsa & 15)
+ goto error;
+ break;
+ error:
+ default:
+ pr_debug("invalid DMA alignment %x for size %x\n",
+ cmd->lsa & 0xf, cmd->size);
+ return -EIO;
+ }
+
+ if (cmd->size > 16 * 1024) {
+ pr_debug("invalid DMA size %x\n", cmd->size);
+ return -EIO;
+ }
+
+ if (cmd->tag & 0xfff0) {
+ /* we reserve the higher tag numbers for kernel use */
+ pr_debug("invalid DMA tag\n");
+ return -EIO;
+ }
+
+ if (cmd->class) {
+ /* not supported in this version */
+ pr_debug("invalid DMA class\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int spu_send_mfc_command(struct spu_context *ctx,
+ struct mfc_dma_command cmd,
+ int *error)
+{
+ *error = ctx->ops->send_mfc_command(ctx, &cmd);
+ if (*error == -EAGAIN) {
+ /* wait for any tag group to complete
+ so we have space for the new command */
+ ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
+ /* try again, because the queue might be
+ empty again */
+ *error = ctx->ops->send_mfc_command(ctx, &cmd);
+ if (*error == -EAGAIN)
+ return 0;
+ }
+ return 1;
+}
+
+static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ struct mfc_dma_command cmd;
+ int ret = -EINVAL;
+
+ if (size != sizeof cmd)
+ goto out;
+
+ ret = -EFAULT;
+ if (copy_from_user(&cmd, buffer, sizeof cmd))
+ goto out;
+
+ ret = spufs_check_valid_dma(&cmd);
+ if (ret)
+ goto out;
+
+ spu_acquire_runnable(ctx);
+ if (file->f_flags & O_NONBLOCK) {
+ ret = ctx->ops->send_mfc_command(ctx, &cmd);
+ } else {
+ int status;
+ ret = spufs_wait(ctx->mfc_wq,
+ spu_send_mfc_command(ctx, cmd, &status));
+ if (status)
+ ret = status;
+ }
+ spu_release(ctx);
+
+ if (ret)
+ goto out;
+
+ ctx->tagwait |= 1 << cmd.tag;
+
+out:
+ return ret;
+}
+
+static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 free_elements, tagstatus;
+ unsigned int mask;
+
+ spu_acquire(ctx);
+ ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
+ free_elements = ctx->ops->get_mfc_free_elements(ctx);
+ tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
+ spu_release(ctx);
+
+ poll_wait(file, &ctx->mfc_wq, wait);
+
+ mask = 0;
+ if (free_elements & 0xffff)
+ mask |= POLLOUT | POLLWRNORM;
+ if (tagstatus & ctx->tagwait)
+ mask |= POLLIN | POLLRDNORM;
+
+ pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__,
+ free_elements, tagstatus, ctx->tagwait);
+
+ return mask;
+}
+
+static int spufs_mfc_flush(struct file *file)
+{
+ struct spu_context *ctx = file->private_data;
+ int ret;
+
+ spu_acquire(ctx);
+#if 0
+/* this currently hangs */
+ ret = spufs_wait(ctx->mfc_wq,
+ ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));
+ if (ret)
+ goto out;
+ ret = spufs_wait(ctx->mfc_wq,
+ ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);
+out:
+#else
+ ret = 0;
+#endif
+ spu_release(ctx);
+
+ return ret;
+}
+
+static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
+ int datasync)
+{
+ return spufs_mfc_flush(file);
+}
+
+static int spufs_mfc_fasync(int fd, struct file *file, int on)
+{
+ struct spu_context *ctx = file->private_data;
+
+ return fasync_helper(fd, file, on, &ctx->mfc_fasync);
+}
+
+static struct file_operations spufs_mfc_fops = {
+ .open = spufs_mfc_open,
+ .read = spufs_mfc_read,
+ .write = spufs_mfc_write,
+ .poll = spufs_mfc_poll,
+ .flush = spufs_mfc_flush,
+ .fsync = spufs_mfc_fsync,
+ .fasync = spufs_mfc_fasync,
+#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_mfc_mmap,
+#endif
+};
+
static void spufs_npc_set(void *data, u64 val)
{
struct spu_context *ctx = data;
@@ -783,6 +1292,8 @@ struct tree_descr spufs_dir_contents[] = {
{ "signal2", &spufs_signal2_fops, 0666, },
{ "signal1_type", &spufs_signal1_type, 0666, },
{ "signal2_type", &spufs_signal2_type, 0666, },
+ { "mfc", &spufs_mfc_fops, 0666, },
+ { "cntl", &spufs_cntl_fops, 0666, },
{ "npc", &spufs_npc_ops, 0666, },
{ "fpcr", &spufs_fpcr_fops, 0666, },
{ "decr", &spufs_decr_ops, 0666, },
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index 5445719bff7..a13a8b5a014 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -232,6 +232,59 @@ static void spu_hw_runcntl_stop(struct spu_context *ctx)
spin_unlock_irq(&ctx->spu->register_lock);
}
+static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
+{
+ struct spu_problem *prob = ctx->spu->problem;
+ int ret;
+
+ spin_lock_irq(&ctx->spu->register_lock);
+ ret = -EAGAIN;
+ if (in_be32(&prob->dma_querytype_RW))
+ goto out;
+ ret = 0;
+ out_be32(&prob->dma_querymask_RW, mask);
+ out_be32(&prob->dma_querytype_RW, mode);
+out:
+ spin_unlock_irq(&ctx->spu->register_lock);
+ return ret;
+}
+
+static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
+{
+ return in_be32(&ctx->spu->problem->dma_tagstatus_R);
+}
+
+static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
+{
+ return in_be32(&ctx->spu->problem->dma_qstatus_R);
+}
+
+static int spu_hw_send_mfc_command(struct spu_context *ctx,
+ struct mfc_dma_command *cmd)
+{
+ u32 status;
+ struct spu_problem *prob = ctx->spu->problem;
+
+ spin_lock_irq(&ctx->spu->register_lock);
+ out_be32(&prob->mfc_lsa_W, cmd->lsa);
+ out_be64(&prob->mfc_ea_W, cmd->ea);
+ out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
+ cmd->size << 16 | cmd->tag);
+ out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
+ cmd->class << 16 | cmd->cmd);
+ status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
+ spin_unlock_irq(&ctx->spu->register_lock);
+
+ switch (status & 0xffff) {
+ case 0:
+ return 0;
+ case 2:
+ return -EAGAIN;
+ default:
+ return -EINVAL;
+ }
+}
+
struct spu_context_ops spu_hw_ops = {
.mbox_read = spu_hw_mbox_read,
.mbox_stat_read = spu_hw_mbox_stat_read,
@@ -252,4 +305,8 @@ struct spu_context_ops spu_hw_ops = {
.get_ls = spu_hw_get_ls,
.runcntl_write = spu_hw_runcntl_write,
.runcntl_stop = spu_hw_runcntl_stop,
+ .set_mfc_query = spu_hw_set_mfc_query,
+ .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
+ .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
+ .send_mfc_command = spu_hw_send_mfc_command,
};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index b3962c3a034..d9554199afa 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -103,7 +103,7 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr)
static int
spufs_new_file(struct super_block *sb, struct dentry *dentry,
- struct file_operations *fops, int mode,
+ const struct file_operations *fops, int mode,
struct spu_context *ctx)
{
static struct inode_operations spufs_file_iops = {
@@ -241,7 +241,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inode->i_gid = dir->i_gid;
inode->i_mode &= S_ISGID;
}
- ctx = alloc_spu_context(inode->i_mapping);
+ ctx = alloc_spu_context();
SPUFS_I(inode)->i_ctx = ctx;
if (!ctx)
goto out_iput;
@@ -442,7 +442,7 @@ static struct file_system_type spufs_type = {
.kill_sb = kill_litter_super,
};
-static int spufs_init(void)
+static int __init spufs_init(void)
{
int ret;
ret = -ENOMEM;
@@ -472,7 +472,7 @@ out:
}
module_init(spufs_init);
-static void spufs_exit(void)
+static void __exit spufs_exit(void)
{
spu_sched_exit();
unregister_spu_syscalls(&spufs_calls);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 18ea8866c61..c04e078c0fe 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -76,6 +76,90 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
return 0;
}
+/*
+ * SPU syscall restarting is tricky because we violate the basic
+ * assumption that the signal handler is running on the interrupted
+ * thread. Here instead, the handler runs on PowerPC user space code,
+ * while the syscall was called from the SPU.
+ * This means we can only do a very rough approximation of POSIX
+ * signal semantics.
+ */
+int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
+ unsigned int *npc)
+{
+ int ret;
+
+ switch (*spu_ret) {
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ /*
+ * Enter the regular syscall restarting for
+ * sys_spu_run, then restart the SPU syscall
+ * callback.
+ */
+ *npc -= 8;
+ ret = -ERESTARTSYS;
+ break;
+ case -ERESTARTNOHAND:
+ case -ERESTART_RESTARTBLOCK:
+ /*
+ * Restart block is too hard for now, just return -EINTR
+ * to the SPU.
+ * ERESTARTNOHAND comes from sys_pause, we also return
+ * -EINTR from there.
+ * Assume that we need to be restarted ourselves though.
+ */
+ *spu_ret = -EINTR;
+ ret = -ERESTARTSYS;
+ break;
+ default:
+ printk(KERN_WARNING "%s: unexpected return code %ld\n",
+ __FUNCTION__, *spu_ret);
+ ret = 0;
+ }
+ return ret;
+}
+
+int spu_process_callback(struct spu_context *ctx)
+{
+ struct spu_syscall_block s;
+ u32 ls_pointer, npc;
+ char *ls;
+ long spu_ret;
+ int ret;
+
+ /* get syscall block from local store */
+ npc = ctx->ops->npc_read(ctx);
+ ls = ctx->ops->get_ls(ctx);
+ ls_pointer = *(u32*)(ls + npc);
+ if (ls_pointer > (LS_SIZE - sizeof(s)))
+ return -EFAULT;
+ memcpy(&s, ls + ls_pointer, sizeof (s));
+
+ /* do actual syscall without pinning the spu */
+ ret = 0;
+ spu_ret = -ENOSYS;
+ npc += 4;
+
+ if (s.nr_ret < __NR_syscalls) {
+ spu_release(ctx);
+ /* do actual system call from here */
+ spu_ret = spu_sys_callback(&s);
+ if (spu_ret <= -ERESTARTSYS) {
+ ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
+ }
+ spu_acquire(ctx);
+ if (ret == -ERESTARTSYS)
+ return ret;
+ }
+
+ /* write result, jump over indirect pointer */
+ memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
+ ctx->ops->npc_write(ctx, npc);
+ ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+ return ret;
+}
+
static inline int spu_process_events(struct spu_context *ctx)
{
struct spu *spu = ctx->spu;
@@ -107,6 +191,13 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
if (unlikely(ret))
break;
+ if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
+ (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
+ ret = spu_process_callback(ctx);
+ if (ret)
+ break;
+ *status &= ~SPU_STATUS_STOPPED_BY_STOP;
+ }
if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
ret = spu_reacquire_runnable(ctx, npc, status);
if (ret)
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 963182fbd1a..bf652cd7700 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -180,6 +180,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
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();
spu_unmap_mappings(ctx);
spu_restore(&ctx->csa, spu);
@@ -197,6 +198,7 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
spu->ibox_callback = NULL;
spu->wbox_callback = NULL;
spu->stop_callback = NULL;
+ spu->mfc_callback = NULL;
spu->mm = NULL;
spu->pid = 0;
spu->prio = MAX_PRIO;
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index db2601f0abd..4485738e210 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -43,7 +43,11 @@ struct spu_context {
struct spu *spu; /* pointer to a physical SPU */
struct spu_state csa; /* SPU context save area. */
spinlock_t mmio_lock; /* protects mmio access */
- struct address_space *local_store;/* local store backing store */
+ struct address_space *local_store; /* local store mapping. */
+ struct address_space *mfc; /* 'mfc' area mappings. */
+ struct address_space *cntl; /* 'control' area mappings. */
+ struct address_space *signal1; /* 'signal1' area mappings. */
+ struct address_space *signal2; /* 'signal2' area mappings. */
enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
struct rw_semaphore state_sema;
@@ -55,13 +59,27 @@ struct spu_context {
wait_queue_head_t ibox_wq;
wait_queue_head_t wbox_wq;
wait_queue_head_t stop_wq;
+ wait_queue_head_t mfc_wq;
struct fasync_struct *ibox_fasync;
struct fasync_struct *wbox_fasync;
+ struct fasync_struct *mfc_fasync;
+ u32 tagwait;
struct spu_context_ops *ops;
struct work_struct reap_work;
u64 flags;
};
+struct mfc_dma_command {
+ int32_t pad; /* reserved */
+ uint32_t lsa; /* local storage address */
+ uint64_t ea; /* effective address */
+ uint16_t size; /* transfer size */
+ uint16_t tag; /* command tag */
+ uint16_t class; /* class ID */
+ uint16_t cmd; /* command opcode */
+};
+
+
/* SPU context query/set operations. */
struct spu_context_ops {
int (*mbox_read) (struct spu_context * ctx, u32 * data);
@@ -84,6 +102,11 @@ struct spu_context_ops {
char*(*get_ls) (struct spu_context * ctx);
void (*runcntl_write) (struct spu_context * ctx, u32 data);
void (*runcntl_stop) (struct spu_context * ctx);
+ int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
+ u32 (*read_mfc_tagstatus)(struct spu_context * ctx);
+ u32 (*get_mfc_free_elements)(struct spu_context *ctx);
+ int (*send_mfc_command)(struct spu_context *ctx,
+ struct mfc_dma_command *cmd);
};
extern struct spu_context_ops spu_hw_ops;
@@ -106,7 +129,7 @@ long spufs_create_thread(struct nameidata *nd,
extern struct file_operations spufs_context_fops;
/* context management */
-struct spu_context * alloc_spu_context(struct address_space *local_store);
+struct spu_context * alloc_spu_context(void);
void destroy_spu_context(struct kref *kref);
struct spu_context * get_spu_context(struct spu_context *ctx);
int put_spu_context(struct spu_context *ctx);
@@ -159,5 +182,6 @@ size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
void spufs_ibox_callback(struct spu *spu);
void spufs_wbox_callback(struct spu *spu);
void spufs_stop_callback(struct spu *spu);
+void spufs_mfc_callback(struct spu *spu);
#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 212db28531f..97898d5d34e 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -2145,7 +2145,8 @@ static void init_priv1(struct spu_state *csa)
csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
CLASS1_ENABLE_STORAGE_FAULT_INTR;
csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR |
- CLASS2_ENABLE_SPU_HALT_INTR;
+ CLASS2_ENABLE_SPU_HALT_INTR |
+ CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR;
}
static void init_priv2(struct spu_state *csa)
diff --git a/arch/powerpc/platforms/chrp/chrp.h b/arch/powerpc/platforms/chrp/chrp.h
index 814f54742e0..63f0aee4c15 100644
--- a/arch/powerpc/platforms/chrp/chrp.h
+++ b/arch/powerpc/platforms/chrp/chrp.h
@@ -8,4 +8,4 @@ extern int chrp_set_rtc_time(struct rtc_time *);
extern long chrp_time_init(void);
extern void chrp_find_bridges(void);
-extern void chrp_event_scan(void);
+extern void chrp_event_scan(unsigned long);
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 8bf4307e323..23a20171870 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -35,6 +35,7 @@
#include <linux/root_dev.h>
#include <linux/initrd.h>
#include <linux/module.h>
+#include <linux/timer.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -61,6 +62,10 @@ EXPORT_SYMBOL(_chrp_type);
struct mpic *chrp_mpic;
+/* Used for doing CHRP event-scans */
+DEFINE_PER_CPU(struct timer_list, heartbeat_timer);
+unsigned long event_scan_interval;
+
/*
* XXX this should be in xmon.h, but putting it there means xmon.h
* has to include <linux/interrupt.h> (to get irqreturn_t), which
@@ -229,8 +234,6 @@ void __init chrp_setup_arch(void)
{
struct device_node *root = find_path_device ("/");
char *machine = NULL;
- struct device_node *device;
- unsigned int *p = NULL;
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy = 50000000/HZ;
@@ -287,23 +290,12 @@ void __init chrp_setup_arch(void)
*/
sio_init();
- /* Get the event scan rate for the rtas so we know how
- * often it expects a heartbeat. -- Cort
- */
- device = find_devices("rtas");
- if (device)
- p = (unsigned int *) get_property
- (device, "rtas-event-scan-rate", NULL);
- if (p && *p) {
- ppc_md.heartbeat = chrp_event_scan;
- ppc_md.heartbeat_reset = HZ / (*p * 30) - 1;
- ppc_md.heartbeat_count = 1;
- printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
- *p, ppc_md.heartbeat_reset);
- }
-
pci_create_OF_bus_map();
+#ifdef CONFIG_SMP
+ smp_ops = &chrp_smp_ops;
+#endif /* CONFIG_SMP */
+
/*
* Print the banner, then scroll down so boot progress
* can be printed. -- Cort
@@ -312,7 +304,7 @@ void __init chrp_setup_arch(void)
}
void
-chrp_event_scan(void)
+chrp_event_scan(unsigned long unused)
{
unsigned char log[1024];
int ret = 0;
@@ -320,7 +312,8 @@ chrp_event_scan(void)
/* XXX: we should loop until the hardware says no more error logs -- Cort */
rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0,
__pa(log), 1024);
- ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+ mod_timer(&__get_cpu_var(heartbeat_timer),
+ jiffies + event_scan_interval);
}
/*
@@ -465,6 +458,9 @@ void __init chrp_init_IRQ(void)
void __init
chrp_init2(void)
{
+ struct device_node *device;
+ unsigned int *p = NULL;
+
#ifdef CONFIG_NVRAM
chrp_nvram_init();
#endif
@@ -476,12 +472,53 @@ chrp_init2(void)
request_region(0x80,0x10,"dma page reg");
request_region(0xc0,0x20,"dma2");
+ /* Get the event scan rate for the rtas so we know how
+ * often it expects a heartbeat. -- Cort
+ */
+ device = find_devices("rtas");
+ if (device)
+ p = (unsigned int *) get_property
+ (device, "rtas-event-scan-rate", NULL);
+ if (p && *p) {
+ /*
+ * Arrange to call chrp_event_scan at least *p times
+ * per minute. We use 59 rather than 60 here so that
+ * the rate will be slightly higher than the minimum.
+ * This all assumes we don't do hotplug CPU on any
+ * machine that needs the event scans done.
+ */
+ unsigned long interval, offset;
+ int cpu, ncpus;
+ struct timer_list *timer;
+
+ interval = HZ * 59 / *p;
+ offset = HZ;
+ ncpus = num_online_cpus();
+ event_scan_interval = ncpus * interval;
+ for (cpu = 0; cpu < ncpus; ++cpu) {
+ timer = &per_cpu(heartbeat_timer, cpu);
+ setup_timer(timer, chrp_event_scan, 0);
+ timer->expires = jiffies + offset;
+ add_timer_on(timer, cpu);
+ offset += interval;
+ }
+ printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
+ *p, interval);
+ }
+
if (ppc_md.progress)
ppc_md.progress(" Have fun! ", 0x7777);
}
-void __init chrp_init(void)
+static int __init chrp_probe(void)
{
+ char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "device_type", NULL);
+ if (dtype == NULL)
+ return 0;
+ if (strcmp(dtype, "chrp"))
+ return 0;
+
ISA_DMA_THRESHOLD = ~0L;
DMA_MODE_READ = 0x44;
DMA_MODE_WRITE = 0x48;
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 12c6f689b1a..7d788902693 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -120,33 +120,15 @@ int chrp_set_rtc_time(struct rtc_time *tmarg)
void chrp_get_rtc_time(struct rtc_time *tm)
{
unsigned int year, mon, day, hour, min, sec;
- int uip, i;
- /* The Linux interpretation of the CMOS clock register contents:
- * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
- * RTC registers show the second which has precisely just started.
- * Let's hope other operating systems interpret the RTC the same way.
- */
-
- /* Since the UIP flag is set for about 2.2 ms and the clock
- * is typically written with a precision of 1 jiffy, trying
- * to obtain a precision better than a few milliseconds is
- * an illusion. Only consistency is interesting, this also
- * allows to use the routine for /dev/rtc without a potential
- * 1 second kernel busy loop triggered by any reader of /dev/rtc.
- */
-
- for ( i = 0; i<1000000; i++) {
- uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
+ do {
sec = chrp_cmos_clock_read(RTC_SECONDS);
min = chrp_cmos_clock_read(RTC_MINUTES);
hour = chrp_cmos_clock_read(RTC_HOURS);
day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
mon = chrp_cmos_clock_read(RTC_MONTH);
year = chrp_cmos_clock_read(RTC_YEAR);
- uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
- if ((uip & RTC_UIP)==0) break;
- }
+ } while (sec != chrp_cmos_clock_read(RTC_SECONDS));
if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BCD_TO_BIN(sec);
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index fa4550611c1..6ce8a404ba6 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -675,18 +675,20 @@ static void iseries_dedicated_idle(void)
void __init iSeries_init_IRQ(void) { }
#endif
-static int __init iseries_probe(int platform)
+static int __init iseries_probe(void)
{
- if (PLATFORM_ISERIES_LPAR != platform)
+ unsigned long root = of_get_flat_dt_root();
+ if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
return 0;
- ppc64_firmware_features |= FW_FEATURE_ISERIES;
- ppc64_firmware_features |= FW_FEATURE_LPAR;
+ powerpc_firmware_features |= FW_FEATURE_ISERIES;
+ powerpc_firmware_features |= FW_FEATURE_LPAR;
return 1;
}
-struct machdep_calls __initdata iseries_md = {
+define_machine(iseries) {
+ .name = "iSeries",
.setup_arch = iSeries_setup_arch,
.show_cpuinfo = iSeries_show_cpuinfo,
.init_IRQ = iSeries_init_IRQ,
@@ -930,7 +932,6 @@ void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
/* /chosen */
dt_start_node(dt, "chosen");
- dt_prop_u32(dt, "linux,platform", PLATFORM_ISERIES_LPAR);
dt_prop_str(dt, "bootargs", cmd_line);
if (cmd_mem_limit)
dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit);
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index ec5c1e10c40..24c0aef4ea3 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -259,9 +259,10 @@ static void __init maple_progress(char *s, unsigned short hex)
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
-static int __init maple_probe(int platform)
+static int __init maple_probe(void)
{
- if (platform != PLATFORM_MAPLE)
+ unsigned long root = of_get_flat_dt_root();
+ if (!of_flat_dt_is_compatible(root, "Momentum,Maple"))
return 0;
/*
* On U3, the DART (iommu) must be allocated now since it
@@ -274,7 +275,8 @@ static int __init maple_probe(int platform)
return 1;
}
-struct machdep_calls __initdata maple_md = {
+define_machine(maple_md) {
+ .name = "Maple",
.probe = maple_probe,
.setup_arch = maple_setup_arch,
.init_early = maple_init_early,
@@ -290,7 +292,7 @@ struct machdep_calls __initdata maple_md = {
.get_rtc_time = maple_get_rtc_time,
.calibrate_decr = generic_calibrate_decr,
.progress = maple_progress,
- .idle_loop = native_idle,
+ .power_save = power4_idle,
#ifdef CONFIG_KEXEC
.machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare,
diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c
index 5e6981d1737..b9a2b3d4bf3 100644
--- a/arch/powerpc/platforms/maple/time.c
+++ b/arch/powerpc/platforms/maple/time.c
@@ -60,34 +60,14 @@ static void maple_clock_write(unsigned long val, int addr)
void maple_get_rtc_time(struct rtc_time *tm)
{
- int uip, i;
-
- /* The Linux interpretation of the CMOS clock register contents:
- * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
- * RTC registers show the second which has precisely just started.
- * Let's hope other operating systems interpret the RTC the same way.
- */
-
- /* Since the UIP flag is set for about 2.2 ms and the clock
- * is typically written with a precision of 1 jiffy, trying
- * to obtain a precision better than a few milliseconds is
- * an illusion. Only consistency is interesting, this also
- * allows to use the routine for /dev/rtc without a potential
- * 1 second kernel busy loop triggered by any reader of /dev/rtc.
- */
-
- for (i = 0; i<1000000; i++) {
- uip = maple_clock_read(RTC_FREQ_SELECT);
+ do {
tm->tm_sec = maple_clock_read(RTC_SECONDS);
tm->tm_min = maple_clock_read(RTC_MINUTES);
tm->tm_hour = maple_clock_read(RTC_HOURS);
tm->tm_mday = maple_clock_read(RTC_DAY_OF_MONTH);
tm->tm_mon = maple_clock_read(RTC_MONTH);
tm->tm_year = maple_clock_read(RTC_YEAR);
- uip |= maple_clock_read(RTC_FREQ_SELECT);
- if ((uip & RTC_UIP)==0)
- break;
- }
+ } while (tm->tm_sec != maple_clock_read(RTC_SECONDS));
if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY)
|| RTC_ALWAYS_BCD) {
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
index fa8b4d7b5de..eacbfd9beab 100644
--- a/arch/powerpc/platforms/powermac/bootx_init.c
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -161,9 +161,7 @@ static void __init bootx_dt_add_prop(char *name, void *data, int size,
static void __init bootx_add_chosen_props(unsigned long base,
unsigned long *mem_end)
{
- u32 val = _MACH_Pmac;
-
- bootx_dt_add_prop("linux,platform", &val, 4, mem_end);
+ u32 val;
if (bootx_info->kernelParamsOffset) {
char *args = (char *)((unsigned long)bootx_info) +
@@ -493,7 +491,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4)
&& (strcmp(model, "iMac,1") == 0
|| strcmp(model, "PowerMac1,1") == 0)) {
bootx_printf("iMac,1 detected, shutting down USB \n");
- out_le32((unsigned *)0x80880008, 1); /* XXX */
+ out_le32((unsigned __iomem *)0x80880008, 1); /* XXX */
}
}
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index a415e8d2f7a..b57e465a1b7 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -21,6 +21,7 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
#include <linux/completion.h>
+#include <linux/mutex.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/irq.h>
@@ -90,7 +91,7 @@ static void (*g5_switch_volt)(int speed_mode);
static int (*g5_switch_freq)(int speed_mode);
static int (*g5_query_freq)(void);
-static DECLARE_MUTEX(g5_switch_mutex);
+static DEFINE_MUTEX(g5_switch_mutex);
static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */
@@ -327,7 +328,7 @@ static int g5_cpufreq_target(struct cpufreq_policy *policy,
if (g5_pmode_cur == newstate)
return 0;
- down(&g5_switch_mutex);
+ mutex_lock(&g5_switch_mutex);
freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
freqs.new = g5_cpu_freqs[newstate].frequency;
@@ -337,7 +338,7 @@ static int g5_cpufreq_target(struct cpufreq_policy *policy,
rc = g5_switch_freq(newstate);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- up(&g5_switch_mutex);
+ mutex_unlock(&g5_switch_mutex);
return rc;
}
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index e49eddd5042..a5063cd675c 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -2951,7 +2951,7 @@ static void *pmac_early_vresume_data;
void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
{
- if (_machine != _MACH_Pmac)
+ if (!machine_is(powermac))
return;
preempt_disable();
pmac_early_vresume_proc = proc;
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 87eb6bb7f0e..e14f9ac55cf 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1457,6 +1457,9 @@ int __init pmac_i2c_init(void)
return 0;
i2c_inited = 1;
+ if (!machine_is(powermac))
+ return 0;
+
/* Probe keywest-i2c busses */
kw_i2c_probe();
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 5fd28995c74..262f967b880 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -74,7 +74,7 @@ struct core99_header {
* Read and write the non-volatile RAM on PowerMacs and CHRP machines.
*/
static int nvram_naddrs;
-static volatile unsigned char *nvram_data;
+static volatile unsigned char __iomem *nvram_data;
static int is_core_99;
static int core99_bank = 0;
static int nvram_partitions[3];
@@ -148,7 +148,7 @@ static ssize_t core99_nvram_size(void)
}
#ifdef CONFIG_PPC32
-static volatile unsigned char *nvram_addr;
+static volatile unsigned char __iomem *nvram_addr;
static int nvram_mult;
static unsigned char direct_nvram_read_byte(int addr)
@@ -285,7 +285,7 @@ static int sm_erase_bank(int bank)
int stat, i;
unsigned long timeout;
- u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
@@ -317,7 +317,7 @@ static int sm_write_bank(int bank, u8* datas)
int i, stat = 0;
unsigned long timeout;
- u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
@@ -352,7 +352,7 @@ static int amd_erase_bank(int bank)
int i, stat = 0;
unsigned long timeout;
- u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: AMD Erasing bank %d...\n", bank);
@@ -399,7 +399,7 @@ static int amd_write_bank(int bank, u8* datas)
int i, stat = 0;
unsigned long timeout;
- u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+ u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
DBG("nvram: AMD Writing bank %d...\n", bank);
@@ -597,7 +597,7 @@ int __init pmac_nvram_init(void)
}
#ifdef CONFIG_PPC32
- if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+ if (machine_is(chrp) && nvram_naddrs == 1) {
nvram_data = ioremap(r1.start, s1);
nvram_mult = 1;
ppc_md.nvram_read_val = direct_nvram_read_byte;
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index de3f30e6b33..f5d8d15d74f 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1201,7 +1201,7 @@ void __init pmac_pcibios_after_init(void)
#ifdef CONFIG_PPC32
void pmac_pci_fixup_cardbus(struct pci_dev* dev)
{
- if (_machine != _MACH_Pmac)
+ if (!machine_is(powermac))
return;
/*
* Fix the interrupt routing on the various cardbus bridges
@@ -1244,8 +1244,9 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
* On PowerMacs, we try to switch any PCI ATA controller to
* fully native mode
*/
- if (_machine != _MACH_Pmac)
+ if (!machine_is(powermac))
return;
+
/* Some controllers don't have the class IDE */
if (dev->vendor == PCI_VENDOR_ID_PROMISE)
switch(dev->device) {
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index 9b7150f1041..a3bd3e728fa 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -336,6 +336,8 @@ int __init pmac_pfunc_base_install(void)
return 0;
pfbase_inited = 1;
+ if (!machine_is(powermac))
+ return 0;
DBG("Installing base platform functions...\n");
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 385aab90c4d..4d15e396655 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -350,6 +350,13 @@ static void __init pmac_setup_arch(void)
smp_ops = &psurge_smp_ops;
#endif
#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_ADB
+ if (strstr(cmd_line, "adb_sync")) {
+ extern int __adb_probe_sync;
+ __adb_probe_sync = 1;
+ }
+#endif /* CONFIG_ADB */
}
char *bootpath;
@@ -576,30 +583,6 @@ pmac_halt(void)
pmac_power_off();
}
-#ifdef CONFIG_PPC32
-void __init pmac_init(void)
-{
- /* isa_io_base gets set in pmac_pci_init */
- isa_mem_base = PMAC_ISA_MEM_BASE;
- pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
- ISA_DMA_THRESHOLD = ~0L;
- DMA_MODE_READ = 1;
- DMA_MODE_WRITE = 2;
-
- ppc_md = pmac_md;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
- ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
- ppc_ide_md.default_io_base = pmac_ide_get_base;
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
- if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
-
-}
-#endif
-
/*
* Early initialization.
*/
@@ -646,6 +629,12 @@ static int __init pmac_declare_of_platform_devices(void)
{
struct device_node *np;
+ if (machine_is(chrp))
+ return -1;
+
+ if (!machine_is(powermac))
+ return 0;
+
np = of_find_node_by_name(NULL, "valkyrie");
if (np)
of_platform_device_create(np, "valkyrie", NULL);
@@ -666,12 +655,15 @@ device_initcall(pmac_declare_of_platform_devices);
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
-static int __init pmac_probe(int platform)
+static int __init pmac_probe(void)
{
-#ifdef CONFIG_PPC64
- if (platform != PLATFORM_POWERMAC)
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "Power Macintosh") &&
+ !of_flat_dt_is_compatible(root, "MacRISC"))
return 0;
+#ifdef CONFIG_PPC64
/*
* On U3, the DART (iommu) must be allocated now since it
* has an impact on htab_initialize (due to the large page it
@@ -681,6 +673,23 @@ static int __init pmac_probe(int platform)
alloc_dart_table();
#endif
+#ifdef CONFIG_PPC32
+ /* isa_io_base gets set in pmac_pci_init */
+ isa_mem_base = PMAC_ISA_MEM_BASE;
+ pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 1;
+ DMA_MODE_WRITE = 2;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+ ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
+ ppc_ide_md.default_io_base = pmac_ide_get_base;
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+#endif /* CONFIG_PPC32 */
+
#ifdef CONFIG_PMAC_SMU
/*
* SMU based G5s need some memory below 2Gb, at least the current
@@ -709,10 +718,8 @@ static int pmac_pci_probe_mode(struct pci_bus *bus)
}
#endif
-struct machdep_calls __initdata pmac_md = {
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
- .cpu_die = generic_mach_cpu_die,
-#endif
+define_machine(powermac) {
+ .name = "PowerMac",
.probe = pmac_probe,
.setup_arch = pmac_setup_arch,
.init_early = pmac_init_early,
@@ -733,7 +740,7 @@ struct machdep_calls __initdata pmac_md = {
.progress = udbg_progress,
#ifdef CONFIG_PPC64
.pci_probe_mode = pmac_pci_probe_mode,
- .idle_loop = native_idle,
+ .power_save = power4_idle,
.enable_pmcs = power4_enable_pmcs,
#ifdef CONFIG_KEXEC
.machine_kexec = default_machine_kexec,
@@ -746,4 +753,7 @@ struct machdep_calls __initdata pmac_md = {
.pcibios_after_init = pmac_pcibios_after_init,
.phys_mem_access_prot = pci_phys_mem_access_prot,
#endif
+#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
+ .cpu_die = generic_mach_cpu_die,
+#endif
};
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index 5d9afa1fa02..890758aa966 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -336,10 +336,10 @@ static struct pmu_sleep_notifier time_sleep_notifier = {
*/
void __init pmac_calibrate_decr(void)
{
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
/* XXX why here? */
pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PM */
+#endif
generic_calibrate_decr();
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index c4352a8db64..b4fa9f03b46 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -116,7 +116,7 @@ void udbg_scc_init(int force_scc)
/* Setup for 57600 8N1 */
if (ch == ch_a)
addr += 0x20;
- sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
+ sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
sccc += addr & ~PAGE_MASK;
sccd = sccc + 0x10;
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 2ab9dcdfb41..9b2b1cb117b 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1018,7 +1018,7 @@ static int __init eeh_init_proc(void)
{
struct proc_dir_entry *e;
- if (platform_is_pseries()) {
+ if (machine_is(pseries)) {
e = create_proc_entry("ppc64/eeh", 0, NULL);
if (e)
e->proc_fops = &proc_eeh_operations;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index b811d5ff92f..cc2495a0cdd 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -257,6 +257,7 @@ void handle_eeh_events (struct eeh_event *event)
struct pci_bus *frozen_bus;
int rc = 0;
enum pci_ers_result result = PCI_ERS_RESULT_NONE;
+ const char *pci_str, *drv_str;
frozen_dn = find_device_pe(event->dn);
frozen_bus = pcibios_find_pci_bus(frozen_dn);
@@ -291,6 +292,13 @@ void handle_eeh_events (struct eeh_event *event)
frozen_pdn = PCI_DN(frozen_dn);
frozen_pdn->eeh_freeze_count++;
+
+ pci_str = pci_name (frozen_pdn->pcidev);
+ drv_str = pcid_name (frozen_pdn->pcidev);
+ if (!pci_str) {
+ pci_str = pci_name (event->dev);
+ drv_str = pcid_name (event->dev);
+ }
if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
goto hard_fail;
@@ -306,9 +314,7 @@ void handle_eeh_events (struct eeh_event *event)
eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
printk(KERN_WARNING
"EEH: This PCI device has failed %d times since last reboot: %s - %s\n",
- frozen_pdn->eeh_freeze_count,
- pci_name (frozen_pdn->pcidev),
- pcid_name(frozen_pdn->pcidev));
+ frozen_pdn->eeh_freeze_count, drv_str, pci_str);
/* Walk the various device drivers attached to this slot through
* a reset sequence, giving each an opportunity to do what it needs
@@ -360,9 +366,7 @@ hard_fail:
"EEH: PCI device %s - %s has failed %d times \n"
"and has been permanently disabled. Please try reseating\n"
"this device or replacing it.\n",
- pci_name (frozen_pdn->pcidev),
- pcid_name(frozen_pdn->pcidev),
- frozen_pdn->eeh_freeze_count);
+ drv_str, pci_str, frozen_pdn->eeh_freeze_count);
eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */);
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 989f4bc136c..c01d8f0cbe6 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -91,7 +91,7 @@ void __init fw_feature_init(void)
continue;
/* we have a match */
- ppc64_firmware_features |=
+ powerpc_firmware_features |=
firmware_features_table[i].val;
break;
}
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 138e128a388..ba6befd9663 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -62,6 +62,11 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
unsigned long *lbuf = (unsigned long *) buf;
long ret;
+
+ /* hcall will ret H_PARAMETER if 'count' exceeds firmware max.*/
+ if (count > MAX_VIO_PUT_CHARS)
+ count = MAX_VIO_PUT_CHARS;
+
ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0],
lbuf[1]);
if (ret == H_Success)
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 946ad59e335..e97e67f5e07 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -120,7 +120,7 @@ static void fixup_winbond_82c105(struct pci_dev* dev)
int i;
unsigned int reg;
- if (!platform_is_pseries())
+ if (!machine_is(pseries))
return;
printk("Using INTC for W82c105 IDE controller.\n");
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 44abdeb9ca0..6bfacc21708 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
static struct pci_bus *
find_bus_among_children(struct pci_bus *bus,
@@ -152,20 +153,24 @@ pcibios_pci_config_bridge(struct pci_dev *dev)
void
pcibios_add_pci_devices(struct pci_bus * bus)
{
- int slotno, num;
+ int slotno, num, mode;
struct pci_dev *dev;
struct device_node *dn = pci_bus_to_OF_node(bus);
eeh_add_device_tree_early(dn);
- if (_machine == PLATFORM_PSERIES_LPAR) {
+ mode = PCI_PROBE_NORMAL;
+ if (ppc_md.pci_probe_mode)
+ mode = ppc_md.pci_probe_mode(bus);
+
+ if (mode == PCI_PROBE_DEVTREE) {
/* use ofdt-based probe */
of_scan_bus(dn, bus);
if (!list_empty(&bus->devices)) {
pcibios_fixup_new_pci_devices(bus, 0);
pci_bus_add_devices(bus);
}
- } else {
+ } else if (mode == PCI_PROBE_NORMAL) {
/* use legacy probe */
slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index b046bcf7443..9639c66b453 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -132,7 +132,7 @@ static int __init init_ras_IRQ(void)
of_node_put(np);
}
- return 1;
+ return 0;
}
__initcall(init_ras_IRQ);
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 86cfa6ecdcf..1773103354b 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -17,8 +17,9 @@
#include <linux/proc_fs.h>
#include <asm/prom.h>
-#include <asm/pSeries_reconfig.h>
+#include <asm/machdep.h>
#include <asm/uaccess.h>
+#include <asm/pSeries_reconfig.h>
@@ -94,16 +95,16 @@ static struct device_node *derive_parent(const char *path)
return parent;
}
-static struct notifier_block *pSeries_reconfig_chain;
+static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain);
int pSeries_reconfig_notifier_register(struct notifier_block *nb)
{
- return notifier_chain_register(&pSeries_reconfig_chain, nb);
+ return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
}
void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
{
- notifier_chain_unregister(&pSeries_reconfig_chain, nb);
+ blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
}
static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
@@ -131,7 +132,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
goto out_err;
}
- err = notifier_call_chain(&pSeries_reconfig_chain,
+ err = blocking_notifier_call_chain(&pSeries_reconfig_chain,
PSERIES_RECONFIG_ADD, np);
if (err == NOTIFY_BAD) {
printk(KERN_ERR "Failed to add device node %s\n", path);
@@ -171,7 +172,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
remove_node_proc_entries(np);
- notifier_call_chain(&pSeries_reconfig_chain,
+ blocking_notifier_call_chain(&pSeries_reconfig_chain,
PSERIES_RECONFIG_REMOVE, np);
of_detach_node(np);
@@ -508,7 +509,7 @@ static int proc_ppc64_create_ofdt(void)
{
struct proc_dir_entry *ent;
- if (!platform_is_pseries())
+ if (!machine_is(pseries))
return 0;
ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index a6f628d4c9d..fcc4d561a23 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -27,6 +27,7 @@
#include <asm/prom.h>
#include <asm/nvram.h>
#include <asm/atomic.h>
+#include <asm/machdep.h>
#if 0
#define DEBUG(A...) printk(KERN_ERR A)
@@ -481,7 +482,7 @@ static int __init rtas_init(void)
{
struct proc_dir_entry *entry;
- if (!platform_is_pseries())
+ if (!machine_is(pseries))
return 0;
/* No RTAS */
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 44d5c7fdcd9..b2fbf8ba8fb 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -81,8 +81,8 @@ extern void find_udbg_vterm(void);
int fwnmi_active; /* TRUE if an FWNMI handler is present */
-static void pseries_shared_idle(void);
-static void pseries_dedicated_idle(void);
+static void pseries_shared_idle_sleep(void);
+static void pseries_dedicated_idle_sleep(void);
struct mpic *pSeries_mpic;
@@ -236,14 +236,13 @@ static void __init pSeries_setup_arch(void)
vpa_init(boot_cpuid);
if (get_lppaca()->shared_proc) {
printk(KERN_INFO "Using shared processor idle loop\n");
- ppc_md.idle_loop = pseries_shared_idle;
+ ppc_md.power_save = pseries_shared_idle_sleep;
} else {
printk(KERN_INFO "Using dedicated idle loop\n");
- ppc_md.idle_loop = pseries_dedicated_idle;
+ ppc_md.power_save = pseries_dedicated_idle_sleep;
}
} else {
printk(KERN_INFO "Using default idle loop\n");
- ppc_md.idle_loop = default_idle;
}
if (firmware_has_feature(FW_FEATURE_LPAR))
@@ -373,156 +372,123 @@ static int pSeries_check_legacy_ioport(unsigned int baseport)
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
-extern struct machdep_calls pSeries_md;
-static int __init pSeries_probe(int platform)
+static int __init pSeries_probe_hypertas(unsigned long node,
+ const char *uname, int depth,
+ void *data)
{
- if (platform != PLATFORM_PSERIES &&
- platform != PLATFORM_PSERIES_LPAR)
- return 0;
-
- /* if we have some ppc_md fixups for LPAR to do, do
- * it here ...
- */
+ if (depth != 1 ||
+ (strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0))
+ return 0;
- if (platform == PLATFORM_PSERIES_LPAR)
- ppc64_firmware_features |= FW_FEATURE_LPAR;
+ if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
+ powerpc_firmware_features |= FW_FEATURE_LPAR;
- return 1;
+ return 1;
}
-DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
-
-static inline void dedicated_idle_sleep(unsigned int cpu)
+static int __init pSeries_probe(void)
{
- struct lppaca *plppaca = &lppaca[cpu ^ 1];
+ char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "device_type", NULL);
+ if (dtype == NULL)
+ return 0;
+ if (strcmp(dtype, "chrp"))
+ return 0;
- /* Only sleep if the other thread is not idle */
- if (!(plppaca->idle)) {
- local_irq_disable();
+ DBG("pSeries detected, looking for LPAR capability...\n");
- /*
- * We are about to sleep the thread and so wont be polling any
- * more.
- */
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb__after_clear_bit();
-
- /*
- * SMT dynamic mode. Cede will result in this thread going
- * dormant, if the partner thread is still doing work. Thread
- * wakes up if partner goes idle, an interrupt is presented, or
- * a prod occurs. Returning from the cede enables external
- * interrupts.
- */
- if (!need_resched())
- cede_processor();
- else
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
- } else {
- /*
- * Give the HV an opportunity at the processor, since we are
- * not doing any work.
- */
- poll_pending();
- }
+ /* Now try to figure out if we are running on LPAR */
+ of_scan_flat_dt(pSeries_probe_hypertas, NULL);
+
+ DBG("Machine is%s LPAR !\n",
+ (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
+
+ return 1;
}
-static void pseries_dedicated_idle(void)
+
+DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
+
+static void pseries_dedicated_idle_sleep(void)
{
unsigned int cpu = smp_processor_id();
unsigned long start_snooze;
unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while (1) {
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- get_lppaca()->idle = 1;
-
- if (!need_resched()) {
- start_snooze = get_tb() +
- *smt_snooze_delay * tb_ticks_per_usec;
-
- while (!need_resched() && !cpu_is_offline(cpu)) {
- ppc64_runlatch_off();
-
- /*
- * Go into low thread priority and possibly
- * low power mode.
- */
- HMT_low();
- HMT_very_low();
-
- if (*smt_snooze_delay != 0 &&
- get_tb() > start_snooze) {
- HMT_medium();
- dedicated_idle_sleep(cpu);
- }
-
- }
-
- HMT_medium();
- }
-
- get_lppaca()->idle = 0;
- ppc64_runlatch_on();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ get_lppaca()->idle = 1;
- if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
- cpu_die();
- }
-}
+ /*
+ * We come in with interrupts disabled, and need_resched()
+ * has been checked recently. If we should poll for a little
+ * while, do so.
+ */
+ if (*smt_snooze_delay) {
+ start_snooze = get_tb() +
+ *smt_snooze_delay * tb_ticks_per_usec;
+ local_irq_enable();
+ set_thread_flag(TIF_POLLING_NRFLAG);
-static void pseries_shared_idle(void)
-{
- unsigned int cpu = smp_processor_id();
+ while (get_tb() < start_snooze) {
+ if (need_resched() || cpu_is_offline(cpu))
+ goto out;
+ ppc64_runlatch_off();
+ HMT_low();
+ HMT_very_low();
+ }
- while (1) {
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- get_lppaca()->idle = 1;
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ smp_mb();
+ local_irq_disable();
+ if (need_resched() || cpu_is_offline(cpu))
+ goto out;
+ }
- while (!need_resched() && !cpu_is_offline(cpu)) {
- local_irq_disable();
- ppc64_runlatch_off();
+ /*
+ * Cede if the other thread is not idle, so that it can
+ * go single-threaded. If the other thread is idle,
+ * we ask the hypervisor if it has pending work it
+ * wants to do and cede if it does. Otherwise we keep
+ * polling in order to reduce interrupt latency.
+ *
+ * Doing the cede when the other thread is active will
+ * result in this thread going dormant, meaning the other
+ * thread gets to run in single-threaded (ST) mode, which
+ * is slightly faster than SMT mode with this thread at
+ * very low priority. The cede enables interrupts, which
+ * doesn't matter here.
+ */
+ if (!lppaca[cpu ^ 1].idle || poll_pending() == H_Pending)
+ cede_processor();
- /*
- * Yield the processor to the hypervisor. We return if
- * an external interrupt occurs (which are driven prior
- * to returning here) or if a prod occurs from another
- * processor. When returning here, external interrupts
- * are enabled.
- *
- * Check need_resched() again with interrupts disabled
- * to avoid a race.
- */
- if (!need_resched())
- cede_processor();
- else
- local_irq_enable();
-
- HMT_medium();
- }
+out:
+ HMT_medium();
+ get_lppaca()->idle = 0;
+}
- get_lppaca()->idle = 0;
- ppc64_runlatch_on();
+static void pseries_shared_idle_sleep(void)
+{
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ get_lppaca()->idle = 1;
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
+ /*
+ * Yield the processor to the hypervisor. We return if
+ * an external interrupt occurs (which are driven prior
+ * to returning here) or if a prod occurs from another
+ * processor. When returning here, external interrupts
+ * are enabled.
+ */
+ cede_processor();
- if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
- cpu_die();
- }
+ get_lppaca()->idle = 0;
}
static int pSeries_pci_probe_mode(struct pci_bus *bus)
@@ -553,7 +519,8 @@ static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
}
#endif
-struct machdep_calls __initdata pSeries_md = {
+define_machine(pseries) {
+ .name = "pSeries",
.probe = pSeries_probe,
.setup_arch = pSeries_setup_arch,
.init_early = pSeries_init_early,
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index eb86cdb9b80..4864cb32be2 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -500,7 +500,7 @@ nextnode:
np;
np = of_find_node_by_type(np, "cpu")) {
ireg = (uint *)get_property(np, "reg", &ilen);
- if (ireg && ireg[0] == boot_cpuid_phys) {
+ if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) {
ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s",
&ilen);
i = ilen / sizeof(int);
@@ -541,7 +541,7 @@ nextnode:
ops = &pSeriesLP_ops;
else {
#ifdef CONFIG_SMP
- for_each_cpu(i) {
+ for_each_possible_cpu(i) {
int hard_id;
/* FIXME: Do this dynamically! --RR */