diff options
author | Jeff Garzik <jeff@garzik.org> | 2012-07-25 15:58:48 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2012-07-25 15:58:48 -0400 |
commit | 8407884dd9164ec18ed2afc00f56b87e36c51fcf (patch) | |
tree | b6ea42c231d7d39f454de28a068d78ce11709770 /arch/powerpc/platforms/pseries | |
parent | dc7f71f486f4f5fa96f6dcf86833da020cde8a11 (diff) | |
parent | bdc0077af574800d24318b6945cf2344e8dbb050 (diff) | |
download | linux-8407884dd9164ec18ed2afc00f56b87e36c51fcf.tar.gz linux-8407884dd9164ec18ed2afc00f56b87e36c51fcf.tar.bz2 linux-8407884dd9164ec18ed2afc00f56b87e36c51fcf.zip |
Merge branch 'master' [vanilla Linus master] into libata-dev.git/upstream
Two bits were appended to the end of the bitfield
list in struct scsi_device. Resolve that conflict
by including both bits.
Conflicts:
include/scsi/scsi_device.h
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_event.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_pseries.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/hvCall.S | 78 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/iommu.c | 119 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/mobility.c | 8 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/processor_idle.c | 53 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/reconfig.c | 16 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/smp.c | 1 |
9 files changed, 194 insertions, 93 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 4cb375c0f8d1..fb506317ebb0 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -85,8 +85,10 @@ static int eeh_event_handler(void * dummy) set_current_state(TASK_INTERRUPTIBLE); /* Don't add to load average */ edev = handle_eeh_events(event); - eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); - pci_dev_put(edev->pdev); + if (edev) { + eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); + pci_dev_put(edev->pdev); + } kfree(event); mutex_unlock(&eeh_event_mutex); diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 8752f79a6af8..c33360ec4f4f 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -81,7 +81,7 @@ static int pseries_eeh_init(void) ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); ibm_configure_pe = rtas_token("ibm,configure-pe"); - ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); + ibm_configure_bridge = rtas_token("ibm,configure-bridge"); /* necessary sanity check */ if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) { @@ -89,7 +89,7 @@ static int pseries_eeh_init(void) __func__); return -EINVAL; } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: RTAS service <ibm, set-slot-reset> invalid\n", + pr_warning("%s: RTAS service <ibm,set-slot-reset> invalid\n", __func__); return -EINVAL; } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE && diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index 3ce73d0052b1..444fe7759e55 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -13,8 +13,6 @@ #include <asm/asm-offsets.h> #include <asm/ptrace.h> -#define STK_PARM(i) (48 + ((i)-3)*8) - #ifdef CONFIG_TRACEPOINTS .section ".toc","aw" @@ -26,7 +24,7 @@ hcall_tracepoint_refcount: .section ".text" /* - * precall must preserve all registers. use unused STK_PARM() + * precall must preserve all registers. use unused STK_PARAM() * areas to save snapshots and opcode. We branch around this * in early init (eg when populating the MMU hashtable) by using an * unconditional cpu feature. @@ -40,28 +38,28 @@ END_FTR_SECTION(0, 1); \ cmpdi r12,0; \ beq+ 1f; \ mflr r0; \ - std r3,STK_PARM(r3)(r1); \ - std r4,STK_PARM(r4)(r1); \ - std r5,STK_PARM(r5)(r1); \ - std r6,STK_PARM(r6)(r1); \ - std r7,STK_PARM(r7)(r1); \ - std r8,STK_PARM(r8)(r1); \ - std r9,STK_PARM(r9)(r1); \ - std r10,STK_PARM(r10)(r1); \ + std r3,STK_PARAM(R3)(r1); \ + std r4,STK_PARAM(R4)(r1); \ + std r5,STK_PARAM(R5)(r1); \ + std r6,STK_PARAM(R6)(r1); \ + std r7,STK_PARAM(R7)(r1); \ + std r8,STK_PARAM(R8)(r1); \ + std r9,STK_PARAM(R9)(r1); \ + std r10,STK_PARAM(R10)(r1); \ std r0,16(r1); \ - addi r4,r1,STK_PARM(FIRST_REG); \ + addi r4,r1,STK_PARAM(FIRST_REG); \ stdu r1,-STACK_FRAME_OVERHEAD(r1); \ bl .__trace_hcall_entry; \ addi r1,r1,STACK_FRAME_OVERHEAD; \ ld r0,16(r1); \ - ld r3,STK_PARM(r3)(r1); \ - ld r4,STK_PARM(r4)(r1); \ - ld r5,STK_PARM(r5)(r1); \ - ld r6,STK_PARM(r6)(r1); \ - ld r7,STK_PARM(r7)(r1); \ - ld r8,STK_PARM(r8)(r1); \ - ld r9,STK_PARM(r9)(r1); \ - ld r10,STK_PARM(r10)(r1); \ + ld r3,STK_PARAM(R3)(r1); \ + ld r4,STK_PARAM(R4)(r1); \ + ld r5,STK_PARAM(R5)(r1); \ + ld r6,STK_PARAM(R6)(r1); \ + ld r7,STK_PARAM(R7)(r1); \ + ld r8,STK_PARAM(R8)(r1); \ + ld r9,STK_PARAM(R9)(r1); \ + ld r10,STK_PARAM(R10)(r1); \ mtlr r0; \ 1: @@ -79,8 +77,8 @@ END_FTR_SECTION(0, 1); \ cmpdi r12,0; \ beq+ 1f; \ mflr r0; \ - ld r6,STK_PARM(r3)(r1); \ - std r3,STK_PARM(r3)(r1); \ + ld r6,STK_PARAM(R3)(r1); \ + std r3,STK_PARAM(R3)(r1); \ mr r4,r3; \ mr r3,r6; \ std r0,16(r1); \ @@ -88,7 +86,7 @@ END_FTR_SECTION(0, 1); \ bl .__trace_hcall_exit; \ addi r1,r1,STACK_FRAME_OVERHEAD; \ ld r0,16(r1); \ - ld r3,STK_PARM(r3)(r1); \ + ld r3,STK_PARAM(R3)(r1); \ mtlr r0; \ 1: @@ -114,7 +112,7 @@ _GLOBAL(plpar_hcall_norets) mfcr r0 stw r0,8(r1) - HCALL_INST_PRECALL(r4) + HCALL_INST_PRECALL(R4) HVSC /* invoke the hypervisor */ @@ -130,9 +128,9 @@ _GLOBAL(plpar_hcall) mfcr r0 stw r0,8(r1) - HCALL_INST_PRECALL(r5) + HCALL_INST_PRECALL(R5) - std r4,STK_PARM(r4)(r1) /* Save ret buffer */ + std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ mr r4,r5 mr r5,r6 @@ -143,7 +141,7 @@ _GLOBAL(plpar_hcall) HVSC /* invoke the hypervisor */ - ld r12,STK_PARM(r4)(r1) + ld r12,STK_PARAM(R4)(r1) std r4, 0(r12) std r5, 8(r12) std r6, 16(r12) @@ -168,7 +166,7 @@ _GLOBAL(plpar_hcall_raw) mfcr r0 stw r0,8(r1) - std r4,STK_PARM(r4)(r1) /* Save ret buffer */ + std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ mr r4,r5 mr r5,r6 @@ -179,7 +177,7 @@ _GLOBAL(plpar_hcall_raw) HVSC /* invoke the hypervisor */ - ld r12,STK_PARM(r4)(r1) + ld r12,STK_PARAM(R4)(r1) std r4, 0(r12) std r5, 8(r12) std r6, 16(r12) @@ -196,9 +194,9 @@ _GLOBAL(plpar_hcall9) mfcr r0 stw r0,8(r1) - HCALL_INST_PRECALL(r5) + HCALL_INST_PRECALL(R5) - std r4,STK_PARM(r4)(r1) /* Save ret buffer */ + std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ mr r4,r5 mr r5,r6 @@ -206,14 +204,14 @@ _GLOBAL(plpar_hcall9) mr r7,r8 mr r8,r9 mr r9,r10 - ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */ - ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */ - ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */ + ld r10,STK_PARAM(R11)(r1) /* put arg7 in R10 */ + ld r11,STK_PARAM(R12)(r1) /* put arg8 in R11 */ + ld r12,STK_PARAM(R13)(r1) /* put arg9 in R12 */ HVSC /* invoke the hypervisor */ mr r0,r12 - ld r12,STK_PARM(r4)(r1) + ld r12,STK_PARAM(R4)(r1) std r4, 0(r12) std r5, 8(r12) std r6, 16(r12) @@ -238,7 +236,7 @@ _GLOBAL(plpar_hcall9_raw) mfcr r0 stw r0,8(r1) - std r4,STK_PARM(r4)(r1) /* Save ret buffer */ + std r4,STK_PARAM(R4)(r1) /* Save ret buffer */ mr r4,r5 mr r5,r6 @@ -246,14 +244,14 @@ _GLOBAL(plpar_hcall9_raw) mr r7,r8 mr r8,r9 mr r9,r10 - ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */ - ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */ - ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */ + ld r10,STK_PARAM(R11)(r1) /* put arg7 in R10 */ + ld r11,STK_PARAM(R12)(r1) /* put arg8 in R11 */ + ld r12,STK_PARAM(R13)(r1) /* put arg9 in R12 */ HVSC /* invoke the hypervisor */ mr r0,r12 - ld r12,STK_PARM(r4)(r1) + ld r12,STK_PARAM(R4)(r1) std r4, 0(r12) std r5, 8(r12) std r6, 16(r12) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 0915b1ad66ce..bca220f2873c 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -106,7 +106,7 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index, tcep++; } - if (tbl->it_type == TCE_PCI_SWINV_CREATE) + if (tbl->it_type & TCE_PCI_SWINV_CREATE) tce_invalidate_pSeries_sw(tbl, tces, tcep - 1); return 0; } @@ -121,7 +121,7 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) while (npages--) *(tcep++) = 0; - if (tbl->it_type == TCE_PCI_SWINV_FREE) + if (tbl->it_type & TCE_PCI_SWINV_FREE) tce_invalidate_pSeries_sw(tbl, tces, tcep - 1); } @@ -192,12 +192,15 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long l, limit; long tcenum_start = tcenum, npages_start = npages; int ret = 0; + unsigned long flags; if (npages == 1) { return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, direction, attrs); } + local_irq_save(flags); /* to protect tcep and the page behind it */ + tcep = __get_cpu_var(tce_page); /* This is safe to do since interrupts are off when we're called @@ -207,6 +210,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, tcep = (u64 *)__get_free_page(GFP_ATOMIC); /* If allocation fails, fall back to the loop implementation */ if (!tcep) { + local_irq_restore(flags); return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, direction, attrs); } @@ -240,6 +244,8 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, tcenum += limit; } while (npages > 0 && !rc); + local_irq_restore(flags); + if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) { ret = (int)rc; tce_freemulti_pSeriesLP(tbl, tcenum_start, @@ -707,6 +713,21 @@ static int __init disable_ddw_setup(char *str) early_param("disable_ddw", disable_ddw_setup); +static inline void __remove_ddw(struct device_node *np, const u32 *ddw_avail, u64 liobn) +{ + int ret; + + ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); + if (ret) + pr_warning("%s: failed to remove DMA window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddw_avail[2], liobn); + else + pr_debug("%s: successfully removed DMA window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddw_avail[2], liobn); +} + static void remove_ddw(struct device_node *np) { struct dynamic_dma_window_prop *dwp; @@ -736,15 +757,7 @@ static void remove_ddw(struct device_node *np) pr_debug("%s successfully cleared tces in window.\n", np->full_name); - ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); - if (ret) - pr_warning("%s: failed to remove direct window: rtas returned " - "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddw_avail[2], liobn); - else - pr_debug("%s: successfully removed direct window: rtas returned " - "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddw_avail[2], liobn); + __remove_ddw(np, ddw_avail, liobn); delprop: ret = prom_remove_property(np, win64); @@ -869,6 +882,35 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, return ret; } +static void restore_default_window(struct pci_dev *dev, + u32 ddw_restore_token, unsigned long liobn) +{ + struct eeh_dev *edev; + u32 cfg_addr; + u64 buid; + int ret; + + /* + * Get the config address and phb buid of the PE window. + * Rely on eeh to retrieve this for us. + * Retrieve them from the pci device, not the node with the + * dma-window property + */ + edev = pci_dev_to_eeh_dev(dev); + cfg_addr = edev->config_addr; + if (edev->pe_config_addr) + cfg_addr = edev->pe_config_addr; + buid = edev->phb->buid; + + do { + ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr, + BUID_HI(buid), BUID_LO(buid)); + } while (rtas_busy_delay(ret)); + dev_info(&dev->dev, + "ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n", + ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret); +} + /* * If the PE supports dynamic dma windows, and there is space for a table * that can map all pages in a linear offset, then setup such a table, @@ -889,9 +931,13 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) u64 dma_addr, max_addr; struct device_node *dn; const u32 *uninitialized_var(ddw_avail); + const u32 *uninitialized_var(ddw_extensions); + u32 ddw_restore_token = 0; struct direct_window *window; struct property *win64; struct dynamic_dma_window_prop *ddwprop; + const void *dma_window = NULL; + unsigned long liobn, offset, size; mutex_lock(&direct_window_init_mutex); @@ -911,7 +957,40 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) if (!ddw_avail || len < 3 * sizeof(u32)) goto out_unlock; - /* + /* + * the extensions property is only required to exist in certain + * levels of firmware and later + * the ibm,ddw-extensions property is a list with the first + * element containing the number of extensions and each + * subsequent entry is a value corresponding to that extension + */ + ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", &len); + if (ddw_extensions) { + /* + * each new defined extension length should be added to + * the top of the switch so the "earlier" entries also + * get picked up + */ + switch (ddw_extensions[0]) { + /* ibm,reset-pe-dma-windows */ + case 1: + ddw_restore_token = ddw_extensions[1]; + break; + } + } + + /* + * Only remove the existing DMA window if we can restore back to + * the default state. Removing the existing window maximizes the + * resources available to firmware for dynamic window creation. + */ + if (ddw_restore_token) { + dma_window = of_get_property(pdn, "ibm,dma-window", NULL); + of_parse_dma_window(pdn, dma_window, &liobn, &offset, &size); + __remove_ddw(pdn, ddw_avail, liobn); + } + + /* * Query if there is a second window of size to map the * whole partition. Query returns number of windows, largest * block assigned to PE (partition endpoint), and two bitmasks @@ -920,7 +999,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) dn = pci_device_to_OF_node(dev); ret = query_ddw(dev, ddw_avail, &query); if (ret != 0) - goto out_unlock; + goto out_restore_window; if (query.windows_available == 0) { /* @@ -929,7 +1008,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) * trading in for a larger page size. */ dev_dbg(&dev->dev, "no free dynamic windows"); - goto out_unlock; + goto out_restore_window; } if (query.page_size & 4) { page_shift = 24; /* 16MB */ @@ -940,7 +1019,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) } else { dev_dbg(&dev->dev, "no supported direct page size in mask %x", query.page_size); - goto out_unlock; + goto out_restore_window; } /* verify the window * number of ptes will map the partition */ /* check largest block * page size > max memory hotplug addr */ @@ -949,14 +1028,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u " "%llu-sized pages\n", max_addr, query.largest_available_block, 1ULL << page_shift); - goto out_unlock; + goto out_restore_window; } len = order_base_2(max_addr); win64 = kzalloc(sizeof(struct property), GFP_KERNEL); if (!win64) { dev_info(&dev->dev, "couldn't allocate property for 64bit dma window\n"); - goto out_unlock; + goto out_restore_window; } win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL); win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL); @@ -1018,6 +1097,10 @@ out_free_prop: kfree(win64->value); kfree(win64); +out_restore_window: + if (ddw_restore_token) + restore_default_window(dev, ddw_restore_token, liobn); + out_unlock: mutex_unlock(&direct_window_init_mutex); return dma_addr; @@ -1051,7 +1134,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) if (!pdn || !PCI_DN(pdn)) { printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: " "no DMA window found for pci dev=%s dn=%s\n", - pci_name(dev), dn? dn->full_name : "<null>"); + pci_name(dev), of_node_full_name(dn)); return; } pr_debug(" parent is %s\n", pdn->full_name); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 029a562af373..dd30b12edfe4 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -67,7 +67,6 @@ static int update_dt_property(struct device_node *dn, struct property **prop, const char *name, u32 vd, char *value) { struct property *new_prop = *prop; - struct property *old_prop; int more = 0; /* A negative 'vd' value indicates that only part of the new property @@ -117,12 +116,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop, } if (!more) { - old_prop = of_find_property(dn, new_prop->name, NULL); - if (old_prop) - prom_update_property(dn, new_prop, old_prop); - else - prom_add_property(dn, new_prop); - + prom_update_property(dn, new_prop); new_prop = NULL; } diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 8b7bafa489c2..3ccebc83dc02 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -121,7 +121,7 @@ void pcibios_add_pci_devices(struct pci_bus * bus) if (!num) return; pcibios_setup_bus_devices(bus); - max = bus->secondary; + max = bus->busn_res.start; for (pass=0; pass < 2; pass++) list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 41a34bc4a9a2..455760b1fe6e 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -11,6 +11,7 @@ #include <linux/moduleparam.h> #include <linux/cpuidle.h> #include <linux/cpu.h> +#include <linux/notifier.h> #include <asm/paca.h> #include <asm/reg.h> @@ -99,15 +100,18 @@ out: static void check_and_cede_processor(void) { /* - * Interrupts are soft-disabled at this point, - * but not hard disabled. So an interrupt might have - * occurred before entering NAP, and would be potentially - * lost (edge events, decrementer events, etc...) unless - * we first hard disable then check. + * Ensure our interrupt state is properly tracked, + * also checks if no interrupt has occurred while we + * were soft-disabled */ - hard_irq_disable(); - if (get_paca()->irq_happened == 0) + if (prep_irq_for_idle()) { cede_processor(); +#ifdef CONFIG_TRACE_IRQFLAGS + /* Ensure that H_CEDE returns with IRQs on */ + if (WARN_ON(!(mfmsr() & MSR_EE))) + __hard_irq_enable(); +#endif + } } static int dedicated_cede_loop(struct cpuidle_device *dev, @@ -186,17 +190,40 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { .enter = &shared_cede_loop }, }; -int pseries_notify_cpuidle_add_cpu(int cpu) +static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n, + unsigned long action, void *hcpu) { + int hotcpu = (unsigned long)hcpu; struct cpuidle_device *dev = - per_cpu_ptr(pseries_cpuidle_devices, cpu); + per_cpu_ptr(pseries_cpuidle_devices, hotcpu); + if (dev && cpuidle_get_driver()) { - cpuidle_disable_device(dev); - cpuidle_enable_device(dev); + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + cpuidle_pause_and_lock(); + cpuidle_enable_device(dev); + cpuidle_resume_and_unlock(); + break; + + case CPU_DEAD: + case CPU_DEAD_FROZEN: + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + cpuidle_resume_and_unlock(); + break; + + default: + return NOTIFY_DONE; + } } - return 0; + return NOTIFY_OK; } +static struct notifier_block setup_hotplug_notifier = { + .notifier_call = pseries_cpuidle_add_cpu_notifier, +}; + /* * pseries_cpuidle_driver_init() */ @@ -321,6 +348,7 @@ static int __init pseries_processor_idle_init(void) return retval; } + register_cpu_notifier(&setup_hotplug_notifier); printk(KERN_DEBUG "pseries_idle_driver registered\n"); return 0; @@ -329,6 +357,7 @@ static int __init pseries_processor_idle_init(void) static void __exit pseries_processor_idle_exit(void) { + unregister_cpu_notifier(&setup_hotplug_notifier); pseries_idle_devices_uninit(); cpuidle_unregister_driver(&pseries_idle_driver); diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 7b3bf76ef834..39f71fba9b38 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -432,7 +432,7 @@ static int do_update_property(char *buf, size_t bufsize) unsigned char *value; char *name, *end, *next_prop; int rc, length; - struct property *newprop, *oldprop; + struct property *newprop; buf = parse_node(buf, bufsize, &np); end = buf + bufsize; @@ -443,6 +443,9 @@ static int do_update_property(char *buf, size_t bufsize) if (!next_prop) return -EINVAL; + if (!strlen(name)) + return -ENODEV; + newprop = new_property(name, length, value, NULL); if (!newprop) return -ENOMEM; @@ -450,18 +453,11 @@ 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); - oldprop = of_find_property(np, name,NULL); - if (!oldprop) { - if (strlen(name)) - return prom_add_property(np, newprop); - return -ENODEV; - } - upd_value.node = np; upd_value.property = newprop; pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value); - rc = prom_update_property(np, newprop, oldprop); + rc = prom_update_property(np, newprop); if (rc) return rc; @@ -486,7 +482,7 @@ static int do_update_property(char *buf, size_t bufsize) rc = pSeries_reconfig_notify(action, value); if (rc) { - prom_update_property(np, oldprop, newprop); + prom_update_property(np, newprop); return rc; } } diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index e16bb8d48550..71706bc34a0d 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -147,7 +147,6 @@ static void __devinit smp_xics_setup_cpu(int cpu) set_cpu_current_state(cpu, CPU_STATE_ONLINE); set_default_offline_state(cpu); #endif - pseries_notify_cpuidle_add_cpu(cpu); } static int __devinit smp_pSeries_kick_cpu(int nr) |