diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 18:58:09 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 18:58:09 +0100 |
commit | 16e024f30ce96ef5fa651e2914e19d175a924cab (patch) | |
tree | d68106151a0b36e22625d7af7b23081a48c92e87 /arch/powerpc/platforms | |
parent | x86, paravirt: fix build error when thp is disabled (diff) | |
parent | Merge remote-tracking branch 'agust/next' into next (diff) | |
download | linux-16e024f30ce96ef5fa651e2914e19d175a924cab.tar.xz linux-16e024f30ce96ef5fa651e2914e19d175a924cab.zip |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull powerpc update from Benjamin Herrenschmidt:
"The main highlight is probably some base POWER8 support. There's more
to come such as transactional memory support but that will wait for
the next one.
Overall it's pretty quiet, or rather I've been pretty poor at picking
things up from patchwork and reviewing them this time around and Kumar
no better on the FSL side it seems..."
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (73 commits)
powerpc+of: Rename and fix OF reconfig notifier error inject module
powerpc: mpc5200: Add a3m071 board support
powerpc/512x: don't compile any platform DIU code if the DIU is not enabled
powerpc/mpc52xx: use module_platform_driver macro
powerpc+of: Export of_reconfig_notifier_[register,unregister]
powerpc/dma/raidengine: add raidengine device
powerpc/iommu/fsl: Add PAMU bypass enable register to ccsr_guts struct
powerpc/mpc85xx: Change spin table to cached memory
powerpc/fsl-pci: Add PCI controller ATMU PM support
powerpc/86xx: fsl_pcibios_fixup_bus requires CONFIG_PCI
drivers/virt: the Freescale hypervisor driver doesn't need to check MSR[GS]
powerpc/85xx: p1022ds: Use NULL instead of 0 for pointers
powerpc: Disable relocation on exceptions when kexecing
powerpc: Enable relocation on during exceptions at boot
powerpc: Move get_longbusy_msecs into hvcall.h and remove duplicate function
powerpc: Add wrappers to enable/disable relocation on exceptions
powerpc: Add set_mode hcall
powerpc: Setup relocation on exceptions for bare metal systems
powerpc: Move initial mfspr LPCR out of __init_LPCR
powerpc: Add relocation on exception vector handlers
...
Diffstat (limited to 'arch/powerpc/platforms')
29 files changed, 259 insertions, 258 deletions
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index b62508b113db..c16999802ecf 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -2,7 +2,6 @@ config PPC_MPC512x bool "512x-based boards" depends on 6xx select FSL_SOC - select FB_FSL_DIU select IPIC select PPC_CLOCK select PPC_PCI_CHOICE diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index dcef6ade48e1..0a134e0469ef 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c @@ -42,7 +42,10 @@ static void __init mpc5121_ads_setup_arch(void) for_each_compatible_node(np, "pci", "fsl,mpc5121-pci") mpc83xx_add_bridge(np); #endif + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) mpc512x_setup_diu(); +#endif } static void __init mpc5121_ads_init_IRQ(void) diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h index 1ab6d11d0b19..c32b399eb952 100644 --- a/arch/powerpc/platforms/512x/mpc512x.h +++ b/arch/powerpc/platforms/512x/mpc512x.h @@ -16,6 +16,13 @@ extern void __init mpc512x_init(void); extern int __init mpc5121_clk_init(void); void __init mpc512x_declare_of_platform_devices(void); extern void mpc512x_restart(char *cmd); -extern void mpc512x_init_diu(void); -extern void mpc512x_setup_diu(void); + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) +void mpc512x_init_diu(void); +void mpc512x_setup_diu(void); +#else +#define mpc512x_init_diu NULL +#define mpc512x_setup_diu NULL +#endif + #endif /* __MPC512X_H__ */ diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index 1650e090ef3a..35f14fda108a 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -58,6 +58,8 @@ void mpc512x_restart(char *cmd) ; } +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + struct fsl_diu_shared_fb { u8 gamma[0x300]; /* 32-bit aligned! */ struct diu_ad ad0; /* 32-bit aligned! */ @@ -66,25 +68,6 @@ struct fsl_diu_shared_fb { bool in_use; }; -u32 mpc512x_get_pixel_format(enum fsl_diu_monitor_port port, - unsigned int bits_per_pixel) -{ - switch (bits_per_pixel) { - case 32: - return 0x88883316; - case 24: - return 0x88082219; - case 16: - return 0x65053118; - } - return 0x00000400; -} - -void mpc512x_set_gamma_table(enum fsl_diu_monitor_port port, - char *gamma_table_base) -{ -} - void mpc512x_set_monitor_port(enum fsl_diu_monitor_port port) { } @@ -320,14 +303,14 @@ void __init mpc512x_setup_diu(void) } } - diu_ops.get_pixel_format = mpc512x_get_pixel_format; - diu_ops.set_gamma_table = mpc512x_set_gamma_table; diu_ops.set_monitor_port = mpc512x_set_monitor_port; diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; diu_ops.valid_monitor_port = mpc512x_valid_monitor_port; diu_ops.release_bootmem = mpc512x_release_bootmem; } +#endif + void __init mpc512x_init_IRQ(void) { struct device_node *np; diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 448d862bcf3d..1843bc932011 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -4,7 +4,7 @@ * Written by: Grant Likely <grant.likely@secretlab.ca> * * Copyright (C) Secret Lab Technologies Ltd. 2006. All rights reserved. - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Description: * This program is free software; you can redistribute it and/or modify it diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index 9cf36020cf0d..792a301a0bf0 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void) /* list of the supported boards */ static const char *board[] __initdata = { + "anonymous,a3m071", "anonymous,a4m072", "anon,charon", "ifm,o2d", diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c index 2351f9e0fb6f..16150fa430f9 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c @@ -578,18 +578,4 @@ static struct platform_driver mpc52xx_lpbfifo_driver = { .probe = mpc52xx_lpbfifo_probe, .remove = __devexit_p(mpc52xx_lpbfifo_remove), }; - -/*********************************************************************** - * Module init/exit - */ -static int __init mpc52xx_lpbfifo_init(void) -{ - return platform_driver_register(&mpc52xx_lpbfifo_driver); -} -module_init(mpc52xx_lpbfifo_init); - -static void __exit mpc52xx_lpbfifo_exit(void) -{ - platform_driver_unregister(&mpc52xx_lpbfifo_driver); -} -module_exit(mpc52xx_lpbfifo_exit); +module_platform_driver(mpc52xx_lpbfifo_driver); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 328d221fd1c0..74861a7fb807 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -16,7 +16,6 @@ #include <linux/spinlock.h> #include <linux/irq.h> #include <linux/types.h> -#include <linux/bootmem.h> #include <linux/slab.h> #include <asm/io.h> @@ -149,7 +148,7 @@ int __init pq2ads_pci_init_irq(void) priv->regs = of_iomap(np, 0); if (!priv->regs) { printk(KERN_ERR "Cannot map PCI PIC registers.\n"); - goto out_free_bootmem; + goto out_free_kmalloc; } /* mask all PCI interrupts */ @@ -171,9 +170,8 @@ int __init pq2ads_pci_init_irq(void) out_unmap_regs: iounmap(priv->regs); -out_free_bootmem: - free_bootmem((unsigned long)priv, - sizeof(struct pq2ads_pci_pic)); +out_free_kmalloc: + kfree(priv); of_node_put(np); out_unmap_irq: irq_dispose_mapping(irq); diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index d440435e055c..8d762203eeff 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Description: * MPC832xE MDS board specific routines. diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 1b1f6c8a1a12..1a26d2f83401 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Author: Li Yang <LeoLi@freescale.com> * Yin Olivia <Hong-hua.Yin@freescale.com> diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c index f8769d713d61..b63b42d11d6c 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_rdk.c +++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c @@ -1,7 +1,7 @@ /* * MPC8360E-RDK board file. * - * Copyright (c) 2006 Freescale Semicondutor, Inc. + * Copyright (c) 2006 Freescale Semiconductor, Inc. * Copyright (c) 2007-2008 MontaVista Software, Inc. * * Author: Anton Vorontsov <avorontsov@ru.mvista.com> diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index eca1f0960fff..9813c81e8e5b 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -1,7 +1,7 @@ /* * arch/powerpc/platforms/83xx/mpc837x_rdb.c * - * Copyright (C) 2007 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. * * MPC837x RDB board specific routines * diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 8498f7323470..bd12588fa252 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc. + * Copyright (C) 2006-2010, 2012 Freescale Semiconductor, Inc. * All rights reserved. * * Author: Andy Fleming <afleming@freescale.com> diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 848a3e98e1c1..7328b8d74129 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -249,7 +249,7 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) goto exit; } - iprop = of_get_property(law_node, "fsl,num-laws", 0); + iprop = of_get_property(law_node, "fsl,num-laws", NULL); if (!iprop) { pr_err("p1022ds: LAW node is missing fsl,num-laws property\n"); goto exit; @@ -539,7 +539,7 @@ static void __init p1022_ds_setup_arch(void) }; /* - * prom_update_property() is called before + * of_update_property() is called before * kmalloc() is available, so the 'new' object * should be allocated in the global area. * The easiest way is to do that is to @@ -548,7 +548,7 @@ static void __init p1022_ds_setup_arch(void) */ pr_info("p1022ds: disabling %s node", np2->full_name); - prom_update_property(np2, &nor_status); + of_update_property(np2, &nor_status); of_node_put(np2); } @@ -564,7 +564,7 @@ static void __init p1022_ds_setup_arch(void) pr_info("p1022ds: disabling %s node", np2->full_name); - prom_update_property(np2, &nand_status); + of_update_property(np2, &nand_status); of_node_put(np2); } diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 6fcfa12e5c56..148c2f2d9780 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -128,6 +128,19 @@ static void __cpuinit smp_85xx_mach_cpu_die(void) } #endif +static inline void flush_spin_table(void *spin_table) +{ + flush_dcache_range((ulong)spin_table, + (ulong)spin_table + sizeof(struct epapr_spin_table)); +} + +static inline u32 read_spin_table_addr_l(void *spin_table) +{ + flush_dcache_range((ulong)spin_table, + (ulong)spin_table + sizeof(struct epapr_spin_table)); + return in_be32(&((struct epapr_spin_table *)spin_table)->addr_l); +} + static int __cpuinit smp_85xx_kick_cpu(int nr) { unsigned long flags; @@ -161,8 +174,8 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) /* Map the spin table */ if (ioremappable) - spin_table = ioremap(*cpu_rel_addr, - sizeof(struct epapr_spin_table)); + spin_table = ioremap_prot(*cpu_rel_addr, + sizeof(struct epapr_spin_table), _PAGE_COHERENT); else spin_table = phys_to_virt(*cpu_rel_addr); @@ -173,7 +186,16 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) generic_set_cpu_up(nr); if (system_state == SYSTEM_RUNNING) { + /* + * To keep it compatible with old boot program which uses + * cache-inhibit spin table, we need to flush the cache + * before accessing spin table to invalidate any staled data. + * We also need to flush the cache after writing to spin + * table to push data out. + */ + flush_spin_table(spin_table); out_be32(&spin_table->addr_l, 0); + flush_spin_table(spin_table); /* * We don't set the BPTR register here since it already points @@ -181,9 +203,14 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) */ mpic_reset_core(hw_cpu); - /* wait until core is ready... */ - if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1, - 10000, 100)) { + /* + * wait until core is ready... + * We need to invalidate the stale data, in case the boot + * loader uses a cache-inhibited spin table. + */ + if (!spin_event_timeout( + read_spin_table_addr_l(spin_table) == 1, + 10000, 100)) { pr_err("%s: timeout waiting for core %d to reset\n", __func__, hw_cpu); ret = -ENOENT; @@ -194,12 +221,10 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) __secondary_hold_acknowledge = -1; } #endif + flush_spin_table(spin_table); out_be32(&spin_table->pir, hw_cpu); out_be32(&spin_table->addr_l, __pa(__early_start)); - - if (!ioremappable) - flush_dcache_range((ulong)spin_table, - (ulong)spin_table + sizeof(struct epapr_spin_table)); + flush_spin_table(spin_table); /* Wait a bit for the CPU to ack. */ if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu, @@ -213,13 +238,11 @@ out: #else smp_generic_kick_cpu(nr); + flush_spin_table(spin_table); out_be32(&spin_table->pir, hw_cpu); out_be64((u64 *)(&spin_table->addr_h), __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); - - if (!ioremappable) - flush_dcache_range((ulong)spin_table, - (ulong)spin_table + sizeof(struct epapr_spin_table)); + flush_spin_table(spin_table); #endif local_irq_restore(flags); diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index a817398a56da..04d9d317f741 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -353,5 +353,7 @@ define_machine(mpc86xx_hpcd) { .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/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 64171198535c..311b804353b1 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -55,6 +55,7 @@ static unsigned int low_freq; static unsigned int hi_freq; static unsigned int cur_freq; static unsigned int sleep_freq; +static unsigned long transition_latency; /* * Different models uses different mechanisms to switch the frequency @@ -403,7 +404,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -ENODEV; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cpuinfo.transition_latency = transition_latency; policy->cur = cur_freq; cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu); @@ -658,12 +659,14 @@ static int __init pmac_cpufreq_setup(void) if (!value) goto out; cur_freq = (*value) / 1000; + transition_latency = CPUFREQ_ETERNAL; /* Check for 7447A based MacRISC3 */ if (of_machine_is_compatible("MacRISC3") && of_get_property(cpunode, "dynamic-power-step", NULL) && PVR_VER(mfspr(SPRN_PVR)) == 0x8003) { pmac_cpufreq_init_7447A(cpunode); + transition_latency = 8000000; /* Check for other MacRISC3 machines */ } else if (of_machine_is_compatible("PowerBook3,4") || of_machine_is_compatible("PowerBook3,5") || diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 471aa3ccd9fd..53d052e95cfc 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -34,24 +34,12 @@ #include "powernv.h" #include "pci.h" -static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe, - struct va_format *vaf) -{ - char pfix[32]; - - if (pe->pdev) - strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix)); - else - sprintf(pfix, "%04x:%02x ", - pci_domain_nr(pe->pbus), pe->pbus->number); - return printk("pci %s%s: [PE# %.3d] %pV", level, pfix, pe->pe_number, vaf); -} - #define define_pe_printk_level(func, kern_level) \ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \ { \ struct va_format vaf; \ va_list args; \ + char pfix[32]; \ int r; \ \ va_start(args, fmt); \ @@ -59,7 +47,16 @@ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \ vaf.fmt = fmt; \ vaf.va = &args; \ \ - r = __pe_printk(kern_level, pe, &vaf); \ + if (pe->pdev) \ + strlcpy(pfix, dev_name(&pe->pdev->dev), \ + sizeof(pfix)); \ + else \ + sprintf(pfix, "%04x:%02x ", \ + pci_domain_nr(pe->pbus), \ + pe->pbus->number); \ + r = printk(kern_level "pci %s: [PE# %.3d] %pV", \ + pfix, pe->pe_number, &vaf); \ + \ va_end(args); \ \ return r; \ diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 56d26bc4fd41..09787139834d 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -280,13 +280,13 @@ static void os_area_set_property(struct device_node *node, if (tmp) { pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name); - prom_remove_property(node, tmp); + of_remove_property(node, tmp); } - result = prom_add_property(node, prop); + result = of_add_property(node, prop); if (result) - pr_debug("%s:%d prom_set_property failed\n", __func__, + pr_debug("%s:%d of_set_property failed\n", __func__, __LINE__); } diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 0f1b706506ed..a1a7b9a67ffd 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -13,17 +13,16 @@ #include <linux/kernel.h> #include <linux/kref.h> #include <linux/notifier.h> -#include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/cpu.h> #include <linux/slab.h> +#include <linux/of.h> #include "offline_states.h" #include <asm/prom.h> #include <asm/machdep.h> #include <asm/uaccess.h> #include <asm/rtas.h> -#include <asm/pSeries_reconfig.h> struct cc_workarea { u32 drc_index; @@ -255,9 +254,6 @@ static struct device_node *derive_parent(const char *path) int dlpar_attach_node(struct device_node *dn) { -#ifdef CONFIG_PROC_DEVICETREE - struct proc_dir_entry *ent; -#endif int rc; of_node_set_flag(dn, OF_DYNAMIC); @@ -266,44 +262,26 @@ int dlpar_attach_node(struct device_node *dn) if (!dn->parent) return -ENOMEM; - rc = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, dn); + rc = of_attach_node(dn); if (rc) { printk(KERN_ERR "Failed to add device node %s\n", dn->full_name); return rc; } - of_attach_node(dn); - -#ifdef CONFIG_PROC_DEVICETREE - ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); - if (ent) - proc_device_tree_add_node(dn, ent); -#endif - of_node_put(dn->parent); return 0; } int dlpar_detach_node(struct device_node *dn) { -#ifdef CONFIG_PROC_DEVICETREE - struct device_node *parent = dn->parent; - struct property *prop = dn->properties; - - while (prop) { - remove_proc_entry(prop->name, dn->pde); - prop = prop->next; - } + int rc; - if (dn->pde) - remove_proc_entry(dn->pde->name, parent->pde); -#endif + rc = of_detach_node(dn); + if (rc) + return rc; - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn); - of_detach_node(dn); of_node_put(dn); /* Must decrement the refcount */ - return 0; } diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 0b0eff0cce35..7b56118f531c 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -56,6 +56,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = { {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, {FW_FEATURE_SPLPAR, "hcall-splpar"}, {FW_FEATURE_VPHN, "hcall-vphn"}, + {FW_FEATURE_SET_MODE, "hcall-set-mode"}, }; /* Build up the firmware features bitmask using the contents of diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 64c97d8ac0c5..a38956269fbf 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -23,12 +23,12 @@ #include <linux/delay.h> #include <linux/sched.h> /* for idle_task_exit */ #include <linux/cpu.h> +#include <linux/of.h> #include <asm/prom.h> #include <asm/rtas.h> #include <asm/firmware.h> #include <asm/machdep.h> #include <asm/vdso_datapage.h> -#include <asm/pSeries_reconfig.h> #include <asm/xics.h> #include "plpar_wrappers.h" #include "offline_states.h" @@ -333,10 +333,10 @@ static int pseries_smp_notifier(struct notifier_block *nb, int err = 0; switch (action) { - case PSERIES_RECONFIG_ADD: + case OF_RECONFIG_ATTACH_NODE: err = pseries_add_processor(node); break; - case PSERIES_RECONFIG_REMOVE: + case OF_RECONFIG_DETACH_NODE: pseries_remove_processor(node); break; } @@ -399,7 +399,7 @@ static int __init pseries_cpu_hotplug_init(void) /* Processors can be added/removed only on LPAR */ if (firmware_has_feature(FW_FEATURE_LPAR)) { - pSeries_reconfig_notifier_register(&pseries_smp_nb); + of_reconfig_notifier_register(&pseries_smp_nb); cpu_maps_update_begin(); if (cede_offline_enabled && parse_cede_parameters() == 0) { default_offline_state = CPU_STATE_INACTIVE; diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index ecdb0a6b3171..2372c609fa2b 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -16,7 +16,6 @@ #include <asm/firmware.h> #include <asm/machdep.h> -#include <asm/pSeries_reconfig.h> #include <asm/sparsemem.h> static unsigned long get_memblock_size(void) @@ -187,42 +186,69 @@ static int pseries_add_memory(struct device_node *np) return (ret < 0) ? -EINVAL : 0; } -static int pseries_drconf_memory(unsigned long *base, unsigned int action) +static int pseries_update_drconf_memory(struct of_prop_reconfig *pr) { + struct of_drconf_cell *new_drmem, *old_drmem; unsigned long memblock_size; - int rc; + u32 entries; + u32 *p; + int i, rc = -EINVAL; memblock_size = get_memblock_size(); if (!memblock_size) return -EINVAL; - if (action == PSERIES_DRCONF_MEM_ADD) { - rc = memblock_add(*base, memblock_size); - rc = (rc < 0) ? -EINVAL : 0; - } else if (action == PSERIES_DRCONF_MEM_REMOVE) { - rc = pseries_remove_memblock(*base, memblock_size); - } else { - rc = -EINVAL; + p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL); + if (!p) + return -EINVAL; + + /* The first int of the property is the number of lmb's described + * by the property. This is followed by an array of of_drconf_cell + * entries. Get the niumber of entries and skip to the array of + * of_drconf_cell's. + */ + entries = *p++; + old_drmem = (struct of_drconf_cell *)p; + + p = (u32 *)pr->prop->value; + p++; + new_drmem = (struct of_drconf_cell *)p; + + for (i = 0; i < entries; i++) { + if ((old_drmem[i].flags & DRCONF_MEM_ASSIGNED) && + (!(new_drmem[i].flags & DRCONF_MEM_ASSIGNED))) { + rc = pseries_remove_memblock(old_drmem[i].base_addr, + memblock_size); + break; + } else if ((!(old_drmem[i].flags & DRCONF_MEM_ASSIGNED)) && + (new_drmem[i].flags & DRCONF_MEM_ASSIGNED)) { + rc = memblock_add(old_drmem[i].base_addr, + memblock_size); + rc = (rc < 0) ? -EINVAL : 0; + break; + } } return rc; } static int pseries_memory_notifier(struct notifier_block *nb, - unsigned long action, void *node) + unsigned long action, void *node) { + struct of_prop_reconfig *pr; int err = 0; switch (action) { - case PSERIES_RECONFIG_ADD: + case OF_RECONFIG_ATTACH_NODE: err = pseries_add_memory(node); break; - case PSERIES_RECONFIG_REMOVE: + case OF_RECONFIG_DETACH_NODE: err = pseries_remove_memory(node); break; - case PSERIES_DRCONF_MEM_ADD: - case PSERIES_DRCONF_MEM_REMOVE: - err = pseries_drconf_memory(node, action); + case OF_RECONFIG_UPDATE_PROPERTY: + pr = (struct of_prop_reconfig *)node; + if (!strcmp(pr->prop->name, "ibm,dynamic-memory")) + err = pseries_update_drconf_memory(pr); break; } return notifier_from_errno(err); @@ -235,7 +261,7 @@ static struct notifier_block pseries_mem_nb = { static int __init pseries_memory_hotplug_init(void) { if (firmware_has_feature(FW_FEATURE_LPAR)) - pSeries_reconfig_notifier_register(&pseries_mem_nb); + of_reconfig_notifier_register(&pseries_mem_nb); return 0; } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 6153eea27ce7..e2685badb5db 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -36,13 +36,13 @@ #include <linux/dma-mapping.h> #include <linux/crash_dump.h> #include <linux/memory.h> +#include <linux/of.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/rtas.h> #include <asm/iommu.h> #include <asm/pci-bridge.h> #include <asm/machdep.h> -#include <asm/pSeries_reconfig.h> #include <asm/firmware.h> #include <asm/tce.h> #include <asm/ppc-pci.h> @@ -760,7 +760,7 @@ static void remove_ddw(struct device_node *np) __remove_ddw(np, ddw_avail, liobn); delprop: - ret = prom_remove_property(np, win64); + ret = of_remove_property(np, win64); if (ret) pr_warning("%s: failed to remove direct window property: %d\n", np->full_name, ret); @@ -1070,7 +1070,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) goto out_free_window; } - ret = prom_add_property(pdn, win64); + ret = of_add_property(pdn, win64); if (ret) { dev_err(&dev->dev, "unable to add dma window property for %s: %d", pdn->full_name, ret); @@ -1294,7 +1294,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti struct direct_window *window; switch (action) { - case PSERIES_RECONFIG_REMOVE: + case OF_RECONFIG_DETACH_NODE: if (pci && pci->iommu_table) iommu_free_table(pci->iommu_table, np->full_name); @@ -1357,7 +1357,7 @@ void iommu_init_early_pSeries(void) } - pSeries_reconfig_notifier_register(&iommu_reconfig_nb); + of_reconfig_notifier_register(&iommu_reconfig_nb); register_memory_notifier(&iommu_mem_nb); set_pci_dma_ops(&dma_iommu_ops); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index dd30b12edfe4..6573808cc5f3 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -116,7 +116,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop, } if (!more) { - prom_update_property(dn, new_prop); + of_update_property(dn, new_prop); new_prop = NULL; } @@ -172,7 +172,7 @@ static int update_dt_node(u32 phandle) case 0x80000000: prop = of_find_property(dn, prop_name, NULL); - prom_remove_property(dn, prop); + of_remove_property(dn, prop); prop = NULL; break; diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index 13e8cc43adf7..e6cc34a67053 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -273,4 +273,35 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len, lbuf[1]); } +/* Set various resource mode parameters */ +static inline long plpar_set_mode(unsigned long mflags, unsigned long resource, + unsigned long value1, unsigned long value2) +{ + return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2); +} + +/* + * Enable relocation on exceptions on this partition + * + * Note: this call has a partition wide scope and can take a while to complete. + * If it returns H_LONG_BUSY_* it should be retried periodically until it + * returns H_SUCCESS. + */ +static inline long enable_reloc_on_exceptions(void) +{ + /* mflags = 3: Exceptions at 0xC000000000004000 */ + return plpar_set_mode(3, 3, 0, 0); +} + +/* + * Disable relocation on exceptions on this partition + * + * Note: this call has a partition wide scope and can take a while to complete. + * If it returns H_LONG_BUSY_* it should be retried periodically until it + * returns H_SUCCESS. + */ +static inline long disable_reloc_on_exceptions(void) { + return plpar_set_mode(0, 3, 0, 0); +} + #endif /* _PSERIES_PLPAR_WRAPPERS_H */ diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 2f4668136b20..d6491bd481d0 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -16,55 +16,13 @@ #include <linux/notifier.h> #include <linux/proc_fs.h> #include <linux/slab.h> +#include <linux/of.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/uaccess.h> -#include <asm/pSeries_reconfig.h> #include <asm/mmu.h> - - -/* - * Routines for "runtime" addition and removal of device tree nodes. - */ -#ifdef CONFIG_PROC_DEVICETREE -/* - * Add a node to /proc/device-tree. - */ -static void add_node_proc_entries(struct device_node *np) -{ - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde); - if (ent) - proc_device_tree_add_node(np, ent); -} - -static void remove_node_proc_entries(struct device_node *np) -{ - struct property *pp = np->properties; - struct device_node *parent = np->parent; - - while (pp) { - remove_proc_entry(pp->name, np->pde); - pp = pp->next; - } - if (np->pde) - remove_proc_entry(np->pde->name, parent->pde); -} -#else /* !CONFIG_PROC_DEVICETREE */ -static void add_node_proc_entries(struct device_node *np) -{ - return; -} - -static void remove_node_proc_entries(struct device_node *np) -{ - return; -} -#endif /* CONFIG_PROC_DEVICETREE */ - /** * derive_parent - basically like dirname(1) * @path: the full_name of a node to be added to the tree @@ -97,28 +55,6 @@ static struct device_node *derive_parent(const char *path) return parent; } -static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); - -int pSeries_reconfig_notifier_register(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb); -} -EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_register); - -void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb); -} -EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_unregister); - -int pSeries_reconfig_notify(unsigned long action, void *p) -{ - int err = blocking_notifier_call_chain(&pSeries_reconfig_chain, - action, p); - - return notifier_to_errno(err); -} - static int pSeries_reconfig_add_node(const char *path, struct property *proplist) { struct device_node *np; @@ -142,16 +78,12 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist goto out_err; } - err = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, np); + err = of_attach_node(np); if (err) { printk(KERN_ERR "Failed to add device node %s\n", path); goto out_err; } - of_attach_node(np); - - add_node_proc_entries(np); - of_node_put(np->parent); return 0; @@ -179,11 +111,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) return -EBUSY; } - remove_node_proc_entries(np); - - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, np); of_detach_node(np); - of_node_put(parent); of_node_put(np); /* Must decrement the refcount */ return 0; @@ -397,7 +325,7 @@ static int do_add_property(char *buf, size_t bufsize) if (!prop) return -ENOMEM; - prom_add_property(np, prop); + of_add_property(np, prop); return 0; } @@ -421,16 +349,15 @@ static int do_remove_property(char *buf, size_t bufsize) prop = of_find_property(np, buf, NULL); - return prom_remove_property(np, prop); + return of_remove_property(np, prop); } static int do_update_property(char *buf, size_t bufsize) { struct device_node *np; - struct pSeries_reconfig_prop_update upd_value; unsigned char *value; char *name, *end, *next_prop; - int rc, length; + int length; struct property *newprop; buf = parse_node(buf, bufsize, &np); end = buf + bufsize; @@ -452,41 +379,7 @@ static int do_update_property(char *buf, size_t bufsize) if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size")) slb_set_size(*(int *)value); - upd_value.node = np; - upd_value.property = newprop; - pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value); - - rc = prom_update_property(np, newprop); - if (rc) - return rc; - - /* For memory under the ibm,dynamic-reconfiguration-memory node - * of the device tree, adding and removing memory is just an update - * to the ibm,dynamic-memory property instead of adding/removing a - * memory node in the device tree. For these cases we still need to - * involve the notifier chain. - */ - if (!strcmp(name, "ibm,dynamic-memory")) { - int action; - - next_prop = parse_next_property(next_prop, end, &name, - &length, &value); - if (!next_prop) - return -EINVAL; - - if (!strcmp(name, "add")) - action = PSERIES_DRCONF_MEM_ADD; - else - action = PSERIES_DRCONF_MEM_REMOVE; - - rc = pSeries_reconfig_notify(action, value); - if (rc) { - prom_update_property(np, newprop); - return rc; - } - } - - return 0; + return of_update_property(np, newprop); } /** diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e3cb7ae61658..ca55882465d6 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -40,6 +40,8 @@ #include <linux/seq_file.h> #include <linux/root_dev.h> #include <linux/cpuidle.h> +#include <linux/of.h> +#include <linux/kexec.h> #include <asm/mmu.h> #include <asm/processor.h> @@ -63,7 +65,6 @@ #include <asm/smp.h> #include <asm/firmware.h> #include <asm/eeh.h> -#include <asm/pSeries_reconfig.h> #include "plpar_wrappers.h" #include "pseries.h" @@ -258,7 +259,7 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act int err = NOTIFY_OK; switch (action) { - case PSERIES_RECONFIG_ADD: + case OF_RECONFIG_ATTACH_NODE: pci = np->parent->data; if (pci) { update_dn_pci_info(np, pci->phb); @@ -367,6 +368,65 @@ static void pSeries_idle(void) } } +/* + * Enable relocation on during exceptions. This has partition wide scope and + * may take a while to complete, if it takes longer than one second we will + * just give up rather than wasting any more time on this - if that turns out + * to ever be a problem in practice we can move this into a kernel thread to + * finish off the process later in boot. + */ +static int __init pSeries_enable_reloc_on_exc(void) +{ + long rc; + unsigned int delay, total_delay = 0; + + while (1) { + rc = enable_reloc_on_exceptions(); + if (!H_IS_LONG_BUSY(rc)) + return rc; + + delay = get_longbusy_msecs(rc); + total_delay += delay; + if (total_delay > 1000) { + pr_warn("Warning: Giving up waiting to enable " + "relocation on exceptions (%u msec)!\n", + total_delay); + return rc; + } + + mdelay(delay); + } +} + +#ifdef CONFIG_KEXEC +static long pSeries_disable_reloc_on_exc(void) +{ + long rc; + + while (1) { + rc = disable_reloc_on_exceptions(); + if (!H_IS_LONG_BUSY(rc)) + return rc; + mdelay(get_longbusy_msecs(rc)); + } +} + +static void pSeries_machine_kexec(struct kimage *image) +{ + long rc; + + if (firmware_has_feature(FW_FEATURE_SET_MODE) && + (image->type != KEXEC_TYPE_CRASH)) { + rc = pSeries_disable_reloc_on_exc(); + if (rc != H_SUCCESS) + pr_warning("Warning: Failed to disable relocation on " + "exceptions: %ld\n", rc); + } + + default_machine_kexec(image); +} +#endif + static void __init pSeries_setup_arch(void) { panic_timeout = 10; @@ -389,7 +449,7 @@ static void __init pSeries_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); find_and_init_phbs(); - pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); + of_reconfig_notifier_register(&pci_dn_reconfig_nb); pSeries_nvram_init(); @@ -402,6 +462,14 @@ static void __init pSeries_setup_arch(void) ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; else ppc_md.enable_pmcs = power4_enable_pmcs; + + if (firmware_has_feature(FW_FEATURE_SET_MODE)) { + long rc; + if ((rc = pSeries_enable_reloc_on_exc()) != H_SUCCESS) { + pr_warn("Unable to enable relocation on exceptions: " + "%ld\n", rc); + } + } } static int __init pSeries_init_panel(void) @@ -659,4 +727,7 @@ define_machine(pseries) { .progress = rtas_progress, .system_reset_exception = pSeries_system_reset_exception, .machine_check_exception = pSeries_machine_check_exception, +#ifdef CONFIG_KEXEC + .machine_kexec = pSeries_machine_kexec, +#endif }; diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 71706bc34a0d..9fc0a4941908 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -38,7 +38,6 @@ #include <asm/cputable.h> #include <asm/firmware.h> #include <asm/rtas.h> -#include <asm/pSeries_reconfig.h> #include <asm/mpic.h> #include <asm/vdso_datapage.h> #include <asm/cputhreads.h> |