diff options
Diffstat (limited to 'arch/powerpc/platforms')
125 files changed, 3127 insertions, 1261 deletions
diff --git a/arch/powerpc/platforms/40x/ep405.c b/arch/powerpc/platforms/40x/ep405.c index 13d1345026d..ae2e7f67c18 100644 --- a/arch/powerpc/platforms/40x/ep405.c +++ b/arch/powerpc/platforms/40x/ep405.c @@ -29,6 +29,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> +#include <asm/ppc4xx.h> static struct device_node *bcsr_node; static void __iomem *bcsr_regs; @@ -119,5 +120,6 @@ define_machine(ep405) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/40x/kilauea.c b/arch/powerpc/platforms/40x/kilauea.c index f9206a7fede..1dd24ffc0dc 100644 --- a/arch/powerpc/platforms/40x/kilauea.c +++ b/arch/powerpc/platforms/40x/kilauea.c @@ -1,7 +1,7 @@ /* * Kilauea board specific routines * - * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de> + * Copyright 2007-2008 DENX Software Engineering, Stefan Roese <sr@denx.de> * * Based on the Walnut code by * Josh Boyer <jwboyer@linux.vnet.ibm.com> @@ -20,6 +20,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> +#include <asm/ppc4xx.h> static __initdata struct of_device_id kilauea_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -54,5 +55,6 @@ define_machine(kilauea) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/40x/makalu.c b/arch/powerpc/platforms/40x/makalu.c index 4e4df72fc9c..a6a1d6017b7 100644 --- a/arch/powerpc/platforms/40x/makalu.c +++ b/arch/powerpc/platforms/40x/makalu.c @@ -20,6 +20,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> +#include <asm/ppc4xx.h> static __initdata struct of_device_id makalu_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -54,5 +55,6 @@ define_machine(makalu) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c index 0422590040d..fc7fb001276 100644 --- a/arch/powerpc/platforms/40x/virtex.c +++ b/arch/powerpc/platforms/40x/virtex.c @@ -14,6 +14,7 @@ #include <asm/prom.h> #include <asm/time.h> #include <asm/xilinx_intc.h> +#include <asm/ppc4xx.h> static struct of_device_id xilinx_of_bus_ids[] __initdata = { { .compatible = "xlnx,plb-v46-1.00.a", }, @@ -48,5 +49,6 @@ define_machine(virtex) { .probe = virtex_probe, .init_IRQ = xilinx_intc_init_tree, .get_irq = xilinx_intc_get_irq, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c index b8b257efeb7..335df91fbee 100644 --- a/arch/powerpc/platforms/40x/walnut.c +++ b/arch/powerpc/platforms/40x/walnut.c @@ -26,6 +26,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> +#include <asm/ppc4xx.h> static __initdata struct of_device_id walnut_of_bus[] = { { .compatible = "ibm,plb3", }, @@ -61,5 +62,6 @@ define_machine(walnut) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .calibrate_decr = generic_calibrate_decr, + .restart = ppc4xx_reset_system, + .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/44x.h b/arch/powerpc/platforms/44x/44x.h index 42eabf87fea..dbc4d2b4301 100644 --- a/arch/powerpc/platforms/44x/44x.h +++ b/arch/powerpc/platforms/44x/44x.h @@ -3,6 +3,5 @@ extern u8 as1_readb(volatile u8 __iomem *addr); extern void as1_writeb(u8 data, volatile u8 __iomem *addr); -extern void ppc44x_reset_system(char *cmd); #endif /* __POWERPC_PLATFORMS_44X_44X_H */ diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 1bfb2191010..6abe91357ee 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -67,6 +67,25 @@ config WARP See http://www.pikatechnologies.com/ and follow the "PIKA for Computer Telephony Developers" link for more information. +config CANYONLANDS + bool "Canyonlands" + depends on 44x + default n + select 460EX + select PCI + select PPC4xx_PCI_EXPRESS + help + This option enables support for the AMCC PPC460EX evaluation board. + +config YOSEMITE + bool "Yosemite" + depends on 44x + default n + select 440EP + select PCI + help + This option enables support for the AMCC PPC440EP evaluation board. + #config LUAN # bool "Luan" # depends on 44x @@ -122,6 +141,14 @@ config 440SPe bool select IBM_NEW_EMAC_EMAC4 +config 460EX + bool + select PPC_FPU + select IBM_NEW_EMAC_EMAC4 + select IBM_NEW_EMAC_RGMII + select IBM_NEW_EMAC_ZMII + select IBM_NEW_EMAC_TAH + # 44x errata/workaround config symbols, selected by the CPU models above config IBM440EP_ERR42 bool diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 0864d4f1cbc..774165f9acd 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -1,9 +1,11 @@ -obj-$(CONFIG_44x) := misc_44x.o +obj-$(CONFIG_44x) := misc_44x.o idle.o obj-$(CONFIG_EBONY) += ebony.o obj-$(CONFIG_TAISHAN) += taishan.o obj-$(CONFIG_BAMBOO) += bamboo.o +obj-$(CONFIG_YOSEMITE) += bamboo.o obj-$(CONFIG_SEQUOIA) += sequoia.o obj-$(CONFIG_KATMAI) += katmai.o obj-$(CONFIG_RAINIER) += rainier.o obj-$(CONFIG_WARP) += warp.o obj-$(CONFIG_WARP) += warp-nand.o +obj-$(CONFIG_CANYONLANDS) += canyonlands.o diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c index fb9a22a7e8d..cef169e9515 100644 --- a/arch/powerpc/platforms/44x/bamboo.c +++ b/arch/powerpc/platforms/44x/bamboo.c @@ -22,8 +22,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> - -#include "44x.h" +#include <asm/ppc4xx.h> static __initdata struct of_device_id bamboo_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -53,11 +52,11 @@ static int __init bamboo_probe(void) } define_machine(bamboo) { - .name = "Bamboo", - .probe = bamboo_probe, - .progress = udbg_progress, - .init_IRQ = uic_init_tree, - .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .name = "Bamboo", + .probe = bamboo_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/canyonlands.c b/arch/powerpc/platforms/44x/canyonlands.c new file mode 100644 index 00000000000..3949289f51d --- /dev/null +++ b/arch/powerpc/platforms/44x/canyonlands.c @@ -0,0 +1,63 @@ +/* + * Canyonlands board specific routines + * + * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de> + * + * Based on the Katmai code by + * Benjamin Herrenschmidt <benh@kernel.crashing.org> + * Copyright 2007 IBM Corp. + * Josh Boyer <jwboyer@linux.vnet.ibm.com> + * Copyright 2007 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/of_platform.h> + +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/time.h> +#include <asm/uic.h> +#include <asm/pci-bridge.h> +#include <asm/ppc4xx.h> + +static __initdata struct of_device_id canyonlands_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init canyonlands_device_probe(void) +{ + of_platform_bus_probe(NULL, canyonlands_of_bus, NULL); + + return 0; +} +machine_device_initcall(canyonlands, canyonlands_device_probe); + +static int __init canyonlands_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "amcc,canyonlands")) + return 0; + + ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + + return 1; +} + +define_machine(canyonlands) { + .name = "Canyonlands", + .probe = canyonlands_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc4xx_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c index 1a8d467bff8..a0e8fe4662f 100644 --- a/arch/powerpc/platforms/44x/ebony.c +++ b/arch/powerpc/platforms/44x/ebony.c @@ -26,8 +26,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> - -#include "44x.h" +#include <asm/ppc4xx.h> static __initdata struct of_device_id ebony_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -66,6 +65,6 @@ define_machine(ebony) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/idle.c b/arch/powerpc/platforms/44x/idle.c new file mode 100644 index 00000000000..7a81f921fef --- /dev/null +++ b/arch/powerpc/platforms/44x/idle.c @@ -0,0 +1,67 @@ +/* + * Copyright 2008 IBM Corp. + * + * Based on arch/powerpc/platforms/pasemi/idle.c: + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Added by: Jerone Young <jyoung5@us.ibm.com> + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/of.h> +#include <linux/kernel.h> +#include <asm/machdep.h> + +static int mode_spin; + +static void ppc44x_idle(void) +{ + unsigned long msr_save; + + msr_save = mfmsr(); + /* set wait state MSR */ + mtmsr(msr_save|MSR_WE|MSR_EE|MSR_CE|MSR_DE); + isync(); + /* return to initial state */ + mtmsr(msr_save); + isync(); +} + +int __init ppc44x_idle_init(void) +{ + if (!mode_spin) { + /* If we are not setting spin mode + then we set to wait mode */ + ppc_md.power_save = &ppc44x_idle; + } + + return 0; +} + +arch_initcall(ppc44x_idle_init); + +static int __init idle_param(char *p) +{ + + if (!strcmp("spin", p)) { + mode_spin = 1; + ppc_md.power_save = NULL; + } + + return 0; +} + +early_param("idle", idle_param); diff --git a/arch/powerpc/platforms/44x/katmai.c b/arch/powerpc/platforms/44x/katmai.c index 11134121f27..44f4b3a00ce 100644 --- a/arch/powerpc/platforms/44x/katmai.c +++ b/arch/powerpc/platforms/44x/katmai.c @@ -22,8 +22,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> - -#include "44x.h" +#include <asm/ppc4xx.h> static __initdata struct of_device_id katmai_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -58,6 +57,6 @@ define_machine(katmai) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/misc_44x.S b/arch/powerpc/platforms/44x/misc_44x.S index 3bce71d5d75..dc12b8009e4 100644 --- a/arch/powerpc/platforms/44x/misc_44x.S +++ b/arch/powerpc/platforms/44x/misc_44x.S @@ -44,14 +44,3 @@ _GLOBAL(as1_writeb) sync isync blr - -/* - * void ppc44x_reset_system(char *cmd) - * - * At present, this routine just applies a system reset. - */ -_GLOBAL(ppc44x_reset_system) - mfspr r13,SPRN_DBCR0 - oris r13,r13,DBCR0_RST_SYSTEM@h - mtspr SPRN_DBCR0,r13 - b . /* Just in case the reset doesn't work */ diff --git a/arch/powerpc/platforms/44x/rainier.c b/arch/powerpc/platforms/44x/rainier.c index a7fae1cf69c..4f1ff84c4b6 100644 --- a/arch/powerpc/platforms/44x/rainier.c +++ b/arch/powerpc/platforms/44x/rainier.c @@ -22,7 +22,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> -#include "44x.h" +#include <asm/ppc4xx.h> static __initdata struct of_device_id rainier_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -57,6 +57,6 @@ define_machine(rainier) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c index d279db42c89..49eb73daacd 100644 --- a/arch/powerpc/platforms/44x/sequoia.c +++ b/arch/powerpc/platforms/44x/sequoia.c @@ -23,7 +23,7 @@ #include <asm/uic.h> #include <asm/pci-bridge.h> -#include "44x.h" +#include <asm/ppc4xx.h> static __initdata struct of_device_id sequoia_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -58,6 +58,6 @@ define_machine(sequoia) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/taishan.c b/arch/powerpc/platforms/44x/taishan.c index 28ab7e2e02c..49c78b2098b 100644 --- a/arch/powerpc/platforms/44x/taishan.c +++ b/arch/powerpc/platforms/44x/taishan.c @@ -29,8 +29,7 @@ #include <asm/time.h> #include <asm/uic.h> #include <asm/pci-bridge.h> - -#include "44x.h" +#include <asm/ppc4xx.h> static __initdata struct of_device_id taishan_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -68,6 +67,6 @@ define_machine(taishan) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/warp-nand.c b/arch/powerpc/platforms/44x/warp-nand.c index 84ab78ff8c0..9150318cfc5 100644 --- a/arch/powerpc/platforms/44x/warp-nand.c +++ b/arch/powerpc/platforms/44x/warp-nand.c @@ -11,6 +11,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/nand.h> #include <linux/mtd/ndfc.h> +#include <asm/machdep.h> #ifdef CONFIG_MTD_NAND_NDFC @@ -100,6 +101,6 @@ static int warp_setup_nand_flash(void) return 0; } -device_initcall(warp_setup_nand_flash); +machine_device_initcall(warp, warp_setup_nand_flash); #endif diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index da5b7b7599d..39cf6150a72 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -18,9 +18,7 @@ #include <asm/udbg.h> #include <asm/time.h> #include <asm/uic.h> - -#include "44x.h" - +#include <asm/ppc4xx.h> static __initdata struct of_device_id warp_of_bus[] = { { .compatible = "ibm,plb4", }, @@ -49,7 +47,7 @@ define_machine(warp) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 956f459e175..6d584f4e3c9 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -63,7 +63,7 @@ lite5200_fix_clock_config(void) of_node_put(np); if (!cdm) { printk(KERN_ERR "%s() failed; expect abnormal behaviour\n", - __FUNCTION__); + __func__); return; } @@ -98,7 +98,7 @@ lite5200_fix_port_config(void) of_node_put(np); if (!gpio) { printk(KERN_ERR "%s() failed. expect abnormal behavior\n", - __FUNCTION__); + __func__); return; } diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 4fad6c7bf9f..917ac889155 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -11,7 +11,6 @@ config MPC8272_ADS select 8260 select FSL_SOC select PQ2_ADS_PCI_PIC if PCI - select PPC_CPM_NEW_BINDING help This option enables support for the MPC8272 ADS board @@ -22,7 +21,6 @@ config PQ2FADS select 8260 select FSL_SOC select PQ2_ADS_PCI_PIC if PCI - select PPC_CPM_NEW_BINDING help This option enables support for the PQ2FADS board @@ -31,7 +29,6 @@ config EP8248E select 8272 select 8260 select FSL_SOC - select PPC_CPM_NEW_BINDING select MDIO_BITBANG help This enables support for the Embedded Planet EP8248E board. diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index ba93d8ae9b0..d5770fdf7f0 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -138,7 +138,7 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, bus->name = "ep8248e-mdio-bitbang"; bus->dev = &ofdev->dev; - bus->id = res.start; + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); return mdiobus_register(bus); } diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 2293ae51383..c00356bdb1d 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -46,6 +46,7 @@ static void __init mpc837x_rdb_setup_arch(void) static struct of_device_id mpc837x_ids[] = { { .type = "soc", }, { .compatible = "soc", }, + { .compatible = "simple-bus", }, {}, }; diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 68065e62fc3..88a3b5cabb1 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -16,6 +16,7 @@ #define MPC83XX_SCCR_USB_DRCM_10 0x00200000 #define MPC8315_SCCR_USB_MASK 0x00c00000 #define MPC8315_SCCR_USB_DRCM_11 0x00c00000 +#define MPC8315_SCCR_USB_DRCM_01 0x00400000 #define MPC837X_SCCR_USB_DRCM_11 0x00c00000 /* system i/o configuration register low */ @@ -37,6 +38,7 @@ /* USB Control Register */ #define FSL_USB2_CONTROL_OFFS 0x500 #define CONTROL_UTMI_PHY_EN 0x00000200 +#define CONTROL_REFSEL_24MHZ 0x00000040 #define CONTROL_REFSEL_48MHZ 0x00000080 #define CONTROL_PHY_CLK_SEL_ULPI 0x00000400 #define CONTROL_OTG_PORT 0x00000020 diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index 471fdd8f410..64bcf0a33c7 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c @@ -129,7 +129,7 @@ int mpc831x_usb_cfg(void) if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, MPC8315_SCCR_USB_MASK, - MPC8315_SCCR_USB_DRCM_11); + MPC8315_SCCR_USB_DRCM_01); else clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, MPC83XX_SCCR_USB_MASK, @@ -164,9 +164,15 @@ int mpc831x_usb_cfg(void) /* Using on-chip PHY */ if (prop && (!strcmp(prop, "utmi_wide") || !strcmp(prop, "utmi"))) { - /* Set UTMI_PHY_EN, REFSEL to 48MHZ */ + u32 refsel; + + if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) + refsel = CONTROL_REFSEL_24MHZ; + else + refsel = CONTROL_REFSEL_48MHZ; + /* Set UTMI_PHY_EN and REFSEL */ out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, - CONTROL_UTMI_PHY_EN | CONTROL_REFSEL_48MHZ); + CONTROL_UTMI_PHY_EN | refsel); /* Using external UPLI PHY */ } else if (prop && !strcmp(prop, "ulpi")) { /* Set PHY_CLK_SEL to ULPI */ diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 7e76ddbd582..7ff29d53dc2 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -19,7 +19,6 @@ config MPC8540_ADS config MPC8560_ADS bool "Freescale MPC8560 ADS" select DEFAULT_UIMAGE - select PPC_CPM_NEW_BINDING select CPM2 help This option enables support for the MPC 8560 ADS board @@ -46,6 +45,12 @@ config MPC85xx_DS help This option enables support for the MPC85xx DS (MPC8544 DS) board +config KSI8560 + bool "Emerson KSI8560" + select DEFAULT_UIMAGE + help + This option enables support for the Emerson KSI8560 board + config STX_GP3 bool "Silicon Turnkey Express GP3" help @@ -53,14 +58,12 @@ config STX_GP3 board. select CPM2 select DEFAULT_UIMAGE - select PPC_CPM_NEW_BINDING config TQM8540 bool "TQ Components TQM8540" help This option enables support for the TQ Components TQM8540 board. select DEFAULT_UIMAGE - select PPC_CPM_NEW_BINDING select TQM85xx config TQM8541 @@ -68,7 +71,6 @@ config TQM8541 help This option enables support for the TQ Components TQM8541 board. select DEFAULT_UIMAGE - select PPC_CPM_NEW_BINDING select TQM85xx select CPM2 @@ -77,7 +79,6 @@ config TQM8555 help This option enables support for the TQ Components TQM8555 board. select DEFAULT_UIMAGE - select PPC_CPM_NEW_BINDING select TQM85xx select CPM2 @@ -86,7 +87,6 @@ config TQM8560 help This option enables support for the TQ Components TQM8560 board. select DEFAULT_UIMAGE - select PPC_CPM_NEW_BINDING select TQM85xx select CPM2 @@ -99,7 +99,6 @@ config SBC8548 config SBC8560 bool "Wind River SBC8560" select DEFAULT_UIMAGE - select PPC_CPM_NEW_BINDING if CPM2 help This option enables support for the Wind River SBC8560 board diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index cb7af4ebd75..6cea185f62b 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_STX_GP3) += stx_gp3.o obj-$(CONFIG_TQM85xx) += tqm85xx.o obj-$(CONFIG_SBC8560) += sbc8560.o obj-$(CONFIG_SBC8548) += sbc8548.o +obj-$(CONFIG_KSI8560) += ksi8560.o diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c new file mode 100644 index 00000000000..2145adeb220 --- /dev/null +++ b/arch/powerpc/platforms/85xx/ksi8560.c @@ -0,0 +1,257 @@ +/* + * Board setup routines for the Emerson KSI8560 + * + * Author: Alexandr Smirnov <asmirnov@ru.mvista.com> + * + * Based on mpc85xx_ads.c maintained by Kumar Gala + * + * 2008 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> + +#include <asm/system.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/mpic.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> +#include <asm/prom.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> + +#include <asm/cpm2.h> +#include <sysdev/cpm2_pic.h> + + +#define KSI8560_CPLD_HVR 0x04 /* Hardware Version Register */ +#define KSI8560_CPLD_PVR 0x08 /* PLD Version Register */ +#define KSI8560_CPLD_RCR1 0x30 /* Reset Command Register 1 */ + +#define KSI8560_CPLD_RCR1_CPUHR 0x80 /* CPU Hard Reset */ + +static void __iomem *cpld_base = NULL; + +static void machine_restart(char *cmd) +{ + if (cpld_base) + out_8(cpld_base + KSI8560_CPLD_RCR1, KSI8560_CPLD_RCR1_CPUHR); + else + printk(KERN_ERR "Can't find CPLD base, hang forever\n"); + + for (;;); +} + +static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) +{ + int cascade_irq; + + while ((cascade_irq = cpm2_get_irq()) >= 0) + generic_handle_irq(cascade_irq); + + desc->chip->eoi(irq); +} + +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, + 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); + set_irq_chained_handler(irq, cpm2_cascade); + + setup_irq(0, NULL); +#endif +} + +#ifdef CONFIG_CPM2 +/* + * Setup I/O ports + */ +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin __initdata ksi8560_pins[] = { + /* SCC1 */ + {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* SCC2 */ + {3, 26, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC1 */ + {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {2, 23, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK9 */ + {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK10 */ + +}; + +static void __init init_ioports(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ksi8560_pins); i++) { + struct cpm_pin *pin = &ksi8560_pins[i]; + cpm2_set_pin(pin->port, pin->pin, pin->flags); + } + + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK9, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); +} +#endif + +/* + * Setup the architecture + */ +static void __init ksi8560_setup_arch(void) +{ + struct device_node *cpld; + + cpld = of_find_compatible_node(NULL, NULL, "emerson,KSI8560-cpld"); + if (cpld) + cpld_base = of_iomap(cpld, 0); + else + printk(KERN_ERR "Can't find CPLD in device tree\n"); + + if (ppc_md.progress) + ppc_md.progress("ksi8560_setup_arch()", 0); + +#ifdef CONFIG_CPM2 + cpm2_reset(); + init_ioports(); +#endif +} + +static void ksi8560_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Emerson Network Power\n"); + seq_printf(m, "Board\t\t: KSI8560\n"); + + if (cpld_base) { + seq_printf(m, "Hardware rev\t: %d\n", + in_8(cpld_base + KSI8560_CPLD_HVR)); + seq_printf(m, "CPLD rev\t: %d\n", + in_8(cpld_base + KSI8560_CPLD_PVR)); + } else + seq_printf(m, "Unknown Hardware and CPLD revs\n"); + + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .type = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +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); + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init ksi8560_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "emerson,KSI8560"); +} + +define_machine(ksi8560) { + .name = "KSI8560", + .probe = ksi8560_probe, + .setup_arch = ksi8560_setup_arch, + .init_IRQ = ksi8560_pic_init, + .show_cpuinfo = ksi8560_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = machine_restart, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 4e030509611..3582c841844 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -165,7 +165,7 @@ static void __init init_ioports(void) int i; for (i = 0; i < ARRAY_SIZE(mpc8560_ads_pins); i++) { - struct cpm_pin *pin = &mpc8560_ads_pins[i]; + const struct cpm_pin *pin = &mpc8560_ads_pins[i]; cpm2_set_pin(pin->port, pin->pin, pin->flags); } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index bdb3d0b38cd..dfd8b4ad9b2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/seq_file.h> #include <linux/interrupt.h> +#include <linux/of_platform.h> #include <asm/system.h> #include <asm/time.h> @@ -36,7 +37,7 @@ #undef DEBUG #ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) #else #define DBG(fmt, args...) #endif @@ -183,6 +184,18 @@ static int __init mpc8544_ds_probe(void) } } +static struct of_device_id mpc85xxds_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + {}, +}; + +static int __init mpc85xxds_publish_devices(void) +{ + return of_platform_bus_probe(NULL, mpc85xxds_ids, NULL); +} +machine_device_initcall(mpc8544_ds, mpc85xxds_publish_devices); + /* * Called very early, device-tree isn't unflattened */ diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 21d113536b8..7442c58d44f 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -11,6 +11,12 @@ config MPC8641_HPCN help This option enables support for the MPC8641 HPCN board. +config SBC8641D + bool "Wind River SBC8641D" + select DEFAULT_UIMAGE + help + This option enables support for the WRS SBC8641D board. + config MPC8610_HPCD bool "Freescale MPC8610 HPCD" select DEFAULT_UIMAGE @@ -24,7 +30,7 @@ config MPC8641 select FSL_PCI if PCI select PPC_UDBG_16550 select MPIC - default y if MPC8641_HPCN + default y if MPC8641_HPCN || SBC8641D config MPC8610 bool diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index c96706327ea..1b9b4a9b252 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o +obj-$(CONFIG_SBC8641D) += sbc8641d.o obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 0b07485641f..5e1e8cf14e7 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -3,11 +3,12 @@ * * Initial author: Xianghua Xiao <x.xiao@freescale.com> * Recode: Jason Jin <jason.jin@freescale.com> + * York Sun <yorksun@freescale.com> * * Rewrite the interrupt routing. remove the 8259PIC support, * All the integrated device in ULI use sideband interrupt. * - * Copyright 2007 Freescale Semiconductor Inc. + * Copyright 2008 Freescale Semiconductor Inc. * * 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 @@ -38,6 +39,8 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +static unsigned char *pixis_bdcfg0, *pixis_arch; + static struct of_device_id __initdata mpc8610_ids[] = { { .compatible = "fsl,mpc8610-immr", }, {} @@ -52,8 +55,7 @@ static int __init mpc8610_declare_of_platform_devices(void) } machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); -void __init -mpc86xx_hpcd_init_irq(void) +static void __init mpc86xx_hpcd_init_irq(void) { struct mpic *mpic1; struct device_node *np; @@ -161,12 +163,159 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288); #endif /* CONFIG_PCI */ -static void __init -mpc86xx_hpcd_setup_arch(void) +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + +static u32 get_busfreq(void) { -#ifdef CONFIG_PCI - struct device_node *np; + struct device_node *node; + + u32 fs_busfreq = 0; + node = of_find_node_by_type(NULL, "cpu"); + if (node) { + unsigned int size; + const unsigned int *prop = + of_get_property(node, "bus-frequency", &size); + if (prop) + fs_busfreq = *prop; + of_node_put(node); + }; + return fs_busfreq; +} + +unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, + int monitor_port) +{ + static const unsigned long pixelformat[][3] = { + {0x88882317, 0x88083218, 0x65052119}, + {0x88883316, 0x88082219, 0x65053118}, + }; + unsigned int pix_fmt, arch_monitor; + + arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1; + /* DVI port for board version 0x01 */ + + if (bits_per_pixel == 32) + pix_fmt = pixelformat[arch_monitor][0]; + else if (bits_per_pixel == 24) + pix_fmt = pixelformat[arch_monitor][1]; + else if (bits_per_pixel == 16) + pix_fmt = pixelformat[arch_monitor][2]; + else + pix_fmt = pixelformat[1][0]; + + return pix_fmt; +} + +void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base) +{ + int i; + if (monitor_port == 2) { /* dual link LVDS */ + for (i = 0; i < 256*3; i++) + gamma_table_base[i] = (gamma_table_base[i] << 2) | + ((gamma_table_base[i] >> 6) & 0x03); + } +} + +void mpc8610hpcd_set_monitor_port(int monitor_port) +{ + static const u8 bdcfg[] = {0xBD, 0xB5, 0xA5}; + if (monitor_port < 3) + *pixis_bdcfg0 = bdcfg[monitor_port]; +} + +void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) +{ + u32 __iomem *clkdvdr; + u32 temp; + /* variables for pixel clock calcs */ + ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock; + ulong pixval; + long err; + int i; + + clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32)); + if (!clkdvdr) { + printk(KERN_ERR "Err: can't map clock divider register!\n"); + return; + } + + /* Pixel Clock configuration */ + pr_debug("DIU: Bus Frequency = %d\n", get_busfreq()); + speed_ccb = get_busfreq(); + + /* Calculate the pixel clock with the smallest error */ + /* calculate the following in steps to avoid overflow */ + pr_debug("DIU pixclock in ps - %d\n", pixclock); + temp = 1000000000/pixclock; + temp *= 1000; + pixclock = temp; + pr_debug("DIU pixclock freq - %u\n", pixclock); + + temp = pixclock * 5 / 100; + pr_debug("deviation = %d\n", temp); + minpixclock = pixclock - temp; + maxpixclock = pixclock + temp; + pr_debug("DIU minpixclock - %lu\n", minpixclock); + pr_debug("DIU maxpixclock - %lu\n", maxpixclock); + pixval = speed_ccb/pixclock; + pr_debug("DIU pixval = %lu\n", pixval); + + err = 100000000; + bestval = pixval; + pr_debug("DIU bestval = %lu\n", bestval); + + bestfreq = 0; + for (i = -1; i <= 1; i++) { + temp = speed_ccb / ((pixval+i) + 1); + pr_debug("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n", + i, pixval, temp); + if ((temp < minpixclock) || (temp > maxpixclock)) + pr_debug("DIU exceeds monitor range (%lu to %lu)\n", + minpixclock, maxpixclock); + else if (abs(temp - pixclock) < err) { + pr_debug("Entered the else if block %d\n", i); + err = abs(temp - pixclock); + bestval = pixval+i; + bestfreq = temp; + } + } + + pr_debug("DIU chose = %lx\n", bestval); + pr_debug("DIU error = %ld\n NomPixClk ", err); + pr_debug("DIU: Best Freq = %lx\n", bestfreq); + /* Modify PXCLK in GUTS CLKDVDR */ + pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr)); + temp = (*clkdvdr) & 0x2000FFFF; + *clkdvdr = temp; /* turn off clock */ + *clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16); + pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr)); + iounmap(clkdvdr); +} + +ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf) +{ + return snprintf(buf, PAGE_SIZE, + "%c0 - DVI\n" + "%c1 - Single link LVDS\n" + "%c2 - Dual link LVDS\n", + monitor_port == 0 ? '*' : ' ', + monitor_port == 1 ? '*' : ' ', + monitor_port == 2 ? '*' : ' '); +} + +int mpc8610hpcd_set_sysfs_monitor_port(int val) +{ + return val < 3 ? val : 0; +} + #endif + +static void __init mpc86xx_hpcd_setup_arch(void) +{ + struct resource r; + struct device_node *np; + unsigned char *pixis; + if (ppc_md.progress) ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); @@ -183,6 +332,30 @@ mpc86xx_hpcd_setup_arch(void) } } #endif +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + preallocate_diu_videomemory(); + diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format; + diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; + diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port; + diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock; + diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port; + diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port; +#endif + + np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); + if (np) { + of_address_to_resource(np, 0, &r); + of_node_put(np); + pixis = ioremap(r.start, 32); + if (!pixis) { + printk(KERN_ERR "Err: can't map FPGA cfg register!\n"); + return; + } + pixis_bdcfg0 = pixis + 8; + pixis_arch = pixis + 1; + } else + printk(KERN_ERR "Err: " + "can't find device node 'fsl,fpga-pixis'\n"); printk("MPC86xx HPCD board from Freescale Semiconductor\n"); } @@ -200,8 +373,7 @@ static int __init mpc86xx_hpcd_probe(void) return 0; } -long __init -mpc86xx_time_init(void) +static long __init mpc86xx_time_init(void) { unsigned int temp; diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index cfbe8c52e26..f947f555fd4 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -55,7 +55,7 @@ static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) } #endif /* CONFIG_PCI */ -void __init +static void __init mpc86xx_hpcn_init_irq(void) { struct mpic *mpic1; @@ -162,7 +162,7 @@ mpc86xx_hpcn_setup_arch(void) } -void +static void mpc86xx_hpcn_show_cpuinfo(struct seq_file *m) { struct device_node *root; @@ -190,13 +190,19 @@ static int __init mpc86xx_hpcn_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (of_flat_dt_is_compatible(root, "mpc86xx")) + if (of_flat_dt_is_compatible(root, "fsl,mpc8641hpcn")) return 1; /* Looks good */ + /* Be nice and don't give silent boot death. Delete this in 2.6.27 */ + if (of_flat_dt_is_compatible(root, "mpc86xx")) { + pr_warning("WARNING: your dts/dtb is old. You must update before the next kernel release\n"); + return 1; + } + return 0; } -long __init +static long __init mpc86xx_time_init(void) { unsigned int temp; diff --git a/arch/powerpc/platforms/86xx/sbc8641d.c b/arch/powerpc/platforms/86xx/sbc8641d.c new file mode 100644 index 00000000000..510a06ef0b5 --- /dev/null +++ b/arch/powerpc/platforms/86xx/sbc8641d.c @@ -0,0 +1,164 @@ +/* + * SBC8641D board specific routines + * + * Copyright 2008 Wind River Systems Inc. + * + * By Paul Gortmaker (see MAINTAINERS for contact information) + * + * Based largely on the 8641 HPCN support by Freescale Semiconductor Inc. + * + * 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/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> + +#include <asm/system.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/mpc86xx.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#include <asm/mpic.h> + +#include <sysdev/fsl_pci.h> +#include <sysdev/fsl_soc.h> + +#include "mpc86xx.h" + +static void __init +sbc8641_init_irq(void) +{ + struct mpic *mpic1; + struct device_node *np; + struct resource res; + + /* Determine PIC address. */ + np = of_find_node_by_type(NULL, "open-pic"); + if (np == NULL) + return; + of_address_to_resource(np, 0, &res); + + /* Alloc mpic structure and per isu has 16 INT entries. */ + mpic1 = mpic_alloc(np, res.start, + MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + 0, 256, " MPIC "); + of_node_put(np); + BUG_ON(mpic1 == NULL); + + mpic_init(mpic1); +} + +static void __init +sbc8641_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("sbc8641_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") + fsl_add_bridge(np, 0); +#endif + + printk("SBC8641 board from Wind River\n"); + +#ifdef CONFIG_SMP + mpc86xx_smp_init(); +#endif +} + + +static void +sbc8641_show_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + uint memsize = total_memory; + const char *model = ""; + uint svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Wind River Systems\n"); + + root = of_find_node_by_path("/"); + if (root) + model = of_get_property(root, "model", NULL); + seq_printf(m, "Machine\t\t: %s\n", model); + of_node_put(root); + + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); +} + + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init sbc8641_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "wind,sbc8641")) + return 1; /* Looks good */ + + return 0; +} + +static long __init +mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +static __initdata struct of_device_id of_bus_ids[] = { + { .compatible = "simple-bus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +machine_device_initcall(sbc8641, declare_of_platform_devices); + +define_machine(sbc8641) { + .name = "SBC8641D", + .probe = sbc8641_probe, + .setup_arch = sbc8641_setup_arch, + .init_IRQ = sbc8641_init_irq, + .show_cpuinfo = sbc8641_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +}; diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 7fd224ca233..6fc849e51e4 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -18,7 +18,6 @@ config MPC8XXFADS config MPC86XADS bool "MPC86XADS" select CPM1 - select PPC_CPM_NEW_BINDING help MPC86x Application Development System by Freescale Semiconductor. The MPC86xADS is meant to serve as a platform for s/w and h/w @@ -27,7 +26,6 @@ config MPC86XADS config MPC885ADS bool "MPC885ADS" select CPM1 - select PPC_CPM_NEW_BINDING help Freescale Semiconductor MPC885 Application Development System (ADS). Also known as DUET. @@ -37,7 +35,6 @@ config MPC885ADS config PPC_EP88XC bool "Embedded Planet EP88xC (a.k.a. CWH-PPC-885XN-VE)" select CPM1 - select PPC_CPM_NEW_BINDING help This enables support for the Embedded Planet EP88xC board. @@ -47,7 +44,6 @@ config PPC_EP88XC config PPC_ADDER875 bool "Analogue & Micro Adder 875" select CPM1 - select PPC_CPM_NEW_BINDING select REDBOOT help This enables support for the Analogue & Micro Adder 875 diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 184f998d1be..0d9f75c74f8 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -111,17 +111,12 @@ void __init mpc8xx_calibrate_decr(void) /* Processor frequency is MHz. */ - ppc_tb_freq = 50000000; - if (!get_freq("bus-frequency", &ppc_tb_freq)) { - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - } - ppc_tb_freq /= 16; ppc_proc_freq = 50000000; if (!get_freq("clock-frequency", &ppc_proc_freq)) printk(KERN_ERR "WARNING: Estimating processor frequency " "(not found)\n"); + ppc_tb_freq = ppc_proc_freq / 16; printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); /* Perform some more timer/timebase initialization. This used diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index a578b966ecb..87454c52697 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -45,7 +45,6 @@ source "arch/powerpc/platforms/powermac/Kconfig" source "arch/powerpc/platforms/prep/Kconfig" source "arch/powerpc/platforms/maple/Kconfig" source "arch/powerpc/platforms/pasemi/Kconfig" -source "arch/powerpc/platforms/celleb/Kconfig" source "arch/powerpc/platforms/ps3/Kconfig" source "arch/powerpc/platforms/cell/Kconfig" source "arch/powerpc/platforms/8xx/Kconfig" @@ -290,13 +289,7 @@ config CPM2 config PPC_CPM_NEW_BINDING bool depends on CPM1 || CPM2 - help - Select this if your board has been converted to use the new - device tree bindings for CPM, and no longer needs the - ioport callbacks or the platform device glue code. - - The fs_enet and cpm_uart drivers will be built as - of_platform devices. + default y config AXON_RAM tristate "Axon DDR2 memory device driver" diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 0c3face0ddb..f7efaa925a1 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -41,11 +41,13 @@ config 40x bool "AMCC 40x" select PPC_DCR_NATIVE select PPC_UDBG_16550 + select 4xx_SOC config 44x bool "AMCC 44x" select PPC_DCR_NATIVE select PPC_UDBG_16550 + select 4xx_SOC config E200 bool "Freescale e200" @@ -218,8 +220,8 @@ config SMP If you don't know what to do here, say N. config NR_CPUS - int "Maximum number of CPUs (2-128)" - range 2 128 + int "Maximum number of CPUs (2-1024)" + range 2 1024 depends on SMP default "32" if PPC64 default "4" diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index a984894466d..423a0234dc3 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -24,5 +24,4 @@ obj-$(CONFIG_PPC_MAPLE) += maple/ obj-$(CONFIG_PPC_PASEMI) += pasemi/ obj-$(CONFIG_PPC_CELL) += cell/ obj-$(CONFIG_PPC_PS3) += ps3/ -obj-$(CONFIG_PPC_CELLEB) += celleb/ obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 2f169991896..3959fcfe731 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -25,6 +25,19 @@ config PPC_IBM_CELL_BLADE select PPC_UDBG_16550 select UDBG_RTAS_CONSOLE +config PPC_CELLEB + bool "Toshiba's Cell Reference Set 'Celleb' Architecture" + depends on PPC_MULTIPLATFORM && PPC64 + select PPC_CELL + select PPC_CELL_NATIVE + select PPC_RTAS + select PPC_INDIRECT_IO + select PPC_OF_PLATFORM_PCI + select HAS_TXX9_SERIAL + select PPC_UDBG_BEAT + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_EHCI_BIG_ENDIAN_MMIO + menu "Cell Broadband Engine options" depends on PPC_CELL diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index c89964c6fb1..c2a7e4e5ddf 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \ cbe_regs.o spider-pic.o \ - pervasive.o pmu.o io-workarounds.o + pervasive.o pmu.o io-workarounds.o \ + spider-pci.o obj-$(CONFIG_CBE_RAS) += ras.o obj-$(CONFIG_CBE_THERM) += cbe_thermal.o @@ -26,3 +27,20 @@ obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ spufs/ obj-$(CONFIG_PCI_MSI) += axon_msi.o + + +# celleb stuff +ifeq ($(CONFIG_PPC_CELLEB),y) +obj-y += celleb_setup.o \ + celleb_pci.o celleb_scc_epci.o \ + celleb_scc_pciex.o \ + celleb_scc_uhc.o \ + io-workarounds.o spider-pci.o \ + beat.o beat_htab.o beat_hvCall.o \ + beat_interrupt.o beat_iommu.o + +obj-$(CONFIG_SMP) += beat_smp.o +obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o +obj-$(CONFIG_SERIAL_TXX9) += celleb_scc_sio.o +obj-$(CONFIG_SPU_BASE) += beat_spu_priv1.o +endif diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index d95e71dee91..c39f5c225f2 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -123,7 +123,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) return NULL; } - for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) { + for (; dn; dn = of_get_next_parent(dn)) { ph = of_get_property(dn, "msi-translator", NULL); if (ph) break; @@ -169,7 +169,7 @@ static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type) static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) { - struct device_node *dn, *tmp; + struct device_node *dn; struct msi_desc *entry; int len; const u32 *prop; @@ -182,7 +182,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) entry = list_first_entry(&dev->msi_list, struct msi_desc, list); - for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) { + for (; dn; dn = of_get_next_parent(dn)) { if (entry->msi_attrib.is_64) { prop = of_get_property(dn, "msi-address-64", &len); if (prop) diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/cell/beat.c index 93ebb7d8512..48c690ea65d 100644 --- a/arch/powerpc/platforms/celleb/beat.c +++ b/arch/powerpc/platforms/cell/beat.c @@ -33,7 +33,7 @@ #include "beat_wrapper.h" #include "beat.h" -#include "interrupt.h" +#include "beat_interrupt.h" static int beat_pm_poweroff_flag; @@ -48,6 +48,7 @@ void beat_power_off(void) } u64 beat_halt_code = 0x1000000000000000UL; +EXPORT_SYMBOL(beat_halt_code); void beat_halt(void) { @@ -94,9 +95,8 @@ ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index) len = count; if (len > BEAT_NVRW_CNT) len = BEAT_NVRW_CNT; - if (beat_eeprom_read(i, len, p)) { + if (beat_eeprom_read(i, len, p)) return -EIO; - } p += len; i += len; @@ -121,9 +121,8 @@ ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index) len = count; if (len > BEAT_NVRW_CNT) len = BEAT_NVRW_CNT; - if (beat_eeprom_write(i, len, p)) { + if (beat_eeprom_write(i, len, p)) return -EIO; - } p += len; i += len; @@ -149,13 +148,14 @@ int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2) u64 db[2]; s64 ret; - ret = beat_get_characters_from_console(vterm, len, (u8*)db); + ret = beat_get_characters_from_console(vterm, len, (u8 *)db); if (ret == 0) { *t1 = db[0]; *t2 = db[1]; } return ret; } +EXPORT_SYMBOL(beat_get_term_char); int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2) { @@ -163,8 +163,9 @@ int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2) db[0] = t1; db[1] = t2; - return beat_put_characters_to_console(vterm, len, (u8*)db); + return beat_put_characters_to_console(vterm, len, (u8 *)db); } +EXPORT_SYMBOL(beat_put_term_char); void beat_power_save(void) { @@ -261,7 +262,3 @@ static int __init beat_event_init(void) } device_initcall(beat_event_init); - -EXPORT_SYMBOL(beat_get_term_char); -EXPORT_SYMBOL(beat_put_term_char); -EXPORT_SYMBOL(beat_halt_code); diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/cell/beat.h index ac82ac35b99..32c8efcedc8 100644 --- a/arch/powerpc/platforms/celleb/beat.h +++ b/arch/powerpc/platforms/cell/beat.h @@ -21,8 +21,8 @@ #ifndef _CELLEB_BEAT_H #define _CELLEB_BEAT_H -int64_t beat_get_term_char(uint64_t,uint64_t*,uint64_t*,uint64_t*); -int64_t beat_put_term_char(uint64_t,uint64_t,uint64_t,uint64_t); +int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); +int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); int64_t beat_repository_encode(int, const char *, uint64_t[4]); void beat_restart(char *); void beat_power_off(void); diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/cell/beat_htab.c index fbf27c74ebd..81467ff055c 100644 --- a/arch/powerpc/platforms/celleb/htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c @@ -35,9 +35,9 @@ #include "beat_wrapper.h" #ifdef DEBUG_LOW -#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0) +#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while (0) #else -#define DBG_LOW(fmt...) do { } while(0) +#define DBG_LOW(fmt...) do { } while (0) #endif static DEFINE_SPINLOCK(beat_htab_lock); @@ -116,7 +116,8 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, hpte_r &= ~_PAGE_COHERENT; spin_lock(&beat_htab_lock); - if ((lpar_rc = beat_read_mask(hpte_group)) == 0) { + lpar_rc = beat_read_mask(hpte_group); + if (lpar_rc == 0) { if (!(vflags & HPTE_V_BOLTED)) DBG_LOW(" full\n"); spin_unlock(&beat_htab_lock); diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/cell/beat_hvCall.S index 74c81744894..74c81744894 100644 --- a/arch/powerpc/platforms/celleb/hvCall.S +++ b/arch/powerpc/platforms/cell/beat_hvCall.S diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index c7c68ca70c8..192a9350937 100644 --- a/arch/powerpc/platforms/celleb/interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -26,7 +26,7 @@ #include <asm/machdep.h> -#include "interrupt.h" +#include "beat_interrupt.h" #include "beat_wrapper.h" #define MAX_IRQS NR_IRQS @@ -34,7 +34,7 @@ static DEFINE_SPINLOCK(beatic_irq_mask_lock); static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64]; static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64]; -static struct irq_host *beatic_host = NULL; +static struct irq_host *beatic_host; /* * In this implementation, "virq" == "IRQ plug number", @@ -49,13 +49,13 @@ static inline void beatic_update_irq_mask(unsigned int irq_plug) off = (irq_plug / 256) * 4; masks[0] = beatic_irq_mask_enable[off + 0] - & beatic_irq_mask_ack[off + 0]; + & beatic_irq_mask_ack[off + 0]; masks[1] = beatic_irq_mask_enable[off + 1] - & beatic_irq_mask_ack[off + 1]; + & beatic_irq_mask_ack[off + 1]; masks[2] = beatic_irq_mask_enable[off + 2] - & beatic_irq_mask_ack[off + 2]; + & beatic_irq_mask_ack[off + 2]; masks[3] = beatic_irq_mask_enable[off + 3] - & beatic_irq_mask_ack[off + 3]; + & beatic_irq_mask_ack[off + 3]; if (beat_set_interrupt_mask(irq_plug&~255UL, masks[0], masks[1], masks[2], masks[3]) != 0) panic("Failed to set mask IRQ!"); @@ -96,7 +96,8 @@ static void beatic_end_irq(unsigned int irq_plug) s64 err; unsigned long flags; - if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) { + err = beat_downcount_of_interrupt(irq_plug); + if (err != 0) { if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */ panic("Failed to downcount IRQ! Error = %16lx", err); @@ -138,7 +139,8 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, struct irq_desc *desc = get_irq_desc(virq); int64_t err; - if ((err = beat_construct_and_connect_irq_plug(virq, hw)) < 0) + err = beat_construct_and_connect_irq_plug(virq, hw); + if (err < 0) return -EIO; desc->status |= IRQ_LEVEL; @@ -202,22 +204,22 @@ static inline unsigned int beatic_get_irq_plug(void) beat_detect_pending_interrupts(i, pending); __asm__ ("cntlzd %0,%1":"=r"(ub): "r"(pending[0] & beatic_irq_mask_enable[i/64+0] - & beatic_irq_mask_ack[i/64+0])); + & beatic_irq_mask_ack[i/64+0])); if (ub != 64) return i + ub + 0; __asm__ ("cntlzd %0,%1":"=r"(ub): "r"(pending[1] & beatic_irq_mask_enable[i/64+1] - & beatic_irq_mask_ack[i/64+1])); + & beatic_irq_mask_ack[i/64+1])); if (ub != 64) return i + ub + 64; __asm__ ("cntlzd %0,%1":"=r"(ub): "r"(pending[2] & beatic_irq_mask_enable[i/64+2] - & beatic_irq_mask_ack[i/64+2])); + & beatic_irq_mask_ack[i/64+2])); if (ub != 64) return i + ub + 128; __asm__ ("cntlzd %0,%1":"=r"(ub): "r"(pending[3] & beatic_irq_mask_enable[i/64+3] - & beatic_irq_mask_ack[i/64+3])); + & beatic_irq_mask_ack[i/64+3])); if (ub != 64) return i + ub + 192; } @@ -250,7 +252,7 @@ void __init beatic_init_IRQ(void) /* Allocate an irq host */ beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, - &beatic_pic_host_ops, + &beatic_pic_host_ops, 0); BUG_ON(beatic_host == NULL); irq_set_default_host(beatic_host); diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/cell/beat_interrupt.h index b470fd0051f..b470fd0051f 100644 --- a/arch/powerpc/platforms/celleb/interrupt.h +++ b/arch/powerpc/platforms/cell/beat_interrupt.h diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/cell/beat_iommu.c index 93b0efddd65..93b0efddd65 100644 --- a/arch/powerpc/platforms/celleb/iommu.c +++ b/arch/powerpc/platforms/cell/beat_iommu.c diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/cell/beat_smp.c index a7631250aeb..26efc204c47 100644 --- a/arch/powerpc/platforms/celleb/smp.c +++ b/arch/powerpc/platforms/cell/beat_smp.c @@ -37,7 +37,7 @@ #include <asm/machdep.h> #include <asm/udbg.h> -#include "interrupt.h" +#include "beat_interrupt.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/cell/beat_spu_priv1.c index 2bf6700f747..bcc17f7fe8a 100644 --- a/arch/powerpc/platforms/celleb/spu_priv1.c +++ b/arch/powerpc/platforms/cell/beat_spu_priv1.c @@ -183,8 +183,7 @@ static u64 resource_allocation_enable_get(struct spu *spu) return enable; } -const struct spu_priv1_ops spu_priv1_beat_ops = -{ +const struct spu_priv1_ops spu_priv1_beat_ops = { .int_mask_and = int_mask_and, .int_mask_or = int_mask_or, .int_mask_set = int_mask_set, diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/cell/beat_syscall.h index 8580dc7e179..8580dc7e179 100644 --- a/arch/powerpc/platforms/celleb/beat_syscall.h +++ b/arch/powerpc/platforms/cell/beat_syscall.h diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/cell/beat_udbg.c index d888c4674c6..6b418f6b617 100644 --- a/arch/powerpc/platforms/celleb/udbg_beat.c +++ b/arch/powerpc/platforms/cell/beat_udbg.c @@ -54,7 +54,8 @@ static int udbg_getc_poll_beat(void) if (inbuflen == 0) { /* get some more chars. */ inbuflen = 0; - rc = beat_get_term_char(celleb_vtermno, &inbuflen, inbuf+0, inbuf+1); + rc = beat_get_term_char(celleb_vtermno, &inbuflen, + inbuf+0, inbuf+1); if (rc != 0) inbuflen = 0; /* otherwise inbuflen is garbage */ } @@ -78,7 +79,7 @@ static int udbg_getc_beat(void) if (ch == -1) { /* This shouldn't be needed...but... */ volatile unsigned long delay; - for (delay=0; delay < 2000000; delay++) + for (delay = 0; delay < 2000000; delay++) ; } else { return ch; diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/cell/beat_wrapper.h index cbc1487df7d..b47dfda48d0 100644 --- a/arch/powerpc/platforms/celleb/beat_wrapper.h +++ b/arch/powerpc/platforms/cell/beat_wrapper.h @@ -197,7 +197,8 @@ static inline s64 beat_put_characters_to_console(u64 termno, u64 len, u64 b[2]; memcpy(b, buffer, len); - return beat_hcall_norets(HV_put_characters_to_console, termno, len, b[0], b[1]); + return beat_hcall_norets(HV_put_characters_to_console, termno, len, + b[0], b[1]); } static inline s64 beat_get_spe_privileged_state_1_registers( diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/cell/celleb_pci.c index 51b390d34e4..f39a3b2a166 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/cell/celleb_pci.c @@ -37,12 +37,11 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> -#include <asm/machdep.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#include "pci.h" -#include "interrupt.h" +#include "io-workarounds.h" +#include "celleb_pci.h" #define MAX_PCI_DEVICES 32 #define MAX_PCI_FUNCTIONS 8 @@ -190,7 +189,7 @@ static int celleb_fake_pci_read_config(struct pci_bus *bus, static int celleb_fake_pci_write_config(struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 val) + unsigned int devfn, int where, int size, u32 val) { char *config; struct device_node *node; @@ -457,33 +456,42 @@ static int __init celleb_setup_fake_pci(struct device_node *dev, return 0; } -void __init fake_pci_workaround_init(struct pci_controller *phb) -{ - /** - * We will add fake pci bus to scc_pci_bus for the purpose to improve - * I/O Macro performance. But device-tree and device drivers - * are not ready to use address with a token. - */ - - /* celleb_pci_add_one(phb, NULL); */ -} +static struct celleb_phb_spec celleb_fake_pci_spec __initdata = { + .setup = celleb_setup_fake_pci, +}; static struct of_device_id celleb_phb_match[] __initdata = { { .name = "pci-pseudo", - .data = celleb_setup_fake_pci, + .data = &celleb_fake_pci_spec, }, { .name = "epci", - .data = celleb_setup_epci, + .data = &celleb_epci_spec, + }, { + .name = "pcie", + .data = &celleb_pciex_spec, }, { }, }; +static int __init celleb_io_workaround_init(struct pci_controller *phb, + struct celleb_phb_spec *phb_spec) +{ + if (phb_spec->ops) { + iowa_register_bus(phb, phb_spec->ops, phb_spec->iowa_init, + phb_spec->iowa_data); + io_workaround_init(); + } + + return 0; +} + int __init celleb_setup_phb(struct pci_controller *phb) { struct device_node *dev = phb->dn; const struct of_device_id *match; - int (*setup_func)(struct device_node *, struct pci_controller *); + struct celleb_phb_spec *phb_spec; + int rc; match = of_match_node(celleb_phb_match, dev); if (!match) @@ -492,8 +500,12 @@ int __init celleb_setup_phb(struct pci_controller *phb) phb_set_bus_ranges(dev, phb); phb->buid = 1; - setup_func = match->data; - return (*setup_func)(dev, phb); + phb_spec = match->data; + rc = (*phb_spec->setup)(dev, phb); + if (rc) + return 1; + + return celleb_io_workaround_init(phb, phb_spec); } int celleb_pci_probe_mode(struct pci_bus *bus) diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/cell/celleb_pci.h index 5d5544ffedd..4cba1523ec5 100644 --- a/arch/powerpc/platforms/celleb/pci.h +++ b/arch/powerpc/platforms/cell/celleb_pci.h @@ -27,16 +27,19 @@ #include <asm/prom.h> #include <asm/ppc-pci.h> +#include "io-workarounds.h" + +struct celleb_phb_spec { + int (*setup)(struct device_node *, struct pci_controller *); + struct ppc_pci_io *ops; + int (*iowa_init)(struct iowa_bus *, void *); + void *iowa_data; +}; + extern int celleb_setup_phb(struct pci_controller *); extern int celleb_pci_probe_mode(struct pci_bus *); -extern int celleb_setup_epci(struct device_node *, struct pci_controller *); - -extern void *celleb_dummy_page_va; -extern int __init celleb_pci_workaround_init(void); -extern void __init celleb_pci_add_one(struct pci_controller *, - void (*)(struct pci_controller *)); -extern void fake_pci_workaround_init(struct pci_controller *); -extern void epci_workaround_init(struct pci_controller *); +extern struct celleb_phb_spec celleb_epci_spec; +extern struct celleb_phb_spec celleb_pciex_spec; #endif /* _CELLEB_PCI_H */ diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/cell/celleb_scc.h index 6be1542a6e6..b596a711c34 100644 --- a/arch/powerpc/platforms/celleb/scc.h +++ b/arch/powerpc/platforms/cell/celleb_scc.h @@ -125,6 +125,93 @@ /* bits for SCC_EPCI_CNTOPT */ #define SCC_EPCI_CNTOPT_O2PMB 0x00000002 +/* SCC PCIEXC SMMIO registers */ +#define PEXCADRS 0x000 +#define PEXCWDATA 0x004 +#define PEXCRDATA 0x008 +#define PEXDADRS 0x010 +#define PEXDCMND 0x014 +#define PEXDWDATA 0x018 +#define PEXDRDATA 0x01c +#define PEXREQID 0x020 +#define PEXTIDMAP 0x024 +#define PEXINTMASK 0x028 +#define PEXINTSTS 0x02c +#define PEXAERRMASK 0x030 +#define PEXAERRSTS 0x034 +#define PEXPRERRMASK 0x040 +#define PEXPRERRSTS 0x044 +#define PEXPRERRID01 0x048 +#define PEXPRERRID23 0x04c +#define PEXVDMASK 0x050 +#define PEXVDSTS 0x054 +#define PEXRCVCPLIDA 0x060 +#define PEXLENERRIDA 0x068 +#define PEXPHYPLLST 0x070 +#define PEXDMRDEN0 0x100 +#define PEXDMRDADR0 0x104 +#define PEXDMRDENX 0x110 +#define PEXDMRDADRX 0x114 +#define PEXECMODE 0xf00 +#define PEXMAEA(n) (0xf50 + (8 * n)) +#define PEXMAEC(n) (0xf54 + (8 * n)) +#define PEXCCRCTRL 0xff0 + +/* SCC PCIEXC bits and shifts for PEXCADRS */ +#define PEXCADRS_BYTE_EN_SHIFT 20 +#define PEXCADRS_CMD_SHIFT 16 +#define PEXCADRS_CMD_READ (0xa << PEXCADRS_CMD_SHIFT) +#define PEXCADRS_CMD_WRITE (0xb << PEXCADRS_CMD_SHIFT) + +/* SCC PCIEXC shifts for PEXDADRS */ +#define PEXDADRS_BUSNO_SHIFT 20 +#define PEXDADRS_DEVNO_SHIFT 15 +#define PEXDADRS_FUNCNO_SHIFT 12 + +/* SCC PCIEXC bits and shifts for PEXDCMND */ +#define PEXDCMND_BYTE_EN_SHIFT 4 +#define PEXDCMND_IO_READ 0x2 +#define PEXDCMND_IO_WRITE 0x3 +#define PEXDCMND_CONFIG_READ 0xa +#define PEXDCMND_CONFIG_WRITE 0xb + +/* SCC PCIEXC bits for PEXPHYPLLST */ +#define PEXPHYPLLST_PEXPHYAPLLST 0x00000001 + +/* SCC PCIEXC bits for PEXECMODE */ +#define PEXECMODE_ALL_THROUGH 0x00000000 +#define PEXECMODE_ALL_8BIT 0x00550155 +#define PEXECMODE_ALL_16BIT 0x00aa02aa + +/* SCC PCIEXC bits for PEXCCRCTRL */ +#define PEXCCRCTRL_PEXIPCOREEN 0x00040000 +#define PEXCCRCTRL_PEXIPCONTEN 0x00020000 +#define PEXCCRCTRL_PEXPHYPLLEN 0x00010000 +#define PEXCCRCTRL_PCIEXCAOCKEN 0x00000100 + +/* SCC PCIEXC port configuration registers */ +#define PEXTCERRCHK 0x21c +#define PEXTAMAPB0 0x220 +#define PEXTAMAPL0 0x224 +#define PEXTAMAPB(n) (PEXTAMAPB0 + 8 * (n)) +#define PEXTAMAPL(n) (PEXTAMAPL0 + 8 * (n)) +#define PEXCHVC0P 0x500 +#define PEXCHVC0NP 0x504 +#define PEXCHVC0C 0x508 +#define PEXCDVC0P 0x50c +#define PEXCDVC0NP 0x510 +#define PEXCDVC0C 0x514 +#define PEXCHVCXP 0x518 +#define PEXCHVCXNP 0x51c +#define PEXCHVCXC 0x520 +#define PEXCDVCXP 0x524 +#define PEXCDVCXNP 0x528 +#define PEXCDVCXC 0x52c +#define PEXCTTRG 0x530 +#define PEXTSCTRL 0x700 +#define PEXTSSTS 0x704 +#define PEXSKPCTRL 0x708 + /* UHC registers */ #define SCC_UHC_CKRCTRL 0xff0 #define SCC_UHC_ECMODE 0xf00 diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/cell/celleb_scc_epci.c index a3c7cfbcb32..08c285b10e3 100644 --- a/arch/powerpc/platforms/celleb/scc_epci.c +++ b/arch/powerpc/platforms/cell/celleb_scc_epci.c @@ -30,23 +30,17 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> -#include <asm/machdep.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#include "scc.h" -#include "pci.h" -#include "interrupt.h" +#include "celleb_scc.h" +#include "celleb_pci.h" #define MAX_PCI_DEVICES 32 #define MAX_PCI_FUNCTIONS 8 #define iob() __asm__ __volatile__("eieio; sync":::"memory") -struct epci_private { - dma_addr_t dummy_page_da; -}; - static inline PCI_IO_ADDR celleb_epci_get_epci_base( struct pci_controller *hose) { @@ -71,42 +65,6 @@ static inline PCI_IO_ADDR celleb_epci_get_epci_cfg( return hose->cfg_data; } -static void scc_epci_dummy_read(struct pci_controller *hose) -{ - PCI_IO_ADDR epci_base; - u32 val; - - epci_base = celleb_epci_get_epci_base(hose); - - val = in_be32(epci_base + SCC_EPCI_WATRP); - iosync(); - - return; -} - -void __init epci_workaround_init(struct pci_controller *hose) -{ - PCI_IO_ADDR epci_base; - PCI_IO_ADDR reg; - struct epci_private *private = hose->private_data; - - BUG_ON(!private); - - private->dummy_page_da = dma_map_single(hose->parent, - celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE); - if (private->dummy_page_da == DMA_ERROR_CODE) { - printk(KERN_ERR "EPCI: dummy read disabled. " - "Map dummy page failed.\n"); - return; - } - - celleb_pci_add_one(hose, scc_epci_dummy_read); - epci_base = celleb_epci_get_epci_base(hose); - - reg = epci_base + SCC_EPCI_DUMYRADR; - out_be32(reg, private->dummy_page_da); -} - static inline void clear_and_disable_master_abort_interrupt( struct pci_controller *hose) { @@ -151,19 +109,17 @@ static int celleb_epci_check_abort(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } -static PCI_IO_ADDR celleb_epci_make_config_addr( - struct pci_bus *bus, - struct pci_controller *hose, - unsigned int devfn, int where) +static PCI_IO_ADDR celleb_epci_make_config_addr(struct pci_bus *bus, + struct pci_controller *hose, unsigned int devfn, int where) { PCI_IO_ADDR addr; if (bus != hose->bus) addr = celleb_epci_get_epci_cfg(hose) + (((bus->number & 0xff) << 16) - | ((devfn & 0xff) << 8) - | (where & 0xff) - | 0x01000000); + | ((devfn & 0xff) << 8) + | (where & 0xff) + | 0x01000000); else addr = celleb_epci_get_epci_cfg(hose) + (((devfn & 0xff) << 8) | (where & 0xff)); @@ -174,7 +130,7 @@ static PCI_IO_ADDR celleb_epci_make_config_addr( } static int celleb_epci_read_config(struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 * val) + unsigned int devfn, int where, int size, u32 *val) { PCI_IO_ADDR epci_base; PCI_IO_ADDR addr; @@ -425,8 +381,8 @@ static int __init celleb_epci_init(struct pci_controller *hose) return 0; } -int __init celleb_setup_epci(struct device_node *node, - struct pci_controller *hose) +static int __init celleb_setup_epci(struct device_node *node, + struct pci_controller *hose) { struct resource r; @@ -450,8 +406,7 @@ int __init celleb_setup_epci(struct device_node *node, if (!hose->cfg_addr) goto error; pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n", - r.start, (unsigned long)hose->cfg_addr, - (r.end - r.start + 1)); + r.start, (unsigned long)hose->cfg_addr, (r.end - r.start + 1)); if (of_address_to_resource(node, 2, &r)) goto error; @@ -459,14 +414,7 @@ int __init celleb_setup_epci(struct device_node *node, if (!hose->cfg_data) goto error; pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n", - r.start, (unsigned long)hose->cfg_data, - (r.end - r.start + 1)); - - hose->private_data = kzalloc(sizeof(struct epci_private), GFP_KERNEL); - if (hose->private_data == NULL) { - printk(KERN_ERR "EPCI: no memory for private data.\n"); - goto error; - } + r.start, (unsigned long)hose->cfg_data, (r.end - r.start + 1)); hose->ops = &celleb_epci_ops; celleb_epci_init(hose); @@ -474,8 +422,6 @@ int __init celleb_setup_epci(struct device_node *node, return 0; error: - kfree(hose->private_data); - if (hose->cfg_addr) iounmap(hose->cfg_addr); @@ -483,3 +429,10 @@ error: iounmap(hose->cfg_data); return 1; } + +struct celleb_phb_spec celleb_epci_spec __initdata = { + .setup = celleb_setup_epci, + .ops = &spiderpci_ops, + .iowa_init = &spiderpci_iowa_init, + .iowa_data = (void *)0, +}; diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c new file mode 100644 index 00000000000..31da84c458d --- /dev/null +++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c @@ -0,0 +1,547 @@ +/* + * Support for Celleb PCI-Express. + * + * (C) Copyright 2007-2008 TOSHIBA 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/iommu.h> +#include <asm/byteorder.h> + +#include "celleb_scc.h" +#include "celleb_pci.h" + +#define PEX_IN(base, off) in_be32((void __iomem *)(base) + (off)) +#define PEX_OUT(base, off, data) out_be32((void __iomem *)(base) + (off), (data)) + +static void scc_pciex_io_flush(struct iowa_bus *bus) +{ + (void)PEX_IN(bus->phb->cfg_addr, PEXDMRDEN0); +} + +/* + * Memory space access to device on PCIEX + */ +#define PCIEX_MMIO_READ(name, ret) \ +static ret scc_pciex_##name(const PCI_IO_ADDR addr) \ +{ \ + ret val = __do_##name(addr); \ + scc_pciex_io_flush(iowa_mem_find_bus(addr)); \ + return val; \ +} + +#define PCIEX_MMIO_READ_STR(name) \ +static void scc_pciex_##name(const PCI_IO_ADDR addr, void *buf, \ + unsigned long count) \ +{ \ + __do_##name(addr, buf, count); \ + scc_pciex_io_flush(iowa_mem_find_bus(addr)); \ +} + +PCIEX_MMIO_READ(readb, u8) +PCIEX_MMIO_READ(readw, u16) +PCIEX_MMIO_READ(readl, u32) +PCIEX_MMIO_READ(readq, u64) +PCIEX_MMIO_READ(readw_be, u16) +PCIEX_MMIO_READ(readl_be, u32) +PCIEX_MMIO_READ(readq_be, u64) +PCIEX_MMIO_READ_STR(readsb) +PCIEX_MMIO_READ_STR(readsw) +PCIEX_MMIO_READ_STR(readsl) + +static void scc_pciex_memcpy_fromio(void *dest, const PCI_IO_ADDR src, + unsigned long n) +{ + __do_memcpy_fromio(dest, src, n); + scc_pciex_io_flush(iowa_mem_find_bus(src)); +} + +/* + * I/O port access to devices on PCIEX. + */ + +static inline unsigned long get_bus_address(struct pci_controller *phb, + unsigned long port) +{ + return port - ((unsigned long)(phb->io_base_virt) - _IO_BASE); +} + +static u32 scc_pciex_read_port(struct pci_controller *phb, + unsigned long port, int size) +{ + unsigned int byte_enable; + unsigned int cmd, shift; + unsigned long addr; + u32 data, ret; + + BUG_ON(((port & 0x3ul) + size) > 4); + + addr = get_bus_address(phb, port); + shift = addr & 0x3ul; + byte_enable = ((1 << size) - 1) << shift; + cmd = PEXDCMND_IO_READ | (byte_enable << PEXDCMND_BYTE_EN_SHIFT); + PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul)); + PEX_OUT(phb->cfg_addr, PEXDCMND, cmd); + data = PEX_IN(phb->cfg_addr, PEXDRDATA); + ret = (data >> (shift * 8)) & (0xFFFFFFFF >> ((4 - size) * 8)); + + pr_debug("PCIEX:PIO READ:port=0x%lx, addr=0x%lx, size=%d, be=%x," + " cmd=%x, data=%x, ret=%x\n", port, addr, size, byte_enable, + cmd, data, ret); + + return ret; +} + +static void scc_pciex_write_port(struct pci_controller *phb, + unsigned long port, int size, u32 val) +{ + unsigned int byte_enable; + unsigned int cmd, shift; + unsigned long addr; + u32 data; + + BUG_ON(((port & 0x3ul) + size) > 4); + + addr = get_bus_address(phb, port); + shift = addr & 0x3ul; + byte_enable = ((1 << size) - 1) << shift; + cmd = PEXDCMND_IO_WRITE | (byte_enable << PEXDCMND_BYTE_EN_SHIFT); + data = (val & (0xFFFFFFFF >> (4 - size) * 8)) << (shift * 8); + PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul)); + PEX_OUT(phb->cfg_addr, PEXDCMND, cmd); + PEX_OUT(phb->cfg_addr, PEXDWDATA, data); + + pr_debug("PCIEX:PIO WRITE:port=0x%lx, addr=%lx, size=%d, val=%x," + " be=%x, cmd=%x, data=%x\n", port, addr, size, val, + byte_enable, cmd, data); +} + +static u8 __scc_pciex_inb(struct pci_controller *phb, unsigned long port) +{ + return (u8)scc_pciex_read_port(phb, port, 1); +} + +static u16 __scc_pciex_inw(struct pci_controller *phb, unsigned long port) +{ + u32 data; + if ((port & 0x3ul) < 3) + data = scc_pciex_read_port(phb, port, 2); + else { + u32 d1 = scc_pciex_read_port(phb, port, 1); + u32 d2 = scc_pciex_read_port(phb, port + 1, 1); + data = d1 | (d2 << 8); + } + return (u16)data; +} + +static u32 __scc_pciex_inl(struct pci_controller *phb, unsigned long port) +{ + unsigned int mod = port & 0x3ul; + u32 data; + if (mod == 0) + data = scc_pciex_read_port(phb, port, 4); + else { + u32 d1 = scc_pciex_read_port(phb, port, 4 - mod); + u32 d2 = scc_pciex_read_port(phb, port + 1, mod); + data = d1 | (d2 << (mod * 8)); + } + return data; +} + +static void __scc_pciex_outb(struct pci_controller *phb, + u8 val, unsigned long port) +{ + scc_pciex_write_port(phb, port, 1, (u32)val); +} + +static void __scc_pciex_outw(struct pci_controller *phb, + u16 val, unsigned long port) +{ + if ((port & 0x3ul) < 3) + scc_pciex_write_port(phb, port, 2, (u32)val); + else { + u32 d1 = val & 0x000000FF; + u32 d2 = (val & 0x0000FF00) >> 8; + scc_pciex_write_port(phb, port, 1, d1); + scc_pciex_write_port(phb, port + 1, 1, d2); + } +} + +static void __scc_pciex_outl(struct pci_controller *phb, + u32 val, unsigned long port) +{ + unsigned int mod = port & 0x3ul; + if (mod == 0) + scc_pciex_write_port(phb, port, 4, val); + else { + u32 d1 = val & (0xFFFFFFFFul >> (mod * 8)); + u32 d2 = val >> ((4 - mod) * 8); + scc_pciex_write_port(phb, port, 4 - mod, d1); + scc_pciex_write_port(phb, port + 1, mod, d2); + } +} + +#define PCIEX_PIO_FUNC(size, name) \ +static u##size scc_pciex_in##name(unsigned long port) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(port); \ + u##size data = __scc_pciex_in##name(bus->phb, port); \ + scc_pciex_io_flush(bus); \ + return data; \ +} \ +static void scc_pciex_ins##name(unsigned long p, void *b, unsigned long c) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(p); \ + u##size *dst = b; \ + for (; c != 0; c--, dst++) \ + *dst = cpu_to_le##size(__scc_pciex_in##name(bus->phb, p)); \ + scc_pciex_io_flush(bus); \ +} \ +static void scc_pciex_out##name(u##size val, unsigned long port) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(port); \ + __scc_pciex_out##name(bus->phb, val, port); \ +} \ +static void scc_pciex_outs##name(unsigned long p, const void *b, \ + unsigned long c) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(p); \ + const u##size *src = b; \ + for (; c != 0; c--, src++) \ + __scc_pciex_out##name(bus->phb, le##size##_to_cpu(*src), p); \ +} +#define cpu_to_le8(x) (x) +#define le8_to_cpu(x) (x) +PCIEX_PIO_FUNC(8, b) +PCIEX_PIO_FUNC(16, w) +PCIEX_PIO_FUNC(32, l) + +static struct ppc_pci_io scc_pciex_ops = { + .readb = scc_pciex_readb, + .readw = scc_pciex_readw, + .readl = scc_pciex_readl, + .readq = scc_pciex_readq, + .readw_be = scc_pciex_readw_be, + .readl_be = scc_pciex_readl_be, + .readq_be = scc_pciex_readq_be, + .readsb = scc_pciex_readsb, + .readsw = scc_pciex_readsw, + .readsl = scc_pciex_readsl, + .memcpy_fromio = scc_pciex_memcpy_fromio, + .inb = scc_pciex_inb, + .inw = scc_pciex_inw, + .inl = scc_pciex_inl, + .outb = scc_pciex_outb, + .outw = scc_pciex_outw, + .outl = scc_pciex_outl, + .insb = scc_pciex_insb, + .insw = scc_pciex_insw, + .insl = scc_pciex_insl, + .outsb = scc_pciex_outsb, + .outsw = scc_pciex_outsw, + .outsl = scc_pciex_outsl, +}; + +static int __init scc_pciex_iowa_init(struct iowa_bus *bus, void *data) +{ + dma_addr_t dummy_page_da; + void *dummy_page_va; + + dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!dummy_page_va) { + pr_err("PCIEX:Alloc dummy_page_va failed\n"); + return -1; + } + + dummy_page_da = dma_map_single(bus->phb->parent, dummy_page_va, + PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dummy_page_da)) { + pr_err("PCIEX:Map dummy page failed.\n"); + kfree(dummy_page_va); + return -1; + } + + PEX_OUT(bus->phb->cfg_addr, PEXDMRDADR0, dummy_page_da); + + return 0; +} + +/* + * config space access + */ +#define MK_PEXDADRS(bus_no, dev_no, func_no, addr) \ + ((uint32_t)(((addr) & ~0x3UL) | \ + ((bus_no) << PEXDADRS_BUSNO_SHIFT) | \ + ((dev_no) << PEXDADRS_DEVNO_SHIFT) | \ + ((func_no) << PEXDADRS_FUNCNO_SHIFT))) + +#define MK_PEXDCMND_BYTE_EN(addr, size) \ + ((((0x1 << (size))-1) << ((addr) & 0x3)) << PEXDCMND_BYTE_EN_SHIFT) +#define MK_PEXDCMND(cmd, addr, size) ((cmd) | MK_PEXDCMND_BYTE_EN(addr, size)) + +static uint32_t config_read_pciex_dev(unsigned int __iomem *base, + uint64_t bus_no, uint64_t dev_no, uint64_t func_no, + uint64_t off, uint64_t size) +{ + uint32_t ret; + uint32_t addr, cmd; + + addr = MK_PEXDADRS(bus_no, dev_no, func_no, off); + cmd = MK_PEXDCMND(PEXDCMND_CONFIG_READ, off, size); + PEX_OUT(base, PEXDADRS, addr); + PEX_OUT(base, PEXDCMND, cmd); + ret = (PEX_IN(base, PEXDRDATA) + >> ((off & (4-size)) * 8)) & ((0x1 << (size * 8)) - 1); + return ret; +} + +static void config_write_pciex_dev(unsigned int __iomem *base, uint64_t bus_no, + uint64_t dev_no, uint64_t func_no, uint64_t off, uint64_t size, + uint32_t data) +{ + uint32_t addr, cmd; + + addr = MK_PEXDADRS(bus_no, dev_no, func_no, off); + cmd = MK_PEXDCMND(PEXDCMND_CONFIG_WRITE, off, size); + PEX_OUT(base, PEXDADRS, addr); + PEX_OUT(base, PEXDCMND, cmd); + PEX_OUT(base, PEXDWDATA, + (data & ((0x1 << (size * 8)) - 1)) << ((off & (4-size)) * 8)); +} + +#define MK_PEXCADRS_BYTE_EN(off, len) \ + ((((0x1 << (len)) - 1) << ((off) & 0x3)) << PEXCADRS_BYTE_EN_SHIFT) +#define MK_PEXCADRS(cmd, addr, size) \ + ((cmd) | MK_PEXCADRS_BYTE_EN(addr, size) | ((addr) & ~0x3)) +static uint32_t config_read_pciex_rc(unsigned int __iomem *base, + uint32_t where, uint32_t size) +{ + PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_READ, where, size)); + return (PEX_IN(base, PEXCRDATA) + >> ((where & (4 - size)) * 8)) & ((0x1 << (size * 8)) - 1); +} + +static void config_write_pciex_rc(unsigned int __iomem *base, uint32_t where, + uint32_t size, uint32_t val) +{ + uint32_t data; + + data = (val & ((0x1 << (size * 8)) - 1)) << ((where & (4 - size)) * 8); + PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_WRITE, where, size)); + PEX_OUT(base, PEXCWDATA, data); +} + +/* Interfaces */ +/* Note: Work-around + * On SCC PCIEXC, one device is seen on all 32 dev_no. + * As SCC PCIEXC can have only one device on the bus, we look only one dev_no. + * (dev_no = 1) + */ +static int scc_pciex_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int *val) +{ + struct device_node *dn; + struct pci_controller *phb; + + dn = bus->sysdata; + phb = pci_find_hose_for_OF_device(dn); + + if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + if (bus->number == 0 && PCI_SLOT(devfn) == 0) + *val = config_read_pciex_rc(phb->cfg_addr, where, size); + else + *val = config_read_pciex_dev(phb->cfg_addr, bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); + + return PCIBIOS_SUCCESSFUL; +} + +static int scc_pciex_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int val) +{ + struct device_node *dn; + struct pci_controller *phb; + + dn = bus->sysdata; + phb = pci_find_hose_for_OF_device(dn); + + if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == 0 && PCI_SLOT(devfn) == 0) + config_write_pciex_rc(phb->cfg_addr, where, size, val); + else + config_write_pciex_dev(phb->cfg_addr, bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops scc_pciex_pci_ops = { + scc_pciex_read_config, + scc_pciex_write_config, +}; + +static void pciex_clear_intr_all(unsigned int __iomem *base) +{ + PEX_OUT(base, PEXAERRSTS, 0xffffffff); + PEX_OUT(base, PEXPRERRSTS, 0xffffffff); + PEX_OUT(base, PEXINTSTS, 0xffffffff); +} + +#if 0 +static void pciex_disable_intr_all(unsigned int *base) +{ + PEX_OUT(base, PEXINTMASK, 0x0); + PEX_OUT(base, PEXAERRMASK, 0x0); + PEX_OUT(base, PEXPRERRMASK, 0x0); + PEX_OUT(base, PEXVDMASK, 0x0); +} +#endif + +static void pciex_enable_intr_all(unsigned int __iomem *base) +{ + PEX_OUT(base, PEXINTMASK, 0x0000e7f1); + PEX_OUT(base, PEXAERRMASK, 0x03ff01ff); + PEX_OUT(base, PEXPRERRMASK, 0x0001010f); + PEX_OUT(base, PEXVDMASK, 0x00000001); +} + +static void pciex_check_status(unsigned int __iomem *base) +{ + uint32_t err = 0; + uint32_t intsts, aerr, prerr, rcvcp, lenerr; + uint32_t maea, maec; + + intsts = PEX_IN(base, PEXINTSTS); + aerr = PEX_IN(base, PEXAERRSTS); + prerr = PEX_IN(base, PEXPRERRSTS); + rcvcp = PEX_IN(base, PEXRCVCPLIDA); + lenerr = PEX_IN(base, PEXLENERRIDA); + + if (intsts || aerr || prerr || rcvcp || lenerr) + err = 1; + + pr_info("PCEXC interrupt!!\n"); + pr_info("PEXINTSTS :0x%08x\n", intsts); + pr_info("PEXAERRSTS :0x%08x\n", aerr); + pr_info("PEXPRERRSTS :0x%08x\n", prerr); + pr_info("PEXRCVCPLIDA :0x%08x\n", rcvcp); + pr_info("PEXLENERRIDA :0x%08x\n", lenerr); + + /* print detail of Protection Error */ + if (intsts & 0x00004000) { + uint32_t i, n; + for (i = 0; i < 4; i++) { + n = 1 << i; + if (prerr & n) { + maea = PEX_IN(base, PEXMAEA(i)); + maec = PEX_IN(base, PEXMAEC(i)); + pr_info("PEXMAEC%d :0x%08x\n", i, maec); + pr_info("PEXMAEA%d :0x%08x\n", i, maea); + } + } + } + + if (err) + pciex_clear_intr_all(base); +} + +static irqreturn_t pciex_handle_internal_irq(int irq, void *dev_id) +{ + struct pci_controller *phb = dev_id; + + pr_debug("PCIEX:pciex_handle_internal_irq(irq=%d)\n", irq); + + BUG_ON(phb->cfg_addr == NULL); + + pciex_check_status(phb->cfg_addr); + + return IRQ_HANDLED; +} + +static __init int celleb_setup_pciex(struct device_node *node, + struct pci_controller *phb) +{ + struct resource r; + struct of_irq oirq; + int virq; + + /* SMMIO registers; used inside this file */ + if (of_address_to_resource(node, 0, &r)) { + pr_err("PCIEXC:Failed to get config resource.\n"); + return 1; + } + phb->cfg_addr = ioremap(r.start, r.end - r.start + 1); + if (!phb->cfg_addr) { + pr_err("PCIEXC:Failed to remap SMMIO region.\n"); + return 1; + } + + /* Not use cfg_data, cmd and data regs are near address reg */ + phb->cfg_data = NULL; + + /* set pci_ops */ + phb->ops = &scc_pciex_pci_ops; + + /* internal interrupt handler */ + if (of_irq_map_one(node, 1, &oirq)) { + pr_err("PCIEXC:Failed to map irq\n"); + goto error; + } + virq = irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); + if (request_irq(virq, pciex_handle_internal_irq, + IRQF_DISABLED, "pciex", (void *)phb)) { + pr_err("PCIEXC:Failed to request irq\n"); + goto error; + } + + /* enable all interrupts */ + pciex_clear_intr_all(phb->cfg_addr); + pciex_enable_intr_all(phb->cfg_addr); + /* MSI: TBD */ + + return 0; + +error: + phb->cfg_data = NULL; + if (phb->cfg_addr) + iounmap(phb->cfg_addr); + phb->cfg_addr = NULL; + return 1; +} + +struct celleb_phb_spec celleb_pciex_spec __initdata = { + .setup = celleb_setup_pciex, + .ops = &scc_pciex_ops, + .iowa_init = &scc_pciex_iowa_init, +}; diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/cell/celleb_scc_sio.c index 610008211ca..3a16c5b3c46 100644 --- a/arch/powerpc/platforms/celleb/scc_sio.c +++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c @@ -28,7 +28,7 @@ /* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024 mmio=0xfff000-0x1000,0xff2000-0x1000 */ -static int txx9_serial_bitmap __initdata = 0; +static int txx9_serial_bitmap __initdata; static struct { uint32_t offset; @@ -84,7 +84,7 @@ static int __init txx9_serial_config(char *ptr) int i; for (;;) { - switch(get_option(&ptr, &i)) { + switch (get_option(&ptr, &i)) { default: return 0; case 2: diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/cell/celleb_scc_uhc.c index cb430799408..d63b720bfe3 100644 --- a/arch/powerpc/platforms/celleb/scc_uhc.c +++ b/arch/powerpc/platforms/cell/celleb_scc_uhc.c @@ -25,7 +25,7 @@ #include <asm/io.h> #include <asm/machdep.h> -#include "scc.h" +#include "celleb_scc.h" #define UHC_RESET_WAIT_MAX 10000 diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/cell/celleb_setup.c index f27ae1e3fb5..b11cb30decb 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/cell/celleb_setup.c @@ -56,13 +56,13 @@ #include <asm/rtas.h> #include <asm/cell-regs.h> -#include "interrupt.h" +#include "beat_interrupt.h" #include "beat_wrapper.h" #include "beat.h" -#include "pci.h" -#include "../cell/interrupt.h" -#include "../cell/pervasive.h" -#include "../cell/ras.h" +#include "celleb_pci.h" +#include "interrupt.h" +#include "pervasive.h" +#include "ras.h" static char celleb_machine_type[128] = "Celleb"; @@ -114,8 +114,6 @@ static int __init celleb_publish_devices(void) /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, celleb_bus_ids, NULL); - celleb_pci_workaround_init(); - return 0; } machine_device_initcall(celleb_beat, celleb_publish_devices); diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c index 979d4b67efb..3b84e8be314 100644 --- a/arch/powerpc/platforms/cell/io-workarounds.c +++ b/arch/powerpc/platforms/cell/io-workarounds.c @@ -1,6 +1,9 @@ /* + * Support PCI IO workaround + * * Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org> * IBM, Corp. + * (C) Copyright 2007-2008 TOSHIBA CORPORATION * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -9,335 +12,174 @@ #undef DEBUG #include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/pci.h> + #include <asm/io.h> #include <asm/machdep.h> -#include <asm/pci-bridge.h> +#include <asm/pgtable.h> #include <asm/ppc-pci.h> +#include "io-workarounds.h" -#define SPIDER_PCI_REG_BASE 0xd000 -#define SPIDER_PCI_VCI_CNTL_STAT 0x0110 -#define SPIDER_PCI_DUMMY_READ 0x0810 -#define SPIDER_PCI_DUMMY_READ_BASE 0x0814 +#define IOWA_MAX_BUS 8 -/* Undefine that to re-enable bogus prefetch - * - * Without that workaround, the chip will do bogus prefetch past - * page boundary from system memory. This setting will disable that, - * though the documentation is unclear as to the consequences of doing - * so, either purely performances, or possible misbehaviour... It's not - * clear wether the chip can handle unaligned accesses at all without - * prefetching enabled. - * - * For now, things appear to be behaving properly with that prefetching - * disabled and IDE, possibly because IDE isn't doing any unaligned - * access. - */ -#define SPIDER_DISABLE_PREFETCH +static struct iowa_bus iowa_busses[IOWA_MAX_BUS]; +static unsigned int iowa_bus_count; -#define MAX_SPIDERS 3 +static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr) +{ + int i, j; + struct resource *res; + unsigned long vstart, vend; -static struct spider_pci_bus { - void __iomem *regs; - unsigned long mmio_start; - unsigned long mmio_end; - unsigned long pio_vstart; - unsigned long pio_vend; -} spider_pci_busses[MAX_SPIDERS]; -static int spider_pci_count; + for (i = 0; i < iowa_bus_count; i++) { + struct iowa_bus *bus = &iowa_busses[i]; + struct pci_controller *phb = bus->phb; -static struct spider_pci_bus *spider_pci_find(unsigned long vaddr, - unsigned long paddr) -{ - int i; - - for (i = 0; i < spider_pci_count; i++) { - struct spider_pci_bus *bus = &spider_pci_busses[i]; - if (paddr && paddr >= bus->mmio_start && paddr < bus->mmio_end) - return bus; - if (vaddr && vaddr >= bus->pio_vstart && vaddr < bus->pio_vend) - return bus; + if (vaddr) { + vstart = (unsigned long)phb->io_base_virt; + vend = vstart + phb->pci_io_size - 1; + if ((vaddr >= vstart) && (vaddr <= vend)) + return bus; + } + + if (paddr) + for (j = 0; j < 3; j++) { + res = &phb->mem_resources[j]; + if (paddr >= res->start && paddr <= res->end) + return bus; + } } + return NULL; } -static void spider_io_flush(const volatile void __iomem *addr) +struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr) { - struct spider_pci_bus *bus; + struct iowa_bus *bus; int token; - /* Get platform token (set by ioremap) from address */ token = PCI_GET_ADDR_TOKEN(addr); - /* Fast path if we have a non-0 token, it indicates which bus we - * are on. - * - * If the token is 0, that means either that the ioremap was done - * before we initialized this layer, or it's a PIO operation. We - * fallback to a low path in this case. Hopefully, internal devices - * which are ioremap'ed early should use in_XX/out_XX functions - * instead of the PCI ones and thus not suffer from the slowdown. - * - * Also note that currently, the workaround will not work for areas - * that are not mapped with PTEs (bolted in the hash table). This - * is the case for ioremaps done very early at boot (before - * mem_init_done) and includes the mapping of the ISA IO space. - * - * Fortunately, none of the affected devices is expected to do DMA - * and thus there should be no problem in practice. - * - * In order to improve performances, we only do the PTE search for - * addresses falling in the PHB IO space area. That means it will - * not work for hotplug'ed PHBs but those don't exist with Spider. - */ - if (token && token <= spider_pci_count) - bus = &spider_pci_busses[token - 1]; + if (token && token <= iowa_bus_count) + bus = &iowa_busses[token - 1]; else { unsigned long vaddr, paddr; pte_t *ptep; - /* Fixup physical address */ vaddr = (unsigned long)PCI_FIX_ADDR(addr); + if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) + return NULL; - /* Check if it's in allowed range for PIO */ - if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END) - return; - - /* Try to find a PTE. If not, clear the paddr, we'll do - * a vaddr only lookup (PIO only) - */ ptep = find_linux_pte(init_mm.pgd, vaddr); if (ptep == NULL) paddr = 0; else paddr = pte_pfn(*ptep) << PAGE_SHIFT; + bus = iowa_pci_find(vaddr, paddr); - bus = spider_pci_find(vaddr, paddr); if (bus == NULL) - return; + return NULL; } - /* Now do the workaround - */ - (void)in_be32(bus->regs + SPIDER_PCI_DUMMY_READ); + return bus; } -static u8 spider_readb(const volatile void __iomem *addr) +struct iowa_bus *iowa_pio_find_bus(unsigned long port) { - u8 val = __do_readb(addr); - spider_io_flush(addr); - return val; + unsigned long vaddr = (unsigned long)pci_io_base + port; + return iowa_pci_find(vaddr, 0); } -static u16 spider_readw(const volatile void __iomem *addr) -{ - u16 val = __do_readw(addr); - spider_io_flush(addr); - return val; -} -static u32 spider_readl(const volatile void __iomem *addr) -{ - u32 val = __do_readl(addr); - spider_io_flush(addr); - return val; +#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ +static ret iowa_##name at \ +{ \ + struct iowa_bus *bus; \ + bus = iowa_##space##_find_bus(aa); \ + if (bus && bus->ops && bus->ops->name) \ + return bus->ops->name al; \ + return __do_##name al; \ } -static u64 spider_readq(const volatile void __iomem *addr) -{ - u64 val = __do_readq(addr); - spider_io_flush(addr); - return val; +#define DEF_PCI_AC_NORET(name, at, al, space, aa) \ +static void iowa_##name at \ +{ \ + struct iowa_bus *bus; \ + bus = iowa_##space##_find_bus(aa); \ + if (bus && bus->ops && bus->ops->name) { \ + bus->ops->name al; \ + return; \ + } \ + __do_##name al; \ } -static u16 spider_readw_be(const volatile void __iomem *addr) -{ - u16 val = __do_readw_be(addr); - spider_io_flush(addr); - return val; -} +#include <asm/io-defs.h> -static u32 spider_readl_be(const volatile void __iomem *addr) -{ - u32 val = __do_readl_be(addr); - spider_io_flush(addr); - return val; -} +#undef DEF_PCI_AC_RET +#undef DEF_PCI_AC_NORET -static u64 spider_readq_be(const volatile void __iomem *addr) -{ - u64 val = __do_readq_be(addr); - spider_io_flush(addr); - return val; -} +static struct ppc_pci_io __initdata iowa_pci_io = { -static void spider_readsb(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - __do_readsb(addr, buf, count); - spider_io_flush(addr); -} +#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name, +#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name, -static void spider_readsw(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - __do_readsw(addr, buf, count); - spider_io_flush(addr); -} +#include <asm/io-defs.h> -static void spider_readsl(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - __do_readsl(addr, buf, count); - spider_io_flush(addr); -} - -static void spider_memcpy_fromio(void *dest, const volatile void __iomem *src, - unsigned long n) -{ - __do_memcpy_fromio(dest, src, n); - spider_io_flush(src); -} +#undef DEF_PCI_AC_RET +#undef DEF_PCI_AC_NORET +}; -static void __iomem * spider_ioremap(unsigned long addr, unsigned long size, - unsigned long flags) +static void __iomem *iowa_ioremap(unsigned long addr, unsigned long size, + unsigned long flags) { - struct spider_pci_bus *bus; + struct iowa_bus *bus; void __iomem *res = __ioremap(addr, size, flags); int busno; - pr_debug("spider_ioremap(0x%lx, 0x%lx, 0x%lx) -> 0x%p\n", - addr, size, flags, res); - - bus = spider_pci_find(0, addr); + bus = iowa_pci_find(0, addr); if (bus != NULL) { - busno = bus - spider_pci_busses; - pr_debug(" found bus %d, setting token\n", busno); + busno = bus - iowa_busses; PCI_SET_ADDR_TOKEN(res, busno + 1); } - pr_debug(" result=0x%p\n", res); - return res; } -static void __init spider_pci_setup_chip(struct spider_pci_bus *bus) -{ -#ifdef SPIDER_DISABLE_PREFETCH - u32 val = in_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT); - pr_debug(" PVCI_Control_Status was 0x%08x\n", val); - out_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8); -#endif - - /* Configure the dummy address for the workaround */ - out_be32(bus->regs + SPIDER_PCI_DUMMY_READ_BASE, 0x80000000); -} - -static void __init spider_pci_add_one(struct pci_controller *phb) +/* Regist new bus to support workaround */ +void __init iowa_register_bus(struct pci_controller *phb, + struct ppc_pci_io *ops, + int (*initfunc)(struct iowa_bus *, void *), void *data) { - struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count]; + struct iowa_bus *bus; struct device_node *np = phb->dn; - struct resource rsrc; - void __iomem *regs; - if (spider_pci_count >= MAX_SPIDERS) { - printk(KERN_ERR "Too many spider bridges, workarounds" - " disabled for %s\n", np->full_name); + if (iowa_bus_count >= IOWA_MAX_BUS) { + pr_err("IOWA:Too many pci bridges, " + "workarounds disabled for %s\n", np->full_name); return; } - /* Get the registers for the beast */ - if (of_address_to_resource(np, 0, &rsrc)) { - printk(KERN_ERR "Failed to get registers for spider %s" - " workarounds disabled\n", np->full_name); - return; - } + bus = &iowa_busses[iowa_bus_count]; + bus->phb = phb; + bus->ops = ops; - /* Mask out some useless bits in there to get to the base of the - * spider chip - */ - rsrc.start &= ~0xfffffffful; - - /* Map them */ - regs = ioremap(rsrc.start + SPIDER_PCI_REG_BASE, 0x1000); - if (regs == NULL) { - printk(KERN_ERR "Failed to map registers for spider %s" - " workarounds disabled\n", np->full_name); - return; - } - - spider_pci_count++; - - /* We assume spiders only have one MMIO resource */ - bus->mmio_start = phb->mem_resources[0].start; - bus->mmio_end = phb->mem_resources[0].end + 1; - - bus->pio_vstart = (unsigned long)phb->io_base_virt; - bus->pio_vend = bus->pio_vstart + phb->pci_io_size; - - bus->regs = regs; - - printk(KERN_INFO "PCI: Spider MMIO workaround for %s\n",np->full_name); + if (initfunc) + if ((*initfunc)(bus, data)) + return; - pr_debug(" mmio (P) = 0x%016lx..0x%016lx\n", - bus->mmio_start, bus->mmio_end); - pr_debug(" pio (V) = 0x%016lx..0x%016lx\n", - bus->pio_vstart, bus->pio_vend); - pr_debug(" regs (P) = 0x%016lx (V) = 0x%p\n", - rsrc.start + SPIDER_PCI_REG_BASE, bus->regs); + iowa_bus_count++; - spider_pci_setup_chip(bus); + pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name); } -static struct ppc_pci_io __initdata spider_pci_io = { - .readb = spider_readb, - .readw = spider_readw, - .readl = spider_readl, - .readq = spider_readq, - .readw_be = spider_readw_be, - .readl_be = spider_readl_be, - .readq_be = spider_readq_be, - .readsb = spider_readsb, - .readsw = spider_readsw, - .readsl = spider_readsl, - .memcpy_fromio = spider_memcpy_fromio, -}; - -static int __init spider_pci_workaround_init(void) +/* enable IO workaround */ +void __init io_workaround_init(void) { - struct pci_controller *phb; - - /* Find spider bridges. We assume they have been all probed - * in setup_arch(). If that was to change, we would need to - * update this code to cope with dynamically added busses - */ - list_for_each_entry(phb, &hose_list, list_node) { - struct device_node *np = phb->dn; - const char *model = of_get_property(np, "model", NULL); - - /* If no model property or name isn't exactly "pci", skip */ - if (model == NULL || strcmp(np->name, "pci")) - continue; - /* If model is not "Spider", skip */ - if (strcmp(model, "Spider")) - continue; - spider_pci_add_one(phb); - } - - /* No Spider PCI found, exit */ - if (spider_pci_count == 0) - return 0; + static int io_workaround_inited; - /* Setup IO callbacks. We only setup MMIO reads. PIO reads will - * fallback to MMIO reads (though without a token, thus slower) - */ - ppc_pci_io = spider_pci_io; - - /* Setup ioremap callback */ - ppc_md.ioremap = spider_ioremap; - - return 0; + if (io_workaround_inited) + return; + ppc_pci_io = iowa_pci_io; + ppc_md.ioremap = iowa_ioremap; + io_workaround_inited = 1; } -machine_arch_initcall(cell, spider_pci_workaround_init); diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/platforms/cell/io-workarounds.h new file mode 100644 index 00000000000..79d8ed3d510 --- /dev/null +++ b/arch/powerpc/platforms/cell/io-workarounds.h @@ -0,0 +1,49 @@ +/* + * Support PCI IO workaround + * + * (C) Copyright 2007-2008 TOSHIBA 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _IO_WORKAROUNDS_H +#define _IO_WORKAROUNDS_H + +#include <linux/io.h> +#include <asm/pci-bridge.h> + +/* Bus info */ +struct iowa_bus { + struct pci_controller *phb; + struct ppc_pci_io *ops; + void *private; +}; + +void __init io_workaround_init(void); +void __init iowa_register_bus(struct pci_controller *, struct ppc_pci_io *, + int (*)(struct iowa_bus *, void *), void *); +struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR); +struct iowa_bus *iowa_pio_find_bus(unsigned long); + +extern struct ppc_pci_io spiderpci_ops; +extern int spiderpci_iowa_init(struct iowa_bus *, void *); + +#define SPIDER_PCI_REG_BASE 0xd000 +#define SPIDER_PCI_REG_SIZE 0x1000 +#define SPIDER_PCI_VCI_CNTL_STAT 0x0110 +#define SPIDER_PCI_DUMMY_READ 0x0810 +#define SPIDER_PCI_DUMMY_READ_BASE 0x0814 + +#endif /* _IO_WORKAROUNDS_H */ diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index d75ccded7f1..45646b2b4af 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -28,13 +28,13 @@ #include <linux/notifier.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/lmb.h> #include <asm/prom.h> #include <asm/iommu.h> #include <asm/machdep.h> #include <asm/pci-bridge.h> #include <asm/udbg.h> -#include <asm/lmb.h> #include <asm/firmware.h> #include <asm/cell-regs.h> @@ -316,7 +316,7 @@ static void cell_iommu_setup_stab(struct cbe_iommu *iommu, segments = max(dbase + dsize, fbase + fsize) >> IO_SEGMENT_SHIFT; pr_debug("%s: iommu[%d]: segments: %lu\n", - __FUNCTION__, iommu->nid, segments); + __func__, iommu->nid, segments); /* set up the segment table */ stab_size = segments * sizeof(unsigned long); @@ -343,7 +343,7 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu, (1 << 12) / sizeof(unsigned long)); ptab_size = segments * pages_per_segment * sizeof(unsigned long); - pr_debug("%s: iommu[%d]: ptab_size: %lu, order: %d\n", __FUNCTION__, + pr_debug("%s: iommu[%d]: ptab_size: %lu, order: %d\n", __func__, iommu->nid, ptab_size, get_order(ptab_size)); page = alloc_pages_node(iommu->nid, GFP_KERNEL, get_order(ptab_size)); BUG_ON(!page); @@ -355,7 +355,7 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu, n_pte_pages = (pages_per_segment * sizeof(unsigned long)) >> 12; pr_debug("%s: iommu[%d]: stab at %p, ptab at %p, n_pte_pages: %lu\n", - __FUNCTION__, iommu->nid, iommu->stab, ptab, + __func__, iommu->nid, iommu->stab, ptab, n_pte_pages); /* initialise the STEs */ @@ -394,7 +394,7 @@ static void cell_iommu_enable_hardware(struct cbe_iommu *iommu) if (cell_iommu_find_ioc(iommu->nid, &xlate_base)) panic("%s: missing IOC register mappings for node %d\n", - __FUNCTION__, iommu->nid); + __func__, iommu->nid); iommu->xlate_regs = ioremap(xlate_base, IOC_Reg_Size); iommu->cmd_regs = iommu->xlate_regs + IOC_IOCmd_Offset; diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 0304589c0a8..8a3631ce912 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -65,7 +65,7 @@ static void cbe_power_save(void) break; default: printk(KERN_WARNING "%s: unknown configuration\n", - __FUNCTION__); + __func__); break; } mtspr(SPRN_TSC_CELL, thread_switch_control); diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index e43024c0392..655704ad03c 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -132,7 +132,7 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order) (unsigned int)(addr >> 32), (unsigned int)(addr & 0xffffffff))) { printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n", - __FUNCTION__, nid); + __func__, nid); goto out_free_pages; } @@ -162,7 +162,7 @@ static int __init cbe_ptcal_enable(void) if (!size) return -ENODEV; - pr_debug("%s: enabling PTCAL, size = 0x%x\n", __FUNCTION__, *size); + pr_debug("%s: enabling PTCAL, size = 0x%x\n", __func__, *size); order = get_order(*size); of_node_put(np); @@ -180,7 +180,7 @@ static int __init cbe_ptcal_enable(void) const u32 *nid = of_get_property(np, "node-id", NULL); if (!nid) { printk(KERN_ERR "%s: node %s is missing node-id?\n", - __FUNCTION__, np->full_name); + __func__, np->full_name); continue; } cbe_ptcal_enable_on_node(*nid, order); @@ -195,13 +195,13 @@ static int cbe_ptcal_disable(void) struct ptcal_area *area, *tmp; int ret = 0; - pr_debug("%s: disabling PTCAL\n", __FUNCTION__); + pr_debug("%s: disabling PTCAL\n", __func__); list_for_each_entry_safe(area, tmp, &ptcal_list, list) { /* disable ptcal on this node */ if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) { printk(KERN_ERR "%s: error disabling PTCAL " - "on node %d!\n", __FUNCTION__, + "on node %d!\n", __func__, area->nid); ret = -EIO; continue; diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 5c531e8f9f6..ab721b50fbb 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -57,6 +57,7 @@ #include "interrupt.h" #include "pervasive.h" #include "ras.h" +#include "io-workarounds.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -117,13 +118,50 @@ static void cell_fixup_pcie_rootcomplex(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, cell_fixup_pcie_rootcomplex); +static int __devinit cell_setup_phb(struct pci_controller *phb) +{ + const char *model; + struct device_node *np; + + int rc = rtas_setup_phb(phb); + if (rc) + return rc; + + np = phb->dn; + model = of_get_property(np, "model", NULL); + if (model == NULL || strcmp(np->name, "pci")) + return 0; + + /* Setup workarounds for spider */ + if (strcmp(model, "Spider")) + return 0; + + iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init, + (void *)SPIDER_PCI_REG_BASE); + io_workaround_init(); + + return 0; +} + static int __init cell_publish_devices(void) { + struct device_node *root = of_find_node_by_path("/"); + struct device_node *np; int node; /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, NULL, NULL); + /* On spider based blades, we need to manually create the OF + * platform devices for the PCI host bridges + */ + for_each_child_of_node(root, np) { + if (np->type == NULL || (strcmp(np->type, "pci") != 0 && + strcmp(np->type, "pciex") != 0)) + continue; + of_platform_device_create(np, NULL, NULL); + } + /* There is no device for the MIC memory controller, thus we create * a platform device for it to attach the EDAC driver to. */ @@ -132,6 +170,7 @@ static int __init cell_publish_devices(void) continue; platform_device_register_simple("cbe-mic", node, NULL, 0); } + return 0; } machine_subsys_initcall(cell, cell_publish_devices); @@ -213,7 +252,7 @@ static void __init cell_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); - find_and_init_phbs(); + cbe_pervasive_init(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -249,7 +288,7 @@ define_machine(cell) { .calibrate_decr = generic_calibrate_decr, .progress = cell_progress, .init_IRQ = cell_init_irq, - .pci_setup_phb = rtas_setup_phb, + .pci_setup_phb = cell_setup_phb, #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c new file mode 100644 index 00000000000..418b605ac35 --- /dev/null +++ b/arch/powerpc/platforms/cell/spider-pci.c @@ -0,0 +1,184 @@ +/* + * IO workarounds for PCI on Celleb/Cell platform + * + * (C) Copyright 2006-2007 TOSHIBA 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/of_platform.h> +#include <linux/io.h> + +#include <asm/ppc-pci.h> +#include <asm/pci-bridge.h> + +#include "io-workarounds.h" + +#define SPIDER_PCI_DISABLE_PREFETCH + +struct spiderpci_iowa_private { + void __iomem *regs; +}; + +static void spiderpci_io_flush(struct iowa_bus *bus) +{ + struct spiderpci_iowa_private *priv; + u32 val; + + priv = bus->private; + val = in_be32(priv->regs + SPIDER_PCI_DUMMY_READ); + iosync(); +} + +#define SPIDER_PCI_MMIO_READ(name, ret) \ +static ret spiderpci_##name(const PCI_IO_ADDR addr) \ +{ \ + ret val = __do_##name(addr); \ + spiderpci_io_flush(iowa_mem_find_bus(addr)); \ + return val; \ +} + +#define SPIDER_PCI_MMIO_READ_STR(name) \ +static void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \ + unsigned long count) \ +{ \ + __do_##name(addr, buf, count); \ + spiderpci_io_flush(iowa_mem_find_bus(addr)); \ +} + +SPIDER_PCI_MMIO_READ(readb, u8) +SPIDER_PCI_MMIO_READ(readw, u16) +SPIDER_PCI_MMIO_READ(readl, u32) +SPIDER_PCI_MMIO_READ(readq, u64) +SPIDER_PCI_MMIO_READ(readw_be, u16) +SPIDER_PCI_MMIO_READ(readl_be, u32) +SPIDER_PCI_MMIO_READ(readq_be, u64) +SPIDER_PCI_MMIO_READ_STR(readsb) +SPIDER_PCI_MMIO_READ_STR(readsw) +SPIDER_PCI_MMIO_READ_STR(readsl) + +static void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src, + unsigned long n) +{ + __do_memcpy_fromio(dest, src, n); + spiderpci_io_flush(iowa_mem_find_bus(src)); +} + +static int __init spiderpci_pci_setup_chip(struct pci_controller *phb, + void __iomem *regs) +{ + void *dummy_page_va; + dma_addr_t dummy_page_da; + +#ifdef SPIDER_PCI_DISABLE_PREFETCH + u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT); + pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val); + out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8); +#endif /* SPIDER_PCI_DISABLE_PREFETCH */ + + /* setup dummy read */ + /* + * On CellBlade, we can't know that which XDR memory is used by + * kmalloc() to allocate dummy_page_va. + * In order to imporve the performance, the XDR which is used to + * allocate dummy_page_va is the nearest the spider-pci. + * We have to select the CBE which is the nearest the spider-pci + * to allocate memory from the best XDR, but I don't know that + * how to do. + * + * Celleb does not have this problem, because it has only one XDR. + */ + dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!dummy_page_va) { + pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n"); + return -1; + } + + dummy_page_da = dma_map_single(phb->parent, dummy_page_va, + PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dummy_page_da)) { + pr_err("SPIDER-IOWA:Map dummy page filed.\n"); + kfree(dummy_page_va); + return -1; + } + + out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da); + + return 0; +} + +int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data) +{ + void __iomem *regs = NULL; + struct spiderpci_iowa_private *priv; + struct device_node *np = bus->phb->dn; + struct resource r; + unsigned long offset = (unsigned long)data; + + pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%s)\n", + np->full_name); + + priv = kzalloc(sizeof(struct spiderpci_iowa_private), GFP_KERNEL); + if (!priv) { + pr_err("SPIDERPCI-IOWA:" + "Can't allocate struct spiderpci_iowa_private"); + return -1; + } + + if (of_address_to_resource(np, 0, &r)) { + pr_err("SPIDERPCI-IOWA:Can't get resource.\n"); + goto error; + } + + regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE); + if (!regs) { + pr_err("SPIDERPCI-IOWA:ioremap failed.\n"); + goto error; + } + priv->regs = regs; + bus->private = priv; + + if (spiderpci_pci_setup_chip(bus->phb, regs)) + goto error; + + return 0; + +error: + kfree(priv); + bus->private = NULL; + + if (regs) + iounmap(regs); + + return -1; +} + +struct ppc_pci_io spiderpci_ops = { + .readb = spiderpci_readb, + .readw = spiderpci_readw, + .readl = spiderpci_readl, + .readq = spiderpci_readq, + .readw_be = spiderpci_readw_be, + .readl_be = spiderpci_readl_be, + .readq_be = spiderpci_readq_be, + .readsb = spiderpci_readsb, + .readsw = spiderpci_readsw, + .readsl = spiderpci_readsl, + .memcpy_fromio = spiderpci_memcpy_fromio, +}; + diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 712001f6b7d..6bab44b7716 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -165,7 +165,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) struct spu_slb slb; int psize; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); slb.esid = (ea & ESID_MASK) | SLB_ESID_V; @@ -215,7 +215,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) { - pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea); + pr_debug("%s, %lx, %lx\n", __func__, dsisr, ea); /* Handle kernel space hash faults immediately. User hash faults need to be deferred to process context. */ @@ -351,7 +351,7 @@ spu_irq_class_1(int irq, void *data) __spu_trap_data_seg(spu, dar); spin_unlock(&spu->register_lock); - pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat, + pr_debug("%s: %lx %lx %lx %lx\n", __func__, mask, stat, dar, dsisr); if (stat & CLASS1_STORAGE_FAULT_INTR) @@ -726,7 +726,7 @@ static int __init init_spu_base(void) if (ret < 0) { printk(KERN_WARNING "%s: Error initializing spus\n", - __FUNCTION__); + __func__); goto out_unregister_sysdev_class; } diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index dceb8b6a938..19f6bfdbb93 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -54,7 +54,7 @@ long spu_sys_callback(struct spu_syscall_block *s) long (*syscall)(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6); if (s->nr_ret >= ARRAY_SIZE(spu_syscall_table)) { - pr_debug("%s: invalid syscall #%ld", __FUNCTION__, s->nr_ret); + pr_debug("%s: invalid syscall #%ld", __func__, s->nr_ret); return -ENOSYS; } diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index d351bdebf5f..4c506c1463c 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -92,7 +92,7 @@ static int __init spu_map_interrupts_old(struct spu *spu, tmp = of_get_property(np->parent->parent, "node-id", NULL); if (!tmp) { - printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__); + printk(KERN_WARNING "%s: can't find node-id\n", __func__); nid = spu->node; } else nid = tmp[0]; @@ -296,7 +296,7 @@ static int __init of_enumerate_spus(int (*fn)(void *data)) ret = fn(node); if (ret) { printk(KERN_WARNING "%s: Error initializing %s\n", - __FUNCTION__, node->name); + __func__, node->name); break; } n++; @@ -327,7 +327,7 @@ static int __init of_create_spu(struct spu *spu, void *data) if (!legacy_map) { legacy_map = 1; printk(KERN_WARNING "%s: Legacy device tree found, " - "trying to map old style\n", __FUNCTION__); + "trying to map old style\n", __func__); } ret = spu_map_device_old(spu); if (ret) { @@ -342,7 +342,7 @@ static int __init of_create_spu(struct spu *spu, void *data) if (!legacy_irq) { legacy_irq = 1; printk(KERN_WARNING "%s: Legacy device tree found, " - "trying old style irq\n", __FUNCTION__); + "trying old style irq\n", __func__); } ret = spu_map_interrupts_old(spu, spe); if (ret) { diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 0c6a96b82b2..b962c3ab470 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -133,8 +133,6 @@ static struct spu_context *coredump_next_context(int *fd) if (ctx->flags & SPU_CREATE_NOSCHED) continue; - /* start searching the next fd next time we're called */ - (*fd)++; break; } @@ -157,6 +155,9 @@ int spufs_coredump_extra_notes_size(void) break; size += rc; + + /* start searching the next fd next time */ + fd++; } return size; @@ -239,6 +240,9 @@ int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset) } spu_release_saved(ctx); + + /* start searching the next fd next time */ + fd++; } return 0; diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index f7a7e8635fb..08f44d1971a 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -32,7 +32,6 @@ #include <linux/marker.h> #include <asm/io.h> -#include <asm/semaphore.h> #include <asm/spu.h> #include <asm/spu_info.h> #include <asm/uaccess.h> @@ -1337,7 +1336,7 @@ static u64 spufs_signal1_type_get(struct spu_context *ctx) return ctx->ops->signal1_type_get(ctx); } DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, - spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); + spufs_signal1_type_set, "%llu\n", SPU_ATTR_ACQUIRE); static int spufs_signal2_type_set(void *data, u64 val) @@ -1359,7 +1358,7 @@ static u64 spufs_signal2_type_get(struct spu_context *ctx) return ctx->ops->signal2_type_get(ctx); } DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, - spufs_signal2_type_set, "%llu", SPU_ATTR_ACQUIRE); + spufs_signal2_type_set, "%llu\n", SPU_ATTR_ACQUIRE); #if SPUFS_MMAP_4K static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, @@ -1556,7 +1555,7 @@ void spufs_mfc_callback(struct spu *spu) wake_up_all(&ctx->mfc_wq); - pr_debug("%s %s\n", __FUNCTION__, spu->name); + pr_debug("%s %s\n", __func__, spu->name); if (ctx->mfc_fasync) { u32 free_elements, tagstatus; unsigned int mask; @@ -1790,7 +1789,7 @@ static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) if (tagstatus & ctx->tagwait) mask |= POLLIN | POLLRDNORM; - pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, + pr_debug("%s: free %d tagstatus %d tagwait %d\n", __func__, free_elements, tagstatus, ctx->tagwait); return mask; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 6d1228c66c5..0c32a05ab06 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -35,7 +35,6 @@ #include <linux/parser.h> #include <asm/prom.h> -#include <asm/semaphore.h> #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/uaccess.h> diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index cac69e11677..96bf7c2b86f 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -98,7 +98,7 @@ static int spu_setup_isolated(struct spu_context *ctx) != MFC_CNTL_PURGE_DMA_COMPLETE) { if (time_after(jiffies, timeout)) { printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n", - __FUNCTION__); + __func__); ret = -EIO; goto out; } @@ -124,7 +124,7 @@ static int spu_setup_isolated(struct spu_context *ctx) status_loading) { if (time_after(jiffies, timeout)) { printk(KERN_ERR "%s: timeout waiting for loader\n", - __FUNCTION__); + __func__); ret = -EIO; goto out_drop_priv; } @@ -134,7 +134,7 @@ static int spu_setup_isolated(struct spu_context *ctx) if (!(status & SPU_STATUS_RUNNING)) { /* If isolated LOAD has failed: run SPU, we will get a stop-and * signal later. */ - pr_debug("%s: isolated LOAD failed\n", __FUNCTION__); + pr_debug("%s: isolated LOAD failed\n", __func__); ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); ret = -EACCES; goto out_drop_priv; @@ -142,7 +142,7 @@ static int spu_setup_isolated(struct spu_context *ctx) if (!(status & SPU_STATUS_ISOLATED_STATE)) { /* This isn't allowed by the CBEA, but check anyway */ - pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__); + pr_debug("%s: SPU fell out of isolated mode?\n", __func__); ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP); ret = -EINVAL; goto out_drop_priv; @@ -282,7 +282,7 @@ static int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, break; default: printk(KERN_WARNING "%s: unexpected return code %ld\n", - __FUNCTION__, *spu_ret); + __func__, *spu_ret); ret = 0; } return ret; @@ -323,6 +323,10 @@ static int spu_process_callback(struct spu_context *ctx) return -EINTR; } + /* need to re-get the ls, as it may have changed when we released the + * spu */ + ls = (void __iomem *)ctx->ops->get_ls(ctx); + /* write result, jump over indirect pointer */ memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret)); ctx->ops->npc_write(ctx, npc); diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index e9dc7a55d1b..d2a1249d36d 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -1815,6 +1815,7 @@ static void save_csa(struct spu_state *prev, struct spu *spu) save_mfc_csr_ato(prev, spu); /* Step 24. */ save_mfc_tclass_id(prev, spu); /* Step 25. */ set_mfc_tclass_id(prev, spu); /* Step 26. */ + save_mfc_cmd(prev, spu); /* Step 26a - moved from 44. */ purge_mfc_queue(prev, spu); /* Step 27. */ wait_purge_complete(prev, spu); /* Step 28. */ setup_mfc_sr1(prev, spu); /* Step 30. */ @@ -1831,7 +1832,6 @@ static void save_csa(struct spu_state *prev, struct spu *spu) save_ppuint_mb(prev, spu); /* Step 41. */ save_ch_part1(prev, spu); /* Step 42. */ save_spu_mb(prev, spu); /* Step 43. */ - save_mfc_cmd(prev, spu); /* Step 44. */ reset_ch(prev, spu); /* Step 45. */ } diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig deleted file mode 100644 index 372891edcdd..00000000000 --- a/arch/powerpc/platforms/celleb/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config PPC_CELLEB - bool "Toshiba's Cell Reference Set 'Celleb' Architecture" - depends on PPC_MULTIPLATFORM && PPC64 - select PPC_CELL - select PPC_CELL_NATIVE - select PPC_RTAS - select PPC_INDIRECT_IO - select PPC_OF_PLATFORM_PCI - select HAS_TXX9_SERIAL - select PPC_UDBG_BEAT - select USB_OHCI_BIG_ENDIAN_MMIO - select USB_EHCI_BIG_ENDIAN_MMIO diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile deleted file mode 100644 index 889d43f715e..00000000000 --- a/arch/powerpc/platforms/celleb/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -obj-y += interrupt.o iommu.o setup.o \ - htab.o beat.o hvCall.o pci.o \ - scc_epci.o scc_uhc.o \ - io-workarounds.o - -obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o -obj-$(CONFIG_SERIAL_TXX9) += scc_sio.o -obj-$(CONFIG_SPU_BASE) += spu_priv1.o diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c deleted file mode 100644 index 423339be1ba..00000000000 --- a/arch/powerpc/platforms/celleb/io-workarounds.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Support for Celleb io workarounds - * - * (C) Copyright 2006-2007 TOSHIBA CORPORATION - * - * This file is based to arch/powerpc/platform/cell/io-workarounds.c - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#undef DEBUG - -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/irq.h> - -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pci-bridge.h> -#include <asm/ppc-pci.h> - -#include "pci.h" - -#define MAX_CELLEB_PCI_BUS 4 - -void *celleb_dummy_page_va; - -static struct celleb_pci_bus { - struct pci_controller *phb; - void (*dummy_read)(struct pci_controller *); -} celleb_pci_busses[MAX_CELLEB_PCI_BUS]; - -static int celleb_pci_count = 0; - -static struct celleb_pci_bus *celleb_pci_find(unsigned long vaddr, - unsigned long paddr) -{ - int i, j; - struct resource *res; - - for (i = 0; i < celleb_pci_count; i++) { - struct celleb_pci_bus *bus = &celleb_pci_busses[i]; - struct pci_controller *phb = bus->phb; - if (paddr) - for (j = 0; j < 3; j++) { - res = &phb->mem_resources[j]; - if (paddr >= res->start && paddr <= res->end) - return bus; - } - res = &phb->io_resource; - if (vaddr && vaddr >= res->start && vaddr <= res->end) - return bus; - } - return NULL; -} - -static void celleb_io_flush(const PCI_IO_ADDR addr) -{ - struct celleb_pci_bus *bus; - int token; - - token = PCI_GET_ADDR_TOKEN(addr); - - if (token && token <= celleb_pci_count) - bus = &celleb_pci_busses[token - 1]; - else { - unsigned long vaddr, paddr; - pte_t *ptep; - - vaddr = (unsigned long)PCI_FIX_ADDR(addr); - if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) - return; - - ptep = find_linux_pte(init_mm.pgd, vaddr); - if (ptep == NULL) - paddr = 0; - else - paddr = pte_pfn(*ptep) << PAGE_SHIFT; - bus = celleb_pci_find(vaddr, paddr); - - if (bus == NULL) - return; - } - - if (bus->dummy_read) - bus->dummy_read(bus->phb); -} - -static u8 celleb_readb(const PCI_IO_ADDR addr) -{ - u8 val; - val = __do_readb(addr); - celleb_io_flush(addr); - return val; -} - -static u16 celleb_readw(const PCI_IO_ADDR addr) -{ - u16 val; - val = __do_readw(addr); - celleb_io_flush(addr); - return val; -} - -static u32 celleb_readl(const PCI_IO_ADDR addr) -{ - u32 val; - val = __do_readl(addr); - celleb_io_flush(addr); - return val; -} - -static u64 celleb_readq(const PCI_IO_ADDR addr) -{ - u64 val; - val = __do_readq(addr); - celleb_io_flush(addr); - return val; -} - -static u16 celleb_readw_be(const PCI_IO_ADDR addr) -{ - u16 val; - val = __do_readw_be(addr); - celleb_io_flush(addr); - return val; -} - -static u32 celleb_readl_be(const PCI_IO_ADDR addr) -{ - u32 val; - val = __do_readl_be(addr); - celleb_io_flush(addr); - return val; -} - -static u64 celleb_readq_be(const PCI_IO_ADDR addr) -{ - u64 val; - val = __do_readq_be(addr); - celleb_io_flush(addr); - return val; -} - -static void celleb_readsb(const PCI_IO_ADDR addr, - void *buf, unsigned long count) -{ - __do_readsb(addr, buf, count); - celleb_io_flush(addr); -} - -static void celleb_readsw(const PCI_IO_ADDR addr, - void *buf, unsigned long count) -{ - __do_readsw(addr, buf, count); - celleb_io_flush(addr); -} - -static void celleb_readsl(const PCI_IO_ADDR addr, - void *buf, unsigned long count) -{ - __do_readsl(addr, buf, count); - celleb_io_flush(addr); -} - -static void celleb_memcpy_fromio(void *dest, - const PCI_IO_ADDR src, - unsigned long n) -{ - __do_memcpy_fromio(dest, src, n); - celleb_io_flush(src); -} - -static void __iomem *celleb_ioremap(unsigned long addr, - unsigned long size, - unsigned long flags) -{ - struct celleb_pci_bus *bus; - void __iomem *res = __ioremap(addr, size, flags); - int busno; - - bus = celleb_pci_find(0, addr); - if (bus != NULL) { - busno = bus - celleb_pci_busses; - PCI_SET_ADDR_TOKEN(res, busno + 1); - } - return res; -} - -static void celleb_iounmap(volatile void __iomem *addr) -{ - return __iounmap(PCI_FIX_ADDR(addr)); -} - -static struct ppc_pci_io celleb_pci_io __initdata = { - .readb = celleb_readb, - .readw = celleb_readw, - .readl = celleb_readl, - .readq = celleb_readq, - .readw_be = celleb_readw_be, - .readl_be = celleb_readl_be, - .readq_be = celleb_readq_be, - .readsb = celleb_readsb, - .readsw = celleb_readsw, - .readsl = celleb_readsl, - .memcpy_fromio = celleb_memcpy_fromio, -}; - -void __init celleb_pci_add_one(struct pci_controller *phb, - void (*dummy_read)(struct pci_controller *)) -{ - struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count]; - struct device_node *np = phb->dn; - - if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) { - printk(KERN_ERR "Too many pci bridges, workarounds" - " disabled for %s\n", np->full_name); - return; - } - - celleb_pci_count++; - - bus->phb = phb; - bus->dummy_read = dummy_read; -} - -static struct of_device_id celleb_pci_workaround_match[] __initdata = { - { - .name = "pci-pseudo", - .data = fake_pci_workaround_init, - }, { - .name = "epci", - .data = epci_workaround_init, - }, { - }, -}; - -int __init celleb_pci_workaround_init(void) -{ - struct pci_controller *phb; - struct device_node *node; - const struct of_device_id *match; - void (*init_func)(struct pci_controller *); - - celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!celleb_dummy_page_va) { - printk(KERN_ERR "Celleb: dummy read disabled. " - "Alloc celleb_dummy_page_va failed\n"); - return 1; - } - - list_for_each_entry(phb, &hose_list, list_node) { - node = phb->dn; - match = of_match_node(celleb_pci_workaround_match, node); - - if (match) { - init_func = match->data; - (*init_func)(phb); - } - } - - ppc_pci_io = celleb_pci_io; - ppc_md.ioremap = celleb_ioremap; - ppc_md.iounmap = celleb_iounmap; - - return 0; -} diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index d4f8bf581e3..84e2d78b9a6 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -117,11 +117,11 @@ static void __init mpc7448_hpc2_init_IRQ(void) } if (mpic_paddr == 0) { - printk("%s: No tsi108 PIC found !\n", __FUNCTION__); + printk("%s: No tsi108 PIC found !\n", __func__); return; } - DBG("%s: tsi108 pic phys_addr = 0x%x\n", __FUNCTION__, + DBG("%s: tsi108 pic phys_addr = 0x%x\n", __func__, (u32) mpic_paddr); mpic = mpic_alloc(tsi_pic, mpic_paddr, @@ -140,17 +140,17 @@ static void __init mpc7448_hpc2_init_IRQ(void) #ifdef CONFIG_PCI tsi_pci = of_find_node_by_type(NULL, "pci"); if (tsi_pci == NULL) { - printk("%s: No tsi108 pci node found !\n", __FUNCTION__); + printk("%s: No tsi108 pci node found !\n", __func__); return; } cascade_node = of_find_node_by_type(NULL, "pic-router"); if (cascade_node == NULL) { - printk("%s: No tsi108 pci cascade node found !\n", __FUNCTION__); + printk("%s: No tsi108 pci cascade node found !\n", __func__); return; } cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0); - DBG("%s: tsi108 cascade_pci_irq = 0x%x\n", __FUNCTION__, + DBG("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, (u32) cascade_pci_irq); tsi108_pci_int_init(cascade_node); set_irq_data(cascade_pci_irq, mpic); diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c index 653a5eb91c9..5a19b9a1457 100644 --- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c +++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c @@ -49,13 +49,13 @@ static void __init prpmc2800_setup_arch(void) * ioremap mpp and gpp registers in case they are later * needed by prpmc2800_reset_board(). */ - np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-mpp"); + np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-mpp"); reg = of_get_property(np, "reg", NULL); paddr = of_translate_address(np, reg); of_node_put(np); mv64x60_mpp_reg_base = ioremap(paddr, reg[1]); - np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-gpp"); + np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-gpp"); reg = of_get_property(np, "reg", NULL); paddr = of_translate_address(np, reg); of_node_put(np); diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index 5381038f088..8ff330d026c 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -38,11 +38,19 @@ .globl system_reset_iSeries system_reset_iSeries: - mfspr r13,SPRN_SPRG3 /* Get paca address */ + mfspr r13,SPRN_SPRG3 /* Get alpaca address */ + LOAD_REG_IMMEDIATE(r23, alpaca) + li r0,ALPACA_SIZE + sub r23,r13,r23 + divdu r23,r23,r0 /* r23 has cpu number */ + LOAD_REG_IMMEDIATE(r13, paca) + mulli r0,r23,PACA_SIZE + add r13,r13,r0 + mtspr SPRN_SPRG3,r13 /* Save it away for the future */ mfmsr r24 ori r24,r24,MSR_RI mtmsrd r24 /* RI on */ - lhz r24,PACAPACAINDEX(r13) /* Get processor # */ + mr r24,r23 cmpwi 0,r24,0 /* Are we processor 0? */ bne 1f b .__start_initialization_iSeries /* Start up the first processor */ @@ -51,8 +59,33 @@ system_reset_iSeries: andc r4,r4,r5 mtspr SPRN_CTRLT,r4 +/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ +/* In the UP case we'll yeild() later, and we will not access the paca anyway */ +#ifdef CONFIG_SMP 1: HMT_LOW + LOAD_REG_IMMEDIATE(r23, __secondary_hold_spinloop) + ld r23,0(r23) + sync + LOAD_REG_IMMEDIATE(r3,current_set) + sldi r28,r24,3 /* get current_set[cpu#] */ + ldx r3,r3,r28 + addi r1,r3,THREAD_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpwi 0,r23,0 /* Keep poking the Hypervisor until */ + bne 2f /* we're released */ + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + b 1b +#endif + +2: + HMT_LOW #ifdef CONFIG_SMP lbz r23,PACAPROCSTART(r13) /* Test if this processor * should start */ @@ -83,7 +116,7 @@ iSeries_secondary_smp_loop: li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */ - b 1b /* If SMP not configured, secondaries + b 2b /* If SMP not configured, secondaries * loop forever */ /*** ISeries-LPAR interrupt handlers ***/ diff --git a/arch/powerpc/platforms/iseries/ipl_parms.h b/arch/powerpc/platforms/iseries/ipl_parms.h index 77c135ddbf1..83e4ca42fc5 100644 --- a/arch/powerpc/platforms/iseries/ipl_parms.h +++ b/arch/powerpc/platforms/iseries/ipl_parms.h @@ -65,6 +65,4 @@ struct ItIplParmsReal { u64 xRsvd13; // Reserved x38-x3F }; -extern struct ItIplParmsReal xItIplParmsReal; - #endif /* _ISERIES_IPL_PARMS_H */ diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c index 8162049bb04..98bd2d37038 100644 --- a/arch/powerpc/platforms/iseries/lpardata.c +++ b/arch/powerpc/platforms/iseries/lpardata.c @@ -14,10 +14,10 @@ #include <asm/ptrace.h> #include <asm/abs_addr.h> #include <asm/lppaca.h> -#include <asm/iseries/it_lp_reg_save.h> #include <asm/paca.h> #include <asm/iseries/lpar_map.h> #include <asm/iseries/it_lp_queue.h> +#include <asm/iseries/alpaca.h> #include "naca.h" #include "vpd_areas.h" @@ -31,7 +31,7 @@ /* The HvReleaseData is the root of the information shared between * the hypervisor and Linux. */ -struct HvReleaseData hvReleaseData = { +const struct HvReleaseData hvReleaseData = { .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */ .xSize = sizeof(struct HvReleaseData), .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), @@ -61,6 +61,63 @@ struct naca_struct naca = { .xRamDiskSize = 0, }; +struct ItLpRegSave { + u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003 + u16 xSize; // Size of this class 004-005 + u8 xInUse; // Area is live 006-007 + u8 xRsvd1[9]; // Reserved 007-00F + + u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F + u32 xCTRL; // Control Register 170-173 + u32 xDEC; // Decrementer 174-177 + u32 xFPSCR; // FP Status and Control Reg 178-17B + u32 xPVR; // Processor Version Number 17C-17F + + u64 xMMCR0; // Monitor Mode Control Reg 0 180-187 + u32 xPMC1; // Perf Monitor Counter 1 188-18B + u32 xPMC2; // Perf Monitor Counter 2 18C-18F + u32 xPMC3; // Perf Monitor Counter 3 190-193 + u32 xPMC4; // Perf Monitor Counter 4 194-197 + u32 xPIR; // Processor ID Reg 198-19B + + u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F + u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3 + u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7 + u32 xPMC6; // Perf Monitor Counter 6 1A8-1AB + u32 xPMC7; // Perf Monitor Counter 7 1AC-1AF + u32 xPMC8; // Perf Monitor Counter 8 1B0-1B3 + u32 xTSC; // Thread Switch Control 1B4-1B7 + u32 xTST; // Thread Switch Timeout 1B8-1BB + u32 xRsvd; // Reserved 1BC-1BF + + u64 xACCR; // Address Compare Control Reg 1C0-1C7 + u64 xIMR; // Instruction Match Register 1C8-1CF + u64 xSDR1; // Storage Description Reg 1 1D0-1D7 + u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF + u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7 + u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF + u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7 + u64 xTB; // Time Base Register 1F8-1FF + + u64 xFPR[32]; // Floating Point Registers 200-2FF + + u64 xMSR; // Machine State Register 300-307 + u64 xNIA; // Next Instruction Address 308-30F + + u64 xDABR; // Data Address Breakpoint Reg 310-317 + u64 xIABR; // Inst Address Breakpoint Reg 318-31F + + u64 xHID0; // HW Implementation Dependent0 320-327 + + u64 xHID4; // HW Implementation Dependent4 328-32F + u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337 + u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F + u64 xSDAR; // Sample Data Address Register 340-347 + u64 xSIAR; // Sample Inst Address Register 348-34F + + u8 xRsvd3[176]; // Reserved 350-3FF +}; + extern void system_reset_iSeries(void); extern void machine_check_iSeries(void); extern void data_access_iSeries(void); @@ -129,7 +186,7 @@ struct ItLpNaca itLpNaca = { }; /* May be filled in by the hypervisor so cannot end up in the BSS */ -struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); +static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); /* May be filled in by the hypervisor so cannot end up in the BSS */ struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data"))); @@ -152,13 +209,54 @@ u64 xMsVpd[3400] __attribute__((__section__(".data"))); /* Space for Recovery Log Buffer */ /* May be filled in by the hypervisor so cannot end up in the BSS */ -u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data"))); +static u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data"))); -struct SpCommArea xSpCommArea = { +static const struct SpCommArea xSpCommArea = { .xDesc = 0xE2D7C3C2, .xFormat = 1, }; +static const struct ItLpRegSave iseries_reg_save[] = { + [0 ... (NR_CPUS-1)] = { + .xDesc = 0xd397d9e2, /* "LpRS" */ + .xSize = sizeof(struct ItLpRegSave), + }, +}; + +#define ALPACA_INIT(number) \ +{ \ + .lppaca_ptr = &lppaca[number], \ + .reg_save_ptr = &iseries_reg_save[number], \ +} + +const struct alpaca alpaca[] = { + ALPACA_INIT( 0), +#if NR_CPUS > 1 + ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3), +#if NR_CPUS > 4 + ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7), +#if NR_CPUS > 8 + ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11), + ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15), + ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19), + ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23), + ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27), + ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31), +#if NR_CPUS > 32 + ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35), + ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39), + ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43), + ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47), + ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51), + ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55), + ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59), + ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63), +#endif +#endif +#endif +#endif +}; + /* The LparMap data is now located at offset 0x6000 in head.S * It was put there so that the HvReleaseData could address it * with a 32-bit offset as required by the iSeries hypervisor @@ -167,7 +265,7 @@ struct SpCommArea xSpCommArea = { * the Naca via the HvReleaseData area. The HvReleaseData has the * offset into the Naca of the pointer to the ItVpdAreas. */ -struct ItVpdAreas itVpdAreas = { +const struct ItVpdAreas itVpdAreas = { .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */ .xSlicSize = sizeof(struct ItVpdAreas), .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */ @@ -185,7 +283,7 @@ struct ItVpdAreas itVpdAreas = { .xSlicVpdLens = { /* VPD lengths */ 0,0,0, /* 0 - 2 */ sizeof(xItExtVpdPanel), /* 3 Extended VPD */ - sizeof(struct paca_struct), /* 4 length of Paca */ + sizeof(struct alpaca), /* 4 length of (fake) Paca */ 0, /* 5 */ sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */ 26992, /* 7 length of MS VPD */ @@ -203,7 +301,7 @@ struct ItVpdAreas itVpdAreas = { .xSlicVpdAdrs = { /* VPD addresses */ 0,0,0, /* 0 - 2 */ &xItExtVpdPanel, /* 3 Extended VPD */ - &paca[0], /* 4 first Paca */ + &alpaca[0], /* 4 first (fake) Paca */ 0, /* 5 */ &xItIplParmsReal, /* 6 IPL parms */ &xMsVpd, /* 7 MS Vpd */ @@ -219,10 +317,3 @@ struct ItVpdAreas itVpdAreas = { 0,0 } }; - -struct ItLpRegSave iseries_reg_save[] = { - [0 ... (NR_CPUS-1)] = { - .xDesc = 0xd397d9e2, /* "LpRS" */ - .xSize = sizeof(struct ItLpRegSave), - }, -}; diff --git a/arch/powerpc/platforms/iseries/naca.h b/arch/powerpc/platforms/iseries/naca.h index ab2372eb8d2..f01708e1286 100644 --- a/arch/powerpc/platforms/iseries/naca.h +++ b/arch/powerpc/platforms/iseries/naca.h @@ -14,7 +14,7 @@ struct naca_struct { /* Kernel only data - undefined for user space */ - void *xItVpdAreas; /* VPD Data 0x00 */ + const void *xItVpdAreas; /* VPD Data 0x00 */ void *xRamDisk; /* iSeries ramdisk 0x08 */ u64 xRamDiskSize; /* In pages 0x10 */ }; diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index cc562e4c2f3..02a634faedb 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -23,6 +23,7 @@ #undef DEBUG +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/string.h> @@ -586,7 +587,7 @@ static inline struct device_node *xlate_iomm_address( static unsigned long last_jiffies; static int num_printed; - if ((jiffies - last_jiffies) > 60 * HZ) { + if (time_after(jiffies, last_jiffies + 60 * HZ)) { last_jiffies = jiffies; num_printed = 0; } diff --git a/arch/powerpc/platforms/iseries/release_data.h b/arch/powerpc/platforms/iseries/release_data.h index 66189fd2e32..6ad7d843e8f 100644 --- a/arch/powerpc/platforms/iseries/release_data.h +++ b/arch/powerpc/platforms/iseries/release_data.h @@ -58,6 +58,6 @@ struct HvReleaseData { char xRsvd3[20]; /* Reserved x2C-x3F */ }; -extern struct HvReleaseData hvReleaseData; +extern const struct HvReleaseData hvReleaseData; #endif /* _ISERIES_RELEASE_DATA_H */ diff --git a/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h index 6e3b685115c..598b7c14573 100644 --- a/arch/powerpc/platforms/iseries/spcomm_area.h +++ b/arch/powerpc/platforms/iseries/spcomm_area.h @@ -31,6 +31,4 @@ struct SpCommArea { u8 xRsvd2[80]; // Reserved 030-07F }; -extern struct SpCommArea xSpCommArea; - #endif /* _ISERIES_SPCOMM_AREA_H */ diff --git a/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h index 601e6dd860e..feb001f3a5f 100644 --- a/arch/powerpc/platforms/iseries/vpd_areas.h +++ b/arch/powerpc/platforms/iseries/vpd_areas.h @@ -80,9 +80,9 @@ struct ItVpdAreas { u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7 u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F - void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF + const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF }; -extern struct ItVpdAreas itVpdAreas; +extern const struct ItVpdAreas itVpdAreas; #endif /* _ISERIES_VPD_AREAS_H */ diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 3ffa0ac170e..301855263b8 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -592,50 +592,3 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) } return irq; } - -/* XXX: To remove once all firmwares are ok */ -static void fixup_maple_ide(struct pci_dev* dev) -{ - if (!machine_is(maple)) - return; - -#if 0 /* Enable this to enable IDE port 0 */ - { - u8 v; - - pci_read_config_byte(dev, 0x40, &v); - v |= 2; - pci_write_config_byte(dev, 0x40, v); - } -#endif -#if 0 /* fix bus master base */ - pci_write_config_dword(dev, 0x20, 0xcc01); - printk("old ide resource: %lx -> %lx \n", - dev->resource[4].start, dev->resource[4].end); - dev->resource[4].start = 0xcc00; - dev->resource[4].end = 0xcc10; -#endif -#if 0 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */ - { - struct pci_dev *apicdev; - u32 v; - - apicdev = pci_get_slot (dev->bus, PCI_DEVFN(5,0)); - if (apicdev == NULL) - printk("IDE Fixup IRQ: Can't find IO-APIC !\n"); - else { - pci_write_config_byte(apicdev, 0xf2, 0x10 + 2*14); - pci_read_config_dword(apicdev, 0xf4, &v); - v &= ~0x00000022; - pci_write_config_dword(apicdev, 0xf4, v); - pci_write_config_byte(apicdev, 0xf2, 0x10 + 2*15); - pci_read_config_dword(apicdev, 0xf4, &v); - v &= ~0x00000022; - pci_write_config_dword(apicdev, 0xf4, v); - pci_dev_put(apicdev); - } - } -#endif -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, - fixup_maple_ide); diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 3ce2d73b417..364714757cf 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -43,6 +43,7 @@ #include <linux/smp.h> #include <linux/bitops.h> #include <linux/of_device.h> +#include <linux/lmb.h> #include <asm/processor.h> #include <asm/sections.h> @@ -57,7 +58,6 @@ #include <asm/dma.h> #include <asm/cputable.h> #include <asm/time.h> -#include <asm/lmb.h> #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/udbg.h> @@ -319,7 +319,7 @@ static int __init maple_probe(void) return 1; } -define_machine(maple_md) { +define_machine(maple) { .name = "Maple", .probe = maple_probe, .setup_arch = maple_setup_arch, diff --git a/arch/powerpc/platforms/pasemi/dma_lib.c b/arch/powerpc/platforms/pasemi/dma_lib.c index c529d8dff39..217af321b0c 100644 --- a/arch/powerpc/platforms/pasemi/dma_lib.c +++ b/arch/powerpc/platforms/pasemi/dma_lib.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/pci.h> @@ -26,6 +27,8 @@ #define MAX_TXCH 64 #define MAX_RXCH 64 +#define MAX_FLAGS 64 +#define MAX_FUN 8 static struct pasdma_status *dma_status; @@ -43,6 +46,8 @@ static struct pci_dev *dma_pdev; static DECLARE_BITMAP(txch_free, MAX_TXCH); static DECLARE_BITMAP(rxch_free, MAX_RXCH); +static DECLARE_BITMAP(flags_free, MAX_FLAGS); +static DECLARE_BITMAP(fun_free, MAX_FUN); /* pasemi_read_iob_reg - read IOB register * @reg: Register to read (offset into PCI CFG space) @@ -373,6 +378,106 @@ void pasemi_dma_free_buf(struct pasemi_dmachan *chan, int size, } EXPORT_SYMBOL(pasemi_dma_free_buf); +/* pasemi_dma_alloc_flag - Allocate a flag (event) for channel syncronization + * + * Allocates a flag for use with channel syncronization (event descriptors). + * Returns allocated flag (0-63), < 0 on error. + */ +int pasemi_dma_alloc_flag(void) +{ + int bit; + +retry: + bit = find_next_bit(flags_free, MAX_FLAGS, 0); + if (bit >= MAX_FLAGS) + return -ENOSPC; + if (!test_and_clear_bit(bit, flags_free)) + goto retry; + + return bit; +} +EXPORT_SYMBOL(pasemi_dma_alloc_flag); + + +/* pasemi_dma_free_flag - Deallocates a flag (event) + * @flag: Flag number to deallocate + * + * Frees up a flag so it can be reused for other purposes. + */ +void pasemi_dma_free_flag(int flag) +{ + BUG_ON(test_bit(flag, flags_free)); + BUG_ON(flag >= MAX_FLAGS); + set_bit(flag, flags_free); +} +EXPORT_SYMBOL(pasemi_dma_free_flag); + + +/* pasemi_dma_set_flag - Sets a flag (event) to 1 + * @flag: Flag number to set active + * + * Sets the flag provided to 1. + */ +void pasemi_dma_set_flag(int flag) +{ + BUG_ON(flag >= MAX_FLAGS); + if (flag < 32) + pasemi_write_dma_reg(PAS_DMA_TXF_SFLG0, 1 << flag); + else + pasemi_write_dma_reg(PAS_DMA_TXF_SFLG1, 1 << flag); +} +EXPORT_SYMBOL(pasemi_dma_set_flag); + +/* pasemi_dma_clear_flag - Sets a flag (event) to 0 + * @flag: Flag number to set inactive + * + * Sets the flag provided to 0. + */ +void pasemi_dma_clear_flag(int flag) +{ + BUG_ON(flag >= MAX_FLAGS); + if (flag < 32) + pasemi_write_dma_reg(PAS_DMA_TXF_CFLG0, 1 << flag); + else + pasemi_write_dma_reg(PAS_DMA_TXF_CFLG1, 1 << flag); +} +EXPORT_SYMBOL(pasemi_dma_clear_flag); + +/* pasemi_dma_alloc_fun - Allocate a function engine + * + * Allocates a function engine to use for crypto/checksum offload + * Returns allocated engine (0-8), < 0 on error. + */ +int pasemi_dma_alloc_fun(void) +{ + int bit; + +retry: + bit = find_next_bit(fun_free, MAX_FLAGS, 0); + if (bit >= MAX_FLAGS) + return -ENOSPC; + if (!test_and_clear_bit(bit, fun_free)) + goto retry; + + return bit; +} +EXPORT_SYMBOL(pasemi_dma_alloc_fun); + + +/* pasemi_dma_free_fun - Deallocates a function engine + * @flag: Engine number to deallocate + * + * Frees up a function engine so it can be used for other purposes. + */ +void pasemi_dma_free_fun(int fun) +{ + BUG_ON(test_bit(fun, fun_free)); + BUG_ON(fun >= MAX_FLAGS); + set_bit(fun, fun_free); +} +EXPORT_SYMBOL(pasemi_dma_free_fun); + + static void *map_onedev(struct pci_dev *p, int index) { struct device_node *dn; @@ -410,6 +515,7 @@ int pasemi_dma_init(void) struct resource res; struct device_node *dn; int i, intf, err = 0; + unsigned long timeout; u32 tmp; if (!machine_is(pasemi)) @@ -478,6 +584,44 @@ int pasemi_dma_init(void) for (i = 0; i < MAX_RXCH; i++) __set_bit(i, rxch_free); + timeout = jiffies + HZ; + pasemi_write_dma_reg(PAS_DMA_COM_RXCMD, 0); + while (pasemi_read_dma_reg(PAS_DMA_COM_RXSTA) & 1) { + if (time_after(jiffies, timeout)) { + pr_warning("Warning: Could not disable RX section\n"); + break; + } + } + + timeout = jiffies + HZ; + pasemi_write_dma_reg(PAS_DMA_COM_TXCMD, 0); + while (pasemi_read_dma_reg(PAS_DMA_COM_TXSTA) & 1) { + if (time_after(jiffies, timeout)) { + pr_warning("Warning: Could not disable TX section\n"); + break; + } + } + + /* setup resource allocations for the different DMA sections */ + tmp = pasemi_read_dma_reg(PAS_DMA_COM_CFG); + pasemi_write_dma_reg(PAS_DMA_COM_CFG, tmp | 0x18000000); + + /* enable tx section */ + pasemi_write_dma_reg(PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); + + /* enable rx section */ + pasemi_write_dma_reg(PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN); + + for (i = 0; i < MAX_FLAGS; i++) + __set_bit(i, flags_free); + + for (i = 0; i < MAX_FUN; i++) + __set_bit(i, fun_free); + + /* clear all status flags */ + pasemi_write_dma_reg(PAS_DMA_TXF_CFLG0, 0xffffffff); + pasemi_write_dma_reg(PAS_DMA_TXF_CFLG1, 0xffffffff); + printk(KERN_INFO "PA Semi PWRficient DMA library initialized " "(%d tx, %d rx channels)\n", num_txch, num_rxch); diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index b46542990cf..ab6955412ba 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -241,7 +241,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, new_bus->reset = &gpio_mdio_reset; prop = of_get_property(np, "reg", NULL); - new_bus->id = *prop; + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop); new_bus->priv = priv; new_bus->phy_mask = 0; diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 5803f11c77f..86967bdd877 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007, PA Semi, Inc + * Copyright (C) 2005-2008, PA Semi, Inc * * Maintained by: Olof Johansson <olof@lixom.net> * @@ -27,7 +27,6 @@ #include <asm/abs_addr.h> #include <asm/firmware.h> - #define IOBMAP_PAGE_SHIFT 12 #define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT) #define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1) @@ -35,13 +34,13 @@ #define IOB_BASE 0xe0000000 #define IOB_SIZE 0x3000 /* Configuration registers */ -#define IOBCAP_REG 0x10 -#define IOBCOM_REG 0x40 +#define IOBCAP_REG 0x40 +#define IOBCOM_REG 0x100 /* Enable IOB address translation */ #define IOBCOM_ATEN 0x00000100 /* Address decode configuration register */ -#define IOB_AD_REG 0x53 +#define IOB_AD_REG 0x14c /* IOBCOM_AD_REG fields */ #define IOB_AD_VGPRT 0x00000e00 #define IOB_AD_VGAEN 0x00000100 @@ -56,13 +55,13 @@ #define IOB_AD_TRNG_2G 0x00000001 #define IOB_AD_TRNG_128G 0x00000003 -#define IOB_TABLEBASE_REG 0x55 +#define IOB_TABLEBASE_REG 0x154 /* Base of the 64 4-byte L1 registers */ -#define IOB_XLT_L1_REGBASE 0xac0 +#define IOB_XLT_L1_REGBASE 0x2b00 /* Register to invalidate TLB entries */ -#define IOB_AT_INVAL_TLB_REG 0xb40 +#define IOB_AT_INVAL_TLB_REG 0x2d00 /* The top two bits of the level 1 entry contains valid and type flags */ #define IOBMAP_L1E_V 0x40000000 @@ -76,7 +75,7 @@ #define IOBMAP_L2E_V 0x80000000 #define IOBMAP_L2E_V_CACHED 0xc0000000 -static u32 __iomem *iob; +static void __iomem *iob; static u32 iob_l1_emptyval; static u32 iob_l2_emptyval; static u32 *iob_l2_base; @@ -219,7 +218,7 @@ int __init iob_init(struct device_node *dn) for (i = 0; i < 64; i++) { /* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */ regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12); - out_le32(iob+IOB_XLT_L1_REGBASE+i, regword); + out_le32(iob+IOB_XLT_L1_REGBASE+i*4, regword); } /* set 2GB translation window, based at 0 */ diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 1c58db9d42c..bcf50d7056e 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1144,28 +1144,6 @@ void __init pmac_pcibios_after_init(void) { struct device_node* nd; -#ifdef CONFIG_BLK_DEV_IDE - struct pci_dev *dev = NULL; - - /* OF fails to initialize IDE controllers on macs - * (and maybe other machines) - * - * Ideally, this should be moved to the IDE layer, but we need - * to check specifically with Andre Hedrick how to do it cleanly - * since the common IDE code seem to care about the fact that the - * BIOS may have disabled a controller. - * - * -- BenH - */ - for_each_pci_dev(dev) { - if ((dev->class >> 16) != PCI_BASE_CLASS_STORAGE) - continue; - if (pci_enable_device(dev)) - printk(KERN_WARNING - "pci: Failed to enable %s\n", pci_name(dev)); - } -#endif /* CONFIG_BLK_DEV_IDE */ - for_each_node_by_name(nd, "firewire") { if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") || of_device_is_compatible(nd, "pci106b,30") || diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index 85434231ae1..96d5ce50364 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/mutex.h> -#include <asm/semaphore.h> #include <asm/prom.h> #include <asm/pmac_pfunc.h> diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index b3abaaf61eb..3362e781b6a 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -2,7 +2,6 @@ #define __PMAC_H__ #include <linux/pci.h> -#include <linux/ide.h> #include <linux/irq.h> /* @@ -35,10 +34,6 @@ extern void pmac_check_ht_link(void); extern void pmac_setup_smp(void); -extern unsigned long pmac_ide_get_base(int index); -extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, int *irq); - extern int pmac_nvram_init(void); extern void pmac_pic_init(void); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 36ff1b6b7fa..bf44c5441a3 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -53,6 +53,7 @@ #include <linux/suspend.h> #include <linux/of_device.h> #include <linux/of_platform.h> +#include <linux/lmb.h> #include <asm/reg.h> #include <asm/sections.h> @@ -74,7 +75,6 @@ #include <asm/iommu.h> #include <asm/smu.h> #include <asm/pmc.h> -#include <asm/lmb.h> #include <asm/udbg.h> #include "pmac.h" @@ -574,14 +574,6 @@ static int __init pmac_probe(void) ISA_DMA_THRESHOLD = ~0L; DMA_MODE_READ = 1; DMA_MODE_WRITE = 2; - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -#ifdef CONFIG_BLK_DEV_IDE_PMAC - ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; - ppc_ide_md.default_io_base = pmac_ide_get_base; -#endif /* CONFIG_BLK_DEV_IDE_PMAC */ -#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ - #endif /* CONFIG_PPC32 */ #ifdef CONFIG_PMAC_SMU diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index 9d251d0ca8c..3866debfa3c 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -499,41 +499,14 @@ static int __init ps3_register_graphics_devices(void) } /** - * ps3_register_repository_device - Register a device from the repositiory info. - * + * ps3_setup_dynamic_device - Setup a dynamic device from the repository */ -static int ps3_register_repository_device( - const struct ps3_repository_device *repo) +static int ps3_setup_dynamic_device(const struct ps3_repository_device *repo) { int result; switch (repo->dev_type) { - case PS3_DEV_TYPE_SB_GELIC: - result = ps3_setup_gelic_device(repo); - if (result) { - pr_debug("%s:%d ps3_setup_gelic_device failed\n", - __func__, __LINE__); - } - break; - case PS3_DEV_TYPE_SB_USB: - - /* Each USB device has both an EHCI and an OHCI HC */ - - result = ps3_setup_ehci_device(repo); - - if (result) { - pr_debug("%s:%d ps3_setup_ehci_device failed\n", - __func__, __LINE__); - } - - result = ps3_setup_ohci_device(repo); - - if (result) { - pr_debug("%s:%d ps3_setup_ohci_device failed\n", - __func__, __LINE__); - } - break; case PS3_DEV_TYPE_STOR_DISK: result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK); @@ -572,6 +545,48 @@ static int ps3_register_repository_device( return result; } +/** + * ps3_setup_static_device - Setup a static device from the repository + */ + +static int __init ps3_setup_static_device(const struct ps3_repository_device *repo) +{ + int result; + + switch (repo->dev_type) { + case PS3_DEV_TYPE_SB_GELIC: + result = ps3_setup_gelic_device(repo); + if (result) { + pr_debug("%s:%d ps3_setup_gelic_device failed\n", + __func__, __LINE__); + } + break; + case PS3_DEV_TYPE_SB_USB: + + /* Each USB device has both an EHCI and an OHCI HC */ + + result = ps3_setup_ehci_device(repo); + + if (result) { + pr_debug("%s:%d ps3_setup_ehci_device failed\n", + __func__, __LINE__); + } + + result = ps3_setup_ohci_device(repo); + + if (result) { + pr_debug("%s:%d ps3_setup_ohci_device failed\n", + __func__, __LINE__); + } + break; + + default: + return ps3_setup_dynamic_device(repo); + } + + return result; +} + static void ps3_find_and_add_device(u64 bus_id, u64 dev_id) { struct ps3_repository_device repo; @@ -601,7 +616,7 @@ found: pr_debug("%s:%u: device %lu:%lu found after %u retries\n", __func__, __LINE__, bus_id, dev_id, retries); - ps3_register_repository_device(&repo); + ps3_setup_dynamic_device(&repo); return; } @@ -905,8 +920,7 @@ static int __init ps3_register_devices(void) ps3_register_graphics_devices(); - ps3_repository_find_devices(PS3_BUS_TYPE_SB, - ps3_register_repository_device); + ps3_repository_find_devices(PS3_BUS_TYPE_SB, ps3_setup_static_device); ps3_register_sound_devices(); diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 7382f195c4f..1cf901fa903 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -19,9 +19,10 @@ */ #include <linux/kernel.h> +#include <linux/lmb.h> #include <asm/machdep.h> -#include <asm/lmb.h> +#include <asm/prom.h> #include <asm/udbg.h> #include <asm/lv1call.h> #include <asm/ps3fb.h> diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 3a6db04aa94..a14e5cdc2fe 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -709,7 +709,7 @@ static unsigned int ps3_get_irq(void) asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x)); plug &= 0x3f; - if (unlikely(plug) == NO_IRQ) { + if (unlikely(plug == NO_IRQ)) { pr_debug("%s:%d: no plug found: thread_id %lu\n", __func__, __LINE__, pd->thread_id); dump_bmp(&per_cpu(ps3_private, 0)); diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 68900476c84..5b3fb2b321a 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -21,9 +21,10 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/memory_hotplug.h> +#include <linux/lmb.h> #include <asm/firmware.h> -#include <asm/lmb.h> +#include <asm/prom.h> #include <asm/udbg.h> #include <asm/lv1call.h> diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index b9ea09d9d2f..1d201782d4e 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -24,8 +24,10 @@ #include <linux/fs.h> #include <linux/syscalls.h> #include <linux/ctype.h> +#include <linux/lmb.h> +#include <linux/of.h> -#include <asm/lmb.h> +#include <asm/prom.h> #include "platform.h" diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 5c2cbb08eb5..a413abbd412 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -95,6 +95,14 @@ static void ps3_power_off(void) ps3_sys_manager_power_off(); /* never returns */ } +static void ps3_halt(void) +{ + DBG("%s:%d\n", __func__, __LINE__); + + smp_send_stop(); + ps3_sys_manager_halt(); /* never returns */ +} + static void ps3_panic(char *str) { DBG("%s:%d %s\n", __func__, __LINE__, str); @@ -105,7 +113,8 @@ static void ps3_panic(char *str) printk(" Please press POWER button.\n"); printk("\n"); - while(1); + while(1) + lv1_pause(1); } #if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \ @@ -117,7 +126,7 @@ static void __init prealloc(struct ps3_prealloc *p) p->address = __alloc_bootmem(p->size, p->align, __pa(MAX_DMA_ADDRESS)); if (!p->address) { - printk(KERN_ERR "%s: Cannot allocate %s\n", __FUNCTION__, + printk(KERN_ERR "%s: Cannot allocate %s\n", __func__, p->name); return; } @@ -266,6 +275,7 @@ define_machine(ps3) { .progress = ps3_progress, .restart = ps3_restart, .power_off = ps3_power_off, + .halt = ps3_halt, #if defined(CONFIG_KEXEC) .kexec_cpu_down = ps3_kexec_cpu_down, .machine_kexec = default_machine_kexec, diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 5ad41189b49..d135cef9ed6 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -27,6 +27,7 @@ #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/lv1call.h> +#include <asm/ps3.h> #include "../cell/spufs/spufs.h" #include "platform.h" @@ -140,6 +141,12 @@ static void _dump_areas(unsigned int spe_id, unsigned long priv2, pr_debug("%s:%d: shadow: %lxh\n", func, line, shadow); } +inline u64 ps3_get_spe_id(void *arg) +{ + return spu_pdata(arg)->spe_id; +} +EXPORT_SYMBOL_GPL(ps3_get_spe_id); + static unsigned long get_vas_id(void) { unsigned long id; diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 306a9d07491..07fe5b69b9e 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -34,3 +34,8 @@ config LPARCFG help Provide system capacity information via human readable <key word>=<value> pairs through a /proc/ppc64/lparcfg interface. + +config PPC_PSERIES_DEBUG + depends on PPC_PSERIES && PPC_EARLY_DEBUG + bool "Enable extra debug logging in platforms/pseries" + default y diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 992ba6753cf..bd2593ed28d 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -2,6 +2,10 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif +ifeq ($(CONFIG_PPC_PSERIES_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif + obj-y := lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o ras.o rtasd.o \ firmware.o power.o @@ -18,3 +22,4 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o +obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 9eb539ee5f9..a3fd56b186e 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -39,7 +39,6 @@ #include <asm/ppc-pci.h> #include <asm/rtas.h> -#undef DEBUG /** Overview: * EEH, or "Extended Error Handling" is a PCI bridge technology for @@ -945,7 +944,6 @@ static void *early_enable_eeh(struct device_node *dn, void *data) unsigned int rets[3]; struct eeh_early_enable_info *info = data; int ret; - const char *status = of_get_property(dn, "status", NULL); const u32 *class_code = of_get_property(dn, "class-code", NULL); const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); const u32 *device_id = of_get_property(dn, "device-id", NULL); @@ -959,8 +957,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data) pdn->eeh_freeze_count = 0; pdn->eeh_false_positives = 0; - if (status && strncmp(status, "ok", 2) != 0) - return NULL; /* ignore devices with bad status */ + if (!of_device_is_available(dn)) + return NULL; /* Ignore bad nodes. */ if (!class_code || !vendor_id || !device_id) diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index 1e83fcd0df3..ce37040af87 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -28,7 +28,6 @@ #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#undef DEBUG /** * The pci address cache subsystem. This subsystem places diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index b765b7c77b6..9d3a40f4597 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -21,17 +21,11 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG #include <asm/firmware.h> #include <asm/prom.h> #include <asm/udbg.h> -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif typedef struct { unsigned long val; @@ -72,7 +66,7 @@ void __init fw_feature_init(const char *hypertas, unsigned long len) const char *s; int i; - DBG(" -> fw_feature_init()\n"); + pr_debug(" -> fw_feature_init()\n"); for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) { for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) { @@ -88,5 +82,5 @@ void __init fw_feature_init(const char *hypertas, unsigned long len) } } - DBG(" <- fw_feature_init()\n"); + pr_debug(" <- fw_feature_init()\n"); } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index a65c7630820..176f1f39d2d 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -47,7 +47,6 @@ #include "plpar_wrappers.h" -#define DBG(fmt...) static void tce_build_pSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, @@ -322,7 +321,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) dn = pci_bus_to_OF_node(bus); - DBG("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name); + pr_debug("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name); if (bus->self) { /* This is not a root bus, any setup will be done for the @@ -347,7 +346,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling) children++; - DBG("Children: %d\n", children); + pr_debug("Children: %d\n", children); /* Calculate amount of DMA window per slot. Each window must be * a power of two (due to pci_alloc_consistent requirements). @@ -361,8 +360,8 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) while (pci->phb->dma_window_size * children > 0x80000000ul) pci->phb->dma_window_size >>= 1; - DBG("No ISA/IDE, window size is 0x%lx\n", - pci->phb->dma_window_size); + pr_debug("No ISA/IDE, window size is 0x%lx\n", + pci->phb->dma_window_size); pci->phb->dma_window_base_cur = 0; return; @@ -387,8 +386,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) while (pci->phb->dma_window_size * children > 0x70000000ul) pci->phb->dma_window_size >>= 1; - DBG("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size); - + pr_debug("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size); } @@ -401,7 +399,8 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) dn = pci_bus_to_OF_node(bus); - DBG("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n", dn->full_name); + pr_debug("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n", + dn->full_name); /* Find nearest ibm,dma-window, walking up the device tree */ for (pdn = dn; pdn != NULL; pdn = pdn->parent) { @@ -411,14 +410,14 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) } if (dma_window == NULL) { - DBG(" no ibm,dma-window property !\n"); + pr_debug(" no ibm,dma-window property !\n"); return; } ppci = PCI_DN(pdn); - DBG(" parent is %s, iommu_table: 0x%p\n", - pdn->full_name, ppci->iommu_table); + pr_debug(" parent is %s, iommu_table: 0x%p\n", + pdn->full_name, ppci->iommu_table); if (!ppci->iommu_table) { tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, @@ -426,7 +425,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window, bus->number); ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); - DBG(" created table: %p\n", ppci->iommu_table); + pr_debug(" created table: %p\n", ppci->iommu_table); } if (pdn != dn) @@ -439,7 +438,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) struct device_node *dn; struct iommu_table *tbl; - DBG("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev)); + pr_debug("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev)); dn = dev->dev.archdata.of_node; @@ -450,7 +449,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) if (!dev->bus->self) { struct pci_controller *phb = PCI_DN(dn)->phb; - DBG(" --> first child, no bridge. Allocating iommu table.\n"); + pr_debug(" --> first child, no bridge. Allocating iommu table.\n"); tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, phb->node); iommu_table_setparms(phb, dn, tbl); @@ -480,7 +479,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) const void *dma_window = NULL; struct pci_dn *pci; - DBG("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev)); + pr_debug("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev)); /* dev setup for LPAR is a little tricky, since the device tree might * contain the dma-window properties per-device and not neccesarily @@ -489,7 +488,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) * already allocated. */ dn = pci_device_to_OF_node(dev); - DBG(" node is %s\n", dn->full_name); + pr_debug(" node is %s\n", dn->full_name); for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table; pdn = pdn->parent) { @@ -504,13 +503,13 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pci_name(dev), dn? dn->full_name : "<null>"); return; } - DBG(" parent is %s\n", pdn->full_name); + pr_debug(" parent is %s\n", pdn->full_name); /* Check for parent == NULL so we don't try to setup the empty EADS * slots on POWER4 machines. */ if (dma_window == NULL || pdn->parent == NULL) { - DBG(" no dma window for device, linking to parent\n"); + pr_debug(" no dma window for device, linking to parent\n"); dev->dev.archdata.dma_data = PCI_DN(pdn)->iommu_table; return; } @@ -522,9 +521,9 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window, pci->phb->bus->number); pci->iommu_table = iommu_init_table(tbl, pci->phb->node); - DBG(" created table: %p\n", pci->iommu_table); + pr_debug(" created table: %p\n", pci->iommu_table); } else { - DBG(" found DMA window, table: %p\n", pci->iommu_table); + pr_debug(" found DMA window, table: %p\n", pci->iommu_table); } dev->dev.archdata.dma_data = pci->iommu_table; diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 9a455d46379..2cbaedb17f3 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -19,7 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#undef DEBUG_LOW +/* Enables debugging of low-level hash table routines - careful! */ +#undef DEBUG #include <linux/kernel.h> #include <linux/dma-mapping.h> @@ -40,12 +41,8 @@ #include <asm/smp.h> #include "plpar_wrappers.h" +#include "pseries.h" -#ifdef DEBUG_LOW -#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0) -#else -#define DBG_LOW(fmt...) do { } while(0) -#endif /* in hvCall.S */ EXPORT_SYMBOL(plpar_hcall); @@ -195,6 +192,8 @@ void __init udbg_init_debug_lpar(void) udbg_putc = udbg_putcLP; udbg_getc = udbg_getcLP; udbg_getc_poll = udbg_getc_pollLP; + + register_early_udbg_console(); } /* returns 0 if couldn't find or use /chosen/stdout as console */ @@ -203,7 +202,6 @@ void __init find_udbg_vterm(void) struct device_node *stdout_node; const u32 *termno; const char *name; - int add_console; /* find the boot console from /chosen/stdout */ if (!of_chosen) @@ -219,8 +217,6 @@ void __init find_udbg_vterm(void) printk(KERN_WARNING "stdout node missing 'name' property!\n"); goto out; } - /* The user has requested a console so this is already set up. */ - add_console = !strstr(cmd_line, "console="); /* Check if it's a virtual terminal */ if (strncmp(name, "vty", 3) != 0) @@ -234,15 +230,13 @@ void __init find_udbg_vterm(void) udbg_putc = udbg_putcLP; udbg_getc = udbg_getcLP; udbg_getc_poll = udbg_getc_pollLP; - if (add_console) - add_preferred_console("hvc", termno[0] & 0xff, NULL); + add_preferred_console("hvc", termno[0] & 0xff, NULL); } else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) { vtermno = termno[0]; udbg_putc = udbg_hvsi_putc; udbg_getc = udbg_hvsi_getc; udbg_getc_poll = udbg_hvsi_getc_poll; - if (add_console) - add_preferred_console("hvsi", termno[0] & 0xff, NULL); + add_preferred_console("hvsi", termno[0] & 0xff, NULL); } out: of_node_put(stdout_node); @@ -292,15 +286,15 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long hpte_v, hpte_r; if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " - "rflags=%lx, vflags=%lx, psize=%d)\n", - hpte_group, va, pa, rflags, vflags, psize); + pr_debug("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " + "rflags=%lx, vflags=%lx, psize=%d)\n", + hpte_group, va, pa, rflags, vflags, psize); hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); + pr_debug(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); /* Now fill in the actual HPTE */ /* Set CEC cookie to 0 */ @@ -317,7 +311,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot); if (unlikely(lpar_rc == H_PTEG_FULL)) { if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" full\n"); + pr_debug(" full\n"); return -1; } @@ -328,11 +322,11 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, */ if (unlikely(lpar_rc != H_SUCCESS)) { if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" lpar err %d\n", lpar_rc); + pr_debug(" lpar err %lu\n", lpar_rc); return -2; } if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" -> slot: %d\n", slot & 7); + pr_debug(" -> slot: %lu\n", slot & 7); /* Because of iSeries, we have to pass down the secondary * bucket bit here as well @@ -424,17 +418,17 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, want_v = hpte_encode_avpn(va, psize, ssize); - DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ", - want_v, slot, flags, psize); + pr_debug(" update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...", + want_v, slot, flags, psize); lpar_rc = plpar_pte_protect(flags, slot, want_v); if (lpar_rc == H_NOT_FOUND) { - DBG_LOW("not found !\n"); + pr_debug("not found !\n"); return -1; } - DBG_LOW("ok\n"); + pr_debug("ok\n"); BUG_ON(lpar_rc != H_SUCCESS); @@ -509,8 +503,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, unsigned long lpar_rc; unsigned long dummy1, dummy2; - DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d", - slot, va, psize, local); + pr_debug(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", + slot, va, psize, local); want_v = hpte_encode_avpn(va, psize, ssize); lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v, &dummy1, &dummy2); @@ -520,6 +514,20 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, BUG_ON(lpar_rc != H_SUCCESS); } +static void pSeries_lpar_hpte_removebolted(unsigned long ea, + int psize, int ssize) +{ + unsigned long slot, vsid, va; + + vsid = get_kernel_vsid(ea, ssize); + va = hpt_va(ea, vsid, ssize); + + slot = pSeries_lpar_hpte_find(va, psize, ssize); + BUG_ON(slot == -1); + + pSeries_lpar_hpte_invalidate(slot, va, psize, ssize, 0); +} + /* Flag bits for H_BULK_REMOVE */ #define HBR_REQUEST 0x4000000000000000UL #define HBR_RESPONSE 0x8000000000000000UL @@ -597,6 +605,7 @@ void __init hpte_init_lpar(void) ppc_md.hpte_updateboltedpp = pSeries_lpar_hpte_updateboltedpp; ppc_md.hpte_insert = pSeries_lpar_hpte_insert; ppc_md.hpte_remove = pSeries_lpar_hpte_remove; + ppc_md.hpte_removebolted = pSeries_lpar_hpte_removebolted; ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; } diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 5a5a19e40bb..21a6d55418f 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -88,11 +88,8 @@ pcibios_fixup_new_pci_devices(struct pci_bus *bus) struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { - /* - * Skip already-present devices (which are on the - * global device list.) - */ - if (list_empty(&dev->global_list)) { + /* Skip already-added devices */ + if (!dev->is_added) { int i; /* Fill device archdata and setup iommu table */ @@ -123,7 +120,7 @@ pcibios_pci_config_bridge(struct pci_dev *dev) /* Add to children of PCI bridge dev->bus */ child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); if (!child_bus) { - printk (KERN_ERR "%s: could not add second bus\n", __FUNCTION__); + printk (KERN_ERR "%s: could not add second bus\n", __func__); return -EIO; } sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c new file mode 100644 index 00000000000..edbc012c2eb --- /dev/null +++ b/arch/powerpc/platforms/pseries/phyp_dump.c @@ -0,0 +1,507 @@ +/* + * Hypervisor-assisted dump + * + * Linas Vepstas, Manish Ahuja 2008 + * Copyright 2008 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. + * + */ + +#include <linux/init.h> +#include <linux/kobject.h> +#include <linux/mm.h> +#include <linux/of.h> +#include <linux/pfn.h> +#include <linux/swap.h> +#include <linux/sysfs.h> + +#include <asm/page.h> +#include <asm/phyp_dump.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/rtas.h> + +/* Variables, used to communicate data between early boot and late boot */ +static struct phyp_dump phyp_dump_vars; +struct phyp_dump *phyp_dump_info = &phyp_dump_vars; + +static int ibm_configure_kernel_dump; +/* ------------------------------------------------- */ +/* RTAS interfaces to declare the dump regions */ + +struct dump_section { + u32 dump_flags; + u16 source_type; + u16 error_flags; + u64 source_address; + u64 source_length; + u64 length_copied; + u64 destination_address; +}; + +struct phyp_dump_header { + u32 version; + u16 num_of_sections; + u16 status; + + u32 first_offset_section; + u32 dump_disk_section; + u64 block_num_dd; + u64 num_of_blocks_dd; + u32 offset_dd; + u32 maxtime_to_auto; + /* No dump disk path string used */ + + struct dump_section cpu_data; + struct dump_section hpte_data; + struct dump_section kernel_data; +}; + +/* The dump header *must be* in low memory, so .bss it */ +static struct phyp_dump_header phdr; + +#define NUM_DUMP_SECTIONS 3 +#define DUMP_HEADER_VERSION 0x1 +#define DUMP_REQUEST_FLAG 0x1 +#define DUMP_SOURCE_CPU 0x0001 +#define DUMP_SOURCE_HPTE 0x0002 +#define DUMP_SOURCE_RMO 0x0011 +#define DUMP_ERROR_FLAG 0x2000 +#define DUMP_TRIGGERED 0x4000 +#define DUMP_PERFORMED 0x8000 + + +/** + * init_dump_header() - initialize the header declaring a dump + * Returns: length of dump save area. + * + * When the hypervisor saves crashed state, it needs to put + * it somewhere. The dump header tells the hypervisor where + * the data can be saved. + */ +static unsigned long init_dump_header(struct phyp_dump_header *ph) +{ + unsigned long addr_offset = 0; + + /* Set up the dump header */ + ph->version = DUMP_HEADER_VERSION; + ph->num_of_sections = NUM_DUMP_SECTIONS; + ph->status = 0; + + ph->first_offset_section = + (u32)offsetof(struct phyp_dump_header, cpu_data); + ph->dump_disk_section = 0; + ph->block_num_dd = 0; + ph->num_of_blocks_dd = 0; + ph->offset_dd = 0; + + ph->maxtime_to_auto = 0; /* disabled */ + + /* The first two sections are mandatory */ + ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG; + ph->cpu_data.source_type = DUMP_SOURCE_CPU; + ph->cpu_data.source_address = 0; + ph->cpu_data.source_length = phyp_dump_info->cpu_state_size; + ph->cpu_data.destination_address = addr_offset; + addr_offset += phyp_dump_info->cpu_state_size; + + ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG; + ph->hpte_data.source_type = DUMP_SOURCE_HPTE; + ph->hpte_data.source_address = 0; + ph->hpte_data.source_length = phyp_dump_info->hpte_region_size; + ph->hpte_data.destination_address = addr_offset; + addr_offset += phyp_dump_info->hpte_region_size; + + /* This section describes the low kernel region */ + ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG; + ph->kernel_data.source_type = DUMP_SOURCE_RMO; + ph->kernel_data.source_address = PHYP_DUMP_RMR_START; + ph->kernel_data.source_length = PHYP_DUMP_RMR_END; + ph->kernel_data.destination_address = addr_offset; + addr_offset += ph->kernel_data.source_length; + + return addr_offset; +} + +static void print_dump_header(const struct phyp_dump_header *ph) +{ +#ifdef DEBUG + printk(KERN_INFO "dump header:\n"); + /* setup some ph->sections required */ + printk(KERN_INFO "version = %d\n", ph->version); + printk(KERN_INFO "Sections = %d\n", ph->num_of_sections); + printk(KERN_INFO "Status = 0x%x\n", ph->status); + + /* No ph->disk, so all should be set to 0 */ + printk(KERN_INFO "Offset to first section 0x%x\n", + ph->first_offset_section); + printk(KERN_INFO "dump disk sections should be zero\n"); + printk(KERN_INFO "dump disk section = %d\n", ph->dump_disk_section); + printk(KERN_INFO "block num = %ld\n", ph->block_num_dd); + printk(KERN_INFO "number of blocks = %ld\n", ph->num_of_blocks_dd); + printk(KERN_INFO "dump disk offset = %d\n", ph->offset_dd); + printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto); + + /*set cpu state and hpte states as well scratch pad area */ + printk(KERN_INFO " CPU AREA \n"); + printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags); + printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type); + printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags); + printk(KERN_INFO "cpu source_address =%lx\n", + ph->cpu_data.source_address); + printk(KERN_INFO "cpu source_length =%lx\n", + ph->cpu_data.source_length); + printk(KERN_INFO "cpu length_copied =%lx\n", + ph->cpu_data.length_copied); + + printk(KERN_INFO " HPTE AREA \n"); + printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags); + printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type); + printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags); + printk(KERN_INFO "HPTE source_address =%lx\n", + ph->hpte_data.source_address); + printk(KERN_INFO "HPTE source_length =%lx\n", + ph->hpte_data.source_length); + printk(KERN_INFO "HPTE length_copied =%lx\n", + ph->hpte_data.length_copied); + + printk(KERN_INFO " SRSD AREA \n"); + printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags); + printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type); + printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags); + printk(KERN_INFO "SRSD source_address =%lx\n", + ph->kernel_data.source_address); + printk(KERN_INFO "SRSD source_length =%lx\n", + ph->kernel_data.source_length); + printk(KERN_INFO "SRSD length_copied =%lx\n", + ph->kernel_data.length_copied); +#endif +} + +static ssize_t show_phyp_dump_active(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + + /* create filesystem entry so kdump is phyp-dump aware */ + return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot); +} + +static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600, + show_phyp_dump_active, + NULL); + +static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) +{ + int rc; + + /* Add addr value if not initialized before */ + if (ph->cpu_data.destination_address == 0) { + ph->cpu_data.destination_address += addr; + ph->hpte_data.destination_address += addr; + ph->kernel_data.destination_address += addr; + } + + /* ToDo Invalidate kdump and free memory range. */ + + do { + rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, + 1, ph, sizeof(struct phyp_dump_header)); + } while (rtas_busy_delay(rc)); + + if (rc) { + printk(KERN_ERR "phyp-dump: unexpected error (%d) on " + "register\n", rc); + print_dump_header(ph); + return; + } + + rc = sysfs_create_file(kernel_kobj, &pdl.attr); + if (rc) + printk(KERN_ERR "phyp-dump: unable to create sysfs" + " file (%d)\n", rc); +} + +static +void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr) +{ + int rc; + + /* Add addr value if not initialized before */ + if (ph->cpu_data.destination_address == 0) { + ph->cpu_data.destination_address += addr; + ph->hpte_data.destination_address += addr; + ph->kernel_data.destination_address += addr; + } + + do { + rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, + 2, ph, sizeof(struct phyp_dump_header)); + } while (rtas_busy_delay(rc)); + + if (rc) { + printk(KERN_ERR "phyp-dump: unexpected error (%d) " + "on invalidate\n", rc); + print_dump_header(ph); + } +} + +/* ------------------------------------------------- */ +/** + * release_memory_range -- release memory previously lmb_reserved + * @start_pfn: starting physical frame number + * @nr_pages: number of pages to free. + * + * This routine will release memory that had been previously + * lmb_reserved in early boot. The released memory becomes + * available for genreal use. + */ +static void release_memory_range(unsigned long start_pfn, + unsigned long nr_pages) +{ + struct page *rpage; + unsigned long end_pfn; + long i; + + end_pfn = start_pfn + nr_pages; + + for (i = start_pfn; i <= end_pfn; i++) { + rpage = pfn_to_page(i); + if (PageReserved(rpage)) { + ClearPageReserved(rpage); + init_page_count(rpage); + __free_page(rpage); + totalram_pages++; + } + } +} + +/** + * track_freed_range -- Counts the range being freed. + * Once the counter goes to zero, it re-registers dump for + * future use. + */ +static void +track_freed_range(unsigned long addr, unsigned long length) +{ + static unsigned long scratch_area_size, reserved_area_size; + + if (addr < phyp_dump_info->init_reserve_start) + return; + + if ((addr >= phyp_dump_info->init_reserve_start) && + (addr <= phyp_dump_info->init_reserve_start + + phyp_dump_info->init_reserve_size)) + reserved_area_size += length; + + if ((addr >= phyp_dump_info->reserved_scratch_addr) && + (addr <= phyp_dump_info->reserved_scratch_addr + + phyp_dump_info->reserved_scratch_size)) + scratch_area_size += length; + + if ((reserved_area_size == phyp_dump_info->init_reserve_size) && + (scratch_area_size == phyp_dump_info->reserved_scratch_size)) { + + invalidate_last_dump(&phdr, + phyp_dump_info->reserved_scratch_addr); + register_dump_area(&phdr, + phyp_dump_info->reserved_scratch_addr); + } +} + +/* ------------------------------------------------- */ +/** + * sysfs_release_region -- sysfs interface to release memory range. + * + * Usage: + * "echo <start addr> <length> > /sys/kernel/release_region" + * + * Example: + * "echo 0x40000000 0x10000000 > /sys/kernel/release_region" + * + * will release 256MB starting at 1GB. + */ +static ssize_t store_release_region(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned long start_addr, length, end_addr; + unsigned long start_pfn, nr_pages; + ssize_t ret; + + ret = sscanf(buf, "%lx %lx", &start_addr, &length); + if (ret != 2) + return -EINVAL; + + track_freed_range(start_addr, length); + + /* Range-check - don't free any reserved memory that + * wasn't reserved for phyp-dump */ + if (start_addr < phyp_dump_info->init_reserve_start) + start_addr = phyp_dump_info->init_reserve_start; + + end_addr = phyp_dump_info->init_reserve_start + + phyp_dump_info->init_reserve_size; + if (start_addr+length > end_addr) + length = end_addr - start_addr; + + /* Release the region of memory assed in by user */ + start_pfn = PFN_DOWN(start_addr); + nr_pages = PFN_DOWN(length); + release_memory_range(start_pfn, nr_pages); + + return count; +} + +static ssize_t show_release_region(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + u64 second_addr_range; + + /* total reserved size - start of scratch area */ + second_addr_range = phyp_dump_info->init_reserve_size - + phyp_dump_info->reserved_scratch_size; + return sprintf(buf, "CPU:0x%lx-0x%lx: HPTE:0x%lx-0x%lx:" + " DUMP:0x%lx-0x%lx, 0x%lx-0x%lx:\n", + phdr.cpu_data.destination_address, + phdr.cpu_data.length_copied, + phdr.hpte_data.destination_address, + phdr.hpte_data.length_copied, + phdr.kernel_data.destination_address, + phdr.kernel_data.length_copied, + phyp_dump_info->init_reserve_start, + second_addr_range); +} + +static struct kobj_attribute rr = __ATTR(release_region, 0600, + show_release_region, + store_release_region); + +static int __init phyp_dump_setup(void) +{ + struct device_node *rtas; + const struct phyp_dump_header *dump_header = NULL; + unsigned long dump_area_start; + unsigned long dump_area_length; + int header_len = 0; + int rc; + + /* If no memory was reserved in early boot, there is nothing to do */ + if (phyp_dump_info->init_reserve_size == 0) + return 0; + + /* Return if phyp dump not supported */ + if (!phyp_dump_info->phyp_dump_configured) + return -ENOSYS; + + /* Is there dump data waiting for us? If there isn't, + * then register a new dump area, and release all of + * the rest of the reserved ram. + * + * The /rtas/ibm,kernel-dump rtas node is present only + * if there is dump data waiting for us. + */ + rtas = of_find_node_by_path("/rtas"); + if (rtas) { + dump_header = of_get_property(rtas, "ibm,kernel-dump", + &header_len); + of_node_put(rtas); + } + + print_dump_header(dump_header); + dump_area_length = init_dump_header(&phdr); + /* align down */ + dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK; + + if (dump_header == NULL) { + register_dump_area(&phdr, dump_area_start); + return 0; + } + + /* re-register the dump area, if old dump was invalid */ + if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) { + invalidate_last_dump(&phdr, dump_area_start); + register_dump_area(&phdr, dump_area_start); + return 0; + } + + if (dump_header) { + phyp_dump_info->reserved_scratch_addr = + dump_header->cpu_data.destination_address; + phyp_dump_info->reserved_scratch_size = + dump_header->cpu_data.source_length + + dump_header->hpte_data.source_length + + dump_header->kernel_data.source_length; + } + + /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ + rc = sysfs_create_file(kernel_kobj, &rr.attr); + if (rc) + printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", + rc); + + /* ToDo: re-register the dump area, for next time. */ + return 0; +} +machine_subsys_initcall(pseries, phyp_dump_setup); + +int __init early_init_dt_scan_phyp_dump(unsigned long node, + const char *uname, int depth, void *data) +{ + const unsigned int *sizes; + + phyp_dump_info->phyp_dump_configured = 0; + phyp_dump_info->phyp_dump_is_active = 0; + + if (depth != 1 || strcmp(uname, "rtas") != 0) + return 0; + + if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL)) + phyp_dump_info->phyp_dump_configured++; + + if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL)) + phyp_dump_info->phyp_dump_is_active++; + + sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", + NULL); + if (!sizes) + return 0; + + if (sizes[0] == 1) + phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]); + + if (sizes[3] == 2) + phyp_dump_info->hpte_region_size = + *((unsigned long *)&sizes[4]); + return 1; +} + +/* Look for phyp_dump= cmdline option */ +static int __init early_phyp_dump_enabled(char *p) +{ + phyp_dump_info->phyp_dump_at_boot = 1; + + if (!p) + return 0; + + if (strncmp(p, "1", 1) == 0) + phyp_dump_info->phyp_dump_at_boot = 1; + else if (strncmp(p, "0", 1) == 0) + phyp_dump_info->phyp_dump_at_boot = 0; + + return 0; +} +early_param("phyp_dump", early_phyp_dump_enabled); + +/* Look for phyp_dump_reserve_size= cmdline option */ +static int __init early_phyp_dump_reserve_size(char *p) +{ + if (p) + phyp_dump_info->reserve_bootvar = memparse(p, &p); + + return 0; +} +early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size); diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 61136d01955..9e17c0d2a0c 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -38,4 +38,6 @@ extern void pSeries_final_fixup(void); /* Poweron flag used for enabling auto ups restart */ extern unsigned long rtas_poweron_auto; +extern void find_udbg_vterm(void); + #endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index a1ab25c7082..2b548afd100 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -67,8 +67,6 @@ static int ras_check_exception_token; static irqreturn_t ras_epow_interrupt(int irq, void *dev_id); static irqreturn_t ras_error_interrupt(int irq, void *dev_id); -/* #define DEBUG */ - static void request_ras_irqs(struct device_node *np, irq_handler_t handler, @@ -237,7 +235,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n", *((unsigned long *)&ras_log_buf), status); -#ifndef DEBUG +#ifndef DEBUG_RTAS_POWER_OFF /* Don't actually power off when debugging so we can test * without actually failing while injecting errors. * Error data will not be logged to syslog. diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 2800fced8c7..ac75c10de27 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -222,14 +222,14 @@ static char * parse_next_property(char *buf, char *end, char **name, int *length tmp = strchr(buf, ' '); if (!tmp) { printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); return NULL; } *tmp = '\0'; if (++tmp >= end) { printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); return NULL; } @@ -238,12 +238,12 @@ static char * parse_next_property(char *buf, char *end, char **name, int *length *length = simple_strtoul(tmp, &tmp, 10); if (*length == -1) { printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); return NULL; } if (*tmp != ' ' || ++tmp >= end) { printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); return NULL; } @@ -252,12 +252,12 @@ static char * parse_next_property(char *buf, char *end, char **name, int *length tmp += *length; if (tmp > end) { printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); return NULL; } else if (tmp < end && *tmp != ' ' && *tmp != '\0') { printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); return NULL; } tmp++; diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index e3078ce4151..befadd4f952 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -29,11 +29,6 @@ #include <asm/atomic.h> #include <asm/machdep.h> -#if 0 -#define DEBUG(A...) printk(KERN_ERR A) -#else -#define DEBUG(A...) -#endif static DEFINE_SPINLOCK(rtasd_log_lock); @@ -198,7 +193,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) unsigned long s; int len = 0; - DEBUG("logging event\n"); + pr_debug("rtasd: logging event\n"); if (buf == NULL) return; @@ -409,7 +404,8 @@ static int rtasd(void *unused) daemonize("rtasd"); printk(KERN_DEBUG "RTAS daemon started\n"); - DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); + pr_debug("rtasd: will sleep for %d milliseconds\n", + (30000 / rtas_event_scan_rate)); /* See if we have any error stored in NVRAM */ memset(logdata, 0, rtas_error_log_max); @@ -428,9 +424,9 @@ static int rtasd(void *unused) do_event_scan_all_cpus(1000); if (surveillance_timeout != -1) { - DEBUG("enabling surveillance\n"); + pr_debug("rtasd: enabling surveillance\n"); enable_surveillance(surveillance_timeout); - DEBUG("surveillance enabled\n"); + pr_debug("rtasd: surveillance enabled\n"); } /* Delay should be at least one second since some diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 8e1ef168e2d..bec3803f061 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c @@ -38,9 +38,7 @@ #define SCANLOG_HWERROR -1 #define SCANLOG_CONTINUE 1 -#define DEBUG(A...) do { if (scanlog_debug) printk(KERN_ERR "scanlog: " A); } while (0) -static int scanlog_debug; static unsigned int ibm_scan_log_dump; /* RTAS token */ static struct proc_dir_entry *proc_ppc64_scan_log_dump; /* The proc file */ @@ -86,14 +84,14 @@ static ssize_t scanlog_read(struct file *file, char __user *buf, memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); - DEBUG("status=%d, data[0]=%x, data[1]=%x, data[2]=%x\n", - status, data[0], data[1], data[2]); + pr_debug("scanlog: status=%d, data[0]=%x, data[1]=%x, " \ + "data[2]=%x\n", status, data[0], data[1], data[2]); switch (status) { case SCANLOG_COMPLETE: - DEBUG("hit eof\n"); + pr_debug("scanlog: hit eof\n"); return 0; case SCANLOG_HWERROR: - DEBUG("hardware error reading scan log data\n"); + pr_debug("scanlog: hardware error reading data\n"); return -EIO; case SCANLOG_CONTINUE: /* We may or may not have data yet */ @@ -110,7 +108,8 @@ static ssize_t scanlog_read(struct file *file, char __user *buf, /* Assume extended busy */ wait_time = rtas_busy_delay_time(status); if (!wait_time) { - printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); + printk(KERN_ERR "scanlog: unknown error " \ + "from rtas: %d\n", status); return -EIO; } } @@ -134,15 +133,9 @@ static ssize_t scanlog_write(struct file * file, const char __user * buf, if (buf) { if (strncmp(stkbuf, "reset", 5) == 0) { - DEBUG("reset scanlog\n"); + pr_debug("scanlog: reset scanlog\n"); status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, 0, 0); - DEBUG("rtas returns %d\n", status); - } else if (strncmp(stkbuf, "debugon", 7) == 0) { - printk(KERN_ERR "scanlog: debug on\n"); - scanlog_debug = 1; - } else if (strncmp(stkbuf, "debugoff", 8) == 0) { - printk(KERN_ERR "scanlog: debug off\n"); - scanlog_debug = 0; + pr_debug("scanlog: rtas returns %d\n", status); } } return count; @@ -195,31 +188,30 @@ const struct file_operations scanlog_fops = { static int __init scanlog_init(void) { struct proc_dir_entry *ent; + void *data; + int err = -ENOMEM; ibm_scan_log_dump = rtas_token("ibm,scan-log-dump"); - if (ibm_scan_log_dump == RTAS_UNKNOWN_SERVICE) { - printk(KERN_ERR "scan-log-dump not implemented on this system\n"); - return -EIO; - } + if (ibm_scan_log_dump == RTAS_UNKNOWN_SERVICE) + return -ENODEV; - ent = create_proc_entry("ppc64/rtas/scan-log-dump", S_IRUSR, NULL); - if (ent) { - ent->proc_fops = &scanlog_fops; - /* Ideally we could allocate a buffer < 4G */ - ent->data = kmalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); - if (!ent->data) { - printk(KERN_ERR "Failed to allocate a buffer\n"); - remove_proc_entry("scan-log-dump", ent->parent); - return -ENOMEM; - } - ((unsigned int *)ent->data)[0] = 0; - } else { - printk(KERN_ERR "Failed to create ppc64/scan-log-dump proc entry\n"); - return -EIO; - } + /* Ideally we could allocate a buffer < 4G */ + data = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); + if (!data) + goto err; + + ent = proc_create("ppc64/rtas/scan-log-dump", S_IRUSR, NULL, + &scanlog_fops); + if (!ent) + goto err; + + ent->data = data; proc_ppc64_scan_log_dump = ent; return 0; +err: + kfree(data); + return err; } static void __exit scanlog_cleanup(void) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index fdb9b1c8f97..f5d29f5b13c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -16,8 +16,6 @@ * bootup setup stuff.. */ -#undef DEBUG - #include <linux/cpu.h> #include <linux/errno.h> #include <linux/sched.h> @@ -70,14 +68,6 @@ #include "plpar_wrappers.h" #include "pseries.h" -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* move those away to a .h */ -extern void find_udbg_vterm(void); int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -127,14 +117,60 @@ void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc) desc->chip->eoi(irq); } -static void __init pseries_mpic_init_IRQ(void) +static void __init pseries_setup_i8259_cascade(void) { - struct device_node *np, *old, *cascade = NULL; - const unsigned int *addrp; + struct device_node *np, *old, *found = NULL; + unsigned int cascade; + const u32 *addrp; unsigned long intack = 0; + int naddr; + + for_each_node_by_type(np, "interrupt-controller") { + if (of_device_is_compatible(np, "chrp,iic")) { + found = np; + break; + } + } + + if (found == NULL) { + printk(KERN_DEBUG "pic: no ISA interrupt controller\n"); + return; + } + + cascade = irq_of_parse_and_map(found, 0); + if (cascade == NO_IRQ) { + printk(KERN_ERR "pic: failed to map cascade interrupt"); + return; + } + pr_debug("pic: cascade mapped to irq %d\n", cascade); + + for (old = of_node_get(found); old != NULL ; old = np) { + np = of_get_parent(old); + of_node_put(old); + if (np == NULL) + break; + if (strcmp(np->name, "pci") != 0) + continue; + addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL); + if (addrp == NULL) + continue; + naddr = of_n_addr_cells(np); + intack = addrp[naddr-1]; + if (naddr > 1) + intack |= ((unsigned long)addrp[naddr-2]) << 32; + } + if (intack) + printk(KERN_DEBUG "pic: PCI 8259 intack at 0x%016lx\n", intack); + i8259_init(found, intack); + of_node_put(found); + set_irq_chained_handler(cascade, pseries_8259_cascade); +} + +static void __init pseries_mpic_init_IRQ(void) +{ + struct device_node *np; const unsigned int *opprop; unsigned long openpic_addr = 0; - unsigned int cascade_irq; int naddr, n, i, opplen; struct mpic *mpic; @@ -167,43 +203,13 @@ static void __init pseries_mpic_init_IRQ(void) mpic_init(mpic); /* Look for cascade */ - for_each_node_by_type(np, "interrupt-controller") - if (of_device_is_compatible(np, "chrp,iic")) { - cascade = np; - break; - } - if (cascade == NULL) - return; - - cascade_irq = irq_of_parse_and_map(cascade, 0); - if (cascade_irq == NO_IRQ) { - printk(KERN_ERR "mpic: failed to map cascade interrupt"); - return; - } + pseries_setup_i8259_cascade(); +} - /* Check ACK type */ - for (old = of_node_get(cascade); old != NULL ; old = np) { - np = of_get_parent(old); - of_node_put(old); - if (np == NULL) - break; - if (strcmp(np->name, "pci") != 0) - continue; - addrp = of_get_property(np, "8259-interrupt-acknowledge", - NULL); - if (addrp == NULL) - continue; - naddr = of_n_addr_cells(np); - intack = addrp[naddr-1]; - if (naddr > 1) - intack |= ((unsigned long)addrp[naddr-2]) << 32; - } - if (intack) - printk(KERN_DEBUG "mpic: PCI 8259 intack at 0x%016lx\n", - intack); - i8259_init(cascade, intack); - of_node_put(cascade); - set_irq_chained_handler(cascade_irq, pseries_8259_cascade); +static void __init pseries_xics_init_IRQ(void) +{ + xics_init_IRQ(); + pseries_setup_i8259_cascade(); } static void pseries_lpar_enable_pmcs(void) @@ -235,7 +241,7 @@ static void __init pseries_discover_pic(void) smp_init_pseries_mpic(); return; } else if (strstr(typep, "ppc-xicp")) { - ppc_md.init_IRQ = xics_init_IRQ; + ppc_md.init_IRQ = pseries_xics_init_IRQ; setup_kexec_cpu_down_xics(); smp_init_pseries_xics(); return; @@ -313,7 +319,7 @@ static int pseries_set_xdabr(unsigned long dabr) */ static void __init pSeries_init_early(void) { - DBG(" -> pSeries_init_early()\n"); + pr_debug(" -> pSeries_init_early()\n"); if (firmware_has_feature(FW_FEATURE_LPAR)) find_udbg_vterm(); @@ -325,7 +331,7 @@ static void __init pSeries_init_early(void) iommu_init_early_pSeries(); - DBG(" <- pSeries_init_early()\n"); + pr_debug(" <- pSeries_init_early()\n"); } /* @@ -370,7 +376,7 @@ static int __init pSeries_probe(void) of_flat_dt_is_compatible(root, "IBM,CBEA")) return 0; - DBG("pSeries detected, looking for LPAR capability...\n"); + pr_debug("pSeries detected, looking for LPAR capability...\n"); /* Now try to figure out if we are running on LPAR */ of_scan_flat_dt(pSeries_probe_hypertas, NULL); @@ -380,8 +386,8 @@ static int __init pSeries_probe(void) else hpte_init_native(); - DBG("Machine is%s LPAR !\n", - (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); + pr_debug("Machine is%s LPAR !\n", + (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); return 1; } @@ -393,6 +399,7 @@ static void pseries_dedicated_idle_sleep(void) { unsigned int cpu = smp_processor_id(); unsigned long start_snooze; + unsigned long in_purr, out_purr; /* * Indicate to the HV that we are idle. Now would be @@ -400,6 +407,7 @@ static void pseries_dedicated_idle_sleep(void) */ get_lppaca()->idle = 1; get_lppaca()->donate_dedicated_cpu = 1; + in_purr = mfspr(SPRN_PURR); /* * We come in with interrupts disabled, and need_resched() @@ -432,6 +440,8 @@ static void pseries_dedicated_idle_sleep(void) 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; } diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index ea4c65917a6..9d8f8c84ab8 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -12,7 +12,6 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG #include <linux/kernel.h> #include <linux/module.h> @@ -51,12 +50,6 @@ #include "plpar_wrappers.h" #include "pseries.h" -#ifdef DEBUG -#include <asm/udbg.h> -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif /* * The primary thread of each non-boot processor is recorded here before @@ -231,7 +224,7 @@ static void __init smp_init_pseries(void) { int i; - DBG(" -> smp_init_pSeries()\n"); + pr_debug(" -> smp_init_pSeries()\n"); /* Mark threads which are still spinning in hold loops. */ if (cpu_has_feature(CPU_FTR_SMT)) { @@ -255,7 +248,7 @@ static void __init smp_init_pseries(void) smp_ops->take_timebase = pSeries_take_timebase; } - DBG(" <- smp_init_pSeries()\n"); + pr_debug(" <- smp_init_pSeries()\n"); } #ifdef CONFIG_MPIC diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index a977f200db8..ebebc28fe89 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG #include <linux/types.h> #include <linux/threads.h> @@ -516,6 +515,8 @@ static struct irq_chip xics_pic_lpar = { .set_affinity = xics_set_affinity }; +/* Points to the irq_chip we're actually using */ +static struct irq_chip *xics_irq_chip; static int xics_host_match(struct irq_host *h, struct device_node *node) { @@ -526,23 +527,13 @@ static int xics_host_match(struct irq_host *h, struct device_node *node) return !of_device_is_compatible(node, "chrp,iic"); } -static int xics_host_map_direct(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) +static int xics_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) { - pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw); + pr_debug("xics: map virq %d, hwirq 0x%lx\n", virq, hw); get_irq_desc(virq)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(virq, &xics_pic_direct, handle_fasteoi_irq); - return 0; -} - -static int xics_host_map_lpar(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw); - - get_irq_desc(virq)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(virq, &xics_pic_lpar, handle_fasteoi_irq); + set_irq_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq); return 0; } @@ -561,27 +552,20 @@ static int xics_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops xics_host_direct_ops = { +static struct irq_host_ops xics_host_ops = { .match = xics_host_match, - .map = xics_host_map_direct, - .xlate = xics_host_xlate, -}; - -static struct irq_host_ops xics_host_lpar_ops = { - .match = xics_host_match, - .map = xics_host_map_lpar, + .map = xics_host_map, .xlate = xics_host_xlate, }; static void __init xics_init_host(void) { - struct irq_host_ops *ops; - if (firmware_has_feature(FW_FEATURE_LPAR)) - ops = &xics_host_lpar_ops; + xics_irq_chip = &xics_pic_lpar; else - ops = &xics_host_direct_ops; - xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, ops, + xics_irq_chip = &xics_pic_direct; + + xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, XICS_IRQ_SPURIOUS); BUG_ON(xics_host == NULL); irq_set_default_host(xics_host); @@ -655,52 +639,6 @@ static void __init xics_init_one_node(struct device_node *np, } } - -static void __init xics_setup_8259_cascade(void) -{ - struct device_node *np, *old, *found = NULL; - int cascade, naddr; - const u32 *addrp; - unsigned long intack = 0; - - for_each_node_by_type(np, "interrupt-controller") - if (of_device_is_compatible(np, "chrp,iic")) { - found = np; - break; - } - if (found == NULL) { - printk(KERN_DEBUG "xics: no ISA interrupt controller\n"); - return; - } - cascade = irq_of_parse_and_map(found, 0); - if (cascade == NO_IRQ) { - printk(KERN_ERR "xics: failed to map cascade interrupt"); - return; - } - pr_debug("xics: cascade mapped to irq %d\n", cascade); - - for (old = of_node_get(found); old != NULL ; old = np) { - np = of_get_parent(old); - of_node_put(old); - if (np == NULL) - break; - if (strcmp(np->name, "pci") != 0) - continue; - addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL); - if (addrp == NULL) - continue; - naddr = of_n_addr_cells(np); - intack = addrp[naddr-1]; - if (naddr > 1) - intack |= ((unsigned long)addrp[naddr-2]) << 32; - } - if (intack) - printk(KERN_DEBUG "xics: PCI 8259 intack at 0x%016lx\n", intack); - i8259_init(found, intack); - of_node_put(found); - set_irq_chained_handler(cascade, pseries_8259_cascade); -} - void __init xics_init_IRQ(void) { struct device_node *np; @@ -733,8 +671,6 @@ void __init xics_init_IRQ(void) xics_setup_cpu(); - xics_setup_8259_cascade(); - ppc64_boot_msg(0x21, "XICS Done"); } diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h index c26bcff47b6..1c5321ae8f2 100644 --- a/arch/powerpc/platforms/pseries/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h @@ -28,7 +28,4 @@ struct xics_ipi_struct { extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; -struct irq_desc; -extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc); - #endif /* _POWERPC_KERNEL_XICS_H */ |