diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/setup.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 246 |
1 files changed, 129 insertions, 117 deletions
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 476b564a208b..54a52437265c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -76,6 +76,9 @@ | |||
76 | #define DBG(fmt...) | 76 | #define DBG(fmt...) |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | /* move those away to a .h */ | ||
80 | extern void smp_init_pseries_mpic(void); | ||
81 | extern void smp_init_pseries_xics(void); | ||
79 | extern void find_udbg_vterm(void); | 82 | extern void find_udbg_vterm(void); |
80 | 83 | ||
81 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ | 84 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ |
@@ -83,7 +86,7 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */ | |||
83 | static void pseries_shared_idle_sleep(void); | 86 | static void pseries_shared_idle_sleep(void); |
84 | static void pseries_dedicated_idle_sleep(void); | 87 | static void pseries_dedicated_idle_sleep(void); |
85 | 88 | ||
86 | struct mpic *pSeries_mpic; | 89 | static struct device_node *pSeries_mpic_node; |
87 | 90 | ||
88 | static void pSeries_show_cpuinfo(struct seq_file *m) | 91 | static void pSeries_show_cpuinfo(struct seq_file *m) |
89 | { | 92 | { |
@@ -118,78 +121,92 @@ static void __init fwnmi_init(void) | |||
118 | fwnmi_active = 1; | 121 | fwnmi_active = 1; |
119 | } | 122 | } |
120 | 123 | ||
121 | void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc, | 124 | void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc, |
122 | struct pt_regs *regs) | 125 | struct pt_regs *regs) |
123 | { | 126 | { |
124 | unsigned int max = 100; | 127 | unsigned int cascade_irq = i8259_irq(regs); |
125 | 128 | if (cascade_irq != NO_IRQ) | |
126 | while(max--) { | ||
127 | int cascade_irq = i8259_irq(regs); | ||
128 | if (max == 99) | ||
129 | desc->chip->eoi(irq); | ||
130 | if (cascade_irq < 0) | ||
131 | break; | ||
132 | generic_handle_irq(cascade_irq, regs); | 129 | generic_handle_irq(cascade_irq, regs); |
133 | }; | 130 | desc->chip->eoi(irq); |
134 | } | 131 | } |
135 | 132 | ||
136 | static void __init pSeries_init_mpic(void) | 133 | static void __init pseries_mpic_init_IRQ(void) |
137 | { | 134 | { |
135 | struct device_node *np, *old, *cascade = NULL; | ||
138 | unsigned int *addrp; | 136 | unsigned int *addrp; |
139 | struct device_node *np; | ||
140 | unsigned long intack = 0; | 137 | unsigned long intack = 0; |
141 | |||
142 | /* All ISUs are setup, complete initialization */ | ||
143 | mpic_init(pSeries_mpic); | ||
144 | |||
145 | /* Check what kind of cascade ACK we have */ | ||
146 | if (!(np = of_find_node_by_name(NULL, "pci")) | ||
147 | || !(addrp = (unsigned int *) | ||
148 | get_property(np, "8259-interrupt-acknowledge", NULL))) | ||
149 | printk(KERN_ERR "Cannot find pci to get ack address\n"); | ||
150 | else | ||
151 | intack = addrp[prom_n_addr_cells(np)-1]; | ||
152 | of_node_put(np); | ||
153 | |||
154 | /* Setup the legacy interrupts & controller */ | ||
155 | i8259_init(intack, 0); | ||
156 | |||
157 | /* Hook cascade to mpic */ | ||
158 | set_irq_chained_handler(NUM_ISA_INTERRUPTS, pSeries_8259_cascade); | ||
159 | } | ||
160 | |||
161 | static void __init pSeries_setup_mpic(void) | ||
162 | { | ||
163 | unsigned int *opprop; | 138 | unsigned int *opprop; |
164 | unsigned long openpic_addr = 0; | 139 | unsigned long openpic_addr = 0; |
165 | unsigned char senses[NR_IRQS - NUM_ISA_INTERRUPTS]; | 140 | unsigned int cascade_irq; |
166 | struct device_node *root; | 141 | int naddr, n, i, opplen; |
167 | int irq_count; | 142 | struct mpic *mpic; |
168 | 143 | ||
169 | /* Find the Open PIC if present */ | 144 | np = of_find_node_by_path("/"); |
170 | root = of_find_node_by_path("/"); | 145 | naddr = prom_n_addr_cells(np); |
171 | opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); | 146 | opprop = (unsigned int *) get_property(np, "platform-open-pic", &opplen); |
172 | if (opprop != 0) { | 147 | if (opprop != 0) { |
173 | int n = prom_n_addr_cells(root); | 148 | openpic_addr = of_read_number(opprop, naddr); |
174 | |||
175 | for (openpic_addr = 0; n > 0; --n) | ||
176 | openpic_addr = (openpic_addr << 32) + *opprop++; | ||
177 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); | 149 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); |
178 | } | 150 | } |
179 | of_node_put(root); | 151 | of_node_put(np); |
180 | 152 | ||
181 | BUG_ON(openpic_addr == 0); | 153 | BUG_ON(openpic_addr == 0); |
182 | 154 | ||
183 | /* Get the sense values from OF */ | ||
184 | prom_get_irq_senses(senses, NUM_ISA_INTERRUPTS, NR_IRQS); | ||
185 | |||
186 | /* Setup the openpic driver */ | 155 | /* Setup the openpic driver */ |
187 | irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ | 156 | mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, |
188 | pSeries_mpic = mpic_alloc(openpic_addr, MPIC_PRIMARY, | 157 | MPIC_PRIMARY, |
189 | 16, 16, irq_count, /* isu size, irq offset, irq count */ | 158 | 16, 250, /* isu size, irq count */ |
190 | NR_IRQS - 4, /* ipi offset */ | 159 | " MPIC "); |
191 | senses, irq_count, /* sense & sense size */ | 160 | BUG_ON(mpic == NULL); |
192 | " MPIC "); | 161 | |
162 | /* Add ISUs */ | ||
163 | opplen /= sizeof(u32); | ||
164 | for (n = 0, i = naddr; i < opplen; i += naddr, n++) { | ||
165 | unsigned long isuaddr = of_read_number(opprop + i, naddr); | ||
166 | mpic_assign_isu(mpic, n, isuaddr); | ||
167 | } | ||
168 | |||
169 | /* All ISUs are setup, complete initialization */ | ||
170 | mpic_init(mpic); | ||
171 | |||
172 | /* Look for cascade */ | ||
173 | for_each_node_by_type(np, "interrupt-controller") | ||
174 | if (device_is_compatible(np, "chrp,iic")) { | ||
175 | cascade = np; | ||
176 | break; | ||
177 | } | ||
178 | if (cascade == NULL) | ||
179 | return; | ||
180 | |||
181 | cascade_irq = irq_of_parse_and_map(cascade, 0); | ||
182 | if (cascade == NO_IRQ) { | ||
183 | printk(KERN_ERR "xics: failed to map cascade interrupt"); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | /* Check ACK type */ | ||
188 | for (old = of_node_get(cascade); old != NULL ; old = np) { | ||
189 | np = of_get_parent(old); | ||
190 | of_node_put(old); | ||
191 | if (np == NULL) | ||
192 | break; | ||
193 | if (strcmp(np->name, "pci") != 0) | ||
194 | continue; | ||
195 | addrp = (u32 *)get_property(np, "8259-interrupt-acknowledge", | ||
196 | NULL); | ||
197 | if (addrp == NULL) | ||
198 | continue; | ||
199 | naddr = prom_n_addr_cells(np); | ||
200 | intack = addrp[naddr-1]; | ||
201 | if (naddr > 1) | ||
202 | intack |= ((unsigned long)addrp[naddr-2]) << 32; | ||
203 | } | ||
204 | if (intack) | ||
205 | printk(KERN_DEBUG "mpic: PCI 8259 intack at 0x%016lx\n", | ||
206 | intack); | ||
207 | i8259_init(cascade, intack); | ||
208 | of_node_put(cascade); | ||
209 | set_irq_chained_handler(cascade_irq, pseries_8259_cascade); | ||
193 | } | 210 | } |
194 | 211 | ||
195 | static void pseries_lpar_enable_pmcs(void) | 212 | static void pseries_lpar_enable_pmcs(void) |
@@ -207,21 +224,67 @@ static void pseries_lpar_enable_pmcs(void) | |||
207 | get_lppaca()->pmcregs_in_use = 1; | 224 | get_lppaca()->pmcregs_in_use = 1; |
208 | } | 225 | } |
209 | 226 | ||
210 | static void __init pSeries_setup_arch(void) | 227 | #ifdef CONFIG_KEXEC |
228 | static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) | ||
211 | { | 229 | { |
212 | /* Fixup ppc_md depending on the type of interrupt controller */ | 230 | mpic_teardown_this_cpu(secondary); |
213 | if (ppc64_interrupt_controller == IC_OPEN_PIC) { | 231 | } |
214 | ppc_md.init_IRQ = pSeries_init_mpic; | ||
215 | ppc_md.get_irq = mpic_get_irq; | ||
216 | /* Allocate the mpic now, so that find_and_init_phbs() can | ||
217 | * fill the ISUs */ | ||
218 | pSeries_setup_mpic(); | ||
219 | } else | ||
220 | ppc_md.init_IRQ = xics_init_IRQ; | ||
221 | 232 | ||
233 | static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) | ||
234 | { | ||
235 | /* Don't risk a hypervisor call if we're crashing */ | ||
236 | if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { | ||
237 | unsigned long vpa = __pa(get_lppaca()); | ||
238 | |||
239 | if (unregister_vpa(hard_smp_processor_id(), vpa)) { | ||
240 | printk("VPA deregistration of cpu %u (hw_cpu_id %d) " | ||
241 | "failed\n", smp_processor_id(), | ||
242 | hard_smp_processor_id()); | ||
243 | } | ||
244 | } | ||
245 | xics_teardown_cpu(secondary); | ||
246 | } | ||
247 | #endif /* CONFIG_KEXEC */ | ||
248 | |||
249 | static void __init pseries_discover_pic(void) | ||
250 | { | ||
251 | struct device_node *np; | ||
252 | char *typep; | ||
253 | |||
254 | for (np = NULL; (np = of_find_node_by_name(np, | ||
255 | "interrupt-controller"));) { | ||
256 | typep = (char *)get_property(np, "compatible", NULL); | ||
257 | if (strstr(typep, "open-pic")) { | ||
258 | pSeries_mpic_node = of_node_get(np); | ||
259 | ppc_md.init_IRQ = pseries_mpic_init_IRQ; | ||
260 | ppc_md.get_irq = mpic_get_irq; | ||
261 | #ifdef CONFIG_KEXEC | ||
262 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; | ||
263 | #endif | ||
222 | #ifdef CONFIG_SMP | 264 | #ifdef CONFIG_SMP |
223 | smp_init_pSeries(); | 265 | smp_init_pseries_mpic(); |
224 | #endif | 266 | #endif |
267 | return; | ||
268 | } else if (strstr(typep, "ppc-xicp")) { | ||
269 | ppc_md.init_IRQ = xics_init_IRQ; | ||
270 | #ifdef CONFIG_KEXEC | ||
271 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; | ||
272 | #endif | ||
273 | #ifdef CONFIG_SMP | ||
274 | smp_init_pseries_xics(); | ||
275 | #endif | ||
276 | return; | ||
277 | } | ||
278 | } | ||
279 | printk(KERN_ERR "pSeries_discover_pic: failed to recognize" | ||
280 | " interrupt-controller\n"); | ||
281 | } | ||
282 | |||
283 | static void __init pSeries_setup_arch(void) | ||
284 | { | ||
285 | /* Discover PIC type and setup ppc_md accordingly */ | ||
286 | pseries_discover_pic(); | ||
287 | |||
225 | /* openpic global configuration register (64-bit format). */ | 288 | /* openpic global configuration register (64-bit format). */ |
226 | /* openpic Interrupt Source Unit pointer (64-bit format). */ | 289 | /* openpic Interrupt Source Unit pointer (64-bit format). */ |
227 | /* python0 facility area (mmio) (64-bit format) REAL address. */ | 290 | /* python0 facility area (mmio) (64-bit format) REAL address. */ |
@@ -273,33 +336,6 @@ static int __init pSeries_init_panel(void) | |||
273 | } | 336 | } |
274 | arch_initcall(pSeries_init_panel); | 337 | arch_initcall(pSeries_init_panel); |
275 | 338 | ||
276 | static void __init pSeries_discover_pic(void) | ||
277 | { | ||
278 | struct device_node *np; | ||
279 | char *typep; | ||
280 | |||
281 | /* | ||
282 | * Setup interrupt mapping options that are needed for finish_device_tree | ||
283 | * to properly parse the OF interrupt tree & do the virtual irq mapping | ||
284 | */ | ||
285 | __irq_offset_value = NUM_ISA_INTERRUPTS; | ||
286 | ppc64_interrupt_controller = IC_INVALID; | ||
287 | for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { | ||
288 | typep = (char *)get_property(np, "compatible", NULL); | ||
289 | if (strstr(typep, "open-pic")) { | ||
290 | ppc64_interrupt_controller = IC_OPEN_PIC; | ||
291 | break; | ||
292 | } else if (strstr(typep, "ppc-xicp")) { | ||
293 | ppc64_interrupt_controller = IC_PPC_XIC; | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | if (ppc64_interrupt_controller == IC_INVALID) | ||
298 | printk("pSeries_discover_pic: failed to recognize" | ||
299 | " interrupt-controller\n"); | ||
300 | |||
301 | } | ||
302 | |||
303 | static void pSeries_mach_cpu_die(void) | 339 | static void pSeries_mach_cpu_die(void) |
304 | { | 340 | { |
305 | local_irq_disable(); | 341 | local_irq_disable(); |
@@ -342,8 +378,6 @@ static void __init pSeries_init_early(void) | |||
342 | 378 | ||
343 | iommu_init_early_pSeries(); | 379 | iommu_init_early_pSeries(); |
344 | 380 | ||
345 | pSeries_discover_pic(); | ||
346 | |||
347 | DBG(" <- pSeries_init_early()\n"); | 381 | DBG(" <- pSeries_init_early()\n"); |
348 | } | 382 | } |
349 | 383 | ||
@@ -515,27 +549,6 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) | |||
515 | return PCI_PROBE_NORMAL; | 549 | return PCI_PROBE_NORMAL; |
516 | } | 550 | } |
517 | 551 | ||
518 | #ifdef CONFIG_KEXEC | ||
519 | static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) | ||
520 | { | ||
521 | /* Don't risk a hypervisor call if we're crashing */ | ||
522 | if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { | ||
523 | unsigned long vpa = __pa(get_lppaca()); | ||
524 | |||
525 | if (unregister_vpa(hard_smp_processor_id(), vpa)) { | ||
526 | printk("VPA deregistration of cpu %u (hw_cpu_id %d) " | ||
527 | "failed\n", smp_processor_id(), | ||
528 | hard_smp_processor_id()); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | if (ppc64_interrupt_controller == IC_OPEN_PIC) | ||
533 | mpic_teardown_this_cpu(secondary); | ||
534 | else | ||
535 | xics_teardown_cpu(secondary); | ||
536 | } | ||
537 | #endif | ||
538 | |||
539 | define_machine(pseries) { | 552 | define_machine(pseries) { |
540 | .name = "pSeries", | 553 | .name = "pSeries", |
541 | .probe = pSeries_probe, | 554 | .probe = pSeries_probe, |
@@ -560,7 +573,6 @@ define_machine(pseries) { | |||
560 | .system_reset_exception = pSeries_system_reset_exception, | 573 | .system_reset_exception = pSeries_system_reset_exception, |
561 | .machine_check_exception = pSeries_machine_check_exception, | 574 | .machine_check_exception = pSeries_machine_check_exception, |
562 | #ifdef CONFIG_KEXEC | 575 | #ifdef CONFIG_KEXEC |
563 | .kexec_cpu_down = pseries_kexec_cpu_down, | ||
564 | .machine_kexec = default_machine_kexec, | 576 | .machine_kexec = default_machine_kexec, |
565 | .machine_kexec_prepare = default_machine_kexec_prepare, | 577 | .machine_kexec_prepare = default_machine_kexec_prepare, |
566 | .machine_crash_shutdown = default_machine_crash_shutdown, | 578 | .machine_crash_shutdown = default_machine_crash_shutdown, |