diff options
Diffstat (limited to 'arch/powerpc/platforms')
22 files changed, 367 insertions, 312 deletions
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index d2ac1c116454..5538e57c36c1 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -214,7 +214,6 @@ config AKEBONO select ETHERNET select NET_VENDOR_IBM select IBM_EMAC_EMAC4 - select IBM_EMAC_RGMII_WOL select USB if USB_SUPPORT select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c index 6eb614a271fb..f691bcabd710 100644 --- a/arch/powerpc/platforms/512x/clock-commonclk.c +++ b/arch/powerpc/platforms/512x/clock-commonclk.c @@ -1168,6 +1168,11 @@ static void mpc5121_clk_provide_backwards_compat(void) } } +/* + * The "fixed-clock" nodes (which includes the oscillator node if the board's + * DT provides one) has already been scanned by the of_clk_init() in + * time_init(). + */ int __init mpc5121_clk_init(void) { struct device_node *clk_np; @@ -1187,12 +1192,6 @@ int __init mpc5121_clk_init(void) mpc512x_clk_preset_data(); /* - * have the device tree scanned for "fixed-clock" nodes (which - * includes the oscillator node if the board's DT provides one) - */ - of_clk_init(NULL); - - /* * add a dummy clock for those situations where a clock spec is * required yet no real clock is involved */ diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index 1ad748bb39b4..5c31d8292d3b 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c @@ -162,8 +162,7 @@ int mpc831x_usb_cfg(void) iounmap(immap); - if (immr_node) - of_node_put(immr_node); + of_node_put(immr_node); /* Map USB SOC space */ ret = of_address_to_resource(np, 0, &res); diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index f22635a71d01..2fb4b24368a6 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -241,6 +241,12 @@ config SGY_CTS1000 help Enable this to support functionality in Servergy's CTS-1000 systems. +config MVME2500 + bool "Artesyn MVME2500" + select DEFAULT_UIMAGE + help + This option enables support for the Emerson/Artesyn MVME2500 board. + endif # PPC32 config PPC_QEMU_E500 diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 730326046625..1fe7fb95175a 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o obj-$(CONFIG_GE_IMP3A) += ge_imp3a.o obj-$(CONFIG_PPC_QEMU_E500) += qemu_e500.o obj-$(CONFIG_SGY_CTS1000) += sgy_cts1000.o +obj-$(CONFIG_MVME2500) += mvme2500.o diff --git a/arch/powerpc/platforms/85xx/mvme2500.c b/arch/powerpc/platforms/85xx/mvme2500.c new file mode 100644 index 000000000000..1233050560ae --- /dev/null +++ b/arch/powerpc/platforms/85xx/mvme2500.c @@ -0,0 +1,74 @@ +/* + * Board setup routines for the Emerson/Artesyn MVME2500 + * + * Copyright 2014 Elettra-Sincrotrone Trieste S.C.p.A. + * + * Based on earlier code by: + * + * Xianghua Xiao (x.xiao@freescale.com) + * Tom Armistead (tom.armistead@emerson.com) + * Copyright 2012 Emerson + * + * 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. + * + * Author Alessio Igor Bogani <alessio.bogani@elettra.eu> + * + */ + +#include <linux/pci.h> +#include <asm/udbg.h> +#include <asm/mpic.h> +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> + +#include "mpc85xx.h" + +void __init mvme2500_pic_init(void) +{ + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + BUG_ON(mpic == NULL); + mpic_init(mpic); +} + +/* + * Setup the architecture + */ +static void __init mvme2500_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("mvme2500_setup_arch()", 0); + fsl_pci_assign_primary(); + pr_info("MVME2500 board from Artesyn\n"); +} + +machine_arch_initcall(mvme2500, mpc85xx_common_publish_devices); + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mvme2500_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "artesyn,MVME2500"); +} + +define_machine(mvme2500) { + .name = "MVME2500", + .probe = mvme2500_probe, + .setup_arch = mvme2500_setup_arch, + .init_IRQ = mvme2500_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c index f22387598040..94170e4f2ce7 100644 --- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c +++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c @@ -399,8 +399,8 @@ static int scc_pciex_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops scc_pciex_pci_ops = { - scc_pciex_read_config, - scc_pciex_write_config, + .read = scc_pciex_read_config, + .write = scc_pciex_write_config, }; static void pciex_clear_intr_all(unsigned int __iomem *base) diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index c8017a7bcabd..b64e7ead752f 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -106,7 +106,7 @@ static int __init smp_iic_probe(void) { iic_request_IPIs(); - return cpumask_weight(cpu_possible_mask); + return num_possible_cpus(); } static void smp_cell_setup_cpu(int cpu) diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index beeaf4a173e1..df4ad95f183e 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -156,17 +156,6 @@ void mpc7448_hpc2_restart(char *cmd) for (;;) ; /* Spin until reset happens */ } -void mpc7448_hpc2_power_off(void) -{ - local_irq_disable(); - for (;;) ; /* No way to shut power off with software */ -} - -void mpc7448_hpc2_halt(void) -{ - mpc7448_hpc2_power_off(); -} - /* * Called very early, device-tree isn't unflattened */ diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 04702db35d45..f4071a67ad00 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -133,17 +133,23 @@ static void __init fixup_bus_range(struct device_node *bridge) |(((unsigned int)(off)) & 0xFCUL) \ |1UL) -static volatile void __iomem *macrisc_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, u8 offset) +static void __iomem *macrisc_cfg_map_bus(struct pci_bus *bus, + unsigned int dev_fn, + int offset) { unsigned int caddr; + struct pci_controller *hose; - if (bus == hose->first_busno) { + hose = pci_bus_to_host(bus); + if (hose == NULL) + return NULL; + + if (bus->number == hose->first_busno) { if (dev_fn < (11 << 3)) return NULL; caddr = MACRISC_CFA0(dev_fn, offset); } else - caddr = MACRISC_CFA1(bus, dev_fn, offset); + caddr = MACRISC_CFA1(bus->number, dev_fn, offset); /* Uninorth will return garbage if we don't read back the value ! */ do { @@ -154,129 +160,46 @@ static volatile void __iomem *macrisc_cfg_access(struct pci_controller* hose, return hose->cfg_data + offset; } -static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x100) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_le16(addr); - break; - default: - *val = in_le32(addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x100) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_le16(addr, val); - break; - default: - out_le32(addr, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - static struct pci_ops macrisc_pci_ops = { - .read = macrisc_read_config, - .write = macrisc_write_config, + .map_bus = macrisc_cfg_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; #ifdef CONFIG_PPC32 /* * Verify that a specific (bus, dev_fn) exists on chaos */ -static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) +static void __iomem *chaos_map_bus(struct pci_bus *bus, unsigned int devfn, + int offset) { struct device_node *np; const u32 *vendor, *device; if (offset >= 0x100) - return PCIBIOS_BAD_REGISTER_NUMBER; + return NULL; np = of_pci_find_child_device(bus->dev.of_node, devfn); if (np == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; + return NULL; vendor = of_get_property(np, "vendor-id", NULL); device = of_get_property(np, "device-id", NULL); if (vendor == NULL || device == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; + return NULL; if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10) && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) - return PCIBIOS_BAD_REGISTER_NUMBER; - - return PCIBIOS_SUCCESSFUL; -} + return NULL; -static int -chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - int result = chaos_validate_dev(bus, devfn, offset); - if (result == PCIBIOS_BAD_REGISTER_NUMBER) - *val = ~0U; - if (result != PCIBIOS_SUCCESSFUL) - return result; - return macrisc_read_config(bus, devfn, offset, len, val); -} - -static int -chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - int result = chaos_validate_dev(bus, devfn, offset); - if (result != PCIBIOS_SUCCESSFUL) - return result; - return macrisc_write_config(bus, devfn, offset, len, val); + return macrisc_cfg_map_bus(bus, devfn, offset); } static struct pci_ops chaos_pci_ops = { - .read = chaos_read_config, - .write = chaos_write_config, + .map_bus = chaos_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; static void __init setup_chaos(struct pci_controller *hose, @@ -471,15 +394,24 @@ static struct pci_ops u3_ht_pci_ops = |(((unsigned int)(off)) & 0xfcU) \ |1UL) -static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, int offset) +static void __iomem *u4_pcie_cfg_map_bus(struct pci_bus *bus, + unsigned int dev_fn, + int offset) { + struct pci_controller *hose; unsigned int caddr; - if (bus == hose->first_busno) { + if (offset >= 0x1000) + return NULL; + + hose = pci_bus_to_host(bus); + if (!hose) + return NULL; + + if (bus->number == hose->first_busno) { caddr = U4_PCIE_CFA0(dev_fn, offset); } else - caddr = U4_PCIE_CFA1(bus, dev_fn, offset); + caddr = U4_PCIE_CFA1(bus->number, dev_fn, offset); /* Uninorth will return garbage if we don't read back the value ! */ do { @@ -490,74 +422,11 @@ static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, return hose->cfg_data + offset; } -static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x1000) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_le16(addr); - break; - default: - *val = in_le32(addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x1000) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_le16(addr, val); - break; - default: - out_le32(addr, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - static struct pci_ops u4_pcie_pci_ops = { - .read = u4_pcie_read_config, - .write = u4_pcie_write_config, + .map_bus = u4_pcie_cfg_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; static void pmac_pci_fixup_u4_of_node(struct pci_dev *dev) diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index f241accc053d..6f3c5d33c3af 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -1,7 +1,7 @@ obj-y += setup.o opal-wrappers.o opal.o opal-async.o obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o -obj-y += opal-msglog.o opal-hmi.o +obj-y += opal-msglog.o opal-hmi.o opal-power.o obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 1d19e7917d7f..e261869adc86 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -68,6 +68,17 @@ static int powernv_eeh_init(void) if (phb->model == PNV_PHB_MODEL_P7IOC) eeh_add_flag(EEH_ENABLE_IO_FOR_LOG); + + /* + * PE#0 should be regarded as valid by EEH core + * if it's not the reserved one. Currently, we + * have the reserved PE#0 and PE#127 for PHB3 + * and P7IOC separately. So we should regard + * PE#0 as valid for P7IOC. + */ + if (phb->ioda.reserved_pe != 0) + eeh_add_flag(EEH_VALID_PE_ZERO); + break; } diff --git a/arch/powerpc/platforms/powernv/opal-power.c b/arch/powerpc/platforms/powernv/opal-power.c new file mode 100644 index 000000000000..48bf5b080bcf --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-power.c @@ -0,0 +1,65 @@ +/* + * PowerNV OPAL power control for graceful shutdown handling + * + * Copyright 2015 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/kernel.h> +#include <linux/reboot.h> +#include <linux/notifier.h> + +#include <asm/opal.h> +#include <asm/machdep.h> + +#define SOFT_OFF 0x00 +#define SOFT_REBOOT 0x01 + +static int opal_power_control_event(struct notifier_block *nb, + unsigned long msg_type, void *msg) +{ + struct opal_msg *power_msg = msg; + uint64_t type; + + type = be64_to_cpu(power_msg->params[0]); + + switch (type) { + case SOFT_REBOOT: + /* Fall through. The service processor is responsible for + * bringing the machine back up */ + case SOFT_OFF: + pr_info("OPAL: poweroff requested\n"); + orderly_poweroff(true); + break; + default: + pr_err("OPAL: power control type unexpected %016llx\n", type); + } + + return 0; +} + +static struct notifier_block opal_power_control_nb = { + .notifier_call = opal_power_control_event, + .next = NULL, + .priority = 0, +}; + +static int __init opal_power_control_init(void) +{ + int ret; + + ret = opal_message_notifier_register(OPAL_MSG_SHUTDOWN, + &opal_power_control_nb); + if (ret) { + pr_err("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + + return 0; +} +machine_subsys_initcall(powernv, opal_power_control_init); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index f10b9ec8c1f5..18fd4e71c9c1 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -208,7 +208,7 @@ static int __init opal_register_exception_handlers(void) * start catching/handling HMI directly in Linux. */ if (!opal_check_token(OPAL_HANDLE_HMI)) { - pr_info("opal: Old firmware detected, OPAL handles HMIs.\n"); + pr_info("Old firmware detected, OPAL handles HMIs.\n"); opal_register_exception_handler( OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 0, glue); @@ -667,7 +667,13 @@ static void __init opal_dump_region_init(void) /* Register kernel log buffer */ addr = log_buf_addr_get(); + if (addr == NULL) + return; + size = log_buf_len_get(); + if (size == 0) + return; + rc = opal_register_dump_region(OPAL_DUMP_REGION_LOG_BUF, __pa(addr), size); /* Don't warn if this is just an older OPAL that doesn't @@ -695,15 +701,54 @@ static void opal_i2c_create_devs(void) of_platform_device_create(np, NULL, NULL); } +static void __init opal_irq_init(struct device_node *dn) +{ + const __be32 *irqs; + int i, irqlen; + + /* Get interrupt property */ + irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); + opal_irq_count = irqs ? (irqlen / 4) : 0; + pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count); + if (!opal_irq_count) + return; + + /* Install interrupt handlers */ + opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL); + for (i = 0; irqs && i < opal_irq_count; i++, irqs++) { + unsigned int irq, virq; + int rc; + + /* Get hardware and virtual IRQ */ + irq = be32_to_cpup(irqs); + virq = irq_create_mapping(NULL, irq); + if (virq == NO_IRQ) { + pr_warn("Failed to map irq 0x%x\n", irq); + continue; + } + + /* Install interrupt handler */ + rc = request_irq(virq, opal_interrupt, 0, "opal", NULL); + if (rc) { + irq_dispose_mapping(virq); + pr_warn("Error %d requesting irq %d (0x%x)\n", + rc, virq, irq); + continue; + } + + /* Cache IRQ */ + opal_irqs[i] = virq; + } +} + static int __init opal_init(void) { struct device_node *np, *consoles; - const __be32 *irqs; - int rc, i, irqlen; + int rc; opal_node = of_find_node_by_path("/ibm,opal"); if (!opal_node) { - pr_warn("opal: Node not found\n"); + pr_warn("Device node not found\n"); return -ENODEV; } @@ -725,24 +770,7 @@ static int __init opal_init(void) opal_i2c_create_devs(); /* Find all OPAL interrupts and request them */ - irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); - pr_debug("opal: Found %d interrupts reserved for OPAL\n", - irqs ? (irqlen / 4) : 0); - opal_irq_count = irqlen / 4; - opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL); - for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) { - unsigned int hwirq = be32_to_cpup(irqs); - unsigned int irq = irq_create_mapping(NULL, hwirq); - if (irq == NO_IRQ) { - pr_warning("opal: Failed to map irq 0x%x\n", hwirq); - continue; - } - rc = request_irq(irq, opal_interrupt, 0, "opal", NULL); - if (rc) - pr_warning("opal: Error %d requesting irq %d" - " (0x%x)\n", rc, irq, hwirq); - opal_irqs[i] = irq; - } + opal_irq_init(opal_node); /* Create "opal" kobject under /sys/firmware */ rc = opal_sysfs_init(); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index fac88ed8a915..6c9ff2b95119 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -75,6 +75,28 @@ static void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level, #define pe_info(pe, fmt, ...) \ pe_level_printk(pe, KERN_INFO, fmt, ##__VA_ARGS__) +static bool pnv_iommu_bypass_disabled __read_mostly; + +static int __init iommu_setup(char *str) +{ + if (!str) + return -EINVAL; + + while (*str) { + if (!strncmp(str, "nobypass", 8)) { + pnv_iommu_bypass_disabled = true; + pr_info("PowerNV: IOMMU bypass window disabled.\n"); + break; + } + str += strcspn(str, ","); + if (*str == ',') + str++; + } + + return 0; +} +early_param("iommu", iommu_setup); + /* * stdcix is only supposed to be used in hypervisor real mode as per * the architecture spec @@ -357,6 +379,9 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb) phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe; phb->ioda.m64_base = pci_addr; + pr_info(" MEM64 0x%016llx..0x%016llx -> 0x%016llx\n", + res->start, res->end, pci_addr); + /* Use last M64 BAR to cover M64 window */ phb->ioda.m64_bar_idx = 15; phb->init_m64 = pnv_ioda2_init_m64; @@ -1348,7 +1373,9 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, pnv_ioda_setup_bus_dma(pe, pe->pbus, true); /* Also create a bypass window */ - pnv_pci_ioda2_setup_bypass_pe(phb, pe); + if (!pnv_iommu_bypass_disabled) + pnv_pci_ioda2_setup_bypass_pe(phb, pe); + return; fail: if (pe->tce32_seg >= 0) @@ -1460,15 +1487,15 @@ static void set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq) #ifdef CONFIG_CXL_BASE -struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) +struct device_node *pnv_pci_get_phb_node(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); - return hose->dn; + return of_node_get(hose->dn); } -EXPORT_SYMBOL(pnv_pci_to_phb_node); +EXPORT_SYMBOL(pnv_pci_get_phb_node); -int pnv_phb_to_cxl(struct pci_dev *dev) +int pnv_phb_to_cxl_mode(struct pci_dev *dev, uint64_t mode) { struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pnv_phb *phb = hose->private_data; @@ -1481,13 +1508,13 @@ int pnv_phb_to_cxl(struct pci_dev *dev) pe_info(pe, "Switching PHB to CXL\n"); - rc = opal_pci_set_phb_cxl_mode(phb->opal_id, 1, pe->pe_number); + rc = opal_pci_set_phb_cxl_mode(phb->opal_id, mode, pe->pe_number); if (rc) dev_err(&dev->dev, "opal_pci_set_phb_cxl_mode failed: %i\n", rc); return rc; } -EXPORT_SYMBOL(pnv_phb_to_cxl); +EXPORT_SYMBOL(pnv_phb_to_cxl_mode); /* Find PHB for cxl dev and allocate MSI hwirqs? * Returns the absolute hardware IRQ number diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 4945e87f12dc..e69142f4af08 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -781,35 +781,6 @@ static void pnv_p7ioc_rc_quirk(struct pci_dev *dev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IBM, 0x3b9, pnv_p7ioc_rc_quirk); -static int pnv_pci_probe_mode(struct pci_bus *bus) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - const __be64 *tstamp; - u64 now, target; - - - /* We hijack this as a way to ensure we have waited long - * enough since the reset was lifted on the PCI bus - */ - if (bus != hose->bus) - return PCI_PROBE_NORMAL; - tstamp = of_get_property(hose->dn, "reset-clear-timestamp", NULL); - if (!tstamp || !*tstamp) - return PCI_PROBE_NORMAL; - - now = mftb() / tb_ticks_per_usec; - target = (be64_to_cpup(tstamp) / tb_ticks_per_usec) - + PCI_RESET_DELAY_US; - - pr_devel("pci %04d: Reset target: 0x%llx now: 0x%llx\n", - hose->global_number, target, now); - - if (now < target) - msleep((target - now + 999) / 1000); - - return PCI_PROBE_NORMAL; -} - void __init pnv_pci_init(void) { struct device_node *np; @@ -856,7 +827,6 @@ void __init pnv_pci_init(void) ppc_md.tce_build_rm = pnv_tce_build_rm; ppc_md.tce_free_rm = pnv_tce_free_rm; ppc_md.tce_get = pnv_tce_get; - ppc_md.pci_probe_mode = pnv_pci_probe_mode; set_pci_dma_ops(&dma_iommu_ops); /* Configure MSIs */ diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 0c9f643d9e2a..b0f34663b1ae 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -223,6 +223,44 @@ void ps3_mm_vas_destroy(void) } } +static int ps3_mm_get_repository_highmem(struct mem_region *r) +{ + int result; + + /* Assume a single highmem region. */ + + result = ps3_repository_read_highmem_info(0, &r->base, &r->size); + + if (result) + goto zero_region; + + if (!r->base || !r->size) { + result = -1; + goto zero_region; + } + + r->offset = r->base - map.rm.size; + + DBG("%s:%d: Found high region in repository: %llxh %llxh\n", + __func__, __LINE__, r->base, r->size); + + return 0; + +zero_region: + DBG("%s:%d: No high region in repository.\n", __func__, __LINE__); + + r->size = r->base = r->offset = 0; + return result; +} + +static int ps3_mm_set_repository_highmem(const struct mem_region *r) +{ + /* Assume a single highmem region. */ + + return r ? ps3_repository_write_highmem_info(0, r->base, r->size) : + ps3_repository_write_highmem_info(0, 0, 0); +} + /** * ps3_mm_region_create - create a memory region in the vas * @r: pointer to a struct mem_region to accept initialized values @@ -291,36 +329,7 @@ static void ps3_mm_region_destroy(struct mem_region *r) r->size = r->base = r->offset = 0; map.total = map.rm.size; } -} - -static int ps3_mm_get_repository_highmem(struct mem_region *r) -{ - int result; - - /* Assume a single highmem region. */ - - result = ps3_repository_read_highmem_info(0, &r->base, &r->size); - - if (result) - goto zero_region; - - if (!r->base || !r->size) { - result = -1; - goto zero_region; - } - - r->offset = r->base - map.rm.size; - - DBG("%s:%d: Found high region in repository: %llxh %llxh\n", - __func__, __LINE__, r->base, r->size); - - return 0; - -zero_region: - DBG("%s:%d: No high region in repository.\n", __func__, __LINE__); - - r->size = r->base = r->offset = 0; - return result; + ps3_mm_set_repository_highmem(NULL); } /*============================================================================*/ @@ -1210,8 +1219,12 @@ void __init ps3_mm_init(void) /* Check if we got the highmem region from an earlier boot step */ - if (ps3_mm_get_repository_highmem(&map.r1)) - ps3_mm_region_create(&map.r1, map.total - map.rm.size); + if (ps3_mm_get_repository_highmem(&map.r1)) { + result = ps3_mm_region_create(&map.r1, map.total - map.rm.size); + + if (!result) + ps3_mm_set_repository_highmem(&map.r1); + } /* correct map.total for the real total amount of memory we use */ map.total = map.rm.size + map.r1.size; diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index d71329a8e325..1809cfc562ee 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -196,6 +196,7 @@ int ps3_repository_read_highmem_size(unsigned int region_index, int ps3_repository_read_highmem_info(unsigned int region_index, u64 *highmem_base, u64 *highmem_size); +#if defined (CONFIG_PS3_REPOSITORY_WRITE) int ps3_repository_write_highmem_region_count(unsigned int region_count); int ps3_repository_write_highmem_base(unsigned int region_index, u64 highmem_base); @@ -204,6 +205,18 @@ int ps3_repository_write_highmem_size(unsigned int region_index, int ps3_repository_write_highmem_info(unsigned int region_index, u64 highmem_base, u64 highmem_size); int ps3_repository_delete_highmem_info(unsigned int region_index); +#else +static inline int ps3_repository_write_highmem_region_count( + unsigned int region_count) {return 0;} +static inline int ps3_repository_write_highmem_base(unsigned int region_index, + u64 highmem_base) {return 0;} +static inline int ps3_repository_write_highmem_size(unsigned int region_index, + u64 highmem_size) {return 0;} +static inline int ps3_repository_write_highmem_info(unsigned int region_index, + u64 highmem_base, u64 highmem_size) {return 0;} +static inline int ps3_repository_delete_highmem_info(unsigned int region_index) + {return 0;} +#endif /* repository pme info */ diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 756b482f819a..a758a9c3bbba 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -34,6 +34,16 @@ config PPC_SPLPAR processors, that is, which share physical processors between two or more partitions. +config DTL + bool "Dispatch Trace Log" + depends on PPC_SPLPAR && DEBUG_FS + help + SPLPAR machines can log hypervisor preempt & dispatch events to a + kernel buffer. Saying Y here will enable logging these events, + which are accessible through a debugfs file. + + Say N if you are unsure. + config PSERIES_MSI bool depends on PCI_MSI && PPC_PSERIES && EEH @@ -123,13 +133,3 @@ config HV_PERF_CTRS systems. 24x7 is available on Power 8 systems. If unsure, select Y. - -config DTL - bool "Dispatch Trace Log" - depends on PPC_SPLPAR && DEBUG_FS - help - SPLPAR machines can log hypervisor preempt & dispatch events to a - kernel buffer. Saying Y here will enable logging these events, - which are accessible through a debugfs file. - - Say N if you are unsure. diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index f30cf4d136a4..62475440fd45 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -272,7 +272,7 @@ static int pseries_add_processor(struct device_node *np) */ printk(KERN_ERR "Cannot add cpu %s; this system configuration" " supports %d logical cpus.\n", np->full_name, - cpumask_weight(cpu_possible_mask)); + num_possible_cpus()); goto out_unlock; } diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index e7cb6d4a871a..90cf3dcbd9f2 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -316,34 +316,24 @@ void post_mobility_fixup(void) static ssize_t migrate_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { - struct rtas_args args; u64 streamid; int rc; + int vasi_rc = 0; rc = kstrtou64(buf, 0, &streamid); if (rc) return rc; - memset(&args, 0, sizeof(args)); - args.token = rtas_token("ibm,suspend-me"); - args.nargs = 2; - args.nret = 1; - - args.args[0] = streamid >> 32 ; - args.args[1] = streamid & 0xffffffff; - args.rets = &args.args[args.nargs]; - do { - args.rets[0] = 0; - rc = rtas_ibm_suspend_me(&args); - if (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE) + rc = rtas_ibm_suspend_me(streamid, &vasi_rc); + if (!rc && vasi_rc == RTAS_NOT_SUSPENDABLE) ssleep(1); - } while (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE); + } while (!rc && vasi_rc == RTAS_NOT_SUSPENDABLE); if (rc) return rc; - else if (args.rets[0]) - return args.rets[0]; + if (vasi_rc) + return vasi_rc; post_mobility_fixup(); return count; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index c3b2a7e81ddb..02e4a1745516 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -89,6 +89,8 @@ static void handle_system_shutdown(char event_modifier) case EPOW_SHUTDOWN_ON_UPS: pr_emerg("Loss of power reported by firmware, system is " "running on UPS/battery"); + pr_emerg("Check RTAS error log for details"); + orderly_poweroff(true); break; case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS: |