diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-06 17:58:22 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-06 17:58:22 -0800 |
commit | e4e88f31bcb5f05f24b9ae518d4ecb44e1a7774d (patch) | |
tree | 9eef6998f5bbd1a2c999011d9e0151f00c6e7297 /arch/powerpc/platforms | |
parent | 9753dfe19a85e7e45a34a56f4cb2048bb4f50e27 (diff) | |
parent | ef88e3911c0e0301e73fa3b3b2567aabdbe17cc4 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (185 commits)
powerpc: fix compile error with 85xx/p1010rdb.c
powerpc: fix compile error with 85xx/p1023_rds.c
powerpc/fsl: add MSI support for the Freescale hypervisor
arch/powerpc/sysdev/fsl_rmu.c: introduce missing kfree
powerpc/fsl: Add support for Integrated Flash Controller
powerpc/fsl: update compatiable on fsl 16550 uart nodes
powerpc/85xx: fix PCI and localbus properties in p1022ds.dts
powerpc/85xx: re-enable ePAPR byte channel driver in corenet32_smp_defconfig
powerpc/fsl: Update defconfigs to enable some standard FSL HW features
powerpc: Add TBI PHY node to first MDIO bus
sbc834x: put full compat string in board match check
powerpc/fsl-pci: Allow 64-bit PCIe devices to DMA to any memory address
powerpc: Fix unpaired probe_hcall_entry and probe_hcall_exit
offb: Fix setting of the pseudo-palette for >8bpp
offb: Add palette hack for qemu "standard vga" framebuffer
offb: Fix bug in calculating requested vram size
powerpc/boot: Change the WARN to INFO for boot wrapper overlap message
powerpc/44x: Fix build error on currituck platform
powerpc/boot: Change the load address for the wrapper to fit the kernel
powerpc/44x: Enable CRASH_DUMP for 440x
...
Fix up a trivial conflict in arch/powerpc/include/asm/cputime.h due to
the additional sparse-checking code for cputime_t.
Diffstat (limited to 'arch/powerpc/platforms')
90 files changed, 3258 insertions, 1839 deletions
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index 153022971da..baae85584b1 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -100,6 +100,16 @@ config XILINX_VIRTEX_GENERIC_BOARD Most Virtex designs should use this unless it needs to do some special configuration at board probe time. +config OBS600 + bool "OpenBlockS 600" + depends on 40x + default n + select 405EX + select PPC40x_SIMPLE + help + This option enables support for PlatHome OpenBlockS 600 server + + config PPC40x_SIMPLE bool "Simple PowerPC 40x board support" depends on 40x @@ -186,3 +196,14 @@ config IBM405_ERR51 # bool # depends on !STB03xxx && PPC4xx_DMA # default y +# + +config APM8018X + bool "APM8018X" + depends on 40x + default n + select PPC40x_SIMPLE + help + This option enables support for the AppliedMicro APM8018X evaluation + board. + diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index e8dd5c5df7d..97612068fae 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -55,7 +55,9 @@ static const char *board[] __initdata = { "amcc,haleakala", "amcc,kilauea", "amcc,makalu", - "est,hotfoot" + "apm,klondike", + "est,hotfoot", + "plathome,obs600" }; static int __init ppc40x_probe(void) diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 762322ce24a..5d5aaf6c91a 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -186,6 +186,16 @@ config ISS4xx help This option enables support for the IBM ISS simulation environment +config CURRITUCK + bool "IBM Currituck (476fpe) Support" + depends on PPC_47x + default n + select SWIOTLB + select 476FPE + select PPC4xx_PCI_EXPRESS + help + This option enables support for the IBM Currituck (476fpe) evaluation board + config ICON bool "Icon" depends on 44x @@ -308,6 +318,10 @@ config 460SX select IBM_EMAC_ZMII select IBM_EMAC_TAH +config 476FPE + bool + select PPC_FPU + config APM821xx bool select PPC_FPU diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 553db600721..d03833abec0 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o obj-$(CONFIG_ISS4xx) += iss4xx.o obj-$(CONFIG_CANYONLANDS)+= canyonlands.o +obj-$(CONFIG_CURRITUCK) += currituck.o diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c new file mode 100644 index 00000000000..3f6229b5dee --- /dev/null +++ b/arch/powerpc/platforms/44x/currituck.c @@ -0,0 +1,204 @@ +/* + * Currituck board specific routines + * + * Copyright © 2011 Tony Breeds IBM Corporation + * + * Based on earlier code: + * Matt Porter <mporter@kernel.crashing.org> + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * Copyright (c) 2003-2005 Zultys Technologies + * + * Rewritten and ported to the merged powerpc tree: + * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation. + * Copyright © 2011 David Kliekamp IBM Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/init.h> +#include <linux/memblock.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/rtc.h> + +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/time.h> +#include <asm/uic.h> +#include <asm/ppc4xx.h> +#include <asm/mpic.h> +#include <asm/mmu.h> + +#include <linux/pci.h> + +static __initdata struct of_device_id ppc47x_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,plb6", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +/* The EEPROM is missing and the default values are bogus. This forces USB in + * to EHCI mode */ +static void __devinit quirk_ppc_currituck_usb_fixup(struct pci_dev *dev) +{ + if (of_machine_is_compatible("ibm,currituck")) { + pci_write_config_dword(dev, 0xe0, 0x0114231f); + pci_write_config_dword(dev, 0xe4, 0x00006c40); + } +} +DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup); + +static int __init ppc47x_device_probe(void) +{ + of_platform_bus_probe(NULL, ppc47x_of_bus, NULL); + + return 0; +} +machine_device_initcall(ppc47x, ppc47x_device_probe); + +/* We can have either UICs or MPICs */ +static void __init ppc47x_init_irq(void) +{ + struct device_node *np; + + /* Find top level interrupt controller */ + for_each_node_with_property(np, "interrupt-controller") { + if (of_get_property(np, "interrupts", NULL) == NULL) + break; + } + if (np == NULL) + panic("Can't find top level interrupt controller"); + + /* Check type and do appropriate initialization */ + if (of_device_is_compatible(np, "chrp,open-pic")) { + /* The MPIC driver will get everything it needs from the + * device-tree, just pass 0 to all arguments + */ + struct mpic *mpic = + mpic_alloc(np, 0, 0, 0, 0, " MPIC "); + BUG_ON(mpic == NULL); + mpic_init(mpic); + ppc_md.get_irq = mpic_get_irq; + } else + panic("Unrecognized top level interrupt controller"); +} + +#ifdef CONFIG_SMP +static void __cpuinit smp_ppc47x_setup_cpu(int cpu) +{ + mpic_setup_this_cpu(); +} + +static int __cpuinit smp_ppc47x_kick_cpu(int cpu) +{ + struct device_node *cpunode = of_get_cpu_node(cpu, NULL); + const u64 *spin_table_addr_prop; + u32 *spin_table; + extern void start_secondary_47x(void); + + BUG_ON(cpunode == NULL); + + /* Assume spin table. We could test for the enable-method in + * the device-tree but currently there's little point as it's + * our only supported method + */ + spin_table_addr_prop = + of_get_property(cpunode, "cpu-release-addr", NULL); + + if (spin_table_addr_prop == NULL) { + pr_err("CPU%d: Can't start, missing cpu-release-addr !\n", + cpu); + return 1; + } + + /* Assume it's mapped as part of the linear mapping. This is a bit + * fishy but will work fine for now + * + * XXX: Is there any reason to assume differently? + */ + spin_table = (u32 *)__va(*spin_table_addr_prop); + pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table); + + spin_table[3] = cpu; + smp_wmb(); + spin_table[1] = __pa(start_secondary_47x); + mb(); + + return 0; +} + +static struct smp_ops_t ppc47x_smp_ops = { + .probe = smp_mpic_probe, + .message_pass = smp_mpic_message_pass, + .setup_cpu = smp_ppc47x_setup_cpu, + .kick_cpu = smp_ppc47x_kick_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, +}; + +static void __init ppc47x_smp_init(void) +{ + if (mmu_has_feature(MMU_FTR_TYPE_47x)) + smp_ops = &ppc47x_smp_ops; +} + +#else /* CONFIG_SMP */ +static void __init ppc47x_smp_init(void) { } +#endif /* CONFIG_SMP */ + +static void __init ppc47x_setup_arch(void) +{ + + /* No need to check the DMA config as we /know/ our windows are all of + * RAM. Lets hope that doesn't change */ +#ifdef CONFIG_SWIOTLB + if (memblock_end_of_DRAM() > 0xffffffff) { + ppc_swiotlb_enable = 1; + set_pci_dma_ops(&swiotlb_dma_ops); + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; + } +#endif + ppc47x_smp_init(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init ppc47x_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,currituck")) + return 0; + + return 1; +} + +/* Use USB controller should have been hardware swizzled but it wasn't :( */ +static void ppc47x_pci_irq_fixup(struct pci_dev *dev) +{ + if (dev->vendor == 0x1033 && (dev->device == 0x0035 || + dev->device == 0x00e0)) { + dev->irq = irq_create_mapping(NULL, 47); + pr_info("%s: Mapping irq 47 %d\n", __func__, dev->irq); + } +} + +define_machine(ppc47x) { + .name = "PowerPC 47x", + .probe = ppc47x_probe, + .progress = udbg_progress, + .init_IRQ = ppc47x_init_irq, + .setup_arch = ppc47x_setup_arch, + .pci_irq_fixup = ppc47x_pci_irq_fixup, + .restart = ppc4xx_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index 19395f18b1d..5b8cdbb82f8 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -71,7 +71,7 @@ static void __init iss4xx_init_irq(void) /* The MPIC driver will get everything it needs from the * device-tree, just pass 0 to all arguments */ - struct mpic *mpic = mpic_alloc(np, 0, MPIC_PRIMARY, 0, 0, + struct mpic *mpic = mpic_alloc(np, 0, 0, 0, 0, " MPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/83xx/asp834x.c b/arch/powerpc/platforms/83xx/asp834x.c index aa0d84d2258..464ea8e0292 100644 --- a/arch/powerpc/platforms/83xx/asp834x.c +++ b/arch/powerpc/platforms/83xx/asp834x.c @@ -36,38 +36,7 @@ static void __init asp834x_setup_arch(void) mpc834x_usb_cfg(); } -static void __init asp834x_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - of_node_put(np); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} - -static struct __initdata of_device_id asp8347_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init asp8347_declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, asp8347_ids, NULL); - return 0; -} -machine_device_initcall(asp834x, asp8347_declare_of_platform_devices); +machine_device_initcall(asp834x, mpc83xx_declare_of_platform_devices); /* * Called very early, MMU is off, device-tree isn't unflattened @@ -82,7 +51,7 @@ define_machine(asp834x) { .name = "ASP8347E", .probe = asp834x_probe, .setup_arch = asp834x_setup_arch, - .init_IRQ = asp834x_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c index c55129f5760..65eb792a0d0 100644 --- a/arch/powerpc/platforms/83xx/km83xx.c +++ b/arch/powerpc/platforms/83xx/km83xx.c @@ -51,15 +51,14 @@ */ static void __init mpc83xx_km_setup_arch(void) { +#ifdef CONFIG_QUICC_ENGINE struct device_node *np; +#endif if (ppc_md.progress) ppc_md.progress("kmpbec83xx_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); #ifdef CONFIG_QUICC_ENGINE qe_reset(); @@ -122,54 +121,7 @@ static void __init mpc83xx_km_setup_arch(void) #endif /* CONFIG_QUICC_ENGINE */ } -static struct of_device_id kmpbec83xx_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .type = "qe", }, - { .compatible = "fsl,qe", }, - {}, -}; - -static int __init kmeter_declare_of_platform_devices(void) -{ - /* Publish the QE devices */ - of_platform_bus_probe(NULL, kmpbec83xx_ids, NULL); - - return 0; -} -machine_device_initcall(mpc83xx_km, kmeter_declare_of_platform_devices); - -static void __init mpc83xx_km_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,pq2pro-pic"); - if (!np) { - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - } - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); - of_node_put(np); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (!np) { - np = of_find_node_by_type(NULL, "qeic"); - if (!np) - return; - } - qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); - of_node_put(np); -#endif /* CONFIG_QUICC_ENGINE */ -} +machine_device_initcall(mpc83xx_km, mpc83xx_declare_of_platform_devices); /* list of the supported boards */ static char *board[] __initdata = { @@ -198,7 +150,7 @@ define_machine(mpc83xx_km) { .name = "mpc83xx-km-platform", .probe = mpc83xx_km_probe, .setup_arch = mpc83xx_km_setup_arch, - .init_IRQ = mpc83xx_km_init_IRQ, + .init_IRQ = mpc83xx_ipic_and_qe_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c index f01806c940e..125336f750c 100644 --- a/arch/powerpc/platforms/83xx/misc.c +++ b/arch/powerpc/platforms/83xx/misc.c @@ -11,10 +11,15 @@ #include <linux/stddef.h> #include <linux/kernel.h> +#include <linux/of_platform.h> +#include <linux/pci.h> #include <asm/io.h> #include <asm/hw_irq.h> +#include <asm/ipic.h> +#include <asm/qe_ic.h> #include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> #include "mpc83xx.h" @@ -65,3 +70,75 @@ long __init mpc83xx_time_init(void) return 0; } + +void __init mpc83xx_ipic_init_IRQ(void) +{ + struct device_node *np; + + /* looking for fsl,pq2pro-pic which is asl compatible with fsl,ipic */ + np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); + if (!np) + np = of_find_node_by_type(NULL, "ipic"); + if (!np) + return; + + ipic_init(np, 0); + + of_node_put(np); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +#ifdef CONFIG_QUICC_ENGINE +void __init mpc83xx_qe_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); + if (!np) { + np = of_find_node_by_type(NULL, "qeic"); + if (!np) + return; + } + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); + of_node_put(np); +} + +void __init mpc83xx_ipic_and_qe_init_IRQ(void) +{ + mpc83xx_ipic_init_IRQ(); + mpc83xx_qe_init_IRQ(); +} +#endif /* CONFIG_QUICC_ENGINE */ + +static struct of_device_id __initdata of_bus_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .compatible = "simple-bus" }, + { .compatible = "gianfar" }, + { .compatible = "gpio-leds", }, + { .type = "qe", }, + { .compatible = "fsl,qe", }, + {}, +}; + +int __init mpc83xx_declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} + +#ifdef CONFIG_PCI +void __init mpc83xx_setup_pci(void) +{ + struct device_node *np; + + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") + mpc83xx_add_bridge(np); + for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie") + mpc83xx_add_bridge(np); +} +#endif diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c index d0c4e15b779..4f2d9fea77b 100644 --- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c @@ -27,36 +27,13 @@ */ static void __init mpc830x_rdb_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc830x_rdb_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8308-pcie") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); mpc831x_usb_cfg(); } -static void __init mpc830x_rdb_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} - static const char *board[] __initdata = { "MPC8308RDB", "fsl,mpc8308rdb", @@ -72,24 +49,13 @@ static int __init mpc830x_rdb_probe(void) return of_flat_dt_match(of_get_flat_dt_root(), board); } -static struct of_device_id __initdata of_bus_ids[] = { - { .compatible = "simple-bus" }, - { .compatible = "gianfar" }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - return 0; -} -machine_device_initcall(mpc830x_rdb, declare_of_platform_devices); +machine_device_initcall(mpc830x_rdb, mpc83xx_declare_of_platform_devices); define_machine(mpc830x_rdb) { .name = "MPC830x RDB", .probe = mpc830x_rdb_probe, .setup_arch = mpc830x_rdb_setup_arch, - .init_IRQ = mpc830x_rdb_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index f859ead49a8..fa25977c52d 100644 --- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c @@ -28,38 +28,13 @@ */ static void __init mpc831x_rdb_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc831x_rdb_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); - for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); mpc831x_usb_cfg(); } -static void __init mpc831x_rdb_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} - static const char *board[] __initdata = { "MPC8313ERDB", "fsl,mpc8315erdb", @@ -74,25 +49,13 @@ static int __init mpc831x_rdb_probe(void) return of_flat_dt_match(of_get_flat_dt_root(), board); } -static struct of_device_id __initdata of_bus_ids[] = { - { .compatible = "simple-bus" }, - { .compatible = "gianfar" }, - { .compatible = "gpio-leds", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - return 0; -} -machine_device_initcall(mpc831x_rdb, declare_of_platform_devices); +machine_device_initcall(mpc831x_rdb, mpc83xx_declare_of_platform_devices); define_machine(mpc831x_rdb) { .name = "MPC831x RDB", .probe = mpc831x_rdb_probe, .setup_arch = mpc831x_rdb_setup_arch, - .init_IRQ = mpc831x_rdb_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 32a52896822..e36bc611dd6 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -72,10 +72,7 @@ static void __init mpc832x_sys_setup_arch(void) of_node_put(np); } -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); #ifdef CONFIG_QUICC_ENGINE qe_reset(); @@ -101,51 +98,7 @@ static void __init mpc832x_sys_setup_arch(void) #endif /* CONFIG_QUICC_ENGINE */ } -static struct of_device_id mpc832x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .type = "qe", }, - { .compatible = "fsl,qe", }, - {}, -}; - -static int __init mpc832x_declare_of_platform_devices(void) -{ - /* Publish the QE devices */ - of_platform_bus_probe(NULL, mpc832x_ids, NULL); - - return 0; -} -machine_device_initcall(mpc832x_mds, mpc832x_declare_of_platform_devices); - -static void __init mpc832x_sys_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); - of_node_put(np); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (!np) { - np = of_find_node_by_type(NULL, "qeic"); - if (!np) - return; - } - qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); - of_node_put(np); -#endif /* CONFIG_QUICC_ENGINE */ -} +machine_device_initcall(mpc832x_mds, mpc83xx_declare_of_platform_devices); /* * Called very early, MMU is off, device-tree isn't unflattened @@ -161,7 +114,7 @@ define_machine(mpc832x_mds) { .name = "MPC832x MDS", .probe = mpc832x_sys_probe, .setup_arch = mpc832x_sys_setup_arch, - .init_IRQ = mpc832x_sys_init_IRQ, + .init_IRQ = mpc83xx_ipic_and_qe_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 17f99745f0e..eff5baabc3f 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -193,17 +193,14 @@ machine_device_initcall(mpc832x_rdb, mpc832x_spi_init); */ static void __init mpc832x_rdb_setup_arch(void) { -#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE) +#if defined(CONFIG_QUICC_ENGINE) struct device_node *np; #endif if (ppc_md.progress) ppc_md.progress("mpc832x_rdb_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); #ifdef CONFIG_QUICC_ENGINE qe_reset(); @@ -218,52 +215,7 @@ static void __init mpc832x_rdb_setup_arch(void) #endif /* CONFIG_QUICC_ENGINE */ } -static struct of_device_id mpc832x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .type = "qe", }, - { .compatible = "fsl,qe", }, - {}, -}; - -static int __init mpc832x_declare_of_platform_devices(void) -{ - /* Publish the QE devices */ - of_platform_bus_probe(NULL, mpc832x_ids, NULL); - - return 0; -} -machine_device_initcall(mpc832x_rdb, mpc832x_declare_of_platform_devices); - -static void __init mpc832x_rdb_init_IRQ(void) -{ - - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); - of_node_put(np); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (!np) { - np = of_find_node_by_type(NULL, "qeic"); - if (!np) - return; - } - qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); - of_node_put(np); -#endif /* CONFIG_QUICC_ENGINE */ -} +machine_device_initcall(mpc832x_rdb, mpc83xx_declare_of_platform_devices); /* * Called very early, MMU is off, device-tree isn't unflattened @@ -279,7 +231,7 @@ define_machine(mpc832x_rdb) { .name = "MPC832x RDB", .probe = mpc832x_rdb_probe, .setup_arch = mpc832x_rdb_setup_arch, - .init_IRQ = mpc832x_rdb_init_IRQ, + .init_IRQ = mpc83xx_ipic_and_qe_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 6b45969567d..39849dd1b5b 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -41,13 +41,12 @@ static struct of_device_id __initdata mpc834x_itx_ids[] = { { .compatible = "fsl,pq2pro-localbus", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, {}, }; static int __init mpc834x_itx_declare_of_platform_devices(void) { + mpc83xx_declare_of_platform_devices(); return of_platform_bus_probe(NULL, mpc834x_itx_ids, NULL); } machine_device_initcall(mpc834x_itx, mpc834x_itx_declare_of_platform_devices); @@ -59,37 +58,14 @@ machine_device_initcall(mpc834x_itx, mpc834x_itx_declare_of_platform_devices); */ static void __init mpc834x_itx_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc834x_itx_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); mpc834x_usb_cfg(); } -static void __init mpc834x_itx_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} - /* * Called very early, MMU is off, device-tree isn't unflattened */ @@ -104,7 +80,7 @@ define_machine(mpc834x_itx) { .name = "MPC834x ITX", .probe = mpc834x_itx_probe, .setup_arch = mpc834x_itx_setup_arch, - .init_IRQ = mpc834x_itx_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 041c5177e73..5828d8e97c3 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -77,51 +77,15 @@ static int mpc834xemds_usb_cfg(void) */ static void __init mpc834x_mds_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc834x_mds_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); mpc834xemds_usb_cfg(); } -static void __init mpc834x_mds_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} - -static struct of_device_id mpc834x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init mpc834x_declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, mpc834x_ids, NULL); - return 0; -} -machine_device_initcall(mpc834x_mds, mpc834x_declare_of_platform_devices); +machine_device_initcall(mpc834x_mds, mpc83xx_declare_of_platform_devices); /* * Called very early, MMU is off, device-tree isn't unflattened @@ -137,7 +101,7 @@ define_machine(mpc834x_mds) { .name = "MPC834x MDS", .probe = mpc834x_mds_probe, .setup_arch = mpc834x_mds_setup_arch, - .init_IRQ = mpc834x_mds_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 934cc8c46bb..ad8e4bcd7d5 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -80,10 +80,7 @@ static void __init mpc836x_mds_setup_arch(void) of_node_put(np); } -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); #ifdef CONFIG_QUICC_ENGINE qe_reset(); @@ -144,23 +141,7 @@ static void __init mpc836x_mds_setup_arch(void) #endif /* CONFIG_QUICC_ENGINE */ } -static struct of_device_id mpc836x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .type = "qe", }, - { .compatible = "fsl,qe", }, - {}, -}; - -static int __init mpc836x_declare_of_platform_devices(void) -{ - /* Publish the QE devices */ - of_platform_bus_probe(NULL, mpc836x_ids, NULL); - - return 0; -} -machine_device_initcall(mpc836x_mds, mpc836x_declare_of_platform_devices); +machine_device_initcall(mpc836x_mds, mpc83xx_declare_of_platform_devices); #ifdef CONFIG_QE_USB static int __init mpc836x_usb_cfg(void) @@ -226,34 +207,6 @@ err: machine_arch_initcall(mpc836x_mds, mpc836x_usb_cfg); #endif /* CONFIG_QE_USB */ -static void __init mpc836x_mds_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); - of_node_put(np); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (!np) { - np = of_find_node_by_type(NULL, "qeic"); - if (!np) - return; - } - qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); - of_node_put(np); -#endif /* CONFIG_QUICC_ENGINE */ -} - /* * Called very early, MMU is off, device-tree isn't unflattened */ @@ -268,7 +221,7 @@ define_machine(mpc836x_mds) { .name = "MPC836x MDS", .probe = mpc836x_mds_probe, .setup_arch = mpc836x_mds_setup_arch, - .init_IRQ = mpc836x_mds_init_IRQ, + .init_IRQ = mpc83xx_ipic_and_qe_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c index b0090aac964..f8769d713d6 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_rdk.c +++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c @@ -27,61 +27,19 @@ #include "mpc83xx.h" -static struct of_device_id __initdata mpc836x_rdk_ids[] = { - { .compatible = "simple-bus", }, - {}, -}; - -static int __init mpc836x_rdk_declare_of_platform_devices(void) -{ - return of_platform_bus_probe(NULL, mpc836x_rdk_ids, NULL); -} -machine_device_initcall(mpc836x_rdk, mpc836x_rdk_declare_of_platform_devices); +machine_device_initcall(mpc836x_rdk, mpc83xx_declare_of_platform_devices); static void __init mpc836x_rdk_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc836x_rdk_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); #ifdef CONFIG_QUICC_ENGINE qe_reset(); #endif } -static void __init mpc836x_rdk_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* - * Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); - of_node_put(np); -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (!np) - return; - - qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); - of_node_put(np); -#endif -} - /* * Called very early, MMU is off, device-tree isn't unflattened. */ @@ -96,7 +54,7 @@ define_machine(mpc836x_rdk) { .name = "MPC836x RDK", .probe = mpc836x_rdk_probe, .setup_arch = mpc836x_rdk_setup_arch, - .init_IRQ = mpc836x_rdk_init_IRQ, + .init_IRQ = mpc83xx_ipic_and_qe_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc837x_mds.c b/arch/powerpc/platforms/83xx/mpc837x_mds.c index 83068322abd..e53a60b6c86 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc837x_mds.c @@ -79,54 +79,14 @@ out: */ static void __init mpc837x_mds_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc837x_mds_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); - for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); mpc837xmds_usb_cfg(); } -static struct of_device_id mpc837x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init mpc837x_declare_of_platform_devices(void) -{ - /* Publish platform_device */ - of_platform_bus_probe(NULL, mpc837x_ids, NULL); - - return 0; -} -machine_device_initcall(mpc837x_mds, mpc837x_declare_of_platform_devices); - -static void __init mpc837x_mds_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} +machine_device_initcall(mpc837x_mds, mpc83xx_declare_of_platform_devices); /* * Called very early, MMU is off, device-tree isn't unflattened @@ -142,7 +102,7 @@ define_machine(mpc837x_mds) { .name = "MPC837x MDS", .probe = mpc837x_mds_probe, .setup_arch = mpc837x_mds_setup_arch, - .init_IRQ = mpc837x_mds_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 7bafbf2ec0f..16c9c9cbbb7 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -50,56 +50,15 @@ static void mpc837x_rdb_sd_cfg(void) */ static void __init mpc837x_rdb_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc837x_rdb_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); - for_each_compatible_node(np, "pci", "fsl,mpc8314-pcie") - mpc83xx_add_bridge(np); -#endif + mpc83xx_setup_pci(); mpc837x_usb_cfg(); mpc837x_rdb_sd_cfg(); } -static struct of_device_id mpc837x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - { .compatible = "gpio-leds", }, - {}, -}; - -static int __init mpc837x_declare_of_platform_devices(void) -{ - /* Publish platform_device */ - of_platform_bus_probe(NULL, mpc837x_ids, NULL); - - return 0; -} -machine_device_initcall(mpc837x_rdb, mpc837x_declare_of_platform_devices); - -static void __init mpc837x_rdb_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} +machine_device_initcall(mpc837x_rdb, mpc83xx_declare_of_platform_devices); static const char *board[] __initdata = { "fsl,mpc8377rdb", @@ -121,7 +80,7 @@ define_machine(mpc837x_rdb) { .name = "MPC837x RDB/WLAN", .probe = mpc837x_rdb_probe, .setup_arch = mpc837x_rdb_setup_arch, - .init_IRQ = mpc837x_rdb_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 82a434510d8..0cf74d7ea1c 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -70,5 +70,21 @@ extern long mpc83xx_time_init(void); extern int mpc837x_usb_cfg(void); extern int mpc834x_usb_cfg(void); extern int mpc831x_usb_cfg(void); +extern void mpc83xx_ipic_init_IRQ(void); +#ifdef CONFIG_QUICC_ENGINE +extern void mpc83xx_qe_init_IRQ(void); +extern void mpc83xx_ipic_and_qe_init_IRQ(void); +#else +static inline void __init mpc83xx_qe_init_IRQ(void) {} +#define mpc83xx_ipic_and_qe_init_IRQ mpc83xx_ipic_init_IRQ +#endif /* CONFIG_QUICC_ENGINE */ + +#ifdef CONFIG_PCI +extern void mpc83xx_setup_pci(void); +#else +#define mpc83xx_setup_pci() do {} while (0) +#endif + +extern int mpc83xx_declare_of_platform_devices(void); #endif /* __MPC83XX_H__ */ diff --git a/arch/powerpc/platforms/83xx/sbc834x.c b/arch/powerpc/platforms/83xx/sbc834x.c index af41d8c810a..8a81d7640b1 100644 --- a/arch/powerpc/platforms/83xx/sbc834x.c +++ b/arch/powerpc/platforms/83xx/sbc834x.c @@ -48,52 +48,13 @@ */ static void __init sbc834x_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("sbc834x_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") - mpc83xx_add_bridge(np); -#endif - + mpc83xx_setup_pci(); } -static void __init sbc834x_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); - - of_node_put(np); -} - -static struct __initdata of_device_id sbc834x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init sbc834x_declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, sbc834x_ids, NULL); - return 0; -} -machine_device_initcall(sbc834x, sbc834x_declare_of_platform_devices); +machine_device_initcall(sbc834x, mpc83xx_declare_of_platform_devices); /* * Called very early, MMU is off, device-tree isn't unflattened @@ -102,14 +63,14 @@ static int __init sbc834x_probe(void) { unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "SBC834x"); + return of_flat_dt_is_compatible(root, "SBC834xE"); } define_machine(sbc834x) { - .name = "SBC834x", + .name = "SBC834xE", .probe = sbc834x_probe, .setup_arch = sbc834x_setup_arch, - .init_IRQ = sbc834x_init_IRQ, + .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index bc5acb95917..9cb2d4320dc 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,6 +3,8 @@ # obj-$(CONFIG_SMP) += smp.o +obj-y += common.o + obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c new file mode 100644 index 00000000000..9fef5302adc --- /dev/null +++ b/arch/powerpc/platforms/85xx/common.c @@ -0,0 +1,66 @@ +/* + * Routines common to most mpc85xx-based boards. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/of_platform.h> + +#include <sysdev/cpm2_pic.h> + +#include "mpc85xx.h" + +static struct of_device_id __initdata mpc85xx_common_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .compatible = "simple-bus", }, + { .name = "cpm", }, + { .name = "localbus", }, + { .compatible = "gianfar", }, + { .compatible = "fsl,qe", }, + { .compatible = "fsl,cpm2", }, + { .compatible = "fsl,srio", }, + {}, +}; + +int __init mpc85xx_common_publish_devices(void) +{ + return of_platform_bus_probe(NULL, mpc85xx_common_ids, NULL); +} +#ifdef CONFIG_CPM2 +static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + int cascade_irq; + + while ((cascade_irq = cpm2_get_irq()) >= 0) + generic_handle_irq(cascade_irq); + + chip->irq_eoi(&desc->irq_data); +} + + +void __init mpc85xx_cpm2_pic_init(void) +{ + struct device_node *np; + int irq; + + /* Setup CPM2 PIC */ + np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); + if (np == NULL) { + printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); + return; + } + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + of_node_put(np); + printk(KERN_ERR "PIC init: got no IRQ for cpm cascade\n"); + return; + } + + cpm2_pic_init(np); + of_node_put(np); + irq_set_chained_handler(irq, cpm2_cascade); +} +#endif diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c index 802ad110b75..07e3e6c4737 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/arch/powerpc/platforms/85xx/corenet_ds.c @@ -31,32 +31,18 @@ #include <linux/of_platform.h> #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "smp.h" void __init corenet_ds_pic_init(void) { struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; - unsigned int flags = MPIC_PRIMARY | MPIC_BIG_ENDIAN | + unsigned int flags = MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU; - np = of_find_node_by_type(np, "open-pic"); - - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - if (ppc_md.get_irq == mpic_get_coreint_irq) flags |= MPIC_ENABLE_COREINT; - mpic = mpic_alloc(np, r.start, flags, 0, 256, " OpenPIC "); + mpic = mpic_alloc(NULL, 0, flags, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); @@ -65,10 +51,6 @@ void __init corenet_ds_pic_init(void) /* * Setup the architecture */ -#ifdef CONFIG_SMP -void __init mpc85xx_smp_init(void); -#endif - void __init corenet_ds_setup_arch(void) { #ifdef CONFIG_PCI @@ -77,9 +59,7 @@ void __init corenet_ds_setup_arch(void) #endif dma_addr_t max = 0xffffffff; -#ifdef CONFIG_SMP mpc85xx_smp_init(); -#endif #ifdef CONFIG_PCI for_each_node_by_type(np, "pci") { @@ -112,7 +92,7 @@ static const struct of_device_id of_device_ids[] __devinitconst = { .compatible = "simple-bus" }, { - .compatible = "fsl,rapidio-delta", + .compatible = "fsl,srio", }, { .compatible = "fsl,p4080-pcie", diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index c46f9359be1..20f75d7819c 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c @@ -35,6 +35,7 @@ #include <asm/cpm2.h> #include <sysdev/cpm2_pic.h> +#include "mpc85xx.h" #define KSI8560_CPLD_HVR 0x04 /* Hardware Version Register */ #define KSI8560_CPLD_PVR 0x08 /* PLD Version Register */ @@ -54,60 +55,15 @@ static void machine_restart(char *cmd) for (;;); } -static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - int cascade_irq; - - while ((cascade_irq = cpm2_get_irq()) >= 0) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} - static void __init ksi8560_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np; -#ifdef CONFIG_CPM2 - int irq; -#endif - - np = of_find_node_by_type(NULL, "open-pic"); - - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Could not map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); -#ifdef CONFIG_CPM2 - /* Setup CPM2 PIC */ - np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); - if (np == NULL) { - printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); - return; - } - irq = irq_of_parse_and_map(np, 0); - - cpm2_pic_init(np); - of_node_put(np); - irq_set_chained_handler(irq, cpm2_cascade); -#endif + mpc85xx_cpm2_pic_init(); } #ifdef CONFIG_CPM2 @@ -215,22 +171,7 @@ static void ksi8560_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -static struct of_device_id __initdata of_bus_ids[] = { - { .type = "soc", }, - { .type = "simple-bus", }, - { .name = "cpm", }, - { .name = "localbus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - - return 0; -} -machine_device_initcall(ksi8560, declare_of_platform_devices); +machine_device_initcall(ksi8560, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index f79f2f10214..cf266826682 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -32,31 +32,15 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + void __init mpc8536_ds_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np; - - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); } @@ -104,19 +88,7 @@ static void __init mpc8536_ds_setup_arch(void) printk("MPC8536 DS board from Freescale Semiconductor\n"); } -static struct of_device_id __initdata mpc8536_ds_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init mpc8536_ds_publish_devices(void) -{ - return of_platform_bus_probe(NULL, mpc8536_ds_ids, NULL); -} -machine_device_initcall(mpc8536_ds, mpc8536_ds_publish_devices); +machine_device_initcall(mpc8536_ds, mpc85xx_common_publish_devices); machine_arch_initcall(mpc8536_ds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h new file mode 100644 index 00000000000..2aa7c5dc2c7 --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc85xx.h @@ -0,0 +1,11 @@ +#ifndef MPC85xx_H +#define MPC85xx_H +extern int mpc85xx_common_publish_devices(void); + +#ifdef CONFIG_CPM2 +extern void mpc85xx_cpm2_pic_init(void); +#else +static inline void __init mpc85xx_cpm2_pic_init(void) {} +#endif /* CONFIG_CPM2 */ + +#endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 3b2c9bb6619..3bebb5173bf 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -35,6 +35,8 @@ #include <sysdev/cpm2_pic.h> #endif +#include "mpc85xx.h" + #ifdef CONFIG_PCI static int mpc85xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) @@ -46,63 +48,15 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, } #endif /* CONFIG_PCI */ -#ifdef CONFIG_CPM2 - -static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - int cascade_irq; - - while ((cascade_irq = cpm2_get_irq()) >= 0) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} - -#endif /* CONFIG_CPM2 */ - static void __init mpc85xx_ads_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; -#ifdef CONFIG_CPM2 - int irq; -#endif - - np = of_find_node_by_type(np, "open-pic"); - if (!np) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Could not map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); -#ifdef CONFIG_CPM2 - /* Setup CPM2 PIC */ - np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); - if (np == NULL) { - printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); - return; - } - irq = irq_of_parse_and_map(np, 0); - - cpm2_pic_init(np); - of_node_put(np); - irq_set_chained_handler(irq, cpm2_cascade); -#endif + mpc85xx_cpm2_pic_init(); } /* @@ -221,23 +175,7 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -static struct of_device_id __initdata of_bus_ids[] = { - { .name = "soc", }, - { .type = "soc", }, - { .name = "cpm", }, - { .name = "localbus", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - - return 0; -} -machine_device_initcall(mpc85xx_ads, declare_of_platform_devices); +machine_device_initcall(mpc85xx_ads, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 66cb8d64079..40f03da616a 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -46,6 +46,8 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + /* CADMUS info */ /* xxx - galak, move into device tree */ #define CADMUS_BASE (0xf8004000) @@ -177,7 +179,7 @@ static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id) static struct irqaction mpc85xxcds_8259_irqaction = { .handler = mpc85xx_8259_cascade_action, - .flags = IRQF_SHARED, + .flags = IRQF_SHARED | IRQF_NO_THREAD, .name = "8259 cascade", }; #endif /* PPC_I8259 */ @@ -186,30 +188,10 @@ static struct irqaction mpc85xxcds_8259_irqaction = { static void __init mpc85xx_cds_pic_init(void) { struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; - - np = of_find_node_by_type(np, "open-pic"); - - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - - /* Return the mpic node */ - of_node_put(np); - mpic_init(mpic); } @@ -330,19 +312,7 @@ static int __init mpc85xx_cds_probe(void) return of_flat_dt_is_compatible(root, "MPC85xxCDS"); } -static struct of_device_id __initdata of_bus_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - return of_platform_bus_probe(NULL, of_bus_ids, NULL); -} -machine_device_initcall(mpc85xx_cds, declare_of_platform_devices); +machine_device_initcall(mpc85xx_cds, mpc85xx_common_publish_devices); define_machine(mpc85xx_cds) { .name = "MPC85xx CDS", diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 1b9a8cf1873..eefbb91e1d6 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -35,6 +35,9 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "smp.h" + +#include "mpc85xx.h" #undef DEBUG @@ -60,43 +63,27 @@ static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc) void __init mpc85xx_ds_pic_init(void) { struct mpic *mpic; - struct resource r; - struct device_node *np; #ifdef CONFIG_PPC_I8259 + struct device_node *np; struct device_node *cascade_node = NULL; int cascade_irq; #endif unsigned long root = of_get_flat_dt_root(); - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } else { - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); #ifdef CONFIG_PPC_I8259 @@ -152,9 +139,6 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, /* * Setup the architecture */ -#ifdef CONFIG_SMP -extern void __init mpc85xx_smp_init(void); -#endif static void __init mpc85xx_ds_setup_arch(void) { #ifdef CONFIG_PCI @@ -187,9 +171,7 @@ static void __init mpc85xx_ds_setup_arch(void) ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif -#ifdef CONFIG_SMP mpc85xx_smp_init(); -#endif #ifdef CONFIG_SWIOTLB if (memblock_end_of_DRAM() > max) { @@ -219,21 +201,9 @@ static int __init mpc8544_ds_probe(void) return 0; } -static struct of_device_id __initdata mpc85xxds_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init mpc85xxds_publish_devices(void) -{ - return of_platform_bus_probe(NULL, mpc85xxds_ids, NULL); -} -machine_device_initcall(mpc8544_ds, mpc85xxds_publish_devices); -machine_device_initcall(mpc8572_ds, mpc85xxds_publish_devices); -machine_device_initcall(p2020_ds, mpc85xxds_publish_devices); +machine_device_initcall(mpc8544_ds, mpc85xx_common_publish_devices); +machine_device_initcall(mpc8572_ds, mpc85xx_common_publish_devices); +machine_device_initcall(p2020_ds, mpc85xx_common_publish_devices); machine_arch_initcall(mpc8544_ds, swiotlb_setup_bus_notifier); machine_arch_initcall(mpc8572_ds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index a23a3ff634c..1d15a0cd2c8 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -51,6 +51,9 @@ #include <asm/qe_ic.h> #include <asm/mpic.h> #include <asm/swiotlb.h> +#include "smp.h" + +#include "mpc85xx.h" #undef DEBUG #ifdef DEBUG @@ -153,30 +156,7 @@ static int mpc8568_mds_phy_fixups(struct phy_device *phydev) * Setup the architecture * */ -#ifdef CONFIG_SMP -extern void __init mpc85xx_smp_init(void); -#endif - #ifdef CONFIG_QUICC_ENGINE -static struct of_device_id mpc85xx_qe_ids[] __initdata = { - { .type = "qe", }, - { .compatible = "fsl,qe", }, - { }, -}; - -static void __init mpc85xx_publish_qe_devices(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!of_device_is_available(np)) { - of_node_put(np); - return; - } - - of_platform_bus_probe(NULL, mpc85xx_qe_ids, NULL); -} - static void __init mpc85xx_mds_reset_ucc_phys(void) { struct device_node *np; @@ -347,7 +327,6 @@ static void __init mpc85xx_mds_qeic_init(void) of_node_put(np); } #else -static void __init mpc85xx_publish_qe_devices(void) { } static void __init mpc85xx_mds_qe_init(void) { } static void __init mpc85xx_mds_qeic_init(void) { } #endif /* CONFIG_QUICC_ENGINE */ @@ -381,9 +360,7 @@ static void __init mpc85xx_mds_setup_arch(void) } #endif -#ifdef CONFIG_SMP mpc85xx_smp_init(); -#endif mpc85xx_mds_qe_init(); @@ -429,24 +406,11 @@ machine_arch_initcall(mpc8568_mds, board_fixups); machine_arch_initcall(mpc8569_mds, board_fixups); static struct of_device_id mpc85xx_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - { .compatible = "fsl,rapidio-delta", }, { .compatible = "fsl,mpc8548-guts", }, { .compatible = "gpio-leds", }, {}, }; -static struct of_device_id p1021_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - static int __init mpc85xx_publish_devices(void) { if (machine_is(mpc8568_mds)) @@ -454,23 +418,15 @@ static int __init mpc85xx_publish_devices(void) if (machine_is(mpc8569_mds)) simple_gpiochip_init("fsl,mpc8569mds-bcsr-gpio"); + mpc85xx_common_publish_devices(); of_platform_bus_probe(NULL, mpc85xx_ids, NULL); - mpc85xx_publish_qe_devices(); - - return 0; -} - -static int __init p1021_publish_devices(void) -{ - of_platform_bus_probe(NULL, p1021_ids, NULL); - mpc85xx_publish_qe_devices(); return 0; } machine_device_initcall(mpc8568_mds, mpc85xx_publish_devices); machine_device_initcall(mpc8569_mds, mpc85xx_publish_devices); -machine_device_initcall(p1021_mds, p1021_publish_devices); +machine_device_initcall(p1021_mds, mpc85xx_common_publish_devices); machine_arch_initcall(mpc8568_mds, swiotlb_setup_bus_notifier); machine_arch_initcall(mpc8569_mds, swiotlb_setup_bus_notifier); @@ -478,26 +434,11 @@ machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier); static void __init mpc85xx_mds_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; - - np = of_find_node_by_type(NULL, "open-pic"); - if (!np) - return; - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); mpic_init(mpic); mpc85xx_mds_qeic_init(); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index f5ff9110c97..ccf520e890b 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -29,6 +29,9 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "smp.h" + +#include "mpc85xx.h" #undef DEBUG @@ -42,49 +45,28 @@ void __init mpc85xx_rdb_pic_init(void) { struct mpic *mpic; - struct resource r; - struct device_node *np; unsigned long root = of_get_flat_dt_root(); - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) { - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } else { - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); - } /* * Setup the architecture */ -#ifdef CONFIG_SMP -extern void __init mpc85xx_smp_init(void); -#endif static void __init mpc85xx_rdb_setup_arch(void) { #ifdef CONFIG_PCI @@ -102,27 +84,12 @@ static void __init mpc85xx_rdb_setup_arch(void) #endif -#ifdef CONFIG_SMP mpc85xx_smp_init(); -#endif - printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); } -static struct of_device_id __initdata mpc85xxrdb_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init mpc85xxrdb_publish_devices(void) -{ - return of_platform_bus_probe(NULL, mpc85xxrdb_ids, NULL); -} -machine_device_initcall(p2020_rdb, mpc85xxrdb_publish_devices); -machine_device_initcall(p1020_rdb, mpc85xxrdb_publish_devices); +machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices); +machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index d7387fa7f53..538bc3f57e9 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -28,33 +28,18 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + void __init p1010_rdb_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np; - - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); mpic_init(mpic); - } @@ -81,18 +66,7 @@ static void __init p1010_rdb_setup_arch(void) printk(KERN_INFO "P1010 RDB board from Freescale Semiconductor\n"); } -static struct of_device_id __initdata p1010rdb_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - {}, -}; - -static int __init p1010rdb_publish_devices(void) -{ - return of_platform_bus_probe(NULL, p1010rdb_ids, NULL); -} -machine_device_initcall(p1010_rdb, p1010rdb_publish_devices); +machine_device_initcall(p1010_rdb, mpc85xx_common_publish_devices); machine_arch_initcall(p1010_rdb, swiotlb_setup_bus_notifier); /* diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index fda15716fad..bb3d84f4046 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -26,6 +26,9 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> #include <asm/fsl_guts.h> +#include "smp.h" + +#include "mpc85xx.h" #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) @@ -238,38 +241,15 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) void __init p1022_ds_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np; - - np = of_find_node_by_type(NULL, "open-pic"); - if (!np) { - pr_err("Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - pr_err("Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); - BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); } -#ifdef CONFIG_SMP -void __init mpc85xx_smp_init(void); -#endif - /* * Setup the architecture */ @@ -309,9 +289,7 @@ static void __init p1022_ds_setup_arch(void) diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; #endif -#ifdef CONFIG_SMP mpc85xx_smp_init(); -#endif #ifdef CONFIG_SWIOTLB if (memblock_end_of_DRAM() > max) { @@ -325,10 +303,6 @@ static void __init p1022_ds_setup_arch(void) } static struct of_device_id __initdata p1022_ds_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, /* So that the DMA channel nodes can be probed individually: */ { .compatible = "fsl,eloplus-dma", }, {}, @@ -336,6 +310,7 @@ static struct of_device_id __initdata p1022_ds_ids[] = { static int __init p1022_ds_publish_devices(void) { + mpc85xx_common_publish_devices(); return of_platform_bus_probe(NULL, p1022_ds_ids, NULL); } machine_device_initcall(p1022_ds, p1022_ds_publish_devices); diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c index 835e0b335bf..d951e7027bb 100644 --- a/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/arch/powerpc/platforms/85xx/p1023_rds.c @@ -30,19 +30,18 @@ #include <asm/prom.h> #include <asm/udbg.h> #include <asm/mpic.h> +#include "smp.h" #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + /* ************************************************************************ * * Setup the architecture * */ -#ifdef CONFIG_SMP -void __init mpc85xx_smp_init(void); -#endif - static void __init mpc85xx_rds_setup_arch(void) { struct device_node *np; @@ -87,53 +86,19 @@ static void __init mpc85xx_rds_setup_arch(void) fsl_add_bridge(np, 0); #endif -#ifdef CONFIG_SMP mpc85xx_smp_init(); -#endif -} - -static struct of_device_id p1023_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - {}, -}; - - -static int __init p1023_publish_devices(void) -{ - of_platform_bus_probe(NULL, p1023_ids, NULL); - - return 0; } -machine_device_initcall(p1023_rds, p1023_publish_devices); +machine_device_initcall(p1023_rds, mpc85xx_common_publish_devices); static void __init mpc85xx_rds_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; - - np = of_find_node_by_type(NULL, "open-pic"); - if (!np) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); mpic_init(mpic); } diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index 14632a97122..184a5078461 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c @@ -48,35 +48,16 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + static int sbc_rev; static void __init sbc8548_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; - - np = of_find_node_by_type(np, "open-pic"); - - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - - /* Return the mpic node */ - of_node_put(np); - mpic_init(mpic); } @@ -149,21 +130,7 @@ static void sbc8548_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -static struct of_device_id __initdata of_bus_ids[] = { - { .name = "soc", }, - { .type = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - - return 0; -} -machine_device_initcall(sbc8548, declare_of_platform_devices); +machine_device_initcall(sbc8548, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index cebd786dc33..940752e9305 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c @@ -32,68 +32,22 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + #ifdef CONFIG_CPM2 #include <asm/cpm2.h> #include <sysdev/cpm2_pic.h> #endif -#ifdef CONFIG_CPM2 - -static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - int cascade_irq; - - while ((cascade_irq = cpm2_get_irq()) >= 0) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} - -#endif /* CONFIG_CPM2 */ - static void __init sbc8560_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; -#ifdef CONFIG_CPM2 - int irq; -#endif - - np = of_find_node_by_type(np, "open-pic"); - if (!np) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Could not map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); -#ifdef CONFIG_CPM2 - /* Setup CPM2 PIC */ - np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); - if (np == NULL) { - printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); - return; - } - irq = irq_of_parse_and_map(np, 0); - - cpm2_pic_init(np); - of_node_put(np); - irq_set_chained_handler(irq, cpm2_cascade); -#endif + mpc85xx_cpm2_pic_init(); } /* @@ -208,23 +162,7 @@ static void sbc8560_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -static struct of_device_id __initdata of_bus_ids[] = { - { .name = "soc", }, - { .type = "soc", }, - { .name = "cpm", }, - { .name = "localbus", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - - return 0; -} -machine_device_initcall(sbc8560, declare_of_platform_devices); +machine_device_initcall(sbc8560, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 2df4785ffd4..ff4249044a3 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -27,6 +27,7 @@ #include <sysdev/fsl_soc.h> #include <sysdev/mpic.h> +#include "smp.h" extern void __early_start(void); diff --git a/arch/powerpc/platforms/85xx/smp.h b/arch/powerpc/platforms/85xx/smp.h new file mode 100644 index 00000000000..e2b44933ff1 --- /dev/null +++ b/arch/powerpc/platforms/85xx/smp.h @@ -0,0 +1,15 @@ +#ifndef POWERPC_85XX_SMP_H_ +#define POWERPC_85XX_SMP_H_ 1 + +#include <linux/init.h> + +#ifdef CONFIG_SMP +void __init mpc85xx_smp_init(void); +#else +static inline void mpc85xx_smp_init(void) +{ + /* Nothing to do */ +} +#endif + +#endif /* not POWERPC_85XX_SMP_H_ */ diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index 747d8fb3ab8..18f635906b2 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c @@ -41,32 +41,17 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" #include "socrates_fpga_pic.h" static void __init socrates_pic_init(void) { - struct mpic *mpic; - struct resource r; struct device_node *np; - np = of_find_node_by_type(NULL, "open-pic"); - if (!np) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Could not map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); np = of_find_compatible_node(NULL, NULL, "abb,socrates-fpga-pic"); @@ -96,17 +81,7 @@ static void __init socrates_setup_arch(void) #endif } -static struct of_device_id __initdata socrates_of_bus_ids[] = { - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init socrates_publish_devices(void) -{ - return of_platform_bus_probe(NULL, socrates_of_bus_ids, NULL); -} -machine_device_initcall(socrates, socrates_publish_devices); +machine_device_initcall(socrates, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index 5387e9f06bd..e9e5234b4e7 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -40,70 +40,21 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + #ifdef CONFIG_CPM2 #include <asm/cpm2.h> -#include <sysdev/cpm2_pic.h> - -static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - int cascade_irq; - - while ((cascade_irq = cpm2_get_irq()) >= 0) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} #endif /* CONFIG_CPM2 */ static void __init stx_gp3_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np; -#ifdef CONFIG_CPM2 - int irq; -#endif - - np = of_find_node_by_type(NULL, "open-pic"); - if (!np) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Could not map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); -#ifdef CONFIG_CPM2 - /* Setup CPM2 PIC */ - np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); - if (np == NULL) { - printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); - return; - } - irq = irq_of_parse_and_map(np, 0); - - if (irq == NO_IRQ) { - of_node_put(np); - printk(KERN_ERR "PIC init: got no IRQ for cpm cascade\n"); - return; - } - - cpm2_pic_init(np); - of_node_put(np); - irq_set_chained_handler(irq, cpm2_cascade); -#endif + mpc85xx_cpm2_pic_init(); } /* @@ -144,19 +95,7 @@ static void stx_gp3_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -static struct of_device_id __initdata of_bus_ids[] = { - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - - return 0; -} -machine_device_initcall(stx_gp3, declare_of_platform_devices); +machine_device_initcall(stx_gp3, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index 325de772725..bf7c89fb75b 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -38,70 +38,21 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "mpc85xx.h" + #ifdef CONFIG_CPM2 #include <asm/cpm2.h> -#include <sysdev/cpm2_pic.h> - -static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - int cascade_irq; - - while ((cascade_irq = cpm2_get_irq()) >= 0) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} #endif /* CONFIG_CPM2 */ static void __init tqm85xx_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np; -#ifdef CONFIG_CPM2 - int irq; -#endif - - np = of_find_node_by_type(NULL, "open-pic"); - if (!np) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Could not map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); -#ifdef CONFIG_CPM2 - /* Setup CPM2 PIC */ - np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); - if (np == NULL) { - printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); - return; - } - irq = irq_of_parse_and_map(np, 0); - - if (irq == NO_IRQ) { - of_node_put(np); - printk(KERN_ERR "PIC init: got no IRQ for cpm cascade\n"); - return; - } - - cpm2_pic_init(np); - of_node_put(np); - irq_set_chained_handler(irq, cpm2_cascade); -#endif + mpc85xx_cpm2_pic_init(); } /* @@ -173,19 +124,7 @@ static void __init tqm85xx_ti1520_fixup(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, tqm85xx_ti1520_fixup); -static struct of_device_id __initdata of_bus_ids[] = { - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - - return 0; -} -machine_device_initcall(tqm85xx, declare_of_platform_devices); +machine_device_initcall(tqm85xx, mpc85xx_common_publish_devices); static const char *board[] __initdata = { "tqc,tqm8540", diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index a9dc5e79512..3a69f8b77de 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -32,6 +32,9 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> +#include "smp.h" + +#include "mpc85xx.h" /* A few bit definitions needed for fixups on some boards */ #define MPC85xx_L2CTL_L2E 0x80000000 /* L2 enable */ @@ -40,29 +43,11 @@ void __init xes_mpc85xx_pic_init(void) { - struct mpic *mpic; - struct resource r; - struct device_node *np; - - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - of_node_put(np); - mpic_init(mpic); } @@ -136,9 +121,6 @@ static int primary_phb_addr; /* * Setup the architecture */ -#ifdef CONFIG_SMP -extern void __init mpc85xx_smp_init(void); -#endif static void __init xes_mpc85xx_setup_arch(void) { #ifdef CONFIG_PCI @@ -172,26 +154,12 @@ static void __init xes_mpc85xx_setup_arch(void) } #endif -#ifdef CONFIG_SMP mpc85xx_smp_init(); -#endif } -static struct of_device_id __initdata xes_mpc85xx_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, - {}, -}; - -static int __init xes_mpc85xx_publish_devices(void) -{ - return of_platform_bus_probe(NULL, xes_mpc85xx_ids, NULL); -} -machine_device_initcall(xes_mpc8572, xes_mpc85xx_publish_devices); -machine_device_initcall(xes_mpc8548, xes_mpc85xx_publish_devices); -machine_device_initcall(xes_mpc8540, xes_mpc85xx_publish_devices); +machine_device_initcall(xes_mpc8572, mpc85xx_common_publish_devices); +machine_device_initcall(xes_mpc8548, mpc85xx_common_publish_devices); +machine_device_initcall(xes_mpc8540, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index b11c3535f35..569262ca499 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -161,7 +161,7 @@ mpc86xx_time_init(void) static __initdata struct of_device_id of_bus_ids[] = { { .compatible = "simple-bus", }, - { .compatible = "fsl,rapidio-delta", }, + { .compatible = "fsl,srio", }, { .compatible = "gianfar", }, {}, }; diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c index 8ef8960abda..52bbfa03153 100644 --- a/arch/powerpc/platforms/86xx/pic.c +++ b/arch/powerpc/platforms/86xx/pic.c @@ -31,26 +31,16 @@ static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) void __init mpc86xx_init_irq(void) { - struct mpic *mpic; - struct device_node *np; - struct resource res; #ifdef CONFIG_PPC_I8259 + struct device_node *np; struct device_node *cascade_node = NULL; int cascade_irq; #endif - /* Determine PIC address. */ - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) - return; - of_address_to_resource(np, 0, &res); - - mpic = mpic_alloc(np, res.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | - MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " MPIC "); - of_node_put(np); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 3fe6d927ad7..31e1adeaa92 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -211,6 +211,12 @@ config PPC_PASEMI_CPUFREQ endmenu +menu "CPUIdle driver" + +source "drivers/cpuidle/Kconfig" + +endmenu + config PPC601_SYNC_FIX bool "Workarounds for PPC601 bugs" depends on 6xx && (PPC_PREP || PPC_PMAC) diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index fbecae0fbb4..425db18580a 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -174,7 +174,6 @@ config BOOKE config FSL_BOOKE bool depends on (E200 || E500) && PPC32 - select SYS_SUPPORTS_HUGETLBFS if PHYS_64BIT default y # this is for common code between PPC32 & PPC64 FSL BOOKE @@ -182,6 +181,7 @@ config PPC_FSL_BOOK3E bool select FSL_EMB_PERFMON select PPC_SMP_MUXED_IPI + select SYS_SUPPORTS_HUGETLBFS if PHYS_64BIT || PPC64 default y if FSL_BOOKE config PTE_64BIT @@ -236,7 +236,7 @@ config VSX config PPC_ICSWX bool "Support for PowerPC icswx coprocessor instruction" - depends on POWER4 + depends on POWER4 || PPC_A2 default n ---help--- @@ -252,6 +252,25 @@ config PPC_ICSWX If in doubt, say N here. +config PPC_ICSWX_PID + bool "icswx requires direct PID management" + depends on PPC_ICSWX && POWER4 + default y + ---help--- + The PID register in server is used explicitly for ICSWX. In + embedded systems PID managment is done by the system. + +config PPC_ICSWX_USE_SIGILL + bool "Should a bad CT cause a SIGILL?" + depends on PPC_ICSWX + default n + ---help--- + Should a bad CT used for "non-record form ICSWX" cause an + illegal intruction signal or should it be silent as + architected. + + If in doubt, say N here. + config SPE bool "SPE Support" depends on E200 || (E500 && !PPC_E500MC) @@ -290,7 +309,7 @@ config PPC_BOOK3E_MMU config PPC_MM_SLICES bool - default y if (PPC64 && HUGETLB_PAGE) || (PPC_STD_MMU_64 && PPC_64K_PAGES) + default y if (!PPC_FSL_BOOK3E && PPC64 && HUGETLB_PAGE) || (PPC_STD_MMU_64 && PPC_64K_PAGES) default n config VIRT_CPU_ACCOUNTING diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 592c3d51b81..ae9fc7bc17d 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -1037,6 +1037,8 @@ static int __init cell_iommu_fixed_mapping_init(void) /* The fixed mapping is only supported on axon machines */ np = of_find_node_by_name(NULL, "axon"); + of_node_put(np); + if (!np) { pr_debug("iommu: fixed mapping disabled, no axons found\n"); return -1; diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 0fc9b725612..62002a7edfe 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -184,24 +184,10 @@ static int __init cell_publish_devices(void) } machine_subsys_initcall(cell, cell_publish_devices); -static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct mpic *mpic = irq_desc_get_handler_data(desc); - unsigned int virq; - - virq = mpic_get_one_irq(mpic); - if (virq != NO_IRQ) - generic_handle_irq(virq); - - chip->irq_eoi(&desc->irq_data); -} - static void __init mpic_init_IRQ(void) { struct device_node *dn; struct mpic *mpic; - unsigned int virq; for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { @@ -211,19 +197,10 @@ static void __init mpic_init_IRQ(void) /* The MPIC driver will get everything it needs from the * device-tree, just pass 0 to all arguments */ - mpic = mpic_alloc(dn, 0, 0, 0, 0, " MPIC "); + mpic = mpic_alloc(dn, 0, MPIC_SECONDARY, 0, 0, " MPIC "); if (mpic == NULL) continue; mpic_init(mpic); - - virq = irq_of_parse_and_map(dn, 0); - if (virq == NO_IRQ) - continue; - - printk(KERN_INFO "%s : hooking up to IRQ %d\n", - dn->full_name, virq); - irq_set_handler_data(virq, mpic); - irq_set_chained_handler(virq, cell_mpic_cascade); } } diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 12278649841..f1f17bb2c33 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -435,8 +435,7 @@ static void __init chrp_find_openpic(void) if (len > 1) isu_size = iranges[3]; - chrp_mpic = mpic_alloc(np, opaddr, MPIC_PRIMARY, - isu_size, 0, " MPIC "); + chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC "); if (chrp_mpic == NULL) { printk(KERN_ERR "Failed to allocate MPIC structure\n"); goto bail; diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 2e9bcf6444c..9cfcf20c056 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -148,30 +148,14 @@ static void __init holly_setup_arch(void) static void __init holly_init_IRQ(void) { struct mpic *mpic; - phys_addr_t mpic_paddr = 0; - struct device_node *tsi_pic; #ifdef CONFIG_PCI unsigned int cascade_pci_irq; struct device_node *tsi_pci; struct device_node *cascade_node = NULL; #endif - tsi_pic = of_find_node_by_type(NULL, "open-pic"); - if (tsi_pic) { - unsigned int size; - const void *prop = of_get_property(tsi_pic, "reg", &size); - mpic_paddr = of_translate_address(tsi_pic, prop); - } - - if (mpic_paddr == 0) { - printk(KERN_ERR "%s: No tsi108 PIC found !\n", __func__); - return; - } - - pr_debug("%s: tsi108 pic phys_addr = 0x%x\n", __func__, (u32) mpic_paddr); - - mpic = mpic_alloc(tsi_pic, mpic_paddr, - MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, 24, NR_IRQS-4, /* num_sources used */ @@ -179,7 +163,7 @@ static void __init holly_init_IRQ(void) BUG_ON(mpic == NULL); - mpic_assign_isu(mpic, 0, mpic_paddr + 0x100); + mpic_assign_isu(mpic, 0, mpic->paddr + 0x100); mpic_init(mpic); @@ -204,7 +188,6 @@ static void __init holly_init_IRQ(void) #endif /* Configure MPIC outputs to CPU0 */ tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0); - of_node_put(tsi_pic); } void holly_show_cpuinfo(struct seq_file *m) diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 244f997de79..bcfad92c9ce 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -81,29 +81,19 @@ static void __init linkstation_setup_arch(void) static void __init linkstation_init_IRQ(void) { struct mpic *mpic; - struct device_node *dnp; - const u32 *prop; - int size; - phys_addr_t paddr; - dnp = of_find_node_by_type(NULL, "open-pic"); - if (dnp == NULL) - return; - - prop = of_get_property(dnp, "reg", &size); - paddr = (phys_addr_t)of_translate_address(dnp, prop); - - mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 4, 32, " EPIC "); + mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, + 4, 32, " EPIC "); BUG_ON(mpic == NULL); /* PCI IRQs */ - mpic_assign_isu(mpic, 0, paddr + 0x10200); + mpic_assign_isu(mpic, 0, mpic->paddr + 0x10200); /* I2C */ - mpic_assign_isu(mpic, 1, paddr + 0x11000); + mpic_assign_isu(mpic, 1, mpic->paddr + 0x11000); /* ttyS0, ttyS1 */ - mpic_assign_isu(mpic, 2, paddr + 0x11100); + mpic_assign_isu(mpic, 2, mpic->paddr + 0x11100); mpic_init(mpic); } diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index f8f33e16c6b..f3350d786f5 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -102,31 +102,14 @@ static void __init mpc7448_hpc2_setup_arch(void) static void __init mpc7448_hpc2_init_IRQ(void) { struct mpic *mpic; - phys_addr_t mpic_paddr = 0; - struct device_node *tsi_pic; #ifdef CONFIG_PCI unsigned int cascade_pci_irq; struct device_node *tsi_pci; struct device_node *cascade_node = NULL; #endif - tsi_pic = of_find_node_by_type(NULL, "open-pic"); - if (tsi_pic) { - unsigned int size; - const void *prop = of_get_property(tsi_pic, "reg", &size); - mpic_paddr = of_translate_address(tsi_pic, prop); - } - - if (mpic_paddr == 0) { - printk("%s: No tsi108 PIC found !\n", __func__); - return; - } - - DBG("%s: tsi108 pic phys_addr = 0x%x\n", __func__, - (u32) mpic_paddr); - - mpic = mpic_alloc(tsi_pic, mpic_paddr, - MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, 24, NR_IRQS-4, /* num_sources used */ @@ -134,7 +117,7 @@ static void __init mpc7448_hpc2_init_IRQ(void) BUG_ON(mpic == NULL); - mpic_assign_isu(mpic, 0, mpic_paddr + 0x100); + mpic_assign_isu(mpic, 0, mpic->paddr + 0x100); mpic_init(mpic); @@ -159,7 +142,6 @@ static void __init mpc7448_hpc2_init_IRQ(void) #endif /* Configure MPIC outputs to CPU0 */ tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0); - of_node_put(tsi_pic); } void mpc7448_hpc2_show_cpuinfo(struct seq_file *m) diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index f1eebcae9bf..afa63883496 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -83,35 +83,17 @@ static void __init storcenter_setup_arch(void) static void __init storcenter_init_IRQ(void) { struct mpic *mpic; - struct device_node *dnp; - const void *prop; - int size; - phys_addr_t paddr; - - dnp = of_find_node_by_type(NULL, "open-pic"); - if (dnp == NULL) - return; - - prop = of_get_property(dnp, "reg", &size); - if (prop == NULL) { - of_node_put(dnp); - return; - } - - paddr = (phys_addr_t)of_translate_address(dnp, prop); - mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, - 16, 32, " OpenPIC "); - - of_node_put(dnp); + mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, + 16, 32, " OpenPIC "); BUG_ON(mpic == NULL); /* * 16 Serial Interrupts followed by 16 Internal Interrupts. * I2C is the second internal, so it is at 17, 0x11020. */ - mpic_assign_isu(mpic, 0, paddr + 0x10200); - mpic_assign_isu(mpic, 1, paddr + 0x11000); + mpic_assign_isu(mpic, 0, mpic->paddr + 0x10200); + mpic_assign_isu(mpic, 1, mpic->paddr + 0x11000); mpic_init(mpic); } diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index dd2e48b2850..401e3f3f74c 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -207,6 +207,54 @@ static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose, return hose->cfg_data + u3_ht_cfa1(bus, devfn, offset); } +static int u3_ht_root_read_config(struct pci_controller *hose, u8 offset, + int len, u32 *val) +{ + volatile void __iomem *addr; + + addr = hose->cfg_addr; + addr += ((offset & ~3) << 2) + (4 - len - (offset & 3)); + + switch (len) { + case 1: + *val = in_8(addr); + break; + case 2: + *val = in_be16(addr); + break; + default: + *val = in_be32(addr); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int u3_ht_root_write_config(struct pci_controller *hose, u8 offset, + int len, u32 val) +{ + volatile void __iomem *addr; + + addr = hose->cfg_addr + ((offset & ~3) << 2) + (4 - len - (offset & 3)); + + if (offset >= PCI_BASE_ADDRESS_0 && offset < PCI_CAPABILITY_LIST) + return PCIBIOS_SUCCESSFUL; + + switch (len) { + case 1: + out_8(addr, val); + break; + case 2: + out_be16(addr, val); + break; + default: + out_be32(addr, val); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -217,6 +265,9 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; + if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0)) + return u3_ht_root_read_config(hose, offset, len, val); + if (offset > 0xff) return PCIBIOS_BAD_REGISTER_NUMBER; @@ -252,6 +303,9 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; + if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0)) + return u3_ht_root_write_config(hose, offset, len, val); + if (offset > 0xff) return PCIBIOS_BAD_REGISTER_NUMBER; @@ -428,6 +482,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) * reg_property and using some accessor functions instead */ hose->cfg_data = ioremap(0xf2000000, 0x02000000); + hose->cfg_addr = ioremap(0xf8070000, 0x1000); hose->first_busno = 0; hose->last_busno = 0xef; diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 4c372047c94..0bcbfe7b2c5 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -221,7 +221,7 @@ static void __init maple_init_IRQ(void) unsigned long openpic_addr = 0; int naddr, n, i, opplen, has_isus = 0; struct mpic *mpic; - unsigned int flags = MPIC_PRIMARY; + unsigned int flags = 0; /* Locate MPIC in the device-tree. Note that there is a bug * in Maple device-tree where the type of the controller is diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 6f355821055..98b7a7c1317 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -224,7 +224,7 @@ static __init void pas_init_IRQ(void) openpic_addr = of_read_number(opprop, naddr); printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); - mpic_flags = MPIC_PRIMARY | MPIC_LARGE_VECTORS | MPIC_NO_BIAS; + mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS; nmiprop = of_get_property(mpic_node, "nmi-source", NULL); if (nmiprop) @@ -234,7 +234,7 @@ static __init void pas_init_IRQ(void) mpic_flags, 0, 0, "PASEMI-OPIC"); BUG_ON(!mpic); - mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); + mpic_assign_isu(mpic, 0, mpic->paddr + 0x10000); mpic_init(mpic); /* The NMI/MCK source needs to be prio 15 */ if (nmiprop) { diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 901bfbddc3d..7761aabfc29 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -52,13 +52,8 @@ struct device_node *of_irq_dflt_pic; /* Default addresses */ static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4]; -#define GC_LEVEL_MASK 0x3ff00000 -#define OHARE_LEVEL_MASK 0x1ff00000 -#define HEATHROW_LEVEL_MASK 0x1ff00000 - static int max_irqs; static int max_real_irqs; -static u32 level_mask[4]; static DEFINE_RAW_SPINLOCK(pmac_pic_lock); @@ -217,8 +212,7 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id) for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { int i = irq >> 5; bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; - /* We must read level interrupts from the level register */ - bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits |= in_le32(&pmac_irq_hw[i]->level); bits &= ppc_cached_irq_mask[i]; if (bits == 0) continue; @@ -248,8 +242,7 @@ static unsigned int pmac_pic_get_irq(void) for (irq = max_real_irqs; (irq -= 32) >= 0; ) { int i = irq >> 5; bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; - /* We must read level interrupts from the level register */ - bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits |= in_le32(&pmac_irq_hw[i]->level); bits &= ppc_cached_irq_mask[i]; if (bits == 0) continue; @@ -284,19 +277,14 @@ static int pmac_pic_host_match(struct irq_host *h, struct device_node *node) static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { - int level; - if (hw >= max_irqs) return -EINVAL; /* Mark level interrupts, set delayed disable for edge ones and set * handlers */ - level = !!(level_mask[hw >> 5] & (1UL << (hw & 0x1f))); - if (level) - irq_set_status_flags(virq, IRQ_LEVEL); - irq_set_chip_and_handler(virq, &pmac_pic, - level ? handle_level_irq : handle_edge_irq); + irq_set_status_flags(virq, IRQ_LEVEL); + irq_set_chip_and_handler(virq, &pmac_pic, handle_level_irq); return 0; } @@ -334,21 +322,14 @@ static void __init pmac_pic_probe_oldstyle(void) if ((master = of_find_node_by_name(NULL, "gc")) != NULL) { max_irqs = max_real_irqs = 32; - level_mask[0] = GC_LEVEL_MASK; } else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) { max_irqs = max_real_irqs = 32; - level_mask[0] = OHARE_LEVEL_MASK; - /* We might have a second cascaded ohare */ slave = of_find_node_by_name(NULL, "pci106b,7"); - if (slave) { + if (slave) max_irqs = 64; - level_mask[1] = OHARE_LEVEL_MASK; - } } else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) { max_irqs = max_real_irqs = 64; - level_mask[0] = HEATHROW_LEVEL_MASK; - level_mask[1] = 0; /* We might have a second cascaded heathrow */ slave = of_find_node_by_name(master, "mac-io"); @@ -363,11 +344,8 @@ static void __init pmac_pic_probe_oldstyle(void) } /* We found a slave */ - if (slave) { + if (slave) max_irqs = 128; - level_mask[2] = HEATHROW_LEVEL_MASK; - level_mask[3] = 0; - } } BUG_ON(master == NULL); @@ -464,18 +442,6 @@ int of_irq_map_oldworld(struct device_node *device, int index, } #endif /* CONFIG_PPC32 */ -static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct mpic *mpic = irq_desc_get_handler_data(desc); - unsigned int cascade_irq = mpic_get_one_irq(mpic); - - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} - static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) { #if defined(CONFIG_XMON) && defined(CONFIG_PPC32) @@ -498,14 +464,8 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, int master) { const char *name = master ? " MPIC 1 " : " MPIC 2 "; - struct resource r; struct mpic *mpic; - unsigned int flags = master ? MPIC_PRIMARY : 0; - int rc; - - rc = of_address_to_resource(np, 0, &r); - if (rc) - return NULL; + unsigned int flags = master ? 0 : MPIC_SECONDARY; pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); @@ -519,7 +479,7 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, if (master && (flags & MPIC_BIG_ENDIAN)) flags |= MPIC_U3_HT_IRQS; - mpic = mpic_alloc(np, r.start, flags, 0, 0, name); + mpic = mpic_alloc(np, 0, flags, 0, 0, name); if (mpic == NULL) return NULL; @@ -532,7 +492,6 @@ static int __init pmac_pic_probe_mpic(void) { struct mpic *mpic1, *mpic2; struct device_node *np, *master = NULL, *slave = NULL; - unsigned int cascade; /* We can have up to 2 MPICs cascaded */ for (np = NULL; (np = of_find_node_by_type(np, "open-pic")) @@ -568,27 +527,14 @@ static int __init pmac_pic_probe_mpic(void) of_node_put(master); - /* No slave, let's go out */ - if (slave == NULL) - return 0; - - /* Get/Map slave interrupt */ - cascade = irq_of_parse_and_map(slave, 0); - if (cascade == NO_IRQ) { - printk(KERN_ERR "Failed to map cascade IRQ\n"); - return 0; - } - - mpic2 = pmac_setup_one_mpic(slave, 0); - if (mpic2 == NULL) { - printk(KERN_ERR "Failed to setup slave MPIC\n"); + /* Set up a cascaded controller, if present */ + if (slave) { + mpic2 = pmac_setup_one_mpic(slave, 0); + if (mpic2 == NULL) + printk(KERN_ERR "Failed to setup slave MPIC\n"); of_node_put(slave); - return 0; } - irq_set_handler_data(cascade, mpic2); - irq_set_chained_handler(cascade, pmac_u3_cascade); - of_node_put(slave); return 0; } diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 96580b189ec..970ea1de429 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -494,11 +494,15 @@ static int __init pmac_declare_of_platform_devices(void) return -1; np = of_find_node_by_name(NULL, "valkyrie"); - if (np) + if (np) { of_platform_device_create(np, "valkyrie", NULL); + of_node_put(np); + } np = of_find_node_by_name(NULL, "platinum"); - if (np) + if (np) { of_platform_device_create(np, "platinum", NULL); + of_node_put(np); + } np = of_find_node_by_type(NULL, "smu"); if (np) { of_platform_device_create(np, "smu", NULL); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 9b6a820bdd7..44d769258eb 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -200,7 +200,7 @@ static int psurge_secondary_ipi_init(void) if (psurge_secondary_virq) rc = request_irq(psurge_secondary_virq, psurge_ipi_intr, - IRQF_PERCPU, "IPI", NULL); + IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL); if (rc) pr_err("Failed to setup secondary cpu IPI\n"); @@ -408,13 +408,13 @@ static int __init smp_psurge_kick_cpu(int nr) static struct irqaction psurge_irqaction = { .handler = psurge_ipi_intr, - .flags = IRQF_PERCPU, + .flags = IRQF_PERCPU | IRQF_NO_THREAD, .name = "primary IPI", }; static void __init smp_psurge_setup_cpu(int cpu_nr) { - if (cpu_nr != 0) + if (cpu_nr != 0 || !psurge_start) return; /* reset the entry point so if we get another intr we won't diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 31853008b41..bcc3cb48a44 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -2,4 +2,4 @@ obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o obj-y += opal-rtc.o opal-nvram.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o +obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 4a3f46d8533..3bb07e5e43c 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -99,3 +99,11 @@ OPAL_CALL(opal_write_oppanel, OPAL_WRITE_OPPANEL); OPAL_CALL(opal_pci_map_pe_dma_window, OPAL_PCI_MAP_PE_DMA_WINDOW); OPAL_CALL(opal_pci_map_pe_dma_window_real, OPAL_PCI_MAP_PE_DMA_WINDOW_REAL); OPAL_CALL(opal_pci_reset, OPAL_PCI_RESET); +OPAL_CALL(opal_pci_get_hub_diag_data, OPAL_PCI_GET_HUB_DIAG_DATA); +OPAL_CALL(opal_pci_get_phb_diag_data, OPAL_PCI_GET_PHB_DIAG_DATA); +OPAL_CALL(opal_pci_fence_phb, OPAL_PCI_FENCE_PHB); +OPAL_CALL(opal_pci_reinit, OPAL_PCI_REINIT); +OPAL_CALL(opal_pci_mask_pe_error, OPAL_PCI_MASK_PE_ERROR); +OPAL_CALL(opal_set_slot_led_status, OPAL_SET_SLOT_LED_STATUS); +OPAL_CALL(opal_get_epow_status, OPAL_GET_EPOW_STATUS); +OPAL_CALL(opal_set_system_attention_led, OPAL_SET_SYSTEM_ATTENTION_LED); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c new file mode 100644 index 00000000000..f31162cfdaa --- /dev/null +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -0,0 +1,1330 @@ +/* + * Support PCI/PCIe on PowerNV platforms + * + * Copyright 2011 Benjamin Herrenschmidt, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/msi.h> + +#include <asm/sections.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <asm/machdep.h> +#include <asm/ppc-pci.h> +#include <asm/opal.h> +#include <asm/iommu.h> +#include <asm/tce.h> +#include <asm/abs_addr.h> + +#include "powernv.h" +#include "pci.h" + +struct resource_wrap { + struct list_head link; + resource_size_t size; + resource_size_t align; + struct pci_dev *dev; /* Set if it's a device */ + struct pci_bus *bus; /* Set if it's a bridge */ +}; + +static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe, + struct va_format *vaf) +{ + char pfix[32]; + + if (pe->pdev) + strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix)); + else + sprintf(pfix, "%04x:%02x ", + pci_domain_nr(pe->pbus), pe->pbus->number); + return printk("pci %s%s: [PE# %.3d] %pV", level, pfix, pe->pe_number, vaf); +} + +#define define_pe_printk_level(func, kern_level) \ +static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \ +{ \ + struct va_format vaf; \ + va_list args; \ + int r; \ + \ + va_start(args, fmt); \ + \ + vaf.fmt = fmt; \ + vaf.va = &args; \ + \ + r = __pe_printk(kern_level, pe, &vaf); \ + va_end(args); \ + \ + return r; \ +} \ + +define_pe_printk_level(pe_err, KERN_ERR); +define_pe_printk_level(pe_warn, KERN_WARNING); +define_pe_printk_level(pe_info, KERN_INFO); + + +/* Calculate resource usage & alignment requirement of a single + * device. This will also assign all resources within the device + * for a given type starting at 0 for the biggest one and then + * assigning in decreasing order of size. + */ +static void __devinit pnv_ioda_calc_dev(struct pci_dev *dev, unsigned int flags, + resource_size_t *size, + resource_size_t *align) +{ + resource_size_t start; + struct resource *r; + int i; + + pr_devel(" -> CDR %s\n", pci_name(dev)); + + *size = *align = 0; + + /* Clear the resources out and mark them all unset */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + r = &dev->resource[i]; + if (!(r->flags & flags)) + continue; + if (r->start) { + r->end -= r->start; + r->start = 0; + } + r->flags |= IORESOURCE_UNSET; + } + + /* We currently keep all memory resources together, we + * will handle prefetch & 64-bit separately in the future + * but for now we stick everybody in M32 + */ + start = 0; + for (;;) { + resource_size_t max_size = 0; + int max_no = -1; + + /* Find next biggest resource */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + r = &dev->resource[i]; + if (!(r->flags & IORESOURCE_UNSET) || + !(r->flags & flags)) + continue; + if (resource_size(r) > max_size) { + max_size = resource_size(r); + max_no = i; + } + } + if (max_no < 0) + break; + r = &dev->resource[max_no]; + if (max_size > *align) + *align = max_size; + *size += max_size; + r->start = start; + start += max_size; + r->end = r->start + max_size - 1; + r->flags &= ~IORESOURCE_UNSET; + pr_devel(" -> R%d %016llx..%016llx\n", + max_no, r->start, r->end); + } + pr_devel(" <- CDR %s size=%llx align=%llx\n", + pci_name(dev), *size, *align); +} + +/* Allocate a resource "wrap" for a given device or bridge and + * insert it at the right position in the sorted list + */ +static void __devinit pnv_ioda_add_wrap(struct list_head *list, + struct pci_bus *bus, + struct pci_dev *dev, + resource_size_t size, + resource_size_t align) +{ + struct resource_wrap *w1, *w = kzalloc(sizeof(*w), GFP_KERNEL); + + w->size = size; + w->align = align; + w->dev = dev; + w->bus = bus; + + list_for_each_entry(w1, list, link) { + if (w1->align < align) { + list_add_tail(&w->link, &w1->link); + return; + } + } + list_add_tail(&w->link, list); +} + +/* Offset device resources of a given type */ +static void __devinit pnv_ioda_offset_dev(struct pci_dev *dev, + unsigned int flags, + resource_size_t offset) +{ + struct resource *r; + int i; + + pr_devel(" -> ODR %s [%x] +%016llx\n", pci_name(dev), flags, offset); + + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + r = &dev->resource[i]; + if (r->flags & flags) { + dev->resource[i].start += offset; + dev->resource[i].end += offset; + } + } + + pr_devel(" <- ODR %s [%x] +%016llx\n", pci_name(dev), flags, offset); +} + +/* Offset bus resources (& all children) of a given type */ +static void __devinit pnv_ioda_offset_bus(struct pci_bus *bus, + unsigned int flags, + resource_size_t offset) +{ + struct resource *r; + struct pci_dev *dev; + struct pci_bus *cbus; + int i; + + pr_devel(" -> OBR %s [%x] +%016llx\n", + bus->self ? pci_name(bus->self) : "root", flags, offset); + + for (i = 0; i < 2; i++) { + r = bus->resource[i]; + if (r && (r->flags & flags)) { + bus->resource[i]->start += offset; + bus->resource[i]->end += offset; + } + } + list_for_each_entry(dev, &bus->devices, bus_list) + pnv_ioda_offset_dev(dev, flags, offset); + list_for_each_entry(cbus, &bus->children, node) + pnv_ioda_offset_bus(cbus, flags, offset); + + pr_devel(" <- OBR %s [%x]\n", + bus->self ? pci_name(bus->self) : "root", flags); +} + +/* This is the guts of our IODA resource allocation. This is called + * recursively for each bus in the system. It calculates all the + * necessary size and requirements for children and assign them + * resources such that: + * + * - Each function fits in it's own contiguous set of IO/M32 + * segment + * + * - All segments behind a P2P bridge are contiguous and obey + * alignment constraints of those bridges + */ +static void __devinit pnv_ioda_calc_bus(struct pci_bus *bus, unsigned int flags, + resource_size_t *size, + resource_size_t *align) +{ + struct pci_controller *hose = pci_bus_to_host(bus); + struct pnv_phb *phb = hose->private_data; + resource_size_t dev_size, dev_align, start; + resource_size_t min_align, min_balign; + struct pci_dev *cdev; + struct pci_bus *cbus; + struct list_head head; + struct resource_wrap *w; + unsigned int bres; + + *size = *align = 0; + + pr_devel("-> CBR %s [%x]\n", + bus->self ? pci_name(bus->self) : "root", flags); + + /* Calculate alignment requirements based on the type + * of resource we are working on + */ + if (flags & IORESOURCE_IO) { + bres = 0; + min_align = phb->ioda.io_segsize; + min_balign = 0x1000; + } else { + bres = 1; + min_align = phb->ioda.m32_segsize; + min_balign = 0x100000; + } + + /* Gather all our children resources ordered by alignment */ + INIT_LIST_HEAD(&head); + + /* - Busses */ + list_for_each_entry(cbus, &bus->children, node) { + pnv_ioda_calc_bus(cbus, flags, &dev_size, &dev_align); + pnv_ioda_add_wrap(&head, cbus, NULL, dev_size, dev_align); + } + + /* - Devices */ + list_for_each_entry(cdev, &bus->devices, bus_list) { + pnv_ioda_calc_dev(cdev, flags, &dev_size, &dev_align); + /* Align them to segment size */ + if (dev_align < min_align) + dev_align = min_align; + pnv_ioda_add_wrap(&head, NULL, cdev, dev_size, dev_align); + } + if (list_empty(&head)) + goto empty; + + /* Now we can do two things: assign offsets to them within that + * level and get our total alignment & size requirements. The + * assignment algorithm is going to be uber-trivial for now, we + * can try to be smarter later at filling out holes. + */ + start = bus->self ? 0 : bus->resource[bres]->start; + + /* Don't hand out IO 0 */ + if ((flags & IORESOURCE_IO) && !bus->self) + start += 0x1000; + + while(!list_empty(&head)) { + w = list_first_entry(&head, struct resource_wrap, link); + list_del(&w->link); + if (w->size) { + if (start) { + start = ALIGN(start, w->align); + if (w->dev) + pnv_ioda_offset_dev(w->dev,flags,start); + else if (w->bus) + pnv_ioda_offset_bus(w->bus,flags,start); + } + if (w->align > *align) + *align = w->align; + } + start += w->size; + kfree(w); + } + *size = start; + + /* Align and setup bridge resources */ + *align = max_t(resource_size_t, *align, + max_t(resource_size_t, min_align, min_balign)); + *size = ALIGN(*size, + max_t(resource_size_t, min_align, min_balign)); + empty: + /* Only setup P2P's, not the PHB itself */ + if (bus->self) { + WARN_ON(bus->resource[bres] == NULL); + bus->resource[bres]->start = 0; + bus->resource[bres]->flags = (*size) ? flags : 0; + bus->resource[bres]->end = (*size) ? (*size - 1) : 0; + + /* Clear prefetch bus resources for now */ + bus->resource[2]->flags = 0; + } + + pr_devel("<- CBR %s [%x] *size=%016llx *align=%016llx\n", + bus->self ? pci_name(bus->self) : "root", flags,*size,*align); +} + +static struct pci_dn *pnv_ioda_get_pdn(struct pci_dev *dev) +{ + struct device_node *np; + + np = pci_device_to_OF_node(dev); + if (!np) + return NULL; + return PCI_DN(np); +} + +static void __devinit pnv_ioda_setup_pe_segments(struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + unsigned int pe, i; + resource_size_t pos; + struct resource io_res; + struct resource m32_res; + struct pci_bus_region region; + int rc; + + /* Anything not referenced in the device-tree gets PE#0 */ + pe = pdn ? pdn->pe_number : 0; + + /* Calculate the device min/max */ + io_res.start = m32_res.start = (resource_size_t)-1; + io_res.end = m32_res.end = 0; + io_res.flags = IORESOURCE_IO; + m32_res.flags = IORESOURCE_MEM; + + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *r = NULL; + if (dev->resource[i].flags & IORESOURCE_IO) + r = &io_res; + if (dev->resource[i].flags & IORESOURCE_MEM) + r = &m32_res; + if (!r) + continue; + if (dev->resource[i].start < r->start) + r->start = dev->resource[i].start; + if (dev->resource[i].end > r->end) + r->end = dev->resource[i].end; + } + + /* Setup IO segments */ + if (io_res.start < io_res.end) { + pcibios_resource_to_bus(dev, ®ion, &io_res); + pos = region.start; + i = pos / phb->ioda.io_segsize; + while(i < phb->ioda.total_pe && pos <= region.end) { + if (phb->ioda.io_segmap[i]) { + pr_err("%s: Trying to use IO seg #%d which is" + " already used by PE# %d\n", + pci_name(dev), i, + phb->ioda.io_segmap[i]); + /* XXX DO SOMETHING TO DISABLE DEVICE ? */ + break; + } + phb->ioda.io_segmap[i] = pe; + rc = opal_pci_map_pe_mmio_window(phb->opal_id, pe, + OPAL_IO_WINDOW_TYPE, + 0, i); + if (rc != OPAL_SUCCESS) { + pr_err("%s: OPAL error %d setting up mapping" + " for IO seg# %d\n", + pci_name(dev), rc, i); + /* XXX DO SOMETHING TO DISABLE DEVICE ? */ + break; + } + pos += phb->ioda.io_segsize; + i++; + }; + } + + /* Setup M32 segments */ + if (m32_res.start < m32_res.end) { + pcibios_resource_to_bus(dev, ®ion, &m32_res); + pos = region.start; + i = pos / phb->ioda.m32_segsize; + while(i < phb->ioda.total_pe && pos <= region.end) { + if (phb->ioda.m32_segmap[i]) { + pr_err("%s: Trying to use M32 seg #%d which is" + " already used by PE# %d\n", + pci_name(dev), i, + phb->ioda.m32_segmap[i]); + /* XXX DO SOMETHING TO DISABLE DEVICE ? */ + break; + } + phb->ioda.m32_segmap[i] = pe; + rc = opal_pci_map_pe_mmio_window(phb->opal_id, pe, + OPAL_M32_WINDOW_TYPE, + 0, i); + if (rc != OPAL_SUCCESS) { + pr_err("%s: OPAL error %d setting up mapping" + " for M32 seg# %d\n", + pci_name(dev), rc, i); + /* XXX DO SOMETHING TO DISABLE DEVICE ? */ + break; + } + pos += phb->ioda.m32_segsize; + i++; + } + } +} + +/* Check if a resource still fits in the total IO or M32 range + * for a given PHB + */ +static int __devinit pnv_ioda_resource_fit(struct pci_controller *hose, + struct resource *r) +{ + struct resource *bounds; + + if (r->flags & IORESOURCE_IO) + bounds = &hose->io_resource; + else if (r->flags & IORESOURCE_MEM) + bounds = &hose->mem_resources[0]; + else + return 1; + + if (r->start >= bounds->start && r->end <= bounds->end) + return 1; + r->flags = 0; + return 0; +} + +static void __devinit pnv_ioda_update_resources(struct pci_bus *bus) +{ + struct pci_controller *hose = pci_bus_to_host(bus); + struct pci_bus *cbus; + struct pci_dev *cdev; + unsigned int i; + + /* We used to clear all device enables here. However it looks like + * clearing MEM enable causes Obsidian (IPR SCS) to go bonkers, + * and shoot fatal errors to the PHB which in turns fences itself + * and we can't recover from that ... yet. So for now, let's leave + * the enables as-is and hope for the best. + */ + + /* Check if bus resources fit in our IO or M32 range */ + for (i = 0; bus->self && (i < 2); i++) { + struct resource *r = bus->resource[i]; + if (r && !pnv_ioda_resource_fit(hose, r)) + pr_err("%s: Bus %d resource %d disabled, no room\n", + pci_name(bus->self), bus->number, i); + } + + /* Update self if it's not a PHB */ + if (bus->self) + pci_setup_bridge(bus); + + /* Update child devices */ + list_for_each_entry(cdev, &bus->devices, bus_list) { + /* Check if resource fits, if not, disabled it */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *r = &cdev->resource[i]; + if (!pnv_ioda_resource_fit(hose, r)) + pr_err("%s: Resource %d disabled, no room\n", + pci_name(cdev), i); + } + + /* Assign segments */ + pnv_ioda_setup_pe_segments(cdev); + + /* Update HW BARs */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + pci_update_resource(cdev, i); + } + + /* Update child busses */ + list_for_each_entry(cbus, &bus->children, node) + pnv_ioda_update_resources(cbus); +} + +static int __devinit pnv_ioda_alloc_pe(struct pnv_phb *phb) +{ + unsigned long pe; + + do { + pe = find_next_zero_bit(phb->ioda.pe_alloc, + phb->ioda.total_pe, 0); + if (pe >= phb->ioda.total_pe) + return IODA_INVALID_PE; + } while(test_and_set_bit(pe, phb->ioda.pe_alloc)); + + phb->ioda.pe_array[pe].pe_number = pe; + return pe; +} + +static void __devinit pnv_ioda_free_pe(struct pnv_phb *phb, int pe) +{ + WARN_ON(phb->ioda.pe_array[pe].pdev); + + memset(&phb->ioda.pe_array[pe], 0, sizeof(struct pnv_ioda_pe)); + clear_bit(pe, phb->ioda.pe_alloc); +} + +/* Currently those 2 are only used when MSIs are enabled, this will change + * but in the meantime, we need to protect them to avoid warnings + */ +#ifdef CONFIG_PCI_MSI +static struct pnv_ioda_pe * __devinit __pnv_ioda_get_one_pe(struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + + if (!pdn) + return NULL; + if (pdn->pe_number == IODA_INVALID_PE) + return NULL; + return &phb->ioda.pe_array[pdn->pe_number]; +} + +static struct pnv_ioda_pe * __devinit pnv_ioda_get_pe(struct pci_dev *dev) +{ + struct pnv_ioda_pe *pe = __pnv_ioda_get_one_pe(dev); + + while (!pe && dev->bus->self) { + dev = dev->bus->self; + pe = __pnv_ioda_get_one_pe(dev); + if (pe) + pe = pe->bus_pe; + } + return pe; +} +#endif /* CONFIG_PCI_MSI */ + +static int __devinit pnv_ioda_configure_pe(struct pnv_phb *phb, + struct pnv_ioda_pe *pe) +{ + struct pci_dev *parent; + uint8_t bcomp, dcomp, fcomp; + long rc, rid_end, rid; + + /* Bus validation ? */ + if (pe->pbus) { + int count; + + dcomp = OPAL_IGNORE_RID_DEVICE_NUMBER; + fcomp = OPAL_IGNORE_RID_FUNCTION_NUMBER; + parent = pe->pbus->self; + count = pe->pbus->subordinate - pe->pbus->secondary + 1; + switch(count) { + case 1: bcomp = OpalPciBusAll; break; + case 2: bcomp = OpalPciBus7Bits; break; + case 4: bcomp = OpalPciBus6Bits; break; + case 8: bcomp = OpalPciBus5Bits; break; + case 16: bcomp = OpalPciBus4Bits; break; + case 32: bcomp = OpalPciBus3Bits; break; + default: + pr_err("%s: Number of subordinate busses %d" + " unsupported\n", + pci_name(pe->pbus->self), count); + /* Do an exact match only */ + bcomp = OpalPciBusAll; + } + rid_end = pe->rid + (count << 8); + } else { + parent = pe->pdev->bus->self; + bcomp = OpalPciBusAll; + dcomp = OPAL_COMPARE_RID_DEVICE_NUMBER; + fcomp = OPAL_COMPARE_RID_FUNCTION_NUMBER; + rid_end = pe->rid + 1; + } + + /* Associate PE in PELT */ + rc = opal_pci_set_pe(phb->opal_id, pe->pe_number, pe->rid, + bcomp, dcomp, fcomp, OPAL_MAP_PE); + if (rc) { + pe_err(pe, "OPAL error %ld trying to setup PELT table\n", rc); + return -ENXIO; + } + opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number, + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); + + /* Add to all parents PELT-V */ + while (parent) { + struct pci_dn *pdn = pnv_ioda_get_pdn(parent); + if (pdn && pdn->pe_number != IODA_INVALID_PE) { + rc = opal_pci_set_peltv(phb->opal_id, pdn->pe_number, + pe->pe_number, OPAL_ADD_PE_TO_DOMAIN); + /* XXX What to do in case of error ? */ + } + parent = parent->bus->self; + } + /* Setup reverse map */ + for (rid = pe->rid; rid < rid_end; rid++) + phb->ioda.pe_rmap[rid] = pe->pe_number; + + /* Setup one MVTs on IODA1 */ + if (phb->type == PNV_PHB_IODA1) { + pe->mve_number = pe->pe_number; + rc = opal_pci_set_mve(phb->opal_id, pe->mve_number, + pe->pe_number); + if (rc) { + pe_err(pe, "OPAL error %ld setting up MVE %d\n", + rc, pe->mve_number); + pe->mve_number = -1; + } else { + rc = opal_pci_set_mve_enable(phb->opal_id, + pe->mve_number, OPAL_ENABLE_MVE); + if (rc) { + pe_err(pe, "OPAL error %ld enabling MVE %d\n", + rc, pe->mve_number); + pe->mve_number = -1; + } + } + } else if (phb->type == PNV_PHB_IODA2) + pe->mve_number = 0; + + return 0; +} + +static void __devinit pnv_ioda_link_pe_by_weight(struct pnv_phb *phb, + struct pnv_ioda_pe *pe) +{ + struct pnv_ioda_pe *lpe; + + list_for_each_entry(lpe, &phb->ioda.pe_list, link) { + if (lpe->dma_weight < pe->dma_weight) { + list_add_tail(&pe->link, &lpe->link); + return; + } + } + list_add_tail(&pe->link, &phb->ioda.pe_list); +} + +static unsigned int pnv_ioda_dma_weight(struct pci_dev *dev) +{ + /* This is quite simplistic. The "base" weight of a device + * is 10. 0 means no DMA is to be accounted for it. + */ + + /* If it's a bridge, no DMA */ + if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL) + return 0; + + /* Reduce the weight of slow USB controllers */ + if (dev->class == PCI_CLASS_SERIAL_USB_UHCI || + dev->class == PCI_CLASS_SERIAL_USB_OHCI || + dev->class == PCI_CLASS_SERIAL_USB_EHCI) + return 3; + + /* Increase the weight of RAID (includes Obsidian) */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID) + return 15; + + /* Default */ + return 10; +} + +static struct pnv_ioda_pe * __devinit pnv_ioda_setup_dev_PE(struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + struct pnv_ioda_pe *pe; + int pe_num; + + if (!pdn) { + pr_err("%s: Device tree node not associated properly\n", + pci_name(dev)); + return NULL; + } + if (pdn->pe_number != IODA_INVALID_PE) + return NULL; + + /* PE#0 has been pre-set */ + if (dev->bus->number == 0) + pe_num = 0; + else + pe_num = pnv_ioda_alloc_pe(phb); + if (pe_num == IODA_INVALID_PE) { + pr_warning("%s: Not enough PE# available, disabling device\n", + pci_name(dev)); + return NULL; + } + + /* NOTE: We get only one ref to the pci_dev for the pdn, not for the + * pointer in the PE data structure, both should be destroyed at the + * same time. However, this needs to be looked at more closely again + * once we actually start removing things (Hotplug, SR-IOV, ...) + * + * At some point we want to remove the PDN completely anyways + */ + pe = &phb->ioda.pe_array[pe_num]; + pci_dev_get(dev); + pdn->pcidev = dev; + pdn->pe_number = pe_num; + pe->pdev = dev; + pe->pbus = NULL; + pe->tce32_seg = -1; + pe->mve_number = -1; + pe->rid = dev->bus->number << 8 | pdn->devfn; + + pe_info(pe, "Associated device to PE\n"); + + if (pnv_ioda_configure_pe(phb, pe)) { + /* XXX What do we do here ? */ + if (pe_num) + pnv_ioda_free_pe(phb, pe_num); + pdn->pe_number = IODA_INVALID_PE; + pe->pdev = NULL; + pci_dev_put(dev); + return NULL; + } + + /* Assign a DMA weight to the device */ + pe->dma_weight = pnv_ioda_dma_weight(dev); + if (pe->dma_weight != 0) { + phb->ioda.dma_weight += pe->dma_weight; + phb->ioda.dma_pe_count++; + } + + /* Link the PE */ + pnv_ioda_link_pe_by_weight(phb, pe); + + return pe; +} + +static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + + if (pdn == NULL) { + pr_warn("%s: No device node associated with device !\n", + pci_name(dev)); + continue; + } + pci_dev_get(dev); + pdn->pcidev = dev; + pdn->pe_number = pe->pe_number; + pe->dma_weight += pnv_ioda_dma_weight(dev); + if (dev->subordinate) + pnv_ioda_setup_same_PE(dev->subordinate, pe); + } +} + +static void __devinit pnv_ioda_setup_bus_PE(struct pci_dev *dev, + struct pnv_ioda_pe *ppe) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + struct pci_bus *bus = dev->subordinate; + struct pnv_ioda_pe *pe; + int pe_num; + + if (!bus) { + pr_warning("%s: Bridge without a subordinate bus !\n", + pci_name(dev)); + return; + } + pe_num = pnv_ioda_alloc_pe(phb); + if (pe_num == IODA_INVALID_PE) { + pr_warning("%s: Not enough PE# available, disabling bus\n", + pci_name(dev)); + return; + } + + pe = &phb->ioda.pe_array[pe_num]; + ppe->bus_pe = pe; + pe->pbus = bus; + pe->pdev = NULL; + pe->tce32_seg = -1; + pe->mve_number = -1; + pe->rid = bus->secondary << 8; + pe->dma_weight = 0; + + pe_info(pe, "Secondary busses %d..%d associated with PE\n", + bus->secondary, bus->subordinate); + + if (pnv_ioda_configure_pe(phb, pe)) { + /* XXX What do we do here ? */ + if (pe_num) + pnv_ioda_free_pe(phb, pe_num); + pe->pbus = NULL; + return; + } + + /* Associate it with all child devices */ + pnv_ioda_setup_same_PE(bus, pe); + + /* Account for one DMA PE if at least one DMA capable device exist + * below the bridge + */ + if (pe->dma_weight != 0) { + phb->ioda.dma_weight += pe->dma_weight; + phb->ioda.dma_pe_count++; + } + + /* Link the PE */ + pnv_ioda_link_pe_by_weight(phb, pe); +} + +static void __devinit pnv_ioda_setup_PEs(struct pci_bus *bus) +{ + struct pci_dev *dev; + struct pnv_ioda_pe *pe; + + list_for_each_entry(dev, &bus->devices, bus_list) { + pe = pnv_ioda_setup_dev_PE(dev); + if (pe == NULL) + continue; + /* Leaving the PCIe domain ... single PE# */ + if (dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + pnv_ioda_setup_bus_PE(dev, pe); + else if (dev->subordinate) + pnv_ioda_setup_PEs(dev->subordinate); + } +} + +static void __devinit pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, + struct pci_dev *dev) +{ + /* We delay DMA setup after we have assigned all PE# */ +} + +static void __devinit pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, + struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + set_iommu_table_base(&dev->dev, &pe->tce32_table); + if (dev->subordinate) + pnv_ioda_setup_bus_dma(pe, dev->subordinate); + } +} + +static void __devinit pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, + struct pnv_ioda_pe *pe, + unsigned int base, + unsigned int segs) +{ + + struct page *tce_mem = NULL; + const __be64 *swinvp; + struct iommu_table *tbl; + unsigned int i; + int64_t rc; + void *addr; + + /* 256M DMA window, 4K TCE pages, 8 bytes TCE */ +#define TCE32_TABLE_SIZE ((0x10000000 / 0x1000) * 8) + + /* XXX FIXME: Handle 64-bit only DMA devices */ + /* XXX FIXME: Provide 64-bit DMA facilities & non-4K TCE tables etc.. */ + /* XXX FIXME: Allocate multi-level tables on PHB3 */ + + /* We shouldn't already have a 32-bit DMA associated */ + if (WARN_ON(pe->tce32_seg >= 0)) + return; + + /* Grab a 32-bit TCE table */ + pe->tce32_seg = base; + pe_info(pe, " Setting up 32-bit TCE table at %08x..%08x\n", + (base << 28), ((base + segs) << 28) - 1); + + /* XXX Currently, we allocate one big contiguous table for the + * TCEs. We only really need one chunk per 256M of TCE space + * (ie per segment) but that's an optimization for later, it + * requires some added smarts with our get/put_tce implementation + */ + tce_mem = alloc_pages_node(phb->hose->node, GFP_KERNEL, + get_order(TCE32_TABLE_SIZE * segs)); + if (!tce_mem) { + pe_err(pe, " Failed to allocate a 32-bit TCE memory\n"); + goto fail; + } + addr = page_address(tce_mem); + memset(addr, 0, TCE32_TABLE_SIZE * segs); + + /* Configure HW */ + for (i = 0; i < segs; i++) { + rc = opal_pci_map_pe_dma_window(phb->opal_id, + pe->pe_number, + base + i, 1, + __pa(addr) + TCE32_TABLE_SIZE * i, + TCE32_TABLE_SIZE, 0x1000); + if (rc) { + pe_err(pe, " Failed to configure 32-bit TCE table," + " err %ld\n", rc); + goto fail; + } + } + + /* Setup linux iommu table */ + tbl = &pe->tce32_table; + pnv_pci_setup_iommu_table(tbl, addr, TCE32_TABLE_SIZE * segs, + base << 28); + + /* OPAL variant of P7IOC SW invalidated TCEs */ + swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL); + if (swinvp) { + /* We need a couple more fields -- an address and a data + * to or. Since the bus is only printed out on table free + * errors, and on the first pass the data will be a relative + * bus number, print that out instead. + */ + tbl->it_busno = 0; + tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); + tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE + | TCE_PCI_SWINV_PAIR; + } + iommu_init_table(tbl, phb->hose->node); + + if (pe->pdev) + set_iommu_table_base(&pe->pdev->dev, tbl); + else + pnv_ioda_setup_bus_dma(pe, pe->pbus); + + return; + fail: + /* XXX Failure: Try to fallback to 64-bit only ? */ + if (pe->tce32_seg >= 0) + pe->tce32_seg = -1; + if (tce_mem) + __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs)); +} + +static void __devinit pnv_ioda_setup_dma(struct pnv_phb *phb) +{ + struct pci_controller *hose = phb->hose; + unsigned int residual, remaining, segs, tw, base; + struct pnv_ioda_pe *pe; + + /* If we have more PE# than segments available, hand out one + * per PE until we run out and let the rest fail. If not, + * then we assign at least one segment per PE, plus more based + * on the amount of devices under that PE + */ + if (phb->ioda.dma_pe_count > phb->ioda.tce32_count) + residual = 0; + else + residual = phb->ioda.tce32_count - + phb->ioda.dma_pe_count; + + pr_info("PCI: Domain %04x has %ld available 32-bit DMA segments\n", + hose->global_number, phb->ioda.tce32_count); + pr_info("PCI: %d PE# for a total weight of %d\n", + phb->ioda.dma_pe_count, phb->ioda.dma_weight); + + /* Walk our PE list and configure their DMA segments, hand them + * out one base segment plus any residual segments based on + * weight + */ + remaining = phb->ioda.tce32_count; + tw = phb->ioda.dma_weight; + base = 0; + list_for_each_entry(pe, &phb->ioda.pe_list, link) { + if (!pe->dma_weight) + continue; + if (!remaining) { + pe_warn(pe, "No DMA32 resources available\n"); + continue; + } + segs = 1; + if (residual) { + segs += ((pe->dma_weight * residual) + (tw / 2)) / tw; + if (segs > remaining) + segs = remaining; + } + pe_info(pe, "DMA weight %d, assigned %d DMA32 segments\n", + pe->dma_weight, segs); + pnv_pci_ioda_setup_dma_pe(phb, pe, base, segs); + remaining -= segs; + base += segs; + } +} + +#ifdef CONFIG_PCI_MSI +static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, + unsigned int hwirq, unsigned int is_64, + struct msi_msg *msg) +{ + struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev); + unsigned int xive_num = hwirq - phb->msi_base; + uint64_t addr64; + uint32_t addr32, data; + int rc; + + /* No PE assigned ? bail out ... no MSI for you ! */ + if (pe == NULL) + return -ENXIO; + + /* Check if we have an MVE */ + if (pe->mve_number < 0) + return -ENXIO; + + /* Assign XIVE to PE */ + rc = opal_pci_set_xive_pe(phb->opal_id, pe->pe_number, xive_num); + if (rc) { + pr_warn("%s: OPAL error %d setting XIVE %d PE\n", + pci_name(dev), rc, xive_num); + return -EIO; + } + + if (is_64) { + rc = opal_get_msi_64(phb->opal_id, pe->mve_number, xive_num, 1, + &addr64, &data); + if (rc) { + pr_warn("%s: OPAL error %d getting 64-bit MSI data\n", + pci_name(dev), rc); + return -EIO; + } + msg->address_hi = addr64 >> 32; + msg->address_lo = addr64 & 0xfffffffful; + } else { + rc = opal_get_msi_32(phb->opal_id, pe->mve_number, xive_num, 1, + &addr32, &data); + if (rc) { + pr_warn("%s: OPAL error %d getting 32-bit MSI data\n", + pci_name(dev), rc); + return -EIO; + } + msg->address_hi = 0; + msg->address_lo = addr32; + } + msg->data = data; + + pr_devel("%s: %s-bit MSI on hwirq %x (xive #%d)," + " address=%x_%08x data=%x PE# %d\n", + pci_name(dev), is_64 ? "64" : "32", hwirq, xive_num, + msg->address_hi, msg->address_lo, data, pe->pe_number); + + return 0; +} + +static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) +{ + unsigned int bmap_size; + const __be32 *prop = of_get_property(phb->hose->dn, + "ibm,opal-msi-ranges", NULL); + if (!prop) { + /* BML Fallback */ + prop = of_get_property(phb->hose->dn, "msi-ranges", NULL); + } + if (!prop) + return; + + phb->msi_base = be32_to_cpup(prop); + phb->msi_count = be32_to_cpup(prop + 1); + bmap_size = BITS_TO_LONGS(phb->msi_count) * sizeof(unsigned long); + phb->msi_map = zalloc_maybe_bootmem(bmap_size, GFP_KERNEL); + if (!phb->msi_map) { + pr_err("PCI %d: Failed to allocate MSI bitmap !\n", + phb->hose->global_number); + return; + } + phb->msi_setup = pnv_pci_ioda_msi_setup; + phb->msi32_support = 1; + pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", + phb->msi_count, phb->msi_base); +} +#else +static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { } +#endif /* CONFIG_PCI_MSI */ + +/* This is the starting point of our IODA specific resource + * allocation process + */ +static void __devinit pnv_pci_ioda_fixup_phb(struct pci_controller *hose) +{ + resource_size_t size, align; + struct pci_bus *child; + + /* Associate PEs per functions */ + pnv_ioda_setup_PEs(hose->bus); + + /* Calculate all resources */ + pnv_ioda_calc_bus(hose->bus, IORESOURCE_IO, &size, &align); + pnv_ioda_calc_bus(hose->bus, IORESOURCE_MEM, &size, &align); + + /* Apply then to HW */ + pnv_ioda_update_resources(hose->bus); + + /* Setup DMA */ + pnv_ioda_setup_dma(hose->private_data); + + /* Configure PCI Express settings */ + list_for_each_entry(child, &hose->bus->children, node) { + struct pci_dev *self = child->self; + if (!self) + continue; + pcie_bus_configure_settings(child, self->pcie_mpss); + } +} + +/* Prevent enabling devices for which we couldn't properly + * assign a PE + */ +static int __devinit pnv_pci_enable_device_hook(struct pci_dev *dev) +{ + struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + + if (!pdn || pdn->pe_number == IODA_INVALID_PE) + return -EINVAL; + return 0; +} + +static u32 pnv_ioda_bdfn_to_pe(struct pnv_phb *phb, struct pci_bus *bus, + u32 devfn) +{ + return phb->ioda.pe_rmap[(bus->number << 8) | devfn]; +} + +void __init pnv_pci_init_ioda1_phb(struct device_node *np) +{ + struct pci_controller *hose; + static int primary = 1; + struct pnv_phb *phb; + unsigned long size, m32map_off, iomap_off, pemap_off; + const u64 *prop64; + u64 phb_id; + void *aux; + long rc; + + pr_info(" Initializing IODA OPAL PHB %s\n", np->full_name); + + prop64 = of_get_property(np, "ibm,opal-phbid", NULL); + if (!prop64) { + pr_err(" Missing \"ibm,opal-phbid\" property !\n"); + return; + } + phb_id = be64_to_cpup(prop64); + pr_debug(" PHB-ID : 0x%016llx\n", phb_id); + + phb = alloc_bootmem(sizeof(struct pnv_phb)); + if (phb) { + memset(phb, 0, sizeof(struct pnv_phb)); + phb->hose = hose = pcibios_alloc_controller(np); + } + if (!phb || !phb->hose) { + pr_err("PCI: Failed to allocate PCI controller for %s\n", + np->full_name); + return; + } + + spin_lock_init(&phb->lock); + /* XXX Use device-tree */ + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->private_data = phb; + phb->opal_id = phb_id; + phb->type = PNV_PHB_IODA1; + + /* Detect specific models for error handling */ + if (of_device_is_compatible(np, "ibm,p7ioc-pciex")) + phb->model = PNV_PHB_MODEL_P7IOC; + else + phb->model = PNV_PHB_MODEL_UNKNOWN; + + /* We parse "ranges" now since we need to deduce the register base + * from the IO base + */ + pci_process_bridge_OF_ranges(phb->hose, np, primary); + primary = 0; + + /* Magic formula from Milton */ + phb->regs = of_iomap(np, 0); + if (phb->regs == NULL) + pr_err(" Failed to map registers !\n"); + + + /* XXX This is hack-a-thon. This needs to be changed so that: + * - we obtain stuff like PE# etc... from device-tree + * - we properly re-allocate M32 ourselves + * (the OFW one isn't very good) + */ + + /* Initialize more IODA stuff */ + phb->ioda.total_pe = 128; + + phb->ioda.m32_size = resource_size(&hose->mem_resources[0]); + /* OFW Has already off top 64k of M32 space (MSI space) */ + phb->ioda.m32_size += 0x10000; + + phb->ioda.m32_segsize = phb->ioda.m32_size / phb->ioda.total_pe; + phb->ioda.m32_pci_base = hose->mem_resources[0].start - + hose->pci_mem_offset; + phb->ioda.io_size = hose->pci_io_size; + phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe; + phb->ioda.io_pci_base = 0; /* XXX calculate this ? */ + + /* Allocate aux data & arrays */ + size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long)); + m32map_off = size; + size += phb->ioda.total_pe; + iomap_off = size; + size += phb->ioda.total_pe; + pemap_off = size; + size += phb->ioda.total_pe * sizeof(struct pnv_ioda_pe); + aux = alloc_bootmem(size); + memset(aux, 0, size); + phb->ioda.pe_alloc = aux; + phb->ioda.m32_segmap = aux + m32map_off; + phb->ioda.io_segmap = aux + iomap_off; + phb->ioda.pe_array = aux + pemap_off; + set_bit(0, phb->ioda.pe_alloc); + + INIT_LIST_HEAD(&phb->ioda.pe_list); + + /* Calculate how many 32-bit TCE segments we have */ + phb->ioda.tce32_count = phb->ioda.m32_pci_base >> 28; + + /* Clear unusable m64 */ + hose->mem_resources[1].flags = 0; + hose->mem_resources[1].start = 0; + hose->mem_resources[1].end = 0; + hose->mem_resources[2].flags = 0; + hose->mem_resources[2].start = 0; + hose->mem_resources[2].end = 0; + +#if 0 + rc = opal_pci_set_phb_mem_window(opal->phb_id, + window_type, + window_num, + starting_real_address, + starting_pci_address, + segment_size); +#endif + + pr_info(" %d PE's M32: 0x%x [segment=0x%x] IO: 0x%x [segment=0x%x]\n", + phb->ioda.total_pe, + phb->ioda.m32_size, phb->ioda.m32_segsize, + phb->ioda.io_size, phb->ioda.io_segsize); + + if (phb->regs) { + pr_devel(" BUID = 0x%016llx\n", in_be64(phb->regs + 0x100)); + pr_devel(" PHB2_CR = 0x%016llx\n", in_be64(phb->regs + 0x160)); + pr_devel(" IO_BAR = 0x%016llx\n", in_be64(phb->regs + 0x170)); + pr_devel(" IO_BAMR = 0x%016llx\n", in_be64(phb->regs + 0x178)); + pr_devel(" IO_SAR = 0x%016llx\n", in_be64(phb->regs + 0x180)); + pr_devel(" M32_BAR = 0x%016llx\n", in_be64(phb->regs + 0x190)); + pr_devel(" M32_BAMR = 0x%016llx\n", in_be64(phb->regs + 0x198)); + pr_devel(" M32_SAR = 0x%016llx\n", in_be64(phb->regs + 0x1a0)); + } + phb->hose->ops = &pnv_pci_ops; + + /* Setup RID -> PE mapping function */ + phb->bdfn_to_pe = pnv_ioda_bdfn_to_pe; + + /* Setup TCEs */ + phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup; + + /* Setup MSI support */ + pnv_pci_init_ioda_msis(phb); + + /* We set both probe_only and PCI_REASSIGN_ALL_RSRC. This is an + * odd combination which essentially means that we skip all resource + * fixups and assignments in the generic code, and do it all + * ourselves here + */ + pci_probe_only = 1; + ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb; + ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook; + pci_add_flags(PCI_REASSIGN_ALL_RSRC); + + /* Reset IODA tables to a clean state */ + rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET); + if (rc) + pr_warning(" OPAL Error %ld performing IODA table reset !\n", rc); + opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE); +} + +void __init pnv_pci_init_ioda_hub(struct device_node *np) +{ + struct device_node *phbn; + const u64 *prop64; + u64 hub_id; + + pr_info("Probing IODA IO-Hub %s\n", np->full_name); + + prop64 = of_get_property(np, "ibm,opal-hubid", NULL); + if (!prop64) { + pr_err(" Missing \"ibm,opal-hubid\" property !\n"); + return; + } + hub_id = be64_to_cpup(prop64); + pr_devel(" HUB-ID : 0x%016llx\n", hub_id); + + /* Count child PHBs */ + for_each_child_of_node(np, phbn) { + /* Look for IODA1 PHBs */ + if (of_device_is_compatible(phbn, "ibm,ioda-phb")) + pnv_pci_init_ioda1_phb(phbn); + } +} diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c index 4c80f7c77d5..264967770c3 100644 --- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c @@ -137,6 +137,7 @@ static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, phb->hose->private_data = phb; phb->opal_id = phb_id; phb->type = PNV_PHB_P5IOC2; + phb->model = PNV_PHB_MODEL_P5IOC2; phb->regs = of_iomap(np, 0); diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 85bb66d7f93..a70bc1e385e 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -144,6 +144,112 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev) } #endif /* CONFIG_PCI_MSI */ +static void pnv_pci_dump_p7ioc_diag_data(struct pnv_phb *phb) +{ + struct OpalIoP7IOCPhbErrorData *data = &phb->diag.p7ioc; + int i; + + pr_info("PHB %d diagnostic data:\n", phb->hose->global_number); + + pr_info(" brdgCtl = 0x%08x\n", data->brdgCtl); + + pr_info(" portStatusReg = 0x%08x\n", data->portStatusReg); + pr_info(" rootCmplxStatus = 0x%08x\n", data->rootCmplxStatus); + pr_info(" busAgentStatus = 0x%08x\n", data->busAgentStatus); + + pr_info(" deviceStatus = 0x%08x\n", data->deviceStatus); + pr_info(" slotStatus = 0x%08x\n", data->slotStatus); + pr_info(" linkStatus = 0x%08x\n", data->linkStatus); + pr_info(" devCmdStatus = 0x%08x\n", data->devCmdStatus); + pr_info(" devSecStatus = 0x%08x\n", data->devSecStatus); + + pr_info(" rootErrorStatus = 0x%08x\n", data->rootErrorStatus); + pr_info(" uncorrErrorStatus = 0x%08x\n", data->uncorrErrorStatus); + pr_info(" corrErrorStatus = 0x%08x\n", data->corrErrorStatus); + pr_info(" tlpHdr1 = 0x%08x\n", data->tlpHdr1); + pr_info(" tlpHdr2 = 0x%08x\n", data->tlpHdr2); + pr_info(" tlpHdr3 = 0x%08x\n", data->tlpHdr3); + pr_info(" tlpHdr4 = 0x%08x\n", data->tlpHdr4); + pr_info(" sourceId = 0x%08x\n", data->sourceId); + + pr_info(" errorClass = 0x%016llx\n", data->errorClass); + pr_info(" correlator = 0x%016llx\n", data->correlator); + + pr_info(" p7iocPlssr = 0x%016llx\n", data->p7iocPlssr); + pr_info(" p7iocCsr = 0x%016llx\n", data->p7iocCsr); + pr_info(" lemFir = 0x%016llx\n", data->lemFir); + pr_info(" lemErrorMask = 0x%016llx\n", data->lemErrorMask); + pr_info(" lemWOF = 0x%016llx\n", data->lemWOF); + pr_info(" phbErrorStatus = 0x%016llx\n", data->phbErrorStatus); + pr_info(" phbFirstErrorStatus = 0x%016llx\n", data->phbFirstErrorStatus); + pr_info(" phbErrorLog0 = 0x%016llx\n", data->phbErrorLog0); + pr_info(" phbErrorLog1 = 0x%016llx\n", data->phbErrorLog1); + pr_info(" mmioErrorStatus = 0x%016llx\n", data->mmioErrorStatus); + pr_info(" mmioFirstErrorStatus = 0x%016llx\n", data->mmioFirstErrorStatus); + pr_info(" mmioErrorLog0 = 0x%016llx\n", data->mmioErrorLog0); + pr_info(" mmioErrorLog1 = 0x%016llx\n", data->mmioErrorLog1); + pr_info(" dma0ErrorStatus = 0x%016llx\n", data->dma0ErrorStatus); + pr_info(" dma0FirstErrorStatus = 0x%016llx\n", data->dma0FirstErrorStatus); + pr_info(" dma0ErrorLog0 = 0x%016llx\n", data->dma0ErrorLog0); + pr_info(" dma0ErrorLog1 = 0x%016llx\n", data->dma0ErrorLog1); + pr_info(" dma1ErrorStatus = 0x%016llx\n", data->dma1ErrorStatus); + pr_info(" dma1FirstErrorStatus = 0x%016llx\n", data->dma1FirstErrorStatus); + pr_info(" dma1ErrorLog0 = 0x%016llx\n", data->dma1ErrorLog0); + pr_info(" dma1ErrorLog1 = 0x%016llx\n", data->dma1ErrorLog1); + + for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { + if ((data->pestA[i] >> 63) == 0 && + (data->pestB[i] >> 63) == 0) + continue; + pr_info(" PE[%3d] PESTA = 0x%016llx\n", i, data->pestA[i]); + pr_info(" PESTB = 0x%016llx\n", data->pestB[i]); + } +} + +static void pnv_pci_dump_phb_diag_data(struct pnv_phb *phb) +{ + switch(phb->model) { + case PNV_PHB_MODEL_P7IOC: + pnv_pci_dump_p7ioc_diag_data(phb); + break; + default: + pr_warning("PCI %d: Can't decode this PHB diag data\n", + phb->hose->global_number); + } +} + +static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no) +{ + unsigned long flags, rc; + int has_diag; + + spin_lock_irqsave(&phb->lock, flags); + + rc = opal_pci_get_phb_diag_data(phb->opal_id, phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE); + has_diag = (rc == OPAL_SUCCESS); + + rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); + if (rc) { + pr_warning("PCI %d: Failed to clear EEH freeze state" + " for PE#%d, err %ld\n", + phb->hose->global_number, pe_no, rc); + + /* For now, let's only display the diag buffer when we fail to clear + * the EEH status. We'll do more sensible things later when we have + * proper EEH support. We need to make sure we don't pollute ourselves + * with the normal errors generated when probing empty slots + */ + if (has_diag) + pnv_pci_dump_phb_diag_data(phb); + else + pr_warning("PCI %d: No diag data available\n", + phb->hose->global_number); + } + + spin_unlock_irqrestore(&phb->lock, flags); +} + static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus, u32 bdfn) { @@ -165,15 +271,8 @@ static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus, } cfg_dbg(" -> EEH check, bdfn=%04x PE%d fstate=%x\n", bdfn, pe_no, fstate); - if (fstate != 0) { - rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, - OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); - if (rc) { - pr_warning("PCI %d: Failed to clear EEH freeze state" - " for PE#%d, err %lld\n", - phb->hose->global_number, pe_no, rc); - } - } + if (fstate != 0) + pnv_pci_handle_eeh_config(phb, pe_no); } static int pnv_pci_read_config(struct pci_bus *bus, @@ -257,12 +356,54 @@ struct pci_ops pnv_pci_ops = { .write = pnv_pci_write_config, }; + +static void pnv_tce_invalidate(struct iommu_table *tbl, + u64 *startp, u64 *endp) +{ + u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; + unsigned long start, end, inc; + + start = __pa(startp); + end = __pa(endp); + + + /* BML uses this case for p6/p7/galaxy2: Shift addr and put in node */ + if (tbl->it_busno) { + start <<= 12; + end <<= 12; + inc = 128 << 12; + start |= tbl->it_busno; + end |= tbl->it_busno; + } + /* p7ioc-style invalidation, 2 TCEs per write */ + else if (tbl->it_type & TCE_PCI_SWINV_PAIR) { + start |= (1ull << 63); + end |= (1ull << 63); + inc = 16; + } + /* Default (older HW) */ + else + inc = 128; + + end |= inc - 1; /* round up end to be different than start */ + + mb(); /* Ensure above stores are visible */ + while (start <= end) { + __raw_writeq(start, invalidate); + start += inc; + } + /* The iommu layer will do another mb() for us on build() and + * we don't care on free() + */ +} + + static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, enum dma_data_direction direction, struct dma_attrs *attrs) { u64 proto_tce; - u64 *tcep; + u64 *tcep, *tces; u64 rpn; proto_tce = TCE_PCI_READ; // Read allowed @@ -270,25 +411,33 @@ static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, if (direction != DMA_TO_DEVICE) proto_tce |= TCE_PCI_WRITE; - tcep = ((u64 *)tbl->it_base) + index; + tces = tcep = ((u64 *)tbl->it_base) + index - tbl->it_offset; + rpn = __pa(uaddr) >> TCE_SHIFT; - while (npages--) { - /* can't move this out since we might cross LMB boundary */ - rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; - *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; + while (npages--) + *(tcep++) = proto_tce | (rpn++ << TCE_RPN_SHIFT); + + /* Some implementations won't cache invalid TCEs and thus may not + * need that flush. We'll probably turn it_type into a bit mask + * of flags if that becomes the case + */ + if (tbl->it_type & TCE_PCI_SWINV_CREATE) + pnv_tce_invalidate(tbl, tces, tcep - 1); - uaddr += TCE_PAGE_SIZE; - tcep++; - } return 0; } static void pnv_tce_free(struct iommu_table *tbl, long index, long npages) { - u64 *tcep = ((u64 *)tbl->it_base) + index; + u64 *tcep, *tces; + + tces = tcep = ((u64 *)tbl->it_base) + index - tbl->it_offset; while (npages--) *(tcep++) = 0; + + if (tbl->it_type & TCE_PCI_SWINV_FREE) + pnv_tce_invalidate(tbl, tces, tcep - 1); } void pnv_pci_setup_iommu_table(struct iommu_table *tbl, @@ -308,13 +457,14 @@ static struct iommu_table * __devinit pnv_pci_setup_bml_iommu(struct pci_controller *hose) { struct iommu_table *tbl; - const __be64 *basep; + const __be64 *basep, *swinvp; const __be32 *sizep; basep = of_get_property(hose->dn, "linux,tce-base", NULL); sizep = of_get_property(hose->dn, "linux,tce-size", NULL); if (basep == NULL || sizep == NULL) { - pr_err("PCI: %s has missing tce entries !\n", hose->dn->full_name); + pr_err("PCI: %s has missing tce entries !\n", + hose->dn->full_name); return NULL; } tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, hose->node); @@ -323,6 +473,15 @@ pnv_pci_setup_bml_iommu(struct pci_controller *hose) pnv_pci_setup_iommu_table(tbl, __va(be64_to_cpup(basep)), be32_to_cpup(sizep), 0); iommu_init_table(tbl, hose->node); + + /* Deal with SW invalidated TCEs when needed (BML way) */ + swinvp = of_get_property(hose->dn, "linux,tce-sw-invalidate-info", + NULL); + if (swinvp) { + tbl->it_busno = swinvp[1]; + tbl->it_index = (unsigned long)ioremap(swinvp[0], 8); + tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE; + } return tbl; } @@ -356,6 +515,13 @@ static void __devinit pnv_pci_dma_dev_setup(struct pci_dev *pdev) pnv_pci_dma_fallback_setup(hose, pdev); } +/* Fixup wrong class code in p7ioc root complex */ +static void __devinit pnv_p7ioc_rc_quirk(struct pci_dev *dev) +{ + dev->class = PCI_CLASS_BRIDGE_PCI << 8; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IBM, 0x3b9, pnv_p7ioc_rc_quirk); + static int pnv_pci_probe_mode(struct pci_bus *bus) { struct pci_controller *hose = pci_bus_to_host(bus); @@ -400,12 +566,24 @@ void __init pnv_pci_init(void) init_pci_config_tokens(); find_and_init_phbs(); #endif /* CONFIG_PPC_POWERNV_RTAS */ - } else { - /* OPAL is here, do our normal stuff */ + } + /* OPAL is here, do our normal stuff */ + else { + int found_ioda = 0; + + /* Look for IODA IO-Hubs. We don't support mixing IODA + * and p5ioc2 due to the need to change some global + * probing flags + */ + for_each_compatible_node(np, NULL, "ibm,ioda-hub") { + pnv_pci_init_ioda_hub(np); + found_ioda = 1; + } /* Look for p5ioc2 IO-Hubs */ - for_each_compatible_node(np, NULL, "ibm,p5ioc2") - pnv_pci_init_p5ioc2_hub(np); + if (!found_ioda) + for_each_compatible_node(np, NULL, "ibm,p5ioc2") + pnv_pci_init_p5ioc2_hub(np); } /* Setup the linkage between OF nodes and PHBs */ diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index d4dbc495093..8bc47963464 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -9,9 +9,63 @@ enum pnv_phb_type { PNV_PHB_IODA2, }; +/* Precise PHB model for error management */ +enum pnv_phb_model { + PNV_PHB_MODEL_UNKNOWN, + PNV_PHB_MODEL_P5IOC2, + PNV_PHB_MODEL_P7IOC, +}; + +#define PNV_PCI_DIAG_BUF_SIZE 4096 + +/* Data associated with a PE, including IOMMU tracking etc.. */ +struct pnv_ioda_pe { + /* A PE can be associated with a single device or an + * entire bus (& children). In the former case, pdev + * is populated, in the later case, pbus is. + */ + struct pci_dev *pdev; + struct pci_bus *pbus; + + /* Effective RID (device RID for a device PE and base bus + * RID with devfn 0 for a bus PE) + */ + unsigned int rid; + + /* PE number */ + unsigned int pe_number; + + /* "Weight" assigned to the PE for the sake of DMA resource + * allocations + */ + unsigned int dma_weight; + + /* This is a PCI-E -> PCI-X bridge, this points to the + * corresponding bus PE + */ + struct pnv_ioda_pe *bus_pe; + + /* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */ + int tce32_seg; + int tce32_segcount; + struct iommu_table tce32_table; + + /* XXX TODO: Add support for additional 64-bit iommus */ + + /* MSIs. MVE index is identical for for 32 and 64 bit MSI + * and -1 if not supported. (It's actually identical to the + * PE number) + */ + int mve_number; + + /* Link in list of PE#s */ + struct list_head link; +}; + struct pnv_phb { struct pci_controller *hose; enum pnv_phb_type type; + enum pnv_phb_model model; u64 opal_id; void __iomem *regs; spinlock_t lock; @@ -34,7 +88,52 @@ struct pnv_phb { struct { struct iommu_table iommu_table; } p5ioc2; + + struct { + /* Global bridge info */ + unsigned int total_pe; + unsigned int m32_size; + unsigned int m32_segsize; + unsigned int m32_pci_base; + unsigned int io_size; + unsigned int io_segsize; + unsigned int io_pci_base; + + /* PE allocation bitmap */ + unsigned long *pe_alloc; + + /* M32 & IO segment maps */ + unsigned int *m32_segmap; + unsigned int *io_segmap; + struct pnv_ioda_pe *pe_array; + + /* Reverse map of PEs, will have to extend if + * we are to support more than 256 PEs, indexed + * bus { bus, devfn } + */ + unsigned char pe_rmap[0x10000]; + + /* 32-bit TCE tables allocation */ + unsigned long tce32_count; + + /* Total "weight" for the sake of DMA resources + * allocation + */ + unsigned int dma_weight; + unsigned int dma_pe_count; + + /* Sorted list of used PE's, sorted at + * boot for resource allocation purposes + */ + struct list_head pe_list; + } ioda; }; + + /* PHB status structure */ + union { + unsigned char blob[PNV_PCI_DIAG_BUF_SIZE]; + struct OpalIoP7IOCPhbErrorData p7ioc; + } diag; }; extern struct pci_ops pnv_pci_ops; @@ -43,6 +142,7 @@ extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl, void *tce_mem, u64 tce_size, u64 dma_offset); extern void pnv_pci_init_p5ioc2_hub(struct device_node *np); +extern void pnv_pci_init_ioda_hub(struct device_node *np); #endif /* __POWERNV_PCI_H */ diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index e8773668524..17210c526c5 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -75,7 +75,7 @@ int __devinit pnv_smp_kick_cpu(int nr) /* On OPAL v2 the CPU are still spinning inside OPAL itself, * get them back now */ - if (firmware_has_feature(FW_FEATURE_OPALv2)) { + if (!paca[nr].cpu_start && firmware_has_feature(FW_FEATURE_OPALv2)) { pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n", nr, pcpu); rc = opal_start_cpu(pcpu, start_here); if (rc != OPAL_SUCCESS) diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 1d6f4f478fe..617efa12a3a 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -31,18 +31,18 @@ #if defined(DEBUG) #define DBG udbg_printf +#define FAIL udbg_printf #else -#define DBG pr_debug +#define DBG pr_devel +#define FAIL pr_debug #endif /** * struct ps3_bmp - a per cpu irq status and mask bitmap structure * @status: 256 bit status bitmap indexed by plug - * @unused_1: + * @unused_1: Alignment * @mask: 256 bit mask bitmap indexed by plug - * @unused_2: - * @lock: - * @ipi_debug_brk_mask: + * @unused_2: Alignment * * The HV maintains per SMT thread mappings of HV outlet to HV plug on * behalf of the guest. These mappings are implemented as 256 bit guest @@ -73,21 +73,24 @@ struct ps3_bmp { unsigned long mask; u64 unused_2[3]; }; - u64 ipi_debug_brk_mask; - spinlock_t lock; }; /** * struct ps3_private - a per cpu data structure * @bmp: ps3_bmp structure + * @bmp_lock: Syncronize access to bmp. + * @ipi_debug_brk_mask: Mask for debug break IPIs * @ppe_id: HV logical_ppe_id * @thread_id: HV thread_id + * @ipi_mask: Mask of IPI virqs */ struct ps3_private { struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); + spinlock_t bmp_lock; u64 ppe_id; u64 thread_id; + unsigned long ipi_debug_brk_mask; unsigned long ipi_mask; }; @@ -105,7 +108,7 @@ static void ps3_chip_mask(struct irq_data *d) struct ps3_private *pd = irq_data_get_irq_chip_data(d); unsigned long flags; - pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, + DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, pd->thread_id, d->irq); local_irq_save(flags); @@ -126,7 +129,7 @@ static void ps3_chip_unmask(struct irq_data *d) struct ps3_private *pd = irq_data_get_irq_chip_data(d); unsigned long flags; - pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, + DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, pd->thread_id, d->irq); local_irq_save(flags); @@ -190,19 +193,19 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, *virq = irq_create_mapping(NULL, outlet); if (*virq == NO_IRQ) { - pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n", + FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n", __func__, __LINE__, outlet); result = -ENOMEM; goto fail_create; } - pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, + DBG("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, outlet, cpu, *virq); result = irq_set_chip_data(*virq, pd); if (result) { - pr_debug("%s:%d: irq_set_chip_data failed\n", + FAIL("%s:%d: irq_set_chip_data failed\n", __func__, __LINE__); goto fail_set; } @@ -228,13 +231,13 @@ static int ps3_virq_destroy(unsigned int virq) { const struct ps3_private *pd = irq_get_chip_data(virq); - pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, + DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, __LINE__, pd->ppe_id, pd->thread_id, virq); irq_set_chip_data(virq, NULL); irq_dispose_mapping(virq); - pr_debug("%s:%d <-\n", __func__, __LINE__); + DBG("%s:%d <-\n", __func__, __LINE__); return 0; } @@ -257,7 +260,7 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, result = ps3_virq_setup(cpu, outlet, virq); if (result) { - pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__); + FAIL("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__); goto fail_setup; } @@ -269,7 +272,7 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, outlet, 0); if (result) { - pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", + FAIL("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", __func__, __LINE__, ps3_result(result)); result = -EPERM; goto fail_connect; @@ -298,7 +301,7 @@ int ps3_irq_plug_destroy(unsigned int virq) int result; const struct ps3_private *pd = irq_get_chip_data(virq); - pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, + DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, __LINE__, pd->ppe_id, pd->thread_id, virq); ps3_chip_mask(irq_get_irq_data(virq)); @@ -306,7 +309,7 @@ int ps3_irq_plug_destroy(unsigned int virq) result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq); if (result) - pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", + FAIL("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", __func__, __LINE__, ps3_result(result)); ps3_virq_destroy(virq); @@ -334,7 +337,7 @@ int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq) result = lv1_construct_event_receive_port(&outlet); if (result) { - pr_debug("%s:%d: lv1_construct_event_receive_port failed: %s\n", + FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n", __func__, __LINE__, ps3_result(result)); *virq = NO_IRQ; return result; @@ -360,14 +363,14 @@ int ps3_event_receive_port_destroy(unsigned int virq) { int result; - pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq); + DBG(" -> %s:%d virq %u\n", __func__, __LINE__, virq); ps3_chip_mask(irq_get_irq_data(virq)); result = lv1_destruct_event_receive_port(virq_to_hw(virq)); if (result) - pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", + FAIL("%s:%d: lv1_destruct_event_receive_port failed: %s\n", __func__, __LINE__, ps3_result(result)); /* @@ -375,7 +378,7 @@ int ps3_event_receive_port_destroy(unsigned int virq) * calls from interrupt context (smp_call_function) when kexecing. */ - pr_debug(" <- %s:%d\n", __func__, __LINE__); + DBG(" <- %s:%d\n", __func__, __LINE__); return result; } @@ -411,7 +414,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, dev->dev_id, virq_to_hw(*virq), dev->interrupt_id); if (result) { - pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" + FAIL("%s:%d: lv1_connect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); ps3_event_receive_port_destroy(*virq); @@ -419,7 +422,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, return result; } - pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, + DBG("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, dev->interrupt_id, *virq); return 0; @@ -433,14 +436,14 @@ int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, int result; - pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, + DBG(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, dev->interrupt_id, virq); result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, dev->dev_id, virq_to_hw(virq), dev->interrupt_id); if (result) - pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" + FAIL("%s:%d: lv1_disconnect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); @@ -455,7 +458,7 @@ int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, result = ps3_virq_destroy(virq); BUG_ON(result); - pr_debug(" <- %s:%d\n", __func__, __LINE__); + DBG(" <- %s:%d\n", __func__, __LINE__); return result; } EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy); @@ -480,7 +483,7 @@ int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id, result = lv1_construct_io_irq_outlet(interrupt_id, &outlet); if (result) { - pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n", + FAIL("%s:%d: lv1_construct_io_irq_outlet failed: %s\n", __func__, __LINE__, ps3_result(result)); return result; } @@ -510,7 +513,7 @@ int ps3_io_irq_destroy(unsigned int virq) result = lv1_destruct_io_irq_outlet(outlet); if (result) - pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", + FAIL("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", __func__, __LINE__, ps3_result(result)); return result; @@ -542,7 +545,7 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet); if (result) { - pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", + FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", __func__, __LINE__, ps3_result(result)); return result; } @@ -562,7 +565,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) result = lv1_deconfigure_virtual_uart_irq(); if (result) { - pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", + FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", __func__, __LINE__, ps3_result(result)); return result; } @@ -595,7 +598,7 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, result = lv1_get_spe_irq_outlet(spe_id, class, &outlet); if (result) { - pr_debug("%s:%d: lv1_get_spe_irq_outlet failed: %s\n", + FAIL("%s:%d: lv1_get_spe_irq_outlet failed: %s\n", __func__, __LINE__, ps3_result(result)); return result; } @@ -626,7 +629,7 @@ int ps3_spe_irq_destroy(unsigned int virq) static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, const char* func, int line) { - pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", + pr_debug("%s:%d: %s %u {%04llx_%04llx_%04llx_%04llx}\n", func, line, header, cpu, *p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff, *p & 0xffff); @@ -635,7 +638,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, static void __maybe_unused _dump_256_bmp(const char *header, const u64 *p, unsigned cpu, const char* func, int line) { - pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", + pr_debug("%s:%d: %s %u {%016llx:%016llx:%016llx:%016llx}\n", func, line, header, cpu, p[0], p[1], p[2], p[3]); } @@ -644,10 +647,10 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line) { unsigned long flags; - spin_lock_irqsave(&pd->bmp.lock, flags); + spin_lock_irqsave(&pd->bmp_lock, flags); _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line); - _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); - spin_unlock_irqrestore(&pd->bmp.lock, flags); + _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); + spin_unlock_irqrestore(&pd->bmp_lock, flags); } #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) @@ -656,9 +659,9 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd, { unsigned long flags; - spin_lock_irqsave(&pd->bmp.lock, flags); - _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); - spin_unlock_irqrestore(&pd->bmp.lock, flags); + spin_lock_irqsave(&pd->bmp_lock, flags); + _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); + spin_unlock_irqrestore(&pd->bmp_lock, flags); } #else static void dump_bmp(struct ps3_private* pd) {}; @@ -667,7 +670,7 @@ static void dump_bmp(struct ps3_private* pd) {}; static int ps3_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hwirq) { - pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, + DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, virq); irq_set_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); @@ -690,10 +693,10 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) { struct ps3_private *pd = &per_cpu(ps3_private, cpu); - pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq; + set_bit(63 - virq, &pd->ipi_debug_brk_mask); - pr_debug("%s:%d: cpu %u, virq %u, mask %llxh\n", __func__, __LINE__, - cpu, virq, pd->bmp.ipi_debug_brk_mask); + DBG("%s:%d: cpu %u, virq %u, mask %lxh\n", __func__, __LINE__, + cpu, virq, pd->ipi_debug_brk_mask); } void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq) @@ -714,14 +717,14 @@ static unsigned int ps3_get_irq(void) /* check for ipi break first to stop this cpu ASAP */ - if (x & pd->bmp.ipi_debug_brk_mask) - x &= pd->bmp.ipi_debug_brk_mask; + if (x & pd->ipi_debug_brk_mask) + x &= pd->ipi_debug_brk_mask; asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x)); plug &= 0x3f; if (unlikely(plug == NO_IRQ)) { - pr_debug("%s:%d: no plug found: thread_id %llu\n", __func__, + DBG("%s:%d: no plug found: thread_id %llu\n", __func__, __LINE__, pd->thread_id); dump_bmp(&per_cpu(ps3_private, 0)); dump_bmp(&per_cpu(ps3_private, 1)); @@ -760,9 +763,9 @@ void __init ps3_init_IRQ(void) lv1_get_logical_ppe_id(&pd->ppe_id); pd->thread_id = get_hard_smp_processor_id(cpu); - spin_lock_init(&pd->bmp.lock); + spin_lock_init(&pd->bmp_lock); - pr_debug("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n", + DBG("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n", __func__, __LINE__, pd->ppe_id, pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); @@ -770,7 +773,7 @@ void __init ps3_init_IRQ(void) pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); if (result) - pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" + FAIL("%s:%d: lv1_configure_irq_state_bitmap failed:" " %s\n", __func__, __LINE__, ps3_result(result)); } diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index ca40f6afd35..7bdfea336f5 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -44,7 +44,7 @@ static void _dump_field(const char *hdr, u64 n, const char *func, int line) s[i] = (in[i] <= 126 && in[i] >= 32) ? in[i] : '.'; s[i] = 0; - pr_debug("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s); + pr_devel("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s); #endif } @@ -53,7 +53,7 @@ static void _dump_field(const char *hdr, u64 n, const char *func, int line) static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, const char *func, int line) { - pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); + pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id); _dump_field("n1: ", n1, func, line); _dump_field("n2: ", n2, func, line); _dump_field("n3: ", n3, func, line); @@ -65,13 +65,13 @@ static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2, const char *func, int line) { - pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); + pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id); _dump_field("n1: ", n1, func, line); _dump_field("n2: ", n2, func, line); _dump_field("n3: ", n3, func, line); _dump_field("n4: ", n4, func, line); - pr_debug("%s:%d: v1: %016llx\n", func, line, v1); - pr_debug("%s:%d: v2: %016llx\n", func, line, v2); + pr_devel("%s:%d: v1: %016llx\n", func, line, v1); + pr_devel("%s:%d: v2: %016llx\n", func, line, v2); } /** @@ -131,11 +131,11 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, lpar_id = id; } - result = lv1_get_repository_node_value(lpar_id, n1, n2, n3, n4, &v1, + result = lv1_read_repository_node(lpar_id, n1, n2, n3, n4, &v1, &v2); if (result) { - pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n", + pr_warn("%s:%d: lv1_read_repository_node failed: %s\n", __func__, __LINE__, ps3_result(result)); dump_node_name(lpar_id, n1, n2, n3, n4); return -ENOENT; @@ -149,10 +149,10 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, *_v2 = v2; if (v1 && !_v1) - pr_debug("%s:%d: warning: discarding non-zero v1: %016llx\n", + pr_devel("%s:%d: warning: discarding non-zero v1: %016llx\n", __func__, __LINE__, v1); if (v2 && !_v2) - pr_debug("%s:%d: warning: discarding non-zero v2: %016llx\n", + pr_devel("%s:%d: warning: discarding non-zero v2: %016llx\n", __func__, __LINE__, v2); return 0; @@ -323,16 +323,16 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); if (result) { - pr_debug("%s:%d read_bus_num_dev failed\n", __func__, __LINE__); + pr_devel("%s:%d read_bus_num_dev failed\n", __func__, __LINE__); return result; } - pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n", + pr_devel("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n", __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, num_dev); if (tmp.dev_index >= num_dev) { - pr_debug("%s:%d: no device found\n", __func__, __LINE__); + pr_devel("%s:%d: no device found\n", __func__, __LINE__); return -ENODEV; } @@ -340,7 +340,7 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) &tmp.dev_type); if (result) { - pr_debug("%s:%d read_dev_type failed\n", __func__, __LINE__); + pr_devel("%s:%d read_dev_type failed\n", __func__, __LINE__); return result; } @@ -348,12 +348,12 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) &tmp.dev_id); if (result) { - pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, + pr_devel("%s:%d ps3_repository_read_dev_id failed\n", __func__, __LINE__); return result; } - pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n", + pr_devel("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n", __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); *repo = tmp; @@ -367,14 +367,14 @@ int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, struct ps3_repository_device tmp; unsigned int num_dev; - pr_debug(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__, + pr_devel(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__, bus_id, dev_id); for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) { result = ps3_repository_read_bus_id(tmp.bus_index, &tmp.bus_id); if (result) { - pr_debug("%s:%u read_bus_id(%u) failed\n", __func__, + pr_devel("%s:%u read_bus_id(%u) failed\n", __func__, __LINE__, tmp.bus_index); return result; } @@ -382,23 +382,23 @@ int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, if (tmp.bus_id == bus_id) goto found_bus; - pr_debug("%s:%u: skip, bus_id %llu\n", __func__, __LINE__, + pr_devel("%s:%u: skip, bus_id %llu\n", __func__, __LINE__, tmp.bus_id); } - pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); + pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__); return result; found_bus: result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type); if (result) { - pr_debug("%s:%u read_bus_type(%u) failed\n", __func__, + pr_devel("%s:%u read_bus_type(%u) failed\n", __func__, __LINE__, tmp.bus_index); return result; } result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); if (result) { - pr_debug("%s:%u read_bus_num_dev failed\n", __func__, + pr_devel("%s:%u read_bus_num_dev failed\n", __func__, __LINE__); return result; } @@ -408,7 +408,7 @@ found_bus: tmp.dev_index, &tmp.dev_id); if (result) { - pr_debug("%s:%u read_dev_id(%u:%u) failed\n", __func__, + pr_devel("%s:%u read_dev_id(%u:%u) failed\n", __func__, __LINE__, tmp.bus_index, tmp.dev_index); return result; } @@ -416,21 +416,21 @@ found_bus: if (tmp.dev_id == dev_id) goto found_dev; - pr_debug("%s:%u: skip, dev_id %llu\n", __func__, __LINE__, + pr_devel("%s:%u: skip, dev_id %llu\n", __func__, __LINE__, tmp.dev_id); } - pr_debug(" <- %s:%u: dev not found\n", __func__, __LINE__); + pr_devel(" <- %s:%u: dev not found\n", __func__, __LINE__); return result; found_dev: result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index, &tmp.dev_type); if (result) { - pr_debug("%s:%u read_dev_type failed\n", __func__, __LINE__); + pr_devel("%s:%u read_dev_type failed\n", __func__, __LINE__); return result; } - pr_debug(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n", + pr_devel(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n", __func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index, tmp.dev_index, tmp.bus_id, tmp.dev_id); *repo = tmp; @@ -443,18 +443,18 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, int result = 0; struct ps3_repository_device repo; - pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); + pr_devel(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); repo.bus_type = bus_type; result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index); if (result) { - pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); + pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__); return result; } result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id); if (result) { - pr_debug("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, + pr_devel("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, repo.bus_index); return result; } @@ -469,13 +469,13 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, result = callback(&repo); if (result) { - pr_debug("%s:%d: abort at callback\n", __func__, + pr_devel("%s:%d: abort at callback\n", __func__, __LINE__); break; } } - pr_debug(" <- %s:%d\n", __func__, __LINE__); + pr_devel(" <- %s:%d\n", __func__, __LINE__); return result; } @@ -489,7 +489,7 @@ int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, for (i = from; i < 10; i++) { error = ps3_repository_read_bus_type(i, &type); if (error) { - pr_debug("%s:%d read_bus_type failed\n", + pr_devel("%s:%d read_bus_type failed\n", __func__, __LINE__); *bus_index = UINT_MAX; return error; @@ -509,7 +509,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, int result = 0; unsigned int res_index; - pr_debug("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type); + pr_devel("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type); *interrupt_id = UINT_MAX; @@ -521,7 +521,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, repo->dev_index, res_index, &t, &id); if (result) { - pr_debug("%s:%d read_dev_intr failed\n", + pr_devel("%s:%d read_dev_intr failed\n", __func__, __LINE__); return result; } @@ -535,7 +535,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, if (res_index == 10) return -ENODEV; - pr_debug("%s:%d: found intr_type %u at res_index %u\n", + pr_devel("%s:%d: found intr_type %u at res_index %u\n", __func__, __LINE__, intr_type, res_index); return result; @@ -547,7 +547,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo, int result = 0; unsigned int res_index; - pr_debug("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type); + pr_devel("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type); *bus_addr = *len = 0; @@ -560,7 +560,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo, repo->dev_index, res_index, &t, &a, &l); if (result) { - pr_debug("%s:%d read_dev_reg failed\n", + pr_devel("%s:%d read_dev_reg failed\n", __func__, __LINE__); return result; } @@ -575,7 +575,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo, if (res_index == 10) return -ENODEV; - pr_debug("%s:%d: found reg_type %u at res_index %u\n", + pr_devel("%s:%d: found reg_type %u at res_index %u\n", __func__, __LINE__, reg_type, res_index); return result; @@ -1009,7 +1009,7 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) int result = 0; unsigned int res_index; - pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, + pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, repo->bus_index, repo->dev_index); for (res_index = 0; res_index < 10; res_index++) { @@ -1021,13 +1021,13 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) if (result) { if (result != LV1_NO_ENTRY) - pr_debug("%s:%d ps3_repository_read_dev_intr" + pr_devel("%s:%d ps3_repository_read_dev_intr" " (%u:%u) failed\n", __func__, __LINE__, repo->bus_index, repo->dev_index); break; } - pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", + pr_devel("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", __func__, __LINE__, repo->bus_index, repo->dev_index, intr_type, interrupt_id); } @@ -1042,18 +1042,18 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) if (result) { if (result != LV1_NO_ENTRY) - pr_debug("%s:%d ps3_repository_read_dev_reg" + pr_devel("%s:%d ps3_repository_read_dev_reg" " (%u:%u) failed\n", __func__, __LINE__, repo->bus_index, repo->dev_index); break; } - pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n", + pr_devel("%s:%d (%u:%u) reg_type %u, bus_addr %llxh, len %llxh\n", __func__, __LINE__, repo->bus_index, repo->dev_index, reg_type, bus_addr, len); } - pr_debug(" <- %s:%d\n", __func__, __LINE__); + pr_devel(" <- %s:%d\n", __func__, __LINE__); return result; } @@ -1063,22 +1063,22 @@ static int dump_stor_dev_info(struct ps3_repository_device *repo) unsigned int num_regions, region_index; u64 port, blk_size, num_blocks; - pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, + pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, repo->bus_index, repo->dev_index); result = ps3_repository_read_stor_dev_info(repo->bus_index, repo->dev_index, &port, &blk_size, &num_blocks, &num_regions); if (result) { - pr_debug("%s:%d ps3_repository_read_stor_dev_info" + pr_devel("%s:%d ps3_repository_read_stor_dev_info" " (%u:%u) failed\n", __func__, __LINE__, repo->bus_index, repo->dev_index); goto out; } - pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks " - "%lu, num_regions %u\n", - __func__, __LINE__, repo->bus_index, repo->dev_index, port, - blk_size, num_blocks, num_regions); + pr_devel("%s:%d (%u:%u): port %llu, blk_size %llu, num_blocks " + "%llu, num_regions %u\n", + __func__, __LINE__, repo->bus_index, repo->dev_index, + port, blk_size, num_blocks, num_regions); for (region_index = 0; region_index < num_regions; region_index++) { unsigned int region_id; @@ -1088,19 +1088,20 @@ static int dump_stor_dev_info(struct ps3_repository_device *repo) repo->dev_index, region_index, ®ion_id, ®ion_start, ®ion_size); if (result) { - pr_debug("%s:%d ps3_repository_read_stor_dev_region" + pr_devel("%s:%d ps3_repository_read_stor_dev_region" " (%u:%u) failed\n", __func__, __LINE__, repo->bus_index, repo->dev_index); break; } - pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", + pr_devel("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", __func__, __LINE__, repo->bus_index, repo->dev_index, - region_id, region_start, region_size); + region_id, (unsigned long)region_start, + (unsigned long)region_size); } out: - pr_debug(" <- %s:%d\n", __func__, __LINE__); + pr_devel(" <- %s:%d\n", __func__, __LINE__); return result; } @@ -1109,7 +1110,7 @@ static int dump_device_info(struct ps3_repository_device *repo, { int result = 0; - pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index); + pr_devel(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index); for (repo->dev_index = 0; repo->dev_index < num_dev; repo->dev_index++) { @@ -1118,7 +1119,7 @@ static int dump_device_info(struct ps3_repository_device *repo, repo->dev_index, &repo->dev_type); if (result) { - pr_debug("%s:%d ps3_repository_read_dev_type" + pr_devel("%s:%d ps3_repository_read_dev_type" " (%u:%u) failed\n", __func__, __LINE__, repo->bus_index, repo->dev_index); break; @@ -1128,15 +1129,15 @@ static int dump_device_info(struct ps3_repository_device *repo, repo->dev_index, &repo->dev_id); if (result) { - pr_debug("%s:%d ps3_repository_read_dev_id" + pr_devel("%s:%d ps3_repository_read_dev_id" " (%u:%u) failed\n", __func__, __LINE__, repo->bus_index, repo->dev_index); continue; } - pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__, + pr_devel("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__, __LINE__, repo->bus_index, repo->dev_index, - repo->dev_type, repo->dev_id); + repo->dev_type, (unsigned long)repo->dev_id); ps3_repository_dump_resource_info(repo); @@ -1144,7 +1145,7 @@ static int dump_device_info(struct ps3_repository_device *repo, dump_stor_dev_info(repo); } - pr_debug(" <- %s:%d\n", __func__, __LINE__); + pr_devel(" <- %s:%d\n", __func__, __LINE__); return result; } @@ -1153,7 +1154,7 @@ int ps3_repository_dump_bus_info(void) int result = 0; struct ps3_repository_device repo; - pr_debug(" -> %s:%d\n", __func__, __LINE__); + pr_devel(" -> %s:%d\n", __func__, __LINE__); memset(&repo, 0, sizeof(repo)); @@ -1164,7 +1165,7 @@ int ps3_repository_dump_bus_info(void) &repo.bus_type); if (result) { - pr_debug("%s:%d read_bus_type(%u) failed\n", + pr_devel("%s:%d read_bus_type(%u) failed\n", __func__, __LINE__, repo.bus_index); break; } @@ -1173,32 +1174,32 @@ int ps3_repository_dump_bus_info(void) &repo.bus_id); if (result) { - pr_debug("%s:%d read_bus_id(%u) failed\n", + pr_devel("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, repo.bus_index); continue; } if (repo.bus_index != repo.bus_id) - pr_debug("%s:%d bus_index != bus_id\n", + pr_devel("%s:%d bus_index != bus_id\n", __func__, __LINE__); result = ps3_repository_read_bus_num_dev(repo.bus_index, &num_dev); if (result) { - pr_debug("%s:%d read_bus_num_dev(%u) failed\n", + pr_devel("%s:%d read_bus_num_dev(%u) failed\n", __func__, __LINE__, repo.bus_index); continue; } - pr_debug("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n", + pr_devel("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n", __func__, __LINE__, repo.bus_index, repo.bus_type, - repo.bus_id, num_dev); + (unsigned long)repo.bus_id, num_dev); dump_device_info(&repo, num_dev); } - pr_debug(" <- %s:%d\n", __func__, __LINE__); + pr_devel(" <- %s:%d\n", __func__, __LINE__); return result; } diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index e8ec1b2bfff..2d664c5a83b 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -193,10 +193,12 @@ static int ps3_set_dabr(unsigned long dabr) static void __init ps3_setup_arch(void) { + u64 tmp; DBG(" -> %s:%d\n", __func__, __LINE__); - lv1_get_version_info(&ps3_firmware_version.raw); + lv1_get_version_info(&ps3_firmware_version.raw, &tmp); + printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", ps3_firmware_version.major, ps3_firmware_version.minor, ps3_firmware_version.rev); diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index efc1cd8c034..4b35166229f 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -57,7 +57,7 @@ static void ps3_smp_message_pass(int cpu, int msg) " (%d)\n", __func__, __LINE__, cpu, msg, result); } -static int ps3_smp_probe(void) +static int __init ps3_smp_probe(void) { int cpu; diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 451fad1c92a..e17fa1432d8 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -154,7 +154,7 @@ static unsigned long get_vas_id(void) u64 id; lv1_get_logical_ppe_id(&id); - lv1_get_virtual_address_space_id_of_ppe(id, &id); + lv1_get_virtual_address_space_id_of_ppe(&id); return id; } diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index c81f6bb9c10..ae7b6d41fed 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -120,3 +120,12 @@ config DTL which are accessible through a debugfs file. Say N if you are unsure. + +config PSERIES_IDLE + tristate "Cpuidle driver for pSeries platforms" + depends on CPU_IDLE + depends on PPC_PSERIES + default y + help + Select this option to enable processor idle state management + through cpuidle subsystem. diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 3556e402cbf..236db46b407 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o +obj-$(CONFIG_PSERIES_IDLE) += processor_idle.o ifeq ($(CONFIG_PPC_PSERIES),y) obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index f106662f438..c9311cfdfca 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -109,7 +109,7 @@ static void probe_hcall_entry(void *ignored, unsigned long opcode, unsigned long if (opcode > MAX_HCALL_OPCODE) return; - h = &get_cpu_var(hcall_stats)[opcode / 4]; + h = &__get_cpu_var(hcall_stats)[opcode / 4]; h->tb_start = mftb(); h->purr_start = mfspr(SPRN_PURR); } @@ -126,8 +126,6 @@ static void probe_hcall_exit(void *ignored, unsigned long opcode, unsigned long h->num_calls++; h->tb_total += mftb() - h->tb_start; h->purr_total += mfspr(SPRN_PURR) - h->purr_start; - - put_cpu_var(hcall_stats); } static int __init hcall_inst_init(void) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index b719d970973..c442f2b1980 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -52,13 +52,42 @@ #include "plpar_wrappers.h" +static void tce_invalidate_pSeries_sw(struct iommu_table *tbl, + u64 *startp, u64 *endp) +{ + u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; + unsigned long start, end, inc; + + start = __pa(startp); + end = __pa(endp); + inc = L1_CACHE_BYTES; /* invalidate a cacheline of TCEs at a time */ + + /* If this is non-zero, change the format. We shift the + * address and or in the magic from the device tree. */ + if (tbl->it_busno) { + start <<= 12; + end <<= 12; + inc <<= 12; + start |= tbl->it_busno; + end |= tbl->it_busno; + } + + end |= inc - 1; /* round up end to be different than start */ + + mb(); /* Make sure TCEs in memory are written */ + while (start <= end) { + out_be64(invalidate, start); + start += inc; + } +} + static int tce_build_pSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, enum dma_data_direction direction, struct dma_attrs *attrs) { u64 proto_tce; - u64 *tcep; + u64 *tcep, *tces; u64 rpn; proto_tce = TCE_PCI_READ; // Read allowed @@ -66,7 +95,7 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index, if (direction != DMA_TO_DEVICE) proto_tce |= TCE_PCI_WRITE; - tcep = ((u64 *)tbl->it_base) + index; + tces = tcep = ((u64 *)tbl->it_base) + index; while (npages--) { /* can't move this out since we might cross MEMBLOCK boundary */ @@ -76,18 +105,24 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index, uaddr += TCE_PAGE_SIZE; tcep++; } + + if (tbl->it_type == TCE_PCI_SWINV_CREATE) + tce_invalidate_pSeries_sw(tbl, tces, tcep - 1); return 0; } static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) { - u64 *tcep; + u64 *tcep, *tces; - tcep = ((u64 *)tbl->it_base) + index; + tces = tcep = ((u64 *)tbl->it_base) + index; while (npages--) *(tcep++) = 0; + + if (tbl->it_type == TCE_PCI_SWINV_FREE) + tce_invalidate_pSeries_sw(tbl, tces, tcep - 1); } static unsigned long tce_get_pseries(struct iommu_table *tbl, long index) @@ -425,7 +460,7 @@ static void iommu_table_setparms(struct pci_controller *phb, struct iommu_table *tbl) { struct device_node *node; - const unsigned long *basep; + const unsigned long *basep, *sw_inval; const u32 *sizep; node = phb->dn; @@ -462,6 +497,22 @@ static void iommu_table_setparms(struct pci_controller *phb, tbl->it_index = 0; tbl->it_blocksize = 16; tbl->it_type = TCE_PCI; + + sw_inval = of_get_property(node, "linux,tce-sw-invalidate-info", NULL); + if (sw_inval) { + /* + * This property contains information on how to + * invalidate the TCE entry. The first property is + * the base MMIO address used to invalidate entries. + * The second property tells us the format of the TCE + * invalidate (whether it needs to be shifted) and + * some magic routing info to add to our invalidate + * command. + */ + tbl->it_index = (unsigned long) ioremap(sw_inval[0], 8); + tbl->it_busno = sw_inval[1]; /* overload this with magic */ + tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE; + } } /* diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 52d429be6c7..948e0e3b354 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -554,6 +554,7 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) goto out; (*depth)++; + preempt_disable(); trace_hcall_entry(opcode, args); if (opcode == H_CEDE) rcu_idle_enter(); @@ -580,6 +581,7 @@ void __trace_hcall_exit(long opcode, unsigned long retval, if (opcode == H_CEDE) rcu_idle_exit(); trace_hcall_exit(opcode, retval, retbuf); + preempt_enable(); (*depth)--; out: diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index a76b22844d1..330a57b7c17 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -625,6 +625,8 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, { static unsigned int oops_count = 0; static bool panicking = false; + static DEFINE_SPINLOCK(lock); + unsigned long flags; size_t text_len; unsigned int err_type = ERR_TYPE_KERNEL_PANIC_GZ; int rc = -1; @@ -655,6 +657,9 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, if (clobbering_unread_rtas_event()) return; + if (!spin_trylock_irqsave(&lock, flags)) + return; + if (big_oops_buf) { text_len = capture_last_msgs(old_msgs, old_len, new_msgs, new_len, big_oops_buf, big_oops_buf_sz); @@ -670,4 +675,6 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, (void) nvram_write_os_partition(&oops_log_partition, oops_buf, (int) (sizeof(*oops_len) + *oops_len), err_type, ++oops_count); + + spin_unlock_irqrestore(&lock, flags); } diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c new file mode 100644 index 00000000000..085fd3f45ad --- /dev/null +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -0,0 +1,329 @@ +/* + * processor_idle - idle state cpuidle driver. + * Adapted from drivers/idle/intel_idle.c and + * drivers/acpi/processor_idle.c + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/cpuidle.h> +#include <linux/cpu.h> + +#include <asm/paca.h> +#include <asm/reg.h> +#include <asm/system.h> +#include <asm/machdep.h> +#include <asm/firmware.h> + +#include "plpar_wrappers.h" +#include "pseries.h" + +struct cpuidle_driver pseries_idle_driver = { + .name = "pseries_idle", + .owner = THIS_MODULE, +}; + +#define MAX_IDLE_STATE_COUNT 2 + +static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; +static struct cpuidle_device __percpu *pseries_cpuidle_devices; +static struct cpuidle_state *cpuidle_state_table; + +void update_smt_snooze_delay(int snooze) +{ + struct cpuidle_driver *drv = cpuidle_get_driver(); + if (drv) + drv->states[0].target_residency = snooze; +} + +static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) +{ + + *kt_before = ktime_get_real(); + *in_purr = mfspr(SPRN_PURR); + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ + get_lppaca()->idle = 1; +} + +static inline s64 idle_loop_epilog(unsigned long in_purr, ktime_t kt_before) +{ + get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr; + get_lppaca()->idle = 0; + + return ktime_to_us(ktime_sub(ktime_get_real(), kt_before)); +} + +static int snooze_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long in_purr; + ktime_t kt_before; + unsigned long start_snooze; + long snooze = drv->states[0].target_residency; + + idle_loop_prolog(&in_purr, &kt_before); + + if (snooze) { + start_snooze = get_tb() + snooze * tb_ticks_per_usec; + local_irq_enable(); + set_thread_flag(TIF_POLLING_NRFLAG); + + while ((snooze < 0) || (get_tb() < start_snooze)) { + if (need_resched() || cpu_is_offline(dev->cpu)) + goto out; + ppc64_runlatch_off(); + HMT_low(); + HMT_very_low(); + } + + HMT_medium(); + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb(); + local_irq_disable(); + } + +out: + HMT_medium(); + dev->last_residency = + (int)idle_loop_epilog(in_purr, kt_before); + return index; +} + +static int dedicated_cede_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long in_purr; + ktime_t kt_before; + + idle_loop_prolog(&in_purr, &kt_before); + get_lppaca()->donate_dedicated_cpu = 1; + + ppc64_runlatch_off(); + HMT_medium(); + cede_processor(); + + get_lppaca()->donate_dedicated_cpu = 0; + dev->last_residency = + (int)idle_loop_epilog(in_purr, kt_before); + return index; +} + +static int shared_cede_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long in_purr; + ktime_t kt_before; + + idle_loop_prolog(&in_purr, &kt_before); + + /* + * 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(); + + dev->last_residency = + (int)idle_loop_epilog(in_purr, kt_before); + return index; +} + +/* + * States for dedicated partition case. + */ +static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = { + { /* Snooze */ + .name = "snooze", + .desc = "snooze", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 0, + .target_residency = 0, + .enter = &snooze_loop }, + { /* CEDE */ + .name = "CEDE", + .desc = "CEDE", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 1, + .target_residency = 10, + .enter = &dedicated_cede_loop }, +}; + +/* + * States for shared partition case. + */ +static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { + { /* Shared Cede */ + .name = "Shared Cede", + .desc = "Shared Cede", + .flags = CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 0, + .target_residency = 0, + .enter = &shared_cede_loop }, +}; + +int pseries_notify_cpuidle_add_cpu(int cpu) +{ + struct cpuidle_device *dev = + per_cpu_ptr(pseries_cpuidle_devices, cpu); + if (dev && cpuidle_get_driver()) { + cpuidle_disable_device(dev); + cpuidle_enable_device(dev); + } + return 0; +} + +/* + * pseries_cpuidle_driver_init() + */ +static int pseries_cpuidle_driver_init(void) +{ + int idle_state; + struct cpuidle_driver *drv = &pseries_idle_driver; + + drv->state_count = 0; + + for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) { + + if (idle_state > max_idle_state) + break; + + /* is the state not enabled? */ + if (cpuidle_state_table[idle_state].enter == NULL) + continue; + + drv->states[drv->state_count] = /* structure copy */ + cpuidle_state_table[idle_state]; + + if (cpuidle_state_table == dedicated_states) + drv->states[drv->state_count].target_residency = + __get_cpu_var(smt_snooze_delay); + + drv->state_count += 1; + } + + return 0; +} + +/* pseries_idle_devices_uninit(void) + * unregister cpuidle devices and de-allocate memory + */ +static void pseries_idle_devices_uninit(void) +{ + int i; + struct cpuidle_device *dev; + + for_each_possible_cpu(i) { + dev = per_cpu_ptr(pseries_cpuidle_devices, i); + cpuidle_unregister_device(dev); + } + + free_percpu(pseries_cpuidle_devices); + return; +} + +/* pseries_idle_devices_init() + * allocate, initialize and register cpuidle device + */ +static int pseries_idle_devices_init(void) +{ + int i; + struct cpuidle_driver *drv = &pseries_idle_driver; + struct cpuidle_device *dev; + + pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device); + if (pseries_cpuidle_devices == NULL) + return -ENOMEM; + + for_each_possible_cpu(i) { + dev = per_cpu_ptr(pseries_cpuidle_devices, i); + dev->state_count = drv->state_count; + dev->cpu = i; + if (cpuidle_register_device(dev)) { + printk(KERN_DEBUG \ + "cpuidle_register_device %d failed!\n", i); + return -EIO; + } + } + + return 0; +} + +/* + * pseries_idle_probe() + * Choose state table for shared versus dedicated partition + */ +static int pseries_idle_probe(void) +{ + + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) + return -ENODEV; + + if (cpuidle_disable != IDLE_NO_OVERRIDE) + return -ENODEV; + + if (max_idle_state == 0) { + printk(KERN_DEBUG "pseries processor idle disabled.\n"); + return -EPERM; + } + + if (get_lppaca()->shared_proc) + cpuidle_state_table = shared_states; + else + cpuidle_state_table = dedicated_states; + + return 0; +} + +static int __init pseries_processor_idle_init(void) +{ + int retval; + + retval = pseries_idle_probe(); + if (retval) + return retval; + + pseries_cpuidle_driver_init(); + retval = cpuidle_register_driver(&pseries_idle_driver); + if (retval) { + printk(KERN_DEBUG "Registration of pseries driver failed.\n"); + return retval; + } + + retval = pseries_idle_devices_init(); + if (retval) { + pseries_idle_devices_uninit(); + cpuidle_unregister_driver(&pseries_idle_driver); + return retval; + } + + printk(KERN_DEBUG "pseries_idle_driver registered\n"); + + return 0; +} + +static void __exit pseries_processor_idle_exit(void) +{ + + pseries_idle_devices_uninit(); + cpuidle_unregister_driver(&pseries_idle_driver); + + return; +} + +module_init(pseries_processor_idle_init); +module_exit(pseries_processor_idle_exit); + +MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>"); +MODULE_DESCRIPTION("Cpuidle driver for POWER"); +MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 24c7162f11d..9a3dda07566 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -57,4 +57,7 @@ extern struct device_node *dlpar_configure_connector(u32); extern int dlpar_attach_node(struct device_node *); extern int dlpar_detach_node(struct device_node *); +/* Snooze Delay, pseries_idle */ +DECLARE_PER_CPU(long, smt_snooze_delay); + #endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index c3408ca8855..f79f1278dfc 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -39,6 +39,7 @@ #include <linux/irq.h> #include <linux/seq_file.h> #include <linux/root_dev.h> +#include <linux/cpuidle.h> #include <asm/mmu.h> #include <asm/processor.h> @@ -74,9 +75,6 @@ EXPORT_SYMBOL(CMO_PageSize); int fwnmi_active; /* TRUE if an FWNMI handler is present */ -static void pseries_shared_idle_sleep(void); -static void pseries_dedicated_idle_sleep(void); - static struct device_node *pSeries_mpic_node; static void pSeries_show_cpuinfo(struct seq_file *m) @@ -192,8 +190,7 @@ static void __init pseries_mpic_init_IRQ(void) BUG_ON(openpic_addr == 0); /* Setup the openpic driver */ - mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, - MPIC_PRIMARY, + mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, 0, 16, 250, /* isu size, irq count */ " MPIC "); BUG_ON(mpic == NULL); @@ -352,8 +349,25 @@ static int alloc_dispatch_log_kmem_cache(void) } early_initcall(alloc_dispatch_log_kmem_cache); +static void pSeries_idle(void) +{ + /* This would call on the cpuidle framework, and the back-end pseries + * driver to go to idle states + */ + if (cpuidle_idle_call()) { + /* On error, execute default handler + * to go into low thread priority and possibly + * low power mode. + */ + HMT_low(); + HMT_very_low(); + } +} + static void __init pSeries_setup_arch(void) { + panic_timeout = 10; + /* Discover PIC type and setup ppc_md accordingly */ pseries_discover_pic(); @@ -374,18 +388,9 @@ static void __init pSeries_setup_arch(void) pSeries_nvram_init(); - /* Choose an idle loop */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { vpa_init(boot_cpuid); - if (get_lppaca()->shared_proc) { - printk(KERN_DEBUG "Using shared processor idle loop\n"); - ppc_md.power_save = pseries_shared_idle_sleep; - } else { - printk(KERN_DEBUG "Using dedicated idle loop\n"); - ppc_md.power_save = pseries_dedicated_idle_sleep; - } - } else { - printk(KERN_DEBUG "Using default idle loop\n"); + ppc_md.power_save = pSeries_idle; } if (firmware_has_feature(FW_FEATURE_LPAR)) @@ -586,80 +591,6 @@ static int __init pSeries_probe(void) return 1; } - -DECLARE_PER_CPU(long, smt_snooze_delay); - -static void pseries_dedicated_idle_sleep(void) -{ - unsigned int cpu = smp_processor_id(); - unsigned long start_snooze; - unsigned long in_purr, out_purr; - long snooze = __get_cpu_var(smt_snooze_delay); - - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - get_lppaca()->idle = 1; - get_lppaca()->donate_dedicated_cpu = 1; - in_purr = mfspr(SPRN_PURR); - - /* - * We come in with interrupts disabled, and need_resched() - * has been checked recently. If we should poll for a little - * while, do so. - */ - if (snooze) { - start_snooze = get_tb() + snooze * tb_ticks_per_usec; - local_irq_enable(); - set_thread_flag(TIF_POLLING_NRFLAG); - - while ((snooze < 0) || (get_tb() < start_snooze)) { - if (need_resched() || cpu_is_offline(cpu)) - goto out; - ppc64_runlatch_off(); - HMT_low(); - HMT_very_low(); - } - - HMT_medium(); - clear_thread_flag(TIF_POLLING_NRFLAG); - smp_mb(); - local_irq_disable(); - if (need_resched() || cpu_is_offline(cpu)) - goto out; - } - - cede_processor(); - -out: - HMT_medium(); - out_purr = mfspr(SPRN_PURR); - get_lppaca()->wait_state_cycles += out_purr - in_purr; - get_lppaca()->donate_dedicated_cpu = 0; - get_lppaca()->idle = 0; -} - -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; - - /* - * 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(); - - get_lppaca()->idle = 0; -} - static int pSeries_pci_probe_mode(struct pci_bus *bus) { if (firmware_has_feature(FW_FEATURE_LPAR)) diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 26e93fd4c62..bbc3c42f673 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -148,6 +148,7 @@ static void __devinit smp_xics_setup_cpu(int cpu) set_cpu_current_state(cpu, CPU_STATE_ONLINE); set_default_offline_state(cpu); #endif + pseries_notify_cpuidle_add_cpu(cpu); } static int __devinit smp_pSeries_kick_cpu(int nr) diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig index bd560c786ed..57d22a2f4ba 100644 --- a/arch/powerpc/platforms/wsp/Kconfig +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -1,20 +1,28 @@ config PPC_WSP bool select PPC_A2 + select GENERIC_TBSYNC + select PPC_ICSWX select PPC_SCOM select PPC_XICS select PPC_ICP_NATIVE select PCI select PPC_IO_WORKAROUNDS if PCI select PPC_INDIRECT_PIO if PCI + select PPC_WSP_COPRO default n menu "WSP platform selection" depends on PPC_BOOK3E_64 config PPC_PSR2 - bool "PSR-2 platform" - select GENERIC_TBSYNC + bool "PowerEN System Reference Platform 2" + select EPAPR_BOOT + select PPC_WSP + default y + +config PPC_CHROMA + bool "PowerEN PCIe Chroma Card" select EPAPR_BOOT select PPC_WSP default y diff --git a/arch/powerpc/platforms/wsp/Makefile b/arch/powerpc/platforms/wsp/Makefile index a1486b436f0..56817ac98fc 100644 --- a/arch/powerpc/platforms/wsp/Makefile +++ b/arch/powerpc/platforms/wsp/Makefile @@ -1,8 +1,10 @@ ccflags-y += -mno-minimal-toc -obj-y += setup.o ics.o -obj-$(CONFIG_PPC_PSR2) += psr2.o opb_pic.o +obj-y += setup.o ics.o wsp.o +obj-$(CONFIG_PPC_PSR2) += psr2.o +obj-$(CONFIG_PPC_CHROMA) += chroma.o h8.o +obj-$(CONFIG_PPC_WSP) += opb_pic.o obj-$(CONFIG_PPC_WSP) += scom_wsp.o obj-$(CONFIG_SMP) += smp.o scom_smp.o obj-$(CONFIG_PCI) += wsp_pci.o -obj-$(CONFIG_PCI_MSI) += msi.o
\ No newline at end of file +obj-$(CONFIG_PCI_MSI) += msi.o diff --git a/arch/powerpc/platforms/wsp/chroma.c b/arch/powerpc/platforms/wsp/chroma.c new file mode 100644 index 00000000000..ca6fa26f6e6 --- /dev/null +++ b/arch/powerpc/platforms/wsp/chroma.c @@ -0,0 +1,56 @@ +/* + * Copyright 2008-2011, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/of.h> +#include <linux/smp.h> +#include <linux/time.h> + +#include <asm/machdep.h> +#include <asm/system.h> +#include <asm/udbg.h> + +#include "ics.h" +#include "wsp.h" + +void __init chroma_setup_arch(void) +{ + wsp_setup_arch(); + wsp_setup_h8(); + +} + +static int __init chroma_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,wsp-chroma")) + return 0; + + return 1; +} + +define_machine(chroma_md) { + .name = "Chroma PCIe", + .probe = chroma_probe, + .setup_arch = chroma_setup_arch, + .restart = wsp_h8_restart, + .power_off = wsp_h8_power_off, + .halt = wsp_halt, + .calibrate_decr = generic_calibrate_decr, + .init_IRQ = wsp_setup_irq, + .progress = udbg_progress, + .power_save = book3e_idle, +}; + +machine_arch_initcall(chroma_md, wsp_probe_devices); diff --git a/arch/powerpc/platforms/wsp/h8.c b/arch/powerpc/platforms/wsp/h8.c new file mode 100644 index 00000000000..d18e6cc19df --- /dev/null +++ b/arch/powerpc/platforms/wsp/h8.c @@ -0,0 +1,134 @@ +/* + * Copyright 2008-2011, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/io.h> + +#include "wsp.h" + +/* + * The UART connection to the H8 is over ttyS1 which is just a 16550. + * We assume that FW has it setup right and no one messes with it. + */ + + +static u8 __iomem *h8; + +#define RBR 0 /* Receiver Buffer Register */ +#define THR 0 /* Transmitter Holding Register */ +#define LSR 5 /* Line Status Register */ +#define LSR_DR 0x01 /* LSR value for Data-Ready */ +#define LSR_THRE 0x20 /* LSR value for Transmitter-Holding-Register-Empty */ +static void wsp_h8_putc(int c) +{ + u8 lsr; + + do { + lsr = readb(h8 + LSR); + } while ((lsr & LSR_THRE) != LSR_THRE); + writeb(c, h8 + THR); +} + +static int wsp_h8_getc(void) +{ + u8 lsr; + + do { + lsr = readb(h8 + LSR); + } while ((lsr & LSR_DR) != LSR_DR); + + return readb(h8 + RBR); +} + +static void wsp_h8_puts(const char *s, int sz) +{ + int i; + + for (i = 0; i < sz; i++) { + wsp_h8_putc(s[i]); + + /* no flow control so wait for echo */ + wsp_h8_getc(); + } + wsp_h8_putc('\r'); + wsp_h8_putc('\n'); +} + +static void wsp_h8_terminal_cmd(const char *cmd, int sz) +{ + hard_irq_disable(); + wsp_h8_puts(cmd, sz); + /* should never return, but just in case */ + for (;;) + continue; +} + + +void wsp_h8_restart(char *cmd) +{ + static const char restart[] = "warm-reset"; + + (void)cmd; + wsp_h8_terminal_cmd(restart, sizeof(restart) - 1); +} + +void wsp_h8_power_off(void) +{ + static const char off[] = "power-off"; + + wsp_h8_terminal_cmd(off, sizeof(off) - 1); +} + +static void __iomem *wsp_h8_getaddr(void) +{ + struct device_node *aliases; + struct device_node *uart; + struct property *path; + void __iomem *va = NULL; + + /* + * there is nothing in the devtree to tell us which is mapped + * to the H8, but se know it is the second serial port. + */ + + aliases = of_find_node_by_path("/aliases"); + if (aliases == NULL) + return NULL; + + path = of_find_property(aliases, "serial1", NULL); + if (path == NULL) + goto out; + + uart = of_find_node_by_path(path->value); + if (uart == NULL) + goto out; + + va = of_iomap(uart, 0); + + /* remove it so no one messes with it */ + of_detach_node(uart); + of_node_put(uart); + +out: + of_node_put(aliases); + + return va; +} + +void __init wsp_setup_h8(void) +{ + h8 = wsp_h8_getaddr(); + + /* Devtree change? lets hard map it anyway */ + if (h8 == NULL) { + pr_warn("UART to H8 could not be found"); + h8 = ioremap(0xffc0008000ULL, 0x100); + } +} diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c index be05631a3c1..19f353dfcd0 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -320,7 +320,8 @@ void __init opb_pic_init(void) } /* Attach opb interrupt handler to new virtual IRQ */ - rc = request_irq(virq, opb_irq_handler, 0, "OPB LS Cascade", opb); + rc = request_irq(virq, opb_irq_handler, IRQF_NO_THREAD, + "OPB LS Cascade", opb); if (rc) { printk("opb: request_irq failed: %d\n", rc); continue; diff --git a/arch/powerpc/platforms/wsp/psr2.c b/arch/powerpc/platforms/wsp/psr2.c index 166f2e4b4be..0c1ae06d0be 100644 --- a/arch/powerpc/platforms/wsp/psr2.c +++ b/arch/powerpc/platforms/wsp/psr2.c @@ -14,10 +14,10 @@ #include <linux/mm.h> #include <linux/of.h> #include <linux/smp.h> +#include <linux/time.h> #include <asm/machdep.h> #include <asm/system.h> -#include <asm/time.h> #include <asm/udbg.h> #include "ics.h" @@ -27,7 +27,8 @@ static void psr2_spin(void) { hard_irq_disable(); - for (;;) ; + for (;;) + continue; } static void psr2_restart(char *cmd) @@ -35,65 +36,32 @@ static void psr2_restart(char *cmd) psr2_spin(); } -static int psr2_probe_devices(void) -{ - struct device_node *np; - - /* Our RTC is a ds1500. It seems to be programatically compatible - * with the ds1511 for which we have a driver so let's use that - */ - np = of_find_compatible_node(NULL, NULL, "dallas,ds1500"); - if (np != NULL) { - struct resource res; - if (of_address_to_resource(np, 0, &res) == 0) - platform_device_register_simple("ds1511", 0, &res, 1); - } - return 0; -} -machine_arch_initcall(psr2_md, psr2_probe_devices); - -static void __init psr2_setup_arch(void) -{ - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - scom_init_wsp(); - - /* Setup SMP callback */ -#ifdef CONFIG_SMP - a2_setup_smp(); -#endif -#ifdef CONFIG_PCI - wsp_setup_pci(); -#endif - -} - static int __init psr2_probe(void) { unsigned long root = of_get_flat_dt_root(); + if (of_flat_dt_is_compatible(root, "ibm,wsp-chroma")) { + /* chroma systems also claim they are psr2s */ + return 0; + } + if (!of_flat_dt_is_compatible(root, "ibm,psr2")) return 0; return 1; } -static void __init psr2_init_irq(void) -{ - wsp_init_irq(); - opb_pic_init(); -} - define_machine(psr2_md) { .name = "PSR2 A2", .probe = psr2_probe, - .setup_arch = psr2_setup_arch, + .setup_arch = wsp_setup_arch, .restart = psr2_restart, .power_off = psr2_spin, .halt = psr2_spin, .calibrate_decr = generic_calibrate_decr, - .init_IRQ = psr2_init_irq, + .init_IRQ = wsp_setup_irq, .progress = udbg_progress, .power_save = book3e_idle, }; + +machine_arch_initcall(psr2_md, wsp_probe_devices); diff --git a/arch/powerpc/platforms/wsp/wsp.c b/arch/powerpc/platforms/wsp/wsp.c new file mode 100644 index 00000000000..d25cc96c21b --- /dev/null +++ b/arch/powerpc/platforms/wsp/wsp.c @@ -0,0 +1,115 @@ +/* + * Copyright 2008-2011, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/smp.h> +#include <linux/delay.h> +#include <linux/time.h> + +#include <asm/scom.h> + +#include "wsp.h" +#include "ics.h" + +#define WSP_SOC_COMPATIBLE "ibm,wsp-soc" +#define PBIC_COMPATIBLE "ibm,wsp-pbic" +#define COPRO_COMPATIBLE "ibm,wsp-coprocessor" + +static int __init wsp_probe_buses(void) +{ + static __initdata struct of_device_id bus_ids[] = { + /* + * every node in between needs to be here or you won't + * find it + */ + { .compatible = WSP_SOC_COMPATIBLE, }, + { .compatible = PBIC_COMPATIBLE, }, + { .compatible = COPRO_COMPATIBLE, }, + {}, + }; + of_platform_bus_probe(NULL, bus_ids, NULL); + + return 0; +} + +void __init wsp_setup_arch(void) +{ + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + scom_init_wsp(); + + /* Setup SMP callback */ +#ifdef CONFIG_SMP + a2_setup_smp(); +#endif +#ifdef CONFIG_PCI + wsp_setup_pci(); +#endif +} + +void __init wsp_setup_irq(void) +{ + wsp_init_irq(); + opb_pic_init(); +} + + +int __init wsp_probe_devices(void) +{ + struct device_node *np; + + /* Our RTC is a ds1500. It seems to be programatically compatible + * with the ds1511 for which we have a driver so let's use that + */ + np = of_find_compatible_node(NULL, NULL, "dallas,ds1500"); + if (np != NULL) { + struct resource res; + if (of_address_to_resource(np, 0, &res) == 0) + platform_device_register_simple("ds1511", 0, &res, 1); + } + + wsp_probe_buses(); + + return 0; +} + +void wsp_halt(void) +{ + u64 val; + scom_map_t m; + struct device_node *dn; + struct device_node *mine; + struct device_node *me; + + me = of_get_cpu_node(smp_processor_id(), NULL); + mine = scom_find_parent(me); + + /* This will halt all the A2s but not power off the chip */ + for_each_node_with_property(dn, "scom-controller") { + if (dn == mine) + continue; + m = scom_map(dn, 0, 1); + + /* read-modify-write it so the HW probe does not get + * confused */ + val = scom_read(m, 0); + val |= 1; + scom_write(m, 0, val); + scom_unmap(m); + } + m = scom_map(mine, 0, 1); + val = scom_read(m, 0); + val |= 1; + scom_write(m, 0, val); + /* should never return */ + scom_unmap(m); +} diff --git a/arch/powerpc/platforms/wsp/wsp.h b/arch/powerpc/platforms/wsp/wsp.h index 33479818f62..10c1d1fff36 100644 --- a/arch/powerpc/platforms/wsp/wsp.h +++ b/arch/powerpc/platforms/wsp/wsp.h @@ -6,15 +6,25 @@ /* Devtree compatible strings for major devices */ #define PCIE_COMPATIBLE "ibm,wsp-pciex" +extern void wsp_setup_arch(void); +extern void wsp_setup_irq(void); +extern int wsp_probe_devices(void); +extern void wsp_halt(void); + extern void wsp_setup_pci(void); extern void scom_init_wsp(void); extern void a2_setup_smp(void); extern int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, struct device_node *np); -int smp_a2_cpu_bootable(unsigned int nr); -int __devinit smp_a2_kick_cpu(int nr); +extern int smp_a2_cpu_bootable(unsigned int nr); +extern int __devinit smp_a2_kick_cpu(int nr); + +extern void opb_pic_init(void); -void opb_pic_init(void); +/* chroma specific managment */ +extern void wsp_h8_restart(char *cmd); +extern void wsp_h8_power_off(void); +extern void __init wsp_setup_h8(void); #endif /* __WSP_H */ |