diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 09:02:26 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 09:02:26 -0800 |
commit | 37969581301e50872a1ae84dc73962b5f7ee6b76 (patch) | |
tree | 35bbd6a07f903f248f4bd209b8d194a922415fe0 /arch/powerpc/platforms | |
parent | 80ff8a805113850a3ffafcc8e6eaa1fdd51b02f3 (diff) | |
parent | 24f1a849614ba1805e26a05da7cc8c6bd67490ea (diff) |
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (69 commits)
[POWERPC] Add SPE registers to core dumps
[POWERPC] Use regset code for compat PTRACE_*REGS* calls
[POWERPC] Use generic compat_sys_ptrace
[POWERPC] Use generic compat_ptrace_request
[POWERPC] Use generic ptrace peekdata/pokedata
[POWERPC] Use regset code for PTRACE_*REGS* requests
[POWERPC] Switch to generic compat_binfmt_elf code
[POWERPC] Switch to using user_regset-based core dumps
[POWERPC] Add user_regset compat support
[POWERPC] Add user_regset_view definitions
[POWERPC] Use user_regset accessors for GPRs
[POWERPC] ptrace accessors for special regs MSR and TRAP
[POWERPC] Use user_regset accessors for SPE regs
[POWERPC] Use user_regset accessors for altivec regs
[POWERPC] Use user_regset accessors for FP regs
[POWERPC] mpc52xx: fix compile error introduce when rebasing patch
[POWERPC] 4xx: PCIe indirect DCR spinlock fix.
[POWERPC] Add missing native dcr dcr_ind_lock spinlock
[POWERPC] 4xx: Fix offset value on Warp board
[POWERPC] 4xx: Add 440EPx Sequoia ehci dts entry
...
Diffstat (limited to 'arch/powerpc/platforms')
33 files changed, 592 insertions, 175 deletions
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index 74f31177e47..a9260e21451 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -72,6 +72,7 @@ config WALNUT default y select 405GP select PCI + select OF_RTC help This option enables support for the IBM PPC405GP evaluation board. diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c index 88b66444dfb..0422590040d 100644 --- a/arch/powerpc/platforms/40x/virtex.c +++ b/arch/powerpc/platforms/40x/virtex.c @@ -37,7 +37,7 @@ static int __init virtex_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (!of_flat_dt_is_compatible(root, "xilinx,virtex")) + if (!of_flat_dt_is_compatible(root, "xlnx,virtex")) return 0; return 1; diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c index 5d9edd917f9..b8b257efeb7 100644 --- a/arch/powerpc/platforms/40x/walnut.c +++ b/arch/powerpc/platforms/40x/walnut.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/of_platform.h> +#include <linux/rtc.h> #include <asm/machdep.h> #include <asm/prom.h> diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index 8f01563dbd2..da5b7b7599d 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -137,7 +137,7 @@ static int __init pika_dtm_start(void) } of_node_put(np); - fpga = ioremap(res.start + 0x20, 4); + fpga = ioremap(res.start, 0x24); if (fpga == NULL) return -ENOENT; diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig new file mode 100644 index 00000000000..c6fa49e23dc --- /dev/null +++ b/arch/powerpc/platforms/512x/Kconfig @@ -0,0 +1,20 @@ +config PPC_MPC512x + bool + select FSL_SOC + select IPIC + default n + +config PPC_MPC5121 + bool + select PPC_MPC512x + default n + +config MPC5121_ADS + bool "Freescale MPC5121E ADS" + depends on PPC_MULTIPLATFORM && PPC32 + select DEFAULT_UIMAGE + select WANT_DEVICE_TREE + select PPC_MPC5121 + help + This option enables support for the MPC5121E ADS board. + default n diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile new file mode 100644 index 00000000000..232c89f2039 --- /dev/null +++ b/arch/powerpc/platforms/512x/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the Freescale PowerPC 512x linux kernel. +# +obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c new file mode 100644 index 00000000000..50bd3a31902 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007 + * + * Description: + * MPC5121 ADS board setup + * + * This 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/io.h> +#include <linux/irq.h> +#include <linux/of_platform.h> + +#include <asm/machdep.h> +#include <asm/ipic.h> +#include <asm/prom.h> +#include <asm/time.h> + +/** + * mpc512x_find_ips_freq - Find the IPS bus frequency for a device + * @node: device node + * + * Returns IPS bus frequency, or 0 if the bus frequency cannot be found. + */ +unsigned long +mpc512x_find_ips_freq(struct device_node *node) +{ + struct device_node *np; + const unsigned int *p_ips_freq = NULL; + + of_node_get(node); + while (node) { + p_ips_freq = of_get_property(node, "bus-frequency", NULL); + if (p_ips_freq) + break; + + np = of_get_parent(node); + of_node_put(node); + node = np; + } + if (node) + of_node_put(node); + + return p_ips_freq ? *p_ips_freq : 0; +} +EXPORT_SYMBOL(mpc512x_find_ips_freq); + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "localbus", }, + {}, +}; + +static void __init mpc5121_ads_declare_of_platform_devices(void) +{ + /* Find every child of the SOC node and add it to of_platform */ + if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) + printk(KERN_ERR __FILE__ ": " + "Error while probing of_platform bus\n"); +} + +static void __init mpc5121_ads_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); + if (!np) + return; + + ipic_init(np, 0); + of_node_put(np); + + /* + * Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc5121_ads_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,mpc5121ads"); +} + +define_machine(mpc5121_ads) { + .name = "MPC5121 ADS", + .probe = mpc5121_ads_probe, + .init = mpc5121_ads_declare_of_platform_devices, + .init_IRQ = mpc5121_ads_init_IRQ, + .get_irq = ipic_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c index 3fce6b375db..7d301875198 100644 --- a/arch/powerpc/platforms/82xx/mpc8272_ads.c +++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c @@ -134,13 +134,12 @@ static void __init mpc8272_ads_setup_arch(void) } bcsr = of_iomap(np, 0); + of_node_put(np); if (!bcsr) { printk(KERN_ERR "Cannot map BCSR registers\n"); return; } - of_node_put(np); - clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); setbits32(&bcsr[1], BCSR1_FETH_RST); diff --git a/arch/powerpc/platforms/82xx/pq2fads.c b/arch/powerpc/platforms/82xx/pq2fads.c index 68196e34999..e1dceeec499 100644 --- a/arch/powerpc/platforms/82xx/pq2fads.c +++ b/arch/powerpc/platforms/82xx/pq2fads.c @@ -130,13 +130,12 @@ static void __init pq2fads_setup_arch(void) } bcsr = of_iomap(np, 0); + of_node_put(np); if (!bcsr) { printk(KERN_ERR "Cannot map BCSR registers\n"); return; } - of_node_put(np); - /* Enable the serial and ethernet ports */ clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 9f0fd88b2b1..e7f706b624f 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -101,7 +101,7 @@ static void __init mpc832x_rdb_setup_arch(void) #ifdef CONFIG_QUICC_ENGINE qe_reset(); - if ((np = of_find_node_by_name(np, "par_io")) != NULL) { + if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { par_io_init(np); of_node_put(np); diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 88bb748aff0..68065e62fc3 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -14,6 +14,8 @@ #define MPC83XX_SCCR_USB_DRCM_11 0x00300000 #define MPC83XX_SCCR_USB_DRCM_01 0x00100000 #define MPC83XX_SCCR_USB_DRCM_10 0x00200000 +#define MPC8315_SCCR_USB_MASK 0x00c00000 +#define MPC8315_SCCR_USB_DRCM_11 0x00c00000 #define MPC837X_SCCR_USB_DRCM_11 0x00c00000 /* system i/o configuration register low */ diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index 681230a30ac..471fdd8f410 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c @@ -104,6 +104,7 @@ int mpc831x_usb_cfg(void) u32 temp; void __iomem *immap, *usb_regs; struct device_node *np = NULL; + struct device_node *immr_node = NULL; const void *prop; struct resource res; int ret = 0; @@ -124,10 +125,15 @@ int mpc831x_usb_cfg(void) } /* Configure clock */ - temp = in_be32(immap + MPC83XX_SCCR_OFFS); - temp &= ~MPC83XX_SCCR_USB_MASK; - temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ - out_be32(immap + MPC83XX_SCCR_OFFS, temp); + immr_node = of_get_parent(np); + 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); + else + clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, + MPC83XX_SCCR_USB_MASK, + MPC83XX_SCCR_USB_DRCM_11); /* Configure pin mux for ULPI. There is no pin mux for UTMI */ if (prop && !strcmp(prop, "ulpi")) { @@ -144,6 +150,9 @@ int mpc831x_usb_cfg(void) iounmap(immap); + if (immr_node) + of_node_put(immr_node); + /* Map USB SOC space */ ret = of_address_to_resource(np, 0, &res); if (ret) { diff --git a/arch/powerpc/platforms/8xx/adder875.c b/arch/powerpc/platforms/8xx/adder875.c index c6bc0783c3b..82363e98f50 100644 --- a/arch/powerpc/platforms/8xx/adder875.c +++ b/arch/powerpc/platforms/8xx/adder875.c @@ -15,12 +15,12 @@ #include <asm/time.h> #include <asm/machdep.h> -#include <asm/commproc.h> +#include <asm/cpm1.h> #include <asm/fs_pd.h> #include <asm/udbg.h> #include <asm/prom.h> -#include <sysdev/commproc.h> +#include "mpc8xx.h" struct cpm_pin { int port, pin, flags; @@ -108,7 +108,7 @@ define_machine(adder875) { .name = "Adder MPC875", .probe = adder875_probe, .setup_arch = adder875_setup, - .init_IRQ = m8xx_pic_init, + .init_IRQ = mpc8xx_pics_init, .get_irq = mpc8xx_get_irq, .restart = mpc8xx_restart, .calibrate_decr = generic_calibrate_decr, diff --git a/arch/powerpc/platforms/8xx/ep88xc.c b/arch/powerpc/platforms/8xx/ep88xc.c index a8dffa00577..7d9ac6040d6 100644 --- a/arch/powerpc/platforms/8xx/ep88xc.c +++ b/arch/powerpc/platforms/8xx/ep88xc.c @@ -15,7 +15,6 @@ #include <asm/machdep.h> #include <asm/io.h> #include <asm/udbg.h> -#include <asm/commproc.h> #include <asm/cpm1.h> #include "mpc8xx.h" diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index fdce10c4f07..fcedbec07f9 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -24,6 +24,7 @@ config PPC_83xx select MPC83xx select IPIC select WANT_DEVICE_TREE + select FSL_EMB_PERFMON config PPC_86xx bool "Freescale 86xx" @@ -41,6 +42,7 @@ config CLASSIC32 source "arch/powerpc/platforms/pseries/Kconfig" source "arch/powerpc/platforms/iseries/Kconfig" source "arch/powerpc/platforms/chrp/Kconfig" +source "arch/powerpc/platforms/512x/Kconfig" source "arch/powerpc/platforms/52xx/Kconfig" source "arch/powerpc/platforms/powermac/Kconfig" source "arch/powerpc/platforms/prep/Kconfig" diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 7fc41104d53..69941ba7097 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -14,7 +14,7 @@ choice There are five families of 32 bit PowerPC chips supported. The most common ones are the desktop and server CPUs (601, 603, 604, 740, 750, 74xx) CPUs from Freescale and IBM, with their - embedded 52xx/82xx/83xx/86xx counterparts. + embedded 512x/52xx/82xx/83xx/86xx counterparts. The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500 (85xx) each form a family of their own that is not compatible with the others. @@ -22,7 +22,7 @@ choice If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx. config 6xx - bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx" + bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx" select PPC_FPU config PPC_85xx @@ -94,6 +94,7 @@ config 8xx bool config E500 + select FSL_EMB_PERFMON bool config PPC_FPU @@ -115,6 +116,9 @@ config FSL_BOOKE depends on E200 || E500 default y +config FSL_EMB_PERFMON + bool + config PTE_64BIT bool depends on 44x || E500 @@ -221,7 +225,7 @@ config NR_CPUS config NOT_COHERENT_CACHE bool - depends on 4xx || 8xx || E200 + depends on 4xx || 8xx || E200 || PPC_MPC512x default y config CHECK_CACHE_COHERENCY diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 6d9079da5f5..a984894466d 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -11,6 +11,7 @@ endif obj-$(CONFIG_PPC_CHRP) += chrp/ obj-$(CONFIG_40x) += 40x/ obj-$(CONFIG_44x) += 44x/ +obj-$(CONFIG_PPC_MPC512x) += 512x/ obj-$(CONFIG_PPC_MPC52xx) += 52xx/ obj-$(CONFIG_PPC_8xx) += 8xx/ obj-$(CONFIG_PPC_82xx) += 82xx/ diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 3a963b4a9be..2f169991896 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -54,6 +54,13 @@ config SPU_FS_64K_LS uses 4K pages. This can improve performances of applications using multiple SPEs by lowering the TLB pressure on them. +config SPU_TRACE + tristate "SPU event tracing support" + depends on SPU_FS && MARKERS + help + This option allows reading a trace of spu-related events through + the sputrace file in procfs. + config SPU_BASE bool default n diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 095988f13bf..d95e71dee91 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -13,7 +13,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/msi.h> -#include <linux/reboot.h> +#include <linux/of_platform.h> #include <asm/dcr.h> #include <asm/machdep.h> @@ -65,14 +65,12 @@ struct axon_msic { struct irq_host *irq_host; - __le32 *fifo; + __le32 *fifo_virt; + dma_addr_t fifo_phys; dcr_host_t dcr_host; - struct list_head list; u32 read_offset; }; -static LIST_HEAD(axon_msic_list); - static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val) { pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n); @@ -94,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) while (msic->read_offset != write_offset) { idx = msic->read_offset / sizeof(__le32); - msi = le32_to_cpu(msic->fifo[idx]); + msi = le32_to_cpu(msic->fifo_virt[idx]); msi &= 0xFFFF; pr_debug("axon_msi: woff %x roff %x msi %x\n", @@ -139,6 +137,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) tmp = dn; dn = of_find_node_by_phandle(*ph); + of_node_put(tmp); if (!dn) { dev_dbg(&dev->dev, "axon_msi: msi-translator doesn't point to a node\n"); @@ -156,7 +155,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) out_error: of_node_put(dn); - of_node_put(tmp); return msic; } @@ -292,30 +290,24 @@ static struct irq_host_ops msic_host_ops = { .map = msic_host_map, }; -static int axon_msi_notify_reboot(struct notifier_block *nb, - unsigned long code, void *data) +static int axon_msi_shutdown(struct of_device *device) { - struct axon_msic *msic; + struct axon_msic *msic = device->dev.platform_data; u32 tmp; - list_for_each_entry(msic, &axon_msic_list, list) { - pr_debug("axon_msi: disabling %s\n", - msic->irq_host->of_node->full_name); - tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG); - tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; - msic_dcr_write(msic, MSIC_CTRL_REG, tmp); - } + pr_debug("axon_msi: disabling %s\n", + msic->irq_host->of_node->full_name); + tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG); + tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; + msic_dcr_write(msic, MSIC_CTRL_REG, tmp); return 0; } -static struct notifier_block axon_msi_reboot_notifier = { - .notifier_call = axon_msi_notify_reboot -}; - -static int axon_msi_setup_one(struct device_node *dn) +static int axon_msi_probe(struct of_device *device, + const struct of_device_id *device_id) { - struct page *page; + struct device_node *dn = device->node; struct axon_msic *msic; unsigned int virq; int dcr_base, dcr_len; @@ -346,16 +338,14 @@ static int axon_msi_setup_one(struct device_node *dn) goto out_free_msic; } - page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL, - get_order(MSIC_FIFO_SIZE_BYTES)); - if (!page) { + msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, + &msic->fifo_phys, GFP_KERNEL); + if (!msic->fifo_virt) { printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n", dn->full_name); goto out_free_msic; } - msic->fifo = page_address(page); - msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP, NR_IRQS, &msic_host_ops, 0); if (!msic->irq_host) { @@ -378,14 +368,18 @@ static int axon_msi_setup_one(struct device_node *dn) pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq); /* Enable the MSIC hardware */ - msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32); + msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32); msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG, - (u64)msic->fifo & 0xFFFFFFFF); + msic->fifo_phys & 0xFFFFFFFF); msic_dcr_write(msic, MSIC_CTRL_REG, MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE | MSIC_CTRL_FIFO_SIZE); - list_add(&msic->list, &axon_msic_list); + device->dev.platform_data = msic; + + ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; + ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; + ppc_md.msi_check_device = axon_msi_check_device; printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name); @@ -394,7 +388,8 @@ static int axon_msi_setup_one(struct device_node *dn) out_free_host: kfree(msic->irq_host); out_free_fifo: - __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES)); + dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt, + msic->fifo_phys); out_free_msic: kfree(msic); out: @@ -402,28 +397,24 @@ out: return -1; } -static int axon_msi_init(void) -{ - struct device_node *dn; - int found = 0; - - pr_debug("axon_msi: initialising ...\n"); - - for_each_compatible_node(dn, NULL, "ibm,axon-msic") { - if (axon_msi_setup_one(dn) == 0) - found++; - } - - if (found) { - ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; - ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; - ppc_md.msi_check_device = axon_msi_check_device; - - register_reboot_notifier(&axon_msi_reboot_notifier); +static const struct of_device_id axon_msi_device_id[] = { + { + .compatible = "ibm,axon-msic" + }, + {} +}; - pr_debug("axon_msi: registered callbacks!\n"); - } +static struct of_platform_driver axon_msi_driver = { + .match_table = axon_msi_device_id, + .probe = axon_msi_probe, + .shutdown = axon_msi_shutdown, + .driver = { + .name = "axon-msi" + }, +}; - return 0; +static int __init axon_msi_init(void) +{ + return of_register_platform_driver(&axon_msi_driver); } -arch_initcall(axon_msi_init); +subsys_initcall(axon_msi_init); diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index e6534b519c9..a7f609b3b87 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -98,7 +98,7 @@ static int __init cell_publish_devices(void) } return 0; } -machine_device_initcall(cell, cell_publish_devices); +machine_subsys_initcall(cell, cell_publish_devices); static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc) { diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index d3a349fb42e..99610a6361f 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -4,6 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o spufs-y += switch.o fault.o lscsa_alloc.o +obj-$(CONFIG_SPU_TRACE) += sputrace.o + # Rules to build switch.o with the help of SPU tool chain SPU_CROSS := spu- SPU_CC := $(SPU_CROSS)gcc diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 3fcd06418b0..1018acd1746 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -29,6 +29,7 @@ #include <linux/poll.h> #include <linux/ptrace.h> #include <linux/seq_file.h> +#include <linux/marker.h> #include <asm/io.h> #include <asm/semaphore.h> @@ -358,6 +359,8 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, struct spu_context *ctx = vma->vm_file->private_data; unsigned long area, offset = address - vma->vm_start; + spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx); + offset += vma->vm_pgoff << PAGE_SHIFT; if (offset >= ps_size) return NOPFN_SIGBUS; @@ -375,11 +378,14 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, if (ctx->state == SPU_STATE_SAVED) { up_read(¤t->mm->mmap_sem); + spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); + spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); down_read(¤t->mm->mmap_sem); } else { area = ctx->spu->problem_phys + ps_offs; vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); + spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); } spu_release(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index c0e968a4c21..90784c029f2 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -322,7 +322,7 @@ static struct spu_context * spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, struct file *filp) { - struct spu_context *tmp, *neighbor; + struct spu_context *tmp, *neighbor, *err; int count, node; int aff_supp; @@ -354,11 +354,15 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) && !list_is_last(&neighbor->aff_list, &gang->aff_list_head) && !list_entry(neighbor->aff_list.next, struct spu_context, - aff_list)->aff_head) - return ERR_PTR(-EEXIST); + aff_list)->aff_head) { + err = ERR_PTR(-EEXIST); + goto out_put_neighbor; + } - if (gang != neighbor->gang) - return ERR_PTR(-EINVAL); + if (gang != neighbor->gang) { + err = ERR_PTR(-EINVAL); + goto out_put_neighbor; + } count = 1; list_for_each_entry(tmp, &gang->aff_list_head, aff_list) @@ -372,11 +376,17 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, break; } - if (node == MAX_NUMNODES) - return ERR_PTR(-EEXIST); + if (node == MAX_NUMNODES) { + err = ERR_PTR(-EEXIST); + goto out_put_neighbor; + } } return neighbor; + +out_put_neighbor: + put_spu_context(neighbor); + return err; } static void @@ -454,9 +464,12 @@ spufs_create_context(struct inode *inode, struct dentry *dentry, if (ret) goto out_aff_unlock; - if (affinity) + if (affinity) { spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx, neighbor); + if (neighbor) + put_spu_context(neighbor); + } /* * get references for dget and mntget, will be released diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index c01a09da1e5..b4814c740d8 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -410,8 +410,11 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) * since we have TIF_SINGLESTEP set, thus the kernel will do * it upon return from the syscall anyawy */ - if ((status & SPU_STATUS_STOPPED_BY_STOP) - && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { + if (unlikely(status & SPU_STATUS_SINGLE_STEP)) + ret = -ERESTARTSYS; + + else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP) + && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) { force_sig(SIGTRAP, current); ret = -ERESTARTSYS; } diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 00d914232af..5915343e259 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -39,6 +39,7 @@ #include <linux/pid_namespace.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/marker.h> #include <asm/io.h> #include <asm/mmu_context.h> @@ -216,8 +217,8 @@ void do_notify_spus_active(void) */ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) { - pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, - spu->number, spu->node); + spu_context_trace(spu_bind_context__enter, ctx, spu); + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); if (ctx->flags & SPU_CREATE_NOSCHED) @@ -399,8 +400,8 @@ static int has_affinity(struct spu_context *ctx) */ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) { - pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, - spu->pid, spu->number, spu->node); + spu_context_trace(spu_unbind_context__enter, ctx, spu); + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); if (spu->ctx->flags & SPU_CREATE_NOSCHED) @@ -528,6 +529,8 @@ static struct spu *spu_get_idle(struct spu_context *ctx) struct spu *spu, *aff_ref_spu; int node, n; + spu_context_nospu_trace(spu_get_idle__enter, ctx); + if (ctx->gang) { mutex_lock(&ctx->gang->aff_mutex); if (has_affinity(ctx)) { @@ -546,8 +549,7 @@ static struct spu *spu_get_idle(struct spu_context *ctx) if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) ctx->gang->aff_ref_spu = NULL; mutex_unlock(&ctx->gang->aff_mutex); - - return NULL; + goto not_found; } mutex_unlock(&ctx->gang->aff_mutex); } @@ -565,12 +567,14 @@ static struct spu *spu_get_idle(struct spu_context *ctx) mutex_unlock(&cbe_spu_info[node].list_mutex); } + not_found: + spu_context_nospu_trace(spu_get_idle__not_found, ctx); return NULL; found: spu->alloc_state = SPU_USED; mutex_unlock(&cbe_spu_info[node].list_mutex); - pr_debug("Got SPU %d %d\n", spu->number, spu->node); + spu_context_trace(spu_get_idle__found, ctx, spu); spu_init_channels(spu); return spu; } @@ -587,6 +591,8 @@ static struct spu *find_victim(struct spu_context *ctx) struct spu *spu; int node, n; + spu_context_nospu_trace(spu_find_vitim__enter, ctx); + /* * Look for a possible preemption candidate on the local node first. * If there is no candidate look at the other nodes. This isn't @@ -640,6 +646,8 @@ static struct spu *find_victim(struct spu_context *ctx) goto restart; } + spu_context_trace(__spu_deactivate__unload, ctx, spu); + mutex_lock(&cbe_spu_info[node].list_mutex); cbe_spu_info[node].nr_active--; spu_unbind_context(spu, victim); @@ -822,6 +830,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) */ void spu_deactivate(struct spu_context *ctx) { + spu_context_nospu_trace(spu_deactivate__enter, ctx); __spu_deactivate(ctx, 1, MAX_PRIO); } @@ -835,6 +844,7 @@ void spu_deactivate(struct spu_context *ctx) */ void spu_yield(struct spu_context *ctx) { + spu_context_nospu_trace(spu_yield__enter, ctx); if (!(ctx->flags & SPU_CREATE_NOSCHED)) { mutex_lock(&ctx->state_mutex); __spu_deactivate(ctx, 0, MAX_PRIO); @@ -864,11 +874,15 @@ static noinline void spusched_tick(struct spu_context *ctx) goto out; spu = ctx->spu; + + spu_context_trace(spusched_tick__preempt, ctx, spu); + new = grab_runnable_context(ctx->prio + 1, spu->node); if (new) { spu_unschedule(spu, ctx); spu_add_to_rq(ctx); } else { + spu_context_nospu_trace(spusched_tick__newslice, ctx); ctx->time_slice++; } out: diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 0e114038ea6..795a1b52538 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -325,4 +325,9 @@ extern void spu_free_lscsa(struct spu_state *csa); extern void spuctx_switch_state(struct spu_context *ctx, enum spu_utilization_state new_state); +#define spu_context_trace(name, ctx, spu) \ + trace_mark(name, "%p %p", ctx, spu); +#define spu_context_nospu_trace(name, ctx) \ + trace_mark(name, "%p", ctx); + #endif diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c new file mode 100644 index 00000000000..2b1953f6f12 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/sputrace.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2007 IBM Deutschland Entwicklung GmbH + * Released under GPL v2. + * + * Partially based on net/ipv4/tcp_probe.c. + * + * Simple tracing facility for spu contexts. + */ +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/marker.h> +#include <linux/proc_fs.h> +#include <linux/wait.h> +#include <asm/atomic.h> +#include <asm/uaccess.h> +#include "spufs.h" + +struct spu_probe { + const char *name; + const char *format; + marker_probe_func *probe_func; +}; + +struct sputrace { + ktime_t tstamp; + int owner_tid; /* owner */ + int curr_tid; + const char *name; + int number; +}; + +static int bufsize __read_mostly = 16384; +MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)"); +module_param(bufsize, int, 0); + + +static DEFINE_SPINLOCK(sputrace_lock); +static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait); +static ktime_t sputrace_start; +static unsigned long sputrace_head, sputrace_tail; +static struct sputrace *sputrace_log; + +static int sputrace_used(void) +{ + return (sputrace_head - sputrace_tail) % bufsize; +} + +static inline int sputrace_avail(void) +{ + return bufsize - sputrace_used(); +} + +static int sputrace_sprint(char *tbuf, int n) +{ + const struct sputrace *t = sputrace_log + sputrace_tail % bufsize; + struct timespec tv = + ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start)); + + return snprintf(tbuf, n, + "[%lu.%09lu] %d: %s (thread = %d, spu = %d)\n", + (unsigned long) tv.tv_sec, + (unsigned long) tv.tv_nsec, + t->owner_tid, + t->name, + t->curr_tid, + t->number); +} + +static ssize_t sputrace_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + int error = 0, cnt = 0; + + if (!buf || len < 0) + return -EINVAL; + + while (cnt < len) { + char tbuf[128]; + int width; + + error = wait_event_interruptible(sputrace_wait, + sputrace_used() > 0); + if (error) + break; + + spin_lock(&sputrace_lock); + if (sputrace_head == sputrace_tail) { + spin_unlock(&sputrace_lock); + continue; + } + + width = sputrace_sprint(tbuf, sizeof(tbuf)); + if (width < len) + sputrace_tail = (sputrace_tail + 1) % bufsize; + spin_unlock(&sputrace_lock); + + if (width >= len) + break; + + error = copy_to_user(buf + cnt, tbuf, width); + if (error) + break; + cnt += width; + } + + return cnt == 0 ? error : cnt; +} + +static int sputrace_open(struct inode *inode, struct file *file) +{ + spin_lock(&sputrace_lock); + sputrace_head = sputrace_tail = 0; + sputrace_start = ktime_get(); + spin_unlock(&sputrace_lock); + + return 0; +} + +static const struct file_operations sputrace_fops = { + .owner = THIS_MODULE, + .open = sputrace_open, + .read = sputrace_read, +}; + +static void sputrace_log_item(const char *name, struct spu_context *ctx, + struct spu *spu) +{ + spin_lock(&sputrace_lock); + if (sputrace_avail() > 1) { + struct sputrace *t = sputrace_log + sputrace_head; + + t->tstamp = ktime_get(); + t->owner_tid = ctx->tid; + t->name = name; + t->curr_tid = current->pid; + t->number = spu ? spu->number : -1; + + sputrace_head = (sputrace_head + 1) % bufsize; + } else { + printk(KERN_WARNING + "sputrace: lost samples due to full buffer.\n"); + } + spin_unlock(&sputrace_lock); + + wake_up(&sputrace_wait); +} + +static void spu_context_event(const struct marker *mdata, + void *private, const char *format, ...) +{ + struct spu_probe *p = mdata->private; + va_list ap; + struct spu_context *ctx; + struct spu *spu; + + va_start(ap, format); + ctx = va_arg(ap, struct spu_context *); + spu = va_arg(ap, struct spu *); + + sputrace_log_item(p->name, ctx, spu); + va_end(ap); +} + +static void spu_context_nospu_event(const struct marker *mdata, + void *private, const char *format, ...) +{ + struct spu_probe *p = mdata->private; + va_list ap; + struct spu_context *ctx; + + va_start(ap, format); + ctx = va_arg(ap, struct spu_context *); + + sputrace_log_item(p->name, ctx, NULL); + va_end(ap); +} + +struct spu_probe spu_probes[] = { + { "spu_bind_context__enter", "%p %p", spu_context_event }, + { "spu_unbind_context__enter", "%p %p", spu_context_event }, + { "spu_get_idle__enter", "%p", spu_context_nospu_event }, + { "spu_get_idle__found", "%p %p", spu_context_event }, + { "spu_get_idle__not_found", "%p", spu_context_nospu_event }, + { "spu_find_victim__enter", "%p", spu_context_nospu_event }, + { "spusched_tick__preempt", "%p %p", spu_context_event }, + { "spusched_tick__newslice", "%p", spu_context_nospu_event }, + { "spu_yield__enter", "%p", spu_context_nospu_event }, + { "spu_deactivate__enter", "%p", spu_context_nospu_event }, + { "__spu_deactivate__unload", "%p %p", spu_context_event }, + { "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event }, + { "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event }, + { "spufs_ps_nopfn__wake", "%p %p", spu_context_event }, + { "spufs_ps_nopfn__insert", "%p %p", spu_context_event }, + { "spu_acquire_saved__enter", "%p", spu_context_nospu_event }, + { "destroy_spu_context__enter", "%p", spu_context_nospu_event }, +}; + +static int __init sputrace_init(void) +{ + struct proc_dir_entry *entry; + int i, error = -ENOMEM; + + sputrace_log = kcalloc(sizeof(struct sputrace), + bufsize, GFP_KERNEL); + if (!sputrace_log) + goto out; + + entry = create_proc_entry("sputrace", S_IRUSR, NULL); + if (!entry) + goto out_free_log; + entry->proc_fops = &sputrace_fops; + + for (i = 0; i < ARRAY_SIZE(spu_probes); i++) { + struct spu_probe *p = &spu_probes[i]; + + error = marker_probe_register(p->name, p->format, + p->probe_func, p); + if (error) + printk(KERN_INFO "Unable to register probe %s\n", + p->name); + + error = marker_arm(p->name); + if (error) + printk(KERN_INFO "Unable to arm probe %s\n", p->name); + } + + return 0; + +out_free_log: + kfree(sputrace_log); +out: + return -ENOMEM; +} + +static void __exit sputrace_exit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(spu_probes); i++) + marker_probe_unregister(spu_probes[i].name); + + remove_proc_entry("sputrace", NULL); + kfree(sputrace_log); +} + +module_init(sputrace_init); +module_exit(sputrace_exit); + +MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index e12e9d29871..8864e488498 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -132,33 +132,18 @@ static void __init storcenter_init_IRQ(void) paddr = (phys_addr_t)of_translate_address(dnp, prop); mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, - 4, 32, " EPIC "); + 16, 32, " OpenPIC "); of_node_put(dnp); BUG_ON(mpic == NULL); - /* PCI IRQs */ /* - * 2.6.12 patch: - * openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200); - * openpic_set_sources(5, 2, OpenPIC_Addr + 0x11120); - * first_irq, num_irqs, __iomem first_ISR - * o_ss: i, src: 0, fdf50200 - * o_ss: i, src: 1, fdf50220 - * o_ss: i, src: 2, fdf50240 - * o_ss: i, src: 3, fdf50260 - * o_ss: i, src: 4, fdf50280 - * o_ss: i, src: 5, fdf51120 - * o_ss: i, src: 6, fdf51140 + * 16 Serial Interrupts followed by 16 Internal Interrupts. + * I2C is the second internal, so it is at 17, 0x11020. */ mpic_assign_isu(mpic, 0, paddr + 0x10200); - mpic_assign_isu(mpic, 1, paddr + 0x10220); - mpic_assign_isu(mpic, 2, paddr + 0x10240); - mpic_assign_isu(mpic, 3, paddr + 0x10260); - mpic_assign_isu(mpic, 4, paddr + 0x10280); - mpic_assign_isu(mpic, 5, paddr + 0x11120); - mpic_assign_isu(mpic, 6, paddr + 0x11140); + mpic_assign_isu(mpic, 1, paddr + 0x11000); mpic_init(mpic); } @@ -178,7 +163,7 @@ static int __init storcenter_probe(void) { unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "storcenter"); + return of_flat_dt_is_compatible(root, "iomega,storcenter"); } define_machine(storcenter){ diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index c4ad54e0f28..1f032483c02 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -58,7 +58,7 @@ static void pseries_mach_cpu_die(void) { local_irq_disable(); idle_task_exit(); - xics_teardown_cpu(0); + xics_teardown_cpu(); unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow())); rtas_stop_self(); /* Should never get here... */ diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 412a5e7aff2..e9dd5fe081c 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -54,7 +54,7 @@ void __init setup_kexec_cpu_down_mpic(void) static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) { pseries_kexec_cpu_down(crash_shutdown, secondary); - xics_teardown_cpu(secondary); + xics_kexec_teardown_cpu(secondary); } void __init setup_kexec_cpu_down_xics(void) diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index c02f8742c54..2800fced8c7 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -167,6 +167,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) if ((child = of_get_next_child(np, NULL))) { of_node_put(child); + of_node_put(parent); return -EBUSY; } diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 8f8dd9c3ca6..ca52b587166 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -160,6 +160,46 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) /* High level handlers and init code */ +static void xics_update_irq_servers(void) +{ + int i, j; + struct device_node *np; + u32 ilen; + const u32 *ireg, *isize; + u32 hcpuid; + + /* Find the server numbers for the boot cpu. */ + np = of_get_cpu_node(boot_cpuid, NULL); + BUG_ON(!np); + + ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); + if (!ireg) { + of_node_put(np); + return; + } + + i = ilen / sizeof(int); + hcpuid = get_hard_smp_processor_id(boot_cpuid); + + /* Global interrupt distribution server is specified in the last + * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last + * entry fom this property for current boot cpu id and use it as + * default distribution server + */ + for (j = 0; j < i; j += 2) { + if (ireg[j] == hcpuid) { + default_server = hcpuid; + default_distrib_server = ireg[j+1]; + + isize = of_get_property(np, + "ibm,interrupt-server#-size", NULL); + if (isize) + interrupt_server_size = *isize; + } + } + + of_node_put(np); +} #ifdef CONFIG_SMP static int get_irq_server(unsigned int virq, unsigned int strict_check) @@ -169,6 +209,9 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) cpumask_t cpumask = irq_desc[virq].affinity; cpumask_t tmp = CPU_MASK_NONE; + if (! cpu_isset(default_server, cpu_online_map)) + xics_update_irq_servers(); + if (!distribute_irqs) return default_server; @@ -658,39 +701,11 @@ static void __init xics_setup_8259_cascade(void) set_irq_chained_handler(cascade, pseries_8259_cascade); } -static struct device_node *cpuid_to_of_node(int cpu) -{ - struct device_node *np; - u32 hcpuid = get_hard_smp_processor_id(cpu); - - for_each_node_by_type(np, "cpu") { - int i, len; - const u32 *intserv; - - intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", - &len); - - if (!intserv) - intserv = of_get_property(np, "reg", &len); - - i = len / sizeof(u32); - - while (i--) - if (intserv[i] == hcpuid) - return np; - } - - return NULL; -} - void __init xics_init_IRQ(void) { - int i, j; struct device_node *np; - u32 ilen, indx = 0; - const u32 *ireg, *isize; + u32 indx = 0; int found = 0; - u32 hcpuid; ppc64_boot_msg(0x20, "XICS Init"); @@ -709,34 +724,7 @@ void __init xics_init_IRQ(void) return; xics_init_host(); - - /* Find the server numbers for the boot cpu. */ - np = cpuid_to_of_node(boot_cpuid); - BUG_ON(!np); - ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); - if (!ireg) - goto skip_gserver_check; - i = ilen / sizeof(int); - hcpuid = get_hard_smp_processor_id(boot_cpuid); - - /* Global interrupt distribution server is specified in the last - * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last - * entry fom this property for current boot cpu id and use it as - * default distribution server - */ - for (j = 0; j < i; j += 2) { - if (ireg[j] == hcpuid) { - default_server = hcpuid; - default_distrib_server = ireg[j+1]; - - isize = of_get_property(np, - "ibm,interrupt-server#-size", NULL); - if (isize) - interrupt_server_size = *isize; - } - } -skip_gserver_check: - of_node_put(np); + xics_update_irq_servers(); if (firmware_has_feature(FW_FEATURE_LPAR)) ppc_md.get_irq = xics_get_irq_lpar; @@ -775,11 +763,9 @@ void xics_request_IPIs(void) } #endif /* CONFIG_SMP */ -void xics_teardown_cpu(int secondary) +void xics_teardown_cpu() { int cpu = smp_processor_id(); - unsigned int ipi; - struct irq_desc *desc; xics_set_cpu_priority(0); @@ -790,9 +776,17 @@ void xics_teardown_cpu(int secondary) lpar_qirr_info(cpu, 0xff); else direct_qirr_info(cpu, 0xff); +} + +void xics_kexec_teardown_cpu(int secondary) +{ + unsigned int ipi; + struct irq_desc *desc; + + xics_teardown_cpu(); /* - * we need to EOI the IPI if we got here from kexec down IPI + * we need to EOI the IPI * * probably need to check all the other interrupts too * should we be flagging idle loop instead? @@ -880,8 +874,8 @@ void xics_migrate_irqs_away(void) virq, cpu); /* Reset affinity to all cpus */ + irq_desc[virq].affinity = CPU_MASK_ALL; desc->chip->set_affinity(virq, CPU_MASK_ALL); - irq_desc[irq].affinity = CPU_MASK_ALL; unlock: spin_unlock_irqrestore(&desc->lock, flags); } diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h index 9ffd809d29e..c26bcff47b6 100644 --- a/arch/powerpc/platforms/pseries/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h @@ -16,7 +16,8 @@ extern void xics_init_IRQ(void); extern void xics_setup_cpu(void); -extern void xics_teardown_cpu(int secondary); +extern void xics_teardown_cpu(void); +extern void xics_kexec_teardown_cpu(int secondary); extern void xics_cause_IPI(int cpu); extern void xics_request_IPIs(void); extern void xics_migrate_irqs_away(void); |