diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/Makefile | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 21 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_driver.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/firmware.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/firmware.h | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/hvCall_inst.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/kexec.c | 72 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 55 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/power.c | 87 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pseries.h | 39 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/ras.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/ras.h | 9 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/reconfig.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/rtasd.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/scanlog.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 90 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/smp.c | 1 |
18 files changed, 315 insertions, 100 deletions
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 69590fbf83da..2dfd05095a25 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -4,11 +4,12 @@ endif obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ - firmware.o + firmware.o power.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o +obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index da6e5362e7cd..6cedbc002e0f 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -747,6 +747,7 @@ struct eeh_early_enable_info { /* Enable eeh for the given device node. */ static void *early_enable_eeh(struct device_node *dn, void *data) { + unsigned int rets[3]; struct eeh_early_enable_info *info = data; int ret; const char *status = get_property(dn, "status", NULL); @@ -803,16 +804,14 @@ static void *early_enable_eeh(struct device_node *dn, void *data) regs[0], info->buid_hi, info->buid_lo, EEH_ENABLE); + enable = 0; if (ret == 0) { - eeh_subsystem_enabled = 1; - pdn->eeh_mode |= EEH_MODE_SUPPORTED; pdn->eeh_config_addr = regs[0]; /* If the newer, better, ibm,get-config-addr-info is supported, * then use that instead. */ pdn->eeh_pe_config_addr = 0; if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { - unsigned int rets[2]; ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, pdn->eeh_config_addr, info->buid_hi, info->buid_lo, @@ -820,6 +819,20 @@ static void *early_enable_eeh(struct device_node *dn, void *data) if (ret == 0) pdn->eeh_pe_config_addr = rets[0]; } + + /* Some older systems (Power4) allow the + * ibm,set-eeh-option call to succeed even on nodes + * where EEH is not supported. Verify support + * explicitly. */ + ret = read_slot_reset_state(pdn, rets); + if ((ret == 0) && (rets[1] == 1)) + enable = 1; + } + + if (enable) { + eeh_subsystem_enabled = 1; + pdn->eeh_mode |= EEH_MODE_SUPPORTED; + #ifdef DEBUG printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); @@ -1065,7 +1078,7 @@ static int proc_eeh_open(struct inode *inode, struct file *file) return single_open(file, proc_eeh_show, NULL); } -static struct file_operations proc_eeh_operations = { +static const struct file_operations proc_eeh_operations = { .open = proc_eeh_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index cbd6b0711ab4..a4c0bf84ef2e 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -446,7 +446,8 @@ excess_failures: */ printk(KERN_ERR "EEH: PCI device at location=%s driver=%s pci addr=%s \n" - "has failed %d times and has been permanently disabled. \n" + "has failed %d times in the last hour " + "and has been permanently disabled. \n" "Please try reseating this device or replacing it.\n", location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); goto perm_error; diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 1c7b2baa5f73..90522e3c9d46 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -59,6 +59,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = { {FW_FEATURE_XDABR, "hcall-xdabr"}, {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, {FW_FEATURE_SPLPAR, "hcall-splpar"}, + {FW_FEATURE_BULK_REMOVE, "hcall-bulk"}, }; /* Build up the firmware features bitmask using the contents of diff --git a/arch/powerpc/platforms/pseries/firmware.h b/arch/powerpc/platforms/pseries/firmware.h deleted file mode 100644 index 714f56f55362..000000000000 --- a/arch/powerpc/platforms/pseries/firmware.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2006 IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _PSERIES_FIRMWARE_H -#define _PSERIES_FIRMWARE_H - -#include <asm/firmware.h> - -extern void __init fw_feature_init(void); - -#endif /* _PSERIES_FIRMWARE_H */ diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 3ddc04925d50..eae51ef9af24 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -90,7 +90,7 @@ static int hcall_inst_seq_open(struct inode *inode, struct file *file) return rc; } -static struct file_operations hcall_inst_seq_fops = { +static const struct file_operations hcall_inst_seq_fops = { .open = hcall_inst_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c new file mode 100644 index 000000000000..af2685607458 --- /dev/null +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -0,0 +1,72 @@ +/* + * Copyright 2006 Michael Ellerman, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <asm/machdep.h> +#include <asm/page.h> +#include <asm/firmware.h> +#include <asm/kexec.h> +#include <asm/mpic.h> + +#include "pseries.h" +#include "xics.h" +#include "plpar_wrappers.h" + +static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) +{ + /* Don't risk a hypervisor call if we're crashing */ + if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { + unsigned long addr; + + addr = __pa(get_slb_shadow()); + if (unregister_slb_shadow(hard_smp_processor_id(), addr)) + printk("SLB shadow buffer deregistration of " + "cpu %u (hw_cpu_id %d) failed\n", + smp_processor_id(), + hard_smp_processor_id()); + + addr = __pa(get_lppaca()); + if (unregister_vpa(hard_smp_processor_id(), addr)) { + printk("VPA deregistration of cpu %u (hw_cpu_id %d) " + "failed\n", smp_processor_id(), + hard_smp_processor_id()); + } + } +} + +static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) +{ + pseries_kexec_cpu_down(crash_shutdown, secondary); + mpic_teardown_this_cpu(secondary); +} + +void __init setup_kexec_cpu_down_mpic(void) +{ + ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; +} + +static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) +{ + pseries_kexec_cpu_down(crash_shutdown, secondary); + xics_teardown_cpu(secondary); +} + +void __init setup_kexec_cpu_down_xics(void) +{ + ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; +} + +static int __init pseries_kexec_setup(void) +{ + ppc_md.machine_kexec = default_machine_kexec; + ppc_md.machine_kexec_prepare = default_machine_kexec_prepare; + ppc_md.machine_crash_shutdown = default_machine_crash_shutdown; + + return 0; +} +__initcall(pseries_kexec_setup); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 721436db3ef0..7496005566ef 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -502,23 +502,70 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, BUG_ON(lpar_rc != H_SUCCESS); } +/* Flag bits for H_BULK_REMOVE */ +#define HBR_REQUEST 0x4000000000000000UL +#define HBR_RESPONSE 0x8000000000000000UL +#define HBR_END 0xc000000000000000UL +#define HBR_AVPN 0x0200000000000000UL +#define HBR_ANDCOND 0x0100000000000000UL + /* * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie * lock. */ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) { - int i; + unsigned long i, pix, rc; unsigned long flags = 0; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + unsigned long param[9]; + unsigned long va; + unsigned long hash, index, shift, hidx, slot; + real_pte_t pte; + int psize; if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); - for (i = 0; i < number; i++) - flush_hash_page(batch->vaddr[i], batch->pte[i], - batch->psize, local); + psize = batch->psize; + pix = 0; + for (i = 0; i < number; i++) { + va = batch->vaddr[i]; + pte = batch->pte[i]; + pte_iterate_hashed_subpages(pte, psize, va, index, shift) { + hash = hpt_hash(va, shift); + hidx = __rpte_to_hidx(pte, index); + if (hidx & _PTEIDX_SECONDARY) + hash = ~hash; + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + slot += hidx & _PTEIDX_GROUP_IX; + if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { + pSeries_lpar_hpte_invalidate(slot, va, psize, + local); + } else { + param[pix] = HBR_REQUEST | HBR_AVPN | slot; + param[pix+1] = hpte_encode_v(va, psize) & + HPTE_V_AVPN; + pix += 2; + if (pix == 8) { + rc = plpar_hcall9(H_BULK_REMOVE, param, + param[0], param[1], param[2], + param[3], param[4], param[5], + param[6], param[7]); + BUG_ON(rc != H_SUCCESS); + pix = 0; + } + } + } pte_iterate_hashed_end(); + } + if (pix) { + param[pix] = HBR_END; + rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1], + param[2], param[3], param[4], param[5], + param[6], param[7]); + BUG_ON(rc != H_SUCCESS); + } if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 715db5c89908..fa59124ce3fe 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -77,7 +77,7 @@ void __init pSeries_final_fixup(void) /* * Assume the winbond 82c105 is the IDE controller on a - * p610. We should probably be more careful in case + * p610/p615/p630. We should probably be more careful in case * someone tries to plug in a similar adapter. */ static void fixup_winbond_82c105(struct pci_dev* dev) @@ -98,6 +98,10 @@ static void fixup_winbond_82c105(struct pci_dev* dev) if (dev->resource[i].flags & IORESOURCE_IO && dev->bus->number == 0 && dev->devfn == 0x81) dev->resource[i].flags &= ~IORESOURCE_IO; + if (dev->resource[i].start == 0 && dev->resource[i].end) { + dev->resource[i].flags = 0; + dev->resource[i].end = 0; + } } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c new file mode 100644 index 000000000000..2624b71df73d --- /dev/null +++ b/arch/powerpc/platforms/pseries/power.c @@ -0,0 +1,87 @@ +/* + * Interface for power-management for ppc64 compliant platform + * + * Manish Ahuja <mahuja@us.ibm.com> + * + * Feb 2007 + * + * Copyright (C) 2007 IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/init.h> + +unsigned long rtas_poweron_auto; /* default and normal state is 0 */ + +static ssize_t auto_poweron_show(struct subsystem *subsys, char *buf) +{ + return sprintf(buf, "%lu\n", rtas_poweron_auto); +} + +static ssize_t +auto_poweron_store(struct subsystem *subsys, const char *buf, size_t n) +{ + int ret; + unsigned long ups_restart; + ret = sscanf(buf, "%lu", &ups_restart); + + if ((ret == 1) && ((ups_restart == 1) || (ups_restart == 0))){ + rtas_poweron_auto = ups_restart; + return n; + } + return -EINVAL; +} + +static struct subsys_attribute auto_poweron_attr = { + .attr = { + .name = __stringify(auto_poweron), + .mode = 0644, + }, + .show = auto_poweron_show, + .store = auto_poweron_store, +}; + +#ifndef CONFIG_PM +decl_subsys(power,NULL,NULL); + +static struct attribute *g[] = { + &auto_poweron_attr.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = g, +}; + +static int __init pm_init(void) +{ + int error = subsystem_register(&power_subsys); + if (!error) + error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group); + return error; +} +core_initcall(pm_init); +#else +extern struct subsystem power_subsys; + +static int __init apo_pm_init(void) +{ + return (subsys_create_file(&power_subsys, &auto_poweron_attr)); +} +__initcall(apo_pm_init); +#endif diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h new file mode 100644 index 000000000000..22bc01989749 --- /dev/null +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -0,0 +1,39 @@ +/* + * Copyright 2006 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _PSERIES_PSERIES_H +#define _PSERIES_PSERIES_H + +extern void __init fw_feature_init(void); + +struct pt_regs; + +extern int pSeries_system_reset_exception(struct pt_regs *regs); +extern int pSeries_machine_check_exception(struct pt_regs *regs); + +#ifdef CONFIG_SMP +extern void smp_init_pseries_mpic(void); +extern void smp_init_pseries_xics(void); +#else +static inline smp_init_pseries_mpic(void) { }; +static inline smp_init_pseries_xics(void) { }; +#endif + +#ifdef CONFIG_KEXEC +extern void setup_kexec_cpu_down_xics(void); +extern void setup_kexec_cpu_down_mpic(void); +#else +static inline void setup_kexec_cpu_down_xics(void) { } +static inline void setup_kexec_cpu_down_mpic(void) { } +#endif + +/* Poweron flag used for enabling auto ups restart */ +extern unsigned long rtas_poweron_auto; + +#endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index b1d3d161249e..edc038873113 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -51,7 +51,7 @@ #include <asm/udbg.h> #include <asm/firmware.h> -#include "ras.h" +#include "pseries.h" static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; static DEFINE_SPINLOCK(ras_log_buf_lock); diff --git a/arch/powerpc/platforms/pseries/ras.h b/arch/powerpc/platforms/pseries/ras.h deleted file mode 100644 index 0e66b0da55e2..000000000000 --- a/arch/powerpc/platforms/pseries/ras.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _PSERIES_RAS_H -#define _PSERIES_RAS_H - -struct pt_regs; - -extern int pSeries_system_reset_exception(struct pt_regs *regs); -extern int pSeries_machine_check_exception(struct pt_regs *regs); - -#endif /* _PSERIES_RAS_H */ diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 4ad33e41b008..5aa97aff3391 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -499,7 +499,7 @@ out: return rv ? rv : count; } -static struct file_operations ofdt_fops = { +static const struct file_operations ofdt_fops = { .write = ofdt_write }; @@ -513,7 +513,6 @@ static int proc_ppc64_create_ofdt(void) ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); if (ent) { - ent->nlink = 1; ent->data = NULL; ent->size = 0; ent->proc_fops = &ofdt_fops; diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 8ca2612221d6..77d0937d5c07 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -331,7 +331,7 @@ static unsigned int rtas_log_poll(struct file *file, poll_table * wait) return 0; } -struct file_operations proc_rtas_log_operations = { +const struct file_operations proc_rtas_log_operations = { .read = rtas_log_read, .poll = rtas_log_poll, .open = rtas_log_open, diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 45368a57d7dd..8e1ef168e2dd 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c @@ -184,7 +184,7 @@ static int scanlog_release(struct inode * inode, struct file * file) return 0; } -struct file_operations scanlog_fops = { +const struct file_operations scanlog_fops = { .owner = THIS_MODULE, .read = scanlog_read, .write = scanlog_write, diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 042ecae107ac..34aff47b1f55 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -55,7 +55,6 @@ #include <asm/dma.h> #include <asm/machdep.h> #include <asm/irq.h> -#include <asm/kexec.h> #include <asm/time.h> #include <asm/nvram.h> #include "xics.h" @@ -65,10 +64,10 @@ #include <asm/i8259.h> #include <asm/udbg.h> #include <asm/smp.h> +#include <asm/firmware.h> #include "plpar_wrappers.h" -#include "ras.h" -#include "firmware.h" +#include "pseries.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -77,8 +76,6 @@ #endif /* move those away to a .h */ -extern void smp_init_pseries_mpic(void); -extern void smp_init_pseries_xics(void); extern void find_udbg_vterm(void); int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -221,42 +218,6 @@ static void pseries_lpar_enable_pmcs(void) get_lppaca()->pmcregs_in_use = 1; } -#ifdef CONFIG_KEXEC -static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) -{ - /* Don't risk a hypervisor call if we're crashing */ - if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { - unsigned long addr; - - addr = __pa(get_slb_shadow()); - if (unregister_slb_shadow(hard_smp_processor_id(), addr)) - printk("SLB shadow buffer deregistration of " - "cpu %u (hw_cpu_id %d) failed\n", - smp_processor_id(), - hard_smp_processor_id()); - - addr = __pa(get_lppaca()); - if (unregister_vpa(hard_smp_processor_id(), addr)) { - printk("VPA deregistration of cpu %u (hw_cpu_id %d) " - "failed\n", smp_processor_id(), - hard_smp_processor_id()); - } - } -} - -static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) -{ - pseries_kexec_cpu_down(crash_shutdown, secondary); - mpic_teardown_this_cpu(secondary); -} - -static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) -{ - pseries_kexec_cpu_down(crash_shutdown, secondary); - xics_teardown_cpu(secondary); -} -#endif /* CONFIG_KEXEC */ - static void __init pseries_discover_pic(void) { struct device_node *np; @@ -269,21 +230,13 @@ static void __init pseries_discover_pic(void) pSeries_mpic_node = of_node_get(np); ppc_md.init_IRQ = pseries_mpic_init_IRQ; ppc_md.get_irq = mpic_get_irq; -#ifdef CONFIG_KEXEC - ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; -#endif -#ifdef CONFIG_SMP + setup_kexec_cpu_down_mpic(); smp_init_pseries_mpic(); -#endif return; } else if (strstr(typep, "ppc-xicp")) { ppc_md.init_IRQ = xics_init_IRQ; -#ifdef CONFIG_KEXEC - ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; -#endif -#ifdef CONFIG_SMP + setup_kexec_cpu_down_xics(); smp_init_pseries_xics(); -#endif return; } } @@ -533,6 +486,34 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) return PCI_PROBE_NORMAL; } +/** + * pSeries_power_off - tell firmware about how to power off the system. + * + * This function calls either the power-off rtas token in normal cases + * or the ibm,power-off-ups token (if present & requested) in case of + * a power failure. If power-off token is used, power on will only be + * possible with power button press. If ibm,power-off-ups token is used + * it will allow auto poweron after power is restored. + */ +void pSeries_power_off(void) +{ + int rc; + int rtas_poweroff_ups_token = rtas_token("ibm,power-off-ups"); + + if (rtas_flash_term_hook) + rtas_flash_term_hook(SYS_POWER_OFF); + + if (rtas_poweron_auto == 0 || + rtas_poweroff_ups_token == RTAS_UNKNOWN_SERVICE) { + rc = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1); + printk(KERN_INFO "RTAS power-off returned %d\n", rc); + } else { + rc = rtas_call(rtas_poweroff_ups_token, 0, 1, NULL); + printk(KERN_INFO "RTAS ibm,power-off-ups returned %d\n", rc); + } + for (;;); +} + define_machine(pseries) { .name = "pSeries", .probe = pSeries_probe, @@ -543,7 +524,7 @@ define_machine(pseries) { .pcibios_fixup = pSeries_final_fixup, .pci_probe_mode = pSeries_pci_probe_mode, .restart = rtas_restart, - .power_off = rtas_power_off, + .power_off = pSeries_power_off, .halt = rtas_halt, .panic = rtas_os_term, .get_boot_time = rtas_get_boot_time, @@ -554,9 +535,4 @@ define_machine(pseries) { .check_legacy_ioport = pSeries_check_legacy_ioport, .system_reset_exception = pSeries_system_reset_exception, .machine_check_exception = pSeries_machine_check_exception, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 4408518eaebe..116305b22a2b 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -48,6 +48,7 @@ #include <asm/vdso_datapage.h> #include "plpar_wrappers.h" +#include "pseries.h" #ifdef DEBUG #include <asm/udbg.h> |