aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-11 21:24:58 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-11 21:24:58 -0500
commit13d7d84e078f49f08b657a3fba0d7a0b7b44ba65 (patch)
treeae4957d183e2f5fcae62b2c1411b4a32c2f71f21 /arch/powerpc/platforms
parentcbb8fc07974073543fdc61da23713ab49ddd3ced (diff)
parent73c9ceab40b1269d6195e556773167c078ac8311 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (36 commits) [POWERPC] Generic BUG for powerpc [PPC] Fix compile failure do to introduction of PHY_POLL [POWERPC] Only export __mtdcr/__mfdcr if CONFIG_PPC_DCR is set [POWERPC] Remove old dcr.S [POWERPC] Fix SPU coredump code for max_fdset removal [POWERPC] Fix irq routing on some 32-bit PowerMacs [POWERPC] ps3: Add vuart support [POWERPC] Support ibm,dynamic-reconfiguration-memory nodes [POWERPC] dont allow pSeries_probe to succeed without initialising MMU [POWERPC] micro optimise pSeries_probe [POWERPC] Add SPURR SPR to sysfs [POWERPC] Add DSCR SPR to sysfs [POWERPC] Fix 440SPe CPU table entry [POWERPC] Add support for FP emulation for the e300c2 core [POWERPC] of_device_register: propagate device_create_file return code [POWERPC] Fix mmap of PCI resource with hack for X [POWERPC] iSeries: head_64.o needs to depend on lparmap.s [POWERPC] cbe_thermal: Fix initialization of sysfs attribute_group [POWERPC] Remove QE header files from lite5200.c [POWERPC] of_platform_make_bus_id(): make `magic' int ...
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c2
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c2
-rw-r--r--arch/powerpc/platforms/cell/pmu.c5
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c2
-rw-r--r--arch/powerpc/platforms/maple/pci.c2
-rw-r--r--arch/powerpc/platforms/maple/setup.c12
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig11
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c1
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c13
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c275
-rw-r--r--arch/powerpc/platforms/pseries/setup.c30
-rw-r--r--arch/powerpc/platforms/pseries/smp.c200
13 files changed, 326 insertions, 231 deletions
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index a375c15b4315..eaff71e74fb0 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -40,8 +40,6 @@
40#include <asm/prom.h> 40#include <asm/prom.h>
41#include <asm/udbg.h> 41#include <asm/udbg.h>
42#include <sysdev/fsl_soc.h> 42#include <sysdev/fsl_soc.h>
43#include <asm/qe.h>
44#include <asm/qe_ic.h>
45#include <asm/of_platform.h> 43#include <asm/of_platform.h>
46 44
47#include <asm/mpc52xx.h> 45#include <asm/mpc52xx.h>
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index 616a0a3fd0e2..70e0d968d30f 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -115,6 +115,7 @@ static struct sysdev_attribute attr_spu_temperature = {
115 115
116static struct attribute *spu_attributes[] = { 116static struct attribute *spu_attributes[] = {
117 &attr_spu_temperature.attr, 117 &attr_spu_temperature.attr,
118 NULL,
118}; 119};
119 120
120static struct attribute_group spu_attribute_group = { 121static struct attribute_group spu_attribute_group = {
@@ -135,6 +136,7 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
135static struct attribute *ppe_attributes[] = { 136static struct attribute *ppe_attributes[] = {
136 &attr_ppe_temperature0.attr, 137 &attr_ppe_temperature0.attr,
137 &attr_ppe_temperature1.attr, 138 &attr_ppe_temperature1.attr,
139 NULL,
138}; 140};
139 141
140static struct attribute_group ppe_attribute_group = { 142static struct attribute_group ppe_attribute_group = {
diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c
index 99c612025e8f..d04ae1671e6c 100644
--- a/arch/powerpc/platforms/cell/pmu.c
+++ b/arch/powerpc/platforms/cell/pmu.c
@@ -382,11 +382,14 @@ static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
382 return IRQ_HANDLED; 382 return IRQ_HANDLED;
383} 383}
384 384
385int __init cbe_init_pm_irq(void) 385static int __init cbe_init_pm_irq(void)
386{ 386{
387 unsigned int irq; 387 unsigned int irq;
388 int rc, node; 388 int rc, node;
389 389
390 if (!machine_is(cell))
391 return 0;
392
390 for_each_node(node) { 393 for_each_node(node) {
391 irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI | 394 irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
392 (node << IIC_IRQ_NODE_SHIFT)); 395 (node << IIC_IRQ_NODE_SHIFT));
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 26945c491f6b..725e19561159 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -147,7 +147,7 @@ static int spufs_arch_notes_size(void)
147 struct fdtable *fdt = files_fdtable(current->files); 147 struct fdtable *fdt = files_fdtable(current->files);
148 int size = 0, fd; 148 int size = 0, fd;
149 149
150 for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) { 150 for (fd = 0; fd < fdt->max_fds; fd++) {
151 if (FD_ISSET(fd, fdt->open_fds)) { 151 if (FD_ISSET(fd, fdt->open_fds)) {
152 struct file *file = fcheck(fd); 152 struct file *file = fcheck(fd);
153 153
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 3a32deda765d..3f6a69f67195 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -562,7 +562,7 @@ void __init maple_pci_init(void)
562 for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { 562 for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
563 if (np->name == NULL) 563 if (np->name == NULL)
564 continue; 564 continue;
565 if (strcmp(np->name, "pci") == 0) { 565 if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) {
566 if (add_bridge(np) == 0) 566 if (add_bridge(np) == 0)
567 of_node_get(np); 567 of_node_get(np);
568 } 568 }
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 094989d50bab..f12d5c69e74d 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -60,6 +60,7 @@
60#include <asm/of_device.h> 60#include <asm/of_device.h>
61#include <asm/lmb.h> 61#include <asm/lmb.h>
62#include <asm/mpic.h> 62#include <asm/mpic.h>
63#include <asm/rtas.h>
63#include <asm/udbg.h> 64#include <asm/udbg.h>
64 65
65#include "maple.h" 66#include "maple.h"
@@ -166,6 +167,16 @@ struct smp_ops_t maple_smp_ops = {
166}; 167};
167#endif /* CONFIG_SMP */ 168#endif /* CONFIG_SMP */
168 169
170static void __init maple_use_rtas_reboot_and_halt_if_present(void)
171{
172 if (rtas_service_present("system-reboot") &&
173 rtas_service_present("power-off")) {
174 ppc_md.restart = rtas_restart;
175 ppc_md.power_off = rtas_power_off;
176 ppc_md.halt = rtas_halt;
177 }
178}
179
169void __init maple_setup_arch(void) 180void __init maple_setup_arch(void)
170{ 181{
171 /* init to some ~sane value until calibrate_delay() runs */ 182 /* init to some ~sane value until calibrate_delay() runs */
@@ -181,6 +192,7 @@ void __init maple_setup_arch(void)
181#ifdef CONFIG_DUMMY_CONSOLE 192#ifdef CONFIG_DUMMY_CONSOLE
182 conswitchp = &dummy_con; 193 conswitchp = &dummy_con;
183#endif 194#endif
195 maple_use_rtas_reboot_and_halt_if_present();
184 196
185 printk(KERN_DEBUG "Using native/NAP idle loop\n"); 197 printk(KERN_DEBUG "Using native/NAP idle loop\n");
186} 198}
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 451bfcd5502e..de52ec4e9e58 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -40,4 +40,15 @@ config PS3_USE_LPAR_ADDR
40 40
41 If you have any doubt, choose the default y. 41 If you have any doubt, choose the default y.
42 42
43config PS3_VUART
44 depends on PPC_PS3
45 bool "PS3 Virtual UART support"
46 default y
47 help
48 Include support for the PS3 Virtual UART.
49
50 This support is required for several system services
51 including the System Manager and AV Settings. In
52 general, all users will say Y.
53
43endmenu 54endmenu
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 997243a91be8..69590fbf83da 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_XICS) += xics.o
10obj-$(CONFIG_SCANLOG) += scanlog.o 10obj-$(CONFIG_SCANLOG) += scanlog.o
11obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o 11obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
12 12
13obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
14
13obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o 15obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
14obj-$(CONFIG_HVCS) += hvcserver.o 16obj-$(CONFIG_HVCS) += hvcserver.o
15obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o 17obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 3c2d63ebf787..da6e5362e7cd 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -337,6 +337,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
337 printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n", 337 printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
338 pdn->eeh_check_count); 338 pdn->eeh_check_count);
339 dump_stack(); 339 dump_stack();
340 msleep(5000);
340 341
341 /* re-read the slot reset state */ 342 /* re-read the slot reset state */
342 if (read_slot_reset_state(pdn, rets) != 0) 343 if (read_slot_reset_state(pdn, rets) != 0)
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index c2bc9904f1cb..cbd6b0711ab4 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -170,14 +170,19 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
170static void eeh_report_resume(struct pci_dev *dev, void *userdata) 170static void eeh_report_resume(struct pci_dev *dev, void *userdata)
171{ 171{
172 struct pci_driver *driver = dev->driver; 172 struct pci_driver *driver = dev->driver;
173 struct device_node *dn = pci_device_to_OF_node(dev);
173 174
174 dev->error_state = pci_channel_io_normal; 175 dev->error_state = pci_channel_io_normal;
175 176
176 if (!driver) 177 if (!driver)
177 return; 178 return;
178 if (!driver->err_handler) 179
179 return; 180 if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
180 if (!driver->err_handler->resume) 181 PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
182 enable_irq(dev->irq);
183 }
184 if (!driver->err_handler ||
185 !driver->err_handler->resume)
181 return; 186 return;
182 187
183 driver->err_handler->resume(dev); 188 driver->err_handler->resume(dev);
@@ -407,6 +412,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
407 412
408 if (rc) 413 if (rc)
409 result = PCI_ERS_RESULT_NEED_RESET; 414 result = PCI_ERS_RESULT_NEED_RESET;
415 else
416 result = PCI_ERS_RESULT_RECOVERED;
410 } 417 }
411 418
412 /* If any device has a hard failure, then shut off everything. */ 419 /* If any device has a hard failure, then shut off everything. */
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
new file mode 100644
index 000000000000..f460b9cbfd46
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -0,0 +1,275 @@
1/*
2 * pseries CPU Hotplug infrastructure.
3 *
4 * Split out from arch/powerpc/platforms/pseries/setup.c
5 * arch/powerpc/kernel/rtas.c, and arch/powerpc/platforms/pseries/smp.c
6 *
7 * Peter Bergner, IBM March 2001.
8 * Copyright (C) 2001 IBM.
9 * Dave Engebretsen, Peter Bergner, and
10 * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
11 * Plus various changes from other IBM teams...
12 *
13 * Copyright (C) 2006 Michael Ellerman, IBM Corporation
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
19 */
20
21#include <linux/kernel.h>
22#include <linux/delay.h>
23#include <linux/cpu.h>
24#include <asm/system.h>
25#include <asm/prom.h>
26#include <asm/rtas.h>
27#include <asm/firmware.h>
28#include <asm/machdep.h>
29#include <asm/vdso_datapage.h>
30#include <asm/pSeries_reconfig.h>
31#include "xics.h"
32
33/* This version can't take the spinlock, because it never returns */
34static struct rtas_args rtas_stop_self_args = {
35 .token = RTAS_UNKNOWN_SERVICE,
36 .nargs = 0,
37 .nret = 1,
38 .rets = &rtas_stop_self_args.args[0],
39};
40
41static void rtas_stop_self(void)
42{
43 struct rtas_args *args = &rtas_stop_self_args;
44
45 local_irq_disable();
46
47 BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
48
49 printk("cpu %u (hwid %u) Ready to die...\n",
50 smp_processor_id(), hard_smp_processor_id());
51 enter_rtas(__pa(args));
52
53 panic("Alas, I survived.\n");
54}
55
56static void pseries_mach_cpu_die(void)
57{
58 local_irq_disable();
59 idle_task_exit();
60 xics_teardown_cpu(0);
61 rtas_stop_self();
62 /* Should never get here... */
63 BUG();
64 for(;;);
65}
66
67static int qcss_tok; /* query-cpu-stopped-state token */
68
69/* Get state of physical CPU.
70 * Return codes:
71 * 0 - The processor is in the RTAS stopped state
72 * 1 - stop-self is in progress
73 * 2 - The processor is not in the RTAS stopped state
74 * -1 - Hardware Error
75 * -2 - Hardware Busy, Try again later.
76 */
77static int query_cpu_stopped(unsigned int pcpu)
78{
79 int cpu_status, status;
80
81 status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
82 if (status != 0) {
83 printk(KERN_ERR
84 "RTAS query-cpu-stopped-state failed: %i\n", status);
85 return status;
86 }
87
88 return cpu_status;
89}
90
91static int pseries_cpu_disable(void)
92{
93 int cpu = smp_processor_id();
94
95 cpu_clear(cpu, cpu_online_map);
96 vdso_data->processorCount--;
97
98 /*fix boot_cpuid here*/
99 if (cpu == boot_cpuid)
100 boot_cpuid = any_online_cpu(cpu_online_map);
101
102 /* FIXME: abstract this to not be platform specific later on */
103 xics_migrate_irqs_away();
104 return 0;
105}
106
107static void pseries_cpu_die(unsigned int cpu)
108{
109 int tries;
110 int cpu_status;
111 unsigned int pcpu = get_hard_smp_processor_id(cpu);
112
113 for (tries = 0; tries < 25; tries++) {
114 cpu_status = query_cpu_stopped(pcpu);
115 if (cpu_status == 0 || cpu_status == -1)
116 break;
117 msleep(200);
118 }
119 if (cpu_status != 0) {
120 printk("Querying DEAD? cpu %i (%i) shows %i\n",
121 cpu, pcpu, cpu_status);
122 }
123
124 /* Isolation and deallocation are definatly done by
125 * drslot_chrp_cpu. If they were not they would be
126 * done here. Change isolate state to Isolate and
127 * change allocation-state to Unusable.
128 */
129 paca[cpu].cpu_start = 0;
130}
131
132/*
133 * Update cpu_present_map and paca(s) for a new cpu node. The wrinkle
134 * here is that a cpu device node may represent up to two logical cpus
135 * in the SMT case. We must honor the assumption in other code that
136 * the logical ids for sibling SMT threads x and y are adjacent, such
137 * that x^1 == y and y^1 == x.
138 */
139static int pseries_add_processor(struct device_node *np)
140{
141 unsigned int cpu;
142 cpumask_t candidate_map, tmp = CPU_MASK_NONE;
143 int err = -ENOSPC, len, nthreads, i;
144 const u32 *intserv;
145
146 intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
147 if (!intserv)
148 return 0;
149
150 nthreads = len / sizeof(u32);
151 for (i = 0; i < nthreads; i++)
152 cpu_set(i, tmp);
153
154 lock_cpu_hotplug();
155
156 BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
157
158 /* Get a bitmap of unoccupied slots. */
159 cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
160 if (cpus_empty(candidate_map)) {
161 /* If we get here, it most likely means that NR_CPUS is
162 * less than the partition's max processors setting.
163 */
164 printk(KERN_ERR "Cannot add cpu %s; this system configuration"
165 " supports %d logical cpus.\n", np->full_name,
166 cpus_weight(cpu_possible_map));
167 goto out_unlock;
168 }
169
170 while (!cpus_empty(tmp))
171 if (cpus_subset(tmp, candidate_map))
172 /* Found a range where we can insert the new cpu(s) */
173 break;
174 else
175 cpus_shift_left(tmp, tmp, nthreads);
176
177 if (cpus_empty(tmp)) {
178 printk(KERN_ERR "Unable to find space in cpu_present_map for"
179 " processor %s with %d thread(s)\n", np->name,
180 nthreads);
181 goto out_unlock;
182 }
183
184 for_each_cpu_mask(cpu, tmp) {
185 BUG_ON(cpu_isset(cpu, cpu_present_map));
186 cpu_set(cpu, cpu_present_map);
187 set_hard_smp_processor_id(cpu, *intserv++);
188 }
189 err = 0;
190out_unlock:
191 unlock_cpu_hotplug();
192 return err;
193}
194
195/*
196 * Update the present map for a cpu node which is going away, and set
197 * the hard id in the paca(s) to -1 to be consistent with boot time
198 * convention for non-present cpus.
199 */
200static void pseries_remove_processor(struct device_node *np)
201{
202 unsigned int cpu;
203 int len, nthreads, i;
204 const u32 *intserv;
205
206 intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
207 if (!intserv)
208 return;
209
210 nthreads = len / sizeof(u32);
211
212 lock_cpu_hotplug();
213 for (i = 0; i < nthreads; i++) {
214 for_each_present_cpu(cpu) {
215 if (get_hard_smp_processor_id(cpu) != intserv[i])
216 continue;
217 BUG_ON(cpu_online(cpu));
218 cpu_clear(cpu, cpu_present_map);
219 set_hard_smp_processor_id(cpu, -1);
220 break;
221 }
222 if (cpu == NR_CPUS)
223 printk(KERN_WARNING "Could not find cpu to remove "
224 "with physical id 0x%x\n", intserv[i]);
225 }
226 unlock_cpu_hotplug();
227}
228
229static int pseries_smp_notifier(struct notifier_block *nb,
230 unsigned long action, void *node)
231{
232 int err = NOTIFY_OK;
233
234 switch (action) {
235 case PSERIES_RECONFIG_ADD:
236 if (pseries_add_processor(node))
237 err = NOTIFY_BAD;
238 break;
239 case PSERIES_RECONFIG_REMOVE:
240 pseries_remove_processor(node);
241 break;
242 default:
243 err = NOTIFY_DONE;
244 break;
245 }
246 return err;
247}
248
249static struct notifier_block pseries_smp_nb = {
250 .notifier_call = pseries_smp_notifier,
251};
252
253static int __init pseries_cpu_hotplug_init(void)
254{
255 rtas_stop_self_args.token = rtas_token("stop-self");
256 qcss_tok = rtas_token("query-cpu-stopped-state");
257
258 if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
259 qcss_tok == RTAS_UNKNOWN_SERVICE) {
260 printk(KERN_INFO "CPU Hotplug not supported by firmware "
261 "- disabling.\n");
262 return 0;
263 }
264
265 ppc_md.cpu_die = pseries_mach_cpu_die;
266 smp_ops->cpu_disable = pseries_cpu_disable;
267 smp_ops->cpu_die = pseries_cpu_die;
268
269 /* Processors can be added/removed only on LPAR */
270 if (firmware_has_feature(FW_FEATURE_LPAR))
271 pSeries_reconfig_notifier_register(&pseries_smp_nb);
272
273 return 0;
274}
275arch_initcall(pseries_cpu_hotplug_init);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 0dc2548ca9bc..042ecae107ac 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -347,21 +347,6 @@ static int __init pSeries_init_panel(void)
347} 347}
348arch_initcall(pSeries_init_panel); 348arch_initcall(pSeries_init_panel);
349 349
350#ifdef CONFIG_HOTPLUG_CPU
351static void pSeries_mach_cpu_die(void)
352{
353 local_irq_disable();
354 idle_task_exit();
355 xics_teardown_cpu(0);
356 rtas_stop_self();
357 /* Should never get here... */
358 BUG();
359 for(;;);
360}
361#else
362#define pSeries_mach_cpu_die NULL
363#endif
364
365static int pseries_set_dabr(unsigned long dabr) 350static int pseries_set_dabr(unsigned long dabr)
366{ 351{
367 return plpar_hcall_norets(H_SET_DABR, dabr); 352 return plpar_hcall_norets(H_SET_DABR, dabr);
@@ -437,19 +422,14 @@ static int __init pSeries_probe_hypertas(unsigned long node,
437 if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL) 422 if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
438 powerpc_firmware_features |= FW_FEATURE_LPAR; 423 powerpc_firmware_features |= FW_FEATURE_LPAR;
439 424
440 if (firmware_has_feature(FW_FEATURE_LPAR))
441 hpte_init_lpar();
442 else
443 hpte_init_native();
444
445 return 1; 425 return 1;
446} 426}
447 427
448static int __init pSeries_probe(void) 428static int __init pSeries_probe(void)
449{ 429{
450 unsigned long root = of_get_flat_dt_root(); 430 unsigned long root = of_get_flat_dt_root();
451 char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), 431 char *dtype = of_get_flat_dt_prop(root, "device_type", NULL);
452 "device_type", NULL); 432
453 if (dtype == NULL) 433 if (dtype == NULL)
454 return 0; 434 return 0;
455 if (strcmp(dtype, "chrp")) 435 if (strcmp(dtype, "chrp"))
@@ -467,6 +447,11 @@ static int __init pSeries_probe(void)
467 /* Now try to figure out if we are running on LPAR */ 447 /* Now try to figure out if we are running on LPAR */
468 of_scan_flat_dt(pSeries_probe_hypertas, NULL); 448 of_scan_flat_dt(pSeries_probe_hypertas, NULL);
469 449
450 if (firmware_has_feature(FW_FEATURE_LPAR))
451 hpte_init_lpar();
452 else
453 hpte_init_native();
454
470 DBG("Machine is%s LPAR !\n", 455 DBG("Machine is%s LPAR !\n",
471 (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); 456 (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
472 457
@@ -561,7 +546,6 @@ define_machine(pseries) {
561 .power_off = rtas_power_off, 546 .power_off = rtas_power_off,
562 .halt = rtas_halt, 547 .halt = rtas_halt,
563 .panic = rtas_os_term, 548 .panic = rtas_os_term,
564 .cpu_die = pSeries_mach_cpu_die,
565 .get_boot_time = rtas_get_boot_time, 549 .get_boot_time = rtas_get_boot_time,
566 .get_rtc_time = rtas_get_rtc_time, 550 .get_rtc_time = rtas_get_rtc_time,
567 .set_rtc_time = rtas_set_rtc_time, 551 .set_rtc_time = rtas_set_rtc_time,
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index c6624b8a0e77..4408518eaebe 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -64,197 +64,6 @@ static cpumask_t of_spin_map;
64 64
65extern void generic_secondary_smp_init(unsigned long); 65extern void generic_secondary_smp_init(unsigned long);
66 66
67#ifdef CONFIG_HOTPLUG_CPU
68
69/* Get state of physical CPU.
70 * Return codes:
71 * 0 - The processor is in the RTAS stopped state
72 * 1 - stop-self is in progress
73 * 2 - The processor is not in the RTAS stopped state
74 * -1 - Hardware Error
75 * -2 - Hardware Busy, Try again later.
76 */
77static int query_cpu_stopped(unsigned int pcpu)
78{
79 int cpu_status;
80 int status, qcss_tok;
81
82 qcss_tok = rtas_token("query-cpu-stopped-state");
83 if (qcss_tok == RTAS_UNKNOWN_SERVICE)
84 return -1;
85 status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
86 if (status != 0) {
87 printk(KERN_ERR
88 "RTAS query-cpu-stopped-state failed: %i\n", status);
89 return status;
90 }
91
92 return cpu_status;
93}
94
95static int pSeries_cpu_disable(void)
96{
97 int cpu = smp_processor_id();
98
99 cpu_clear(cpu, cpu_online_map);
100 vdso_data->processorCount--;
101
102 /*fix boot_cpuid here*/
103 if (cpu == boot_cpuid)
104 boot_cpuid = any_online_cpu(cpu_online_map);
105
106 /* FIXME: abstract this to not be platform specific later on */
107 xics_migrate_irqs_away();
108 return 0;
109}
110
111static void pSeries_cpu_die(unsigned int cpu)
112{
113 int tries;
114 int cpu_status;
115 unsigned int pcpu = get_hard_smp_processor_id(cpu);
116
117 for (tries = 0; tries < 25; tries++) {
118 cpu_status = query_cpu_stopped(pcpu);
119 if (cpu_status == 0 || cpu_status == -1)
120 break;
121 msleep(200);
122 }
123 if (cpu_status != 0) {
124 printk("Querying DEAD? cpu %i (%i) shows %i\n",
125 cpu, pcpu, cpu_status);
126 }
127
128 /* Isolation and deallocation are definatly done by
129 * drslot_chrp_cpu. If they were not they would be
130 * done here. Change isolate state to Isolate and
131 * change allocation-state to Unusable.
132 */
133 paca[cpu].cpu_start = 0;
134}
135
136/*
137 * Update cpu_present_map and paca(s) for a new cpu node. The wrinkle
138 * here is that a cpu device node may represent up to two logical cpus
139 * in the SMT case. We must honor the assumption in other code that
140 * the logical ids for sibling SMT threads x and y are adjacent, such
141 * that x^1 == y and y^1 == x.
142 */
143static int pSeries_add_processor(struct device_node *np)
144{
145 unsigned int cpu;
146 cpumask_t candidate_map, tmp = CPU_MASK_NONE;
147 int err = -ENOSPC, len, nthreads, i;
148 const u32 *intserv;
149
150 intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
151 if (!intserv)
152 return 0;
153
154 nthreads = len / sizeof(u32);
155 for (i = 0; i < nthreads; i++)
156 cpu_set(i, tmp);
157
158 lock_cpu_hotplug();
159
160 BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
161
162 /* Get a bitmap of unoccupied slots. */
163 cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
164 if (cpus_empty(candidate_map)) {
165 /* If we get here, it most likely means that NR_CPUS is
166 * less than the partition's max processors setting.
167 */
168 printk(KERN_ERR "Cannot add cpu %s; this system configuration"
169 " supports %d logical cpus.\n", np->full_name,
170 cpus_weight(cpu_possible_map));
171 goto out_unlock;
172 }
173
174 while (!cpus_empty(tmp))
175 if (cpus_subset(tmp, candidate_map))
176 /* Found a range where we can insert the new cpu(s) */
177 break;
178 else
179 cpus_shift_left(tmp, tmp, nthreads);
180
181 if (cpus_empty(tmp)) {
182 printk(KERN_ERR "Unable to find space in cpu_present_map for"
183 " processor %s with %d thread(s)\n", np->name,
184 nthreads);
185 goto out_unlock;
186 }
187
188 for_each_cpu_mask(cpu, tmp) {
189 BUG_ON(cpu_isset(cpu, cpu_present_map));
190 cpu_set(cpu, cpu_present_map);
191 set_hard_smp_processor_id(cpu, *intserv++);
192 }
193 err = 0;
194out_unlock:
195 unlock_cpu_hotplug();
196 return err;
197}
198
199/*
200 * Update the present map for a cpu node which is going away, and set
201 * the hard id in the paca(s) to -1 to be consistent with boot time
202 * convention for non-present cpus.
203 */
204static void pSeries_remove_processor(struct device_node *np)
205{
206 unsigned int cpu;
207 int len, nthreads, i;
208 const u32 *intserv;
209
210 intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
211 if (!intserv)
212 return;
213
214 nthreads = len / sizeof(u32);
215
216 lock_cpu_hotplug();
217 for (i = 0; i < nthreads; i++) {
218 for_each_present_cpu(cpu) {
219 if (get_hard_smp_processor_id(cpu) != intserv[i])
220 continue;
221 BUG_ON(cpu_online(cpu));
222 cpu_clear(cpu, cpu_present_map);
223 set_hard_smp_processor_id(cpu, -1);
224 break;
225 }
226 if (cpu == NR_CPUS)
227 printk(KERN_WARNING "Could not find cpu to remove "
228 "with physical id 0x%x\n", intserv[i]);
229 }
230 unlock_cpu_hotplug();
231}
232
233static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node)
234{
235 int err = NOTIFY_OK;
236
237 switch (action) {
238 case PSERIES_RECONFIG_ADD:
239 if (pSeries_add_processor(node))
240 err = NOTIFY_BAD;
241 break;
242 case PSERIES_RECONFIG_REMOVE:
243 pSeries_remove_processor(node);
244 break;
245 default:
246 err = NOTIFY_DONE;
247 break;
248 }
249 return err;
250}
251
252static struct notifier_block pSeries_smp_nb = {
253 .notifier_call = pSeries_smp_notifier,
254};
255
256#endif /* CONFIG_HOTPLUG_CPU */
257
258/** 67/**
259 * smp_startup_cpu() - start the given cpu 68 * smp_startup_cpu() - start the given cpu
260 * 69 *
@@ -422,15 +231,6 @@ static void __init smp_init_pseries(void)
422 231
423 DBG(" -> smp_init_pSeries()\n"); 232 DBG(" -> smp_init_pSeries()\n");
424 233
425#ifdef CONFIG_HOTPLUG_CPU
426 smp_ops->cpu_disable = pSeries_cpu_disable;
427 smp_ops->cpu_die = pSeries_cpu_die;
428
429 /* Processors can be added/removed only on LPAR */
430 if (firmware_has_feature(FW_FEATURE_LPAR))
431 pSeries_reconfig_notifier_register(&pSeries_smp_nb);
432#endif
433
434 /* Mark threads which are still spinning in hold loops. */ 234 /* Mark threads which are still spinning in hold loops. */
435 if (cpu_has_feature(CPU_FTR_SMT)) { 235 if (cpu_has_feature(CPU_FTR_SMT)) {
436 for_each_present_cpu(i) { 236 for_each_present_cpu(i) {