diff options
author | Milton Miller <miltonm@bga.com> | 2008-10-09 21:56:30 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-10-13 01:24:17 -0400 |
commit | 0641cc91b08937578263589feb15182b9ad2b0fc (patch) | |
tree | 0aa0e9d35041faaef04ddc7eb709ec70390e6f14 /arch/powerpc/platforms/pseries | |
parent | d13f7208b211dd3613bdb04e2647081a5160d68f (diff) |
powerpc/xics: Rearrange file to group code by function
Now that xics_update_irq_servers is called only from init and hotplug
code, it becomes possible to clean up the ordering of functions in the
file, grouping them but the interfaces they implement.
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 432 |
1 files changed, 217 insertions, 215 deletions
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index c0cb356833fa..c98e3a128468 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -9,7 +9,6 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | |||
13 | #include <linux/types.h> | 12 | #include <linux/types.h> |
14 | #include <linux/threads.h> | 13 | #include <linux/threads.h> |
15 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
@@ -35,6 +34,8 @@ | |||
35 | #include "xics.h" | 34 | #include "xics.h" |
36 | #include "plpar_wrappers.h" | 35 | #include "plpar_wrappers.h" |
37 | 36 | ||
37 | static struct irq_host *xics_host; | ||
38 | |||
38 | #define XICS_IPI 2 | 39 | #define XICS_IPI 2 |
39 | #define XICS_IRQ_SPURIOUS 0 | 40 | #define XICS_IRQ_SPURIOUS 0 |
40 | 41 | ||
@@ -47,6 +48,20 @@ | |||
47 | */ | 48 | */ |
48 | #define IPI_PRIORITY 4 | 49 | #define IPI_PRIORITY 4 |
49 | 50 | ||
51 | static unsigned int default_server = 0xFF; | ||
52 | static unsigned int default_distrib_server = 0; | ||
53 | static unsigned int interrupt_server_size = 8; | ||
54 | |||
55 | /* RTAS service tokens */ | ||
56 | static int ibm_get_xive; | ||
57 | static int ibm_set_xive; | ||
58 | static int ibm_int_on; | ||
59 | static int ibm_int_off; | ||
60 | |||
61 | |||
62 | /* Direct hardware low level accessors */ | ||
63 | |||
64 | /* The part of the interrupt presentation layer that we care about */ | ||
50 | struct xics_ipl { | 65 | struct xics_ipl { |
51 | union { | 66 | union { |
52 | u32 word; | 67 | u32 word; |
@@ -65,22 +80,6 @@ struct xics_ipl { | |||
65 | 80 | ||
66 | static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; | 81 | static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; |
67 | 82 | ||
68 | static unsigned int default_server = 0xFF; | ||
69 | static unsigned int default_distrib_server = 0; | ||
70 | static unsigned int interrupt_server_size = 8; | ||
71 | |||
72 | static struct irq_host *xics_host; | ||
73 | |||
74 | /* RTAS service tokens */ | ||
75 | static int ibm_get_xive; | ||
76 | static int ibm_set_xive; | ||
77 | static int ibm_int_on; | ||
78 | static int ibm_int_off; | ||
79 | |||
80 | |||
81 | /* Direct HW low level accessors */ | ||
82 | |||
83 | |||
84 | static inline unsigned int direct_xirr_info_get(void) | 83 | static inline unsigned int direct_xirr_info_get(void) |
85 | { | 84 | { |
86 | int cpu = smp_processor_id(); | 85 | int cpu = smp_processor_id(); |
@@ -110,7 +109,6 @@ static inline void direct_qirr_info(int n_cpu, u8 value) | |||
110 | 109 | ||
111 | /* LPAR low level accessors */ | 110 | /* LPAR low level accessors */ |
112 | 111 | ||
113 | |||
114 | static inline unsigned int lpar_xirr_info_get(void) | 112 | static inline unsigned int lpar_xirr_info_get(void) |
115 | { | 113 | { |
116 | unsigned long lpar_rc; | 114 | unsigned long lpar_rc; |
@@ -152,59 +150,9 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) | |||
152 | } | 150 | } |
153 | 151 | ||
154 | 152 | ||
155 | /* High level handlers and init code */ | 153 | /* Interface to generic irq subsystem */ |
156 | |||
157 | static void xics_update_irq_servers(void) | ||
158 | { | ||
159 | int i, j; | ||
160 | struct device_node *np; | ||
161 | u32 ilen; | ||
162 | const u32 *ireg, *isize; | ||
163 | u32 hcpuid; | ||
164 | |||
165 | /* Find the server numbers for the boot cpu. */ | ||
166 | np = of_get_cpu_node(boot_cpuid, NULL); | ||
167 | BUG_ON(!np); | ||
168 | |||
169 | ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); | ||
170 | if (!ireg) { | ||
171 | of_node_put(np); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | i = ilen / sizeof(int); | ||
176 | hcpuid = get_hard_smp_processor_id(boot_cpuid); | ||
177 | |||
178 | /* Global interrupt distribution server is specified in the last | ||
179 | * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last | ||
180 | * entry fom this property for current boot cpu id and use it as | ||
181 | * default distribution server | ||
182 | */ | ||
183 | for (j = 0; j < i; j += 2) { | ||
184 | if (ireg[j] == hcpuid) { | ||
185 | default_server = hcpuid; | ||
186 | default_distrib_server = ireg[j+1]; | ||
187 | |||
188 | isize = of_get_property(np, | ||
189 | "ibm,interrupt-server#-size", NULL); | ||
190 | if (isize) | ||
191 | interrupt_server_size = *isize; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | of_node_put(np); | ||
196 | } | ||
197 | 154 | ||
198 | #ifdef CONFIG_SMP | 155 | #ifdef CONFIG_SMP |
199 | /* | ||
200 | * XICS only has a single IPI, so encode the messages per CPU | ||
201 | */ | ||
202 | struct xics_ipi_struct { | ||
203 | unsigned long value; | ||
204 | } ____cacheline_aligned; | ||
205 | |||
206 | static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; | ||
207 | |||
208 | static int get_irq_server(unsigned int virq, unsigned int strict_check) | 156 | static int get_irq_server(unsigned int virq, unsigned int strict_check) |
209 | { | 157 | { |
210 | int server; | 158 | int server; |
@@ -239,7 +187,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) | |||
239 | } | 187 | } |
240 | #endif | 188 | #endif |
241 | 189 | ||
242 | |||
243 | static void xics_unmask_irq(unsigned int virq) | 190 | static void xics_unmask_irq(unsigned int virq) |
244 | { | 191 | { |
245 | unsigned int irq; | 192 | unsigned int irq; |
@@ -273,6 +220,13 @@ static void xics_unmask_irq(unsigned int virq) | |||
273 | } | 220 | } |
274 | } | 221 | } |
275 | 222 | ||
223 | static unsigned int xics_startup(unsigned int virq) | ||
224 | { | ||
225 | /* unmask it */ | ||
226 | xics_unmask_irq(virq); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
276 | static void xics_mask_real_irq(unsigned int irq) | 230 | static void xics_mask_real_irq(unsigned int irq) |
277 | { | 231 | { |
278 | int call_status; | 232 | int call_status; |
@@ -309,28 +263,10 @@ static void xics_mask_irq(unsigned int virq) | |||
309 | xics_mask_real_irq(irq); | 263 | xics_mask_real_irq(irq); |
310 | } | 264 | } |
311 | 265 | ||
312 | static unsigned int xics_startup(unsigned int virq) | 266 | static void xics_mask_unknown_vec(unsigned int vec) |
313 | { | ||
314 | /* unmask it */ | ||
315 | xics_unmask_irq(virq); | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static void xics_eoi_direct(unsigned int virq) | ||
320 | { | ||
321 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | ||
322 | |||
323 | iosync(); | ||
324 | direct_xirr_info_set((0xff << 24) | irq); | ||
325 | } | ||
326 | |||
327 | |||
328 | static void xics_eoi_lpar(unsigned int virq) | ||
329 | { | 267 | { |
330 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | 268 | printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); |
331 | 269 | xics_mask_real_irq(vec); | |
332 | iosync(); | ||
333 | lpar_xirr_info_set((0xff << 24) | irq); | ||
334 | } | 270 | } |
335 | 271 | ||
336 | static inline unsigned int xics_xirr_vector(unsigned int xirr) | 272 | static inline unsigned int xics_xirr_vector(unsigned int xirr) |
@@ -342,12 +278,6 @@ static inline unsigned int xics_xirr_vector(unsigned int xirr) | |||
342 | return xirr & 0x00ffffff; | 278 | return xirr & 0x00ffffff; |
343 | } | 279 | } |
344 | 280 | ||
345 | static void xics_mask_unknown_vec(unsigned int vec) | ||
346 | { | ||
347 | printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); | ||
348 | xics_mask_real_irq(vec); | ||
349 | } | ||
350 | |||
351 | static unsigned int xics_get_irq_direct(void) | 281 | static unsigned int xics_get_irq_direct(void) |
352 | { | 282 | { |
353 | unsigned int xirr = direct_xirr_info_get(); | 283 | unsigned int xirr = direct_xirr_info_get(); |
@@ -390,91 +320,20 @@ static unsigned int xics_get_irq_lpar(void) | |||
390 | return NO_IRQ; | 320 | return NO_IRQ; |
391 | } | 321 | } |
392 | 322 | ||
393 | #ifdef CONFIG_SMP | 323 | static void xics_eoi_direct(unsigned int virq) |
394 | static irqreturn_t xics_ipi_dispatch(int cpu) | ||
395 | { | ||
396 | WARN_ON(cpu_is_offline(cpu)); | ||
397 | |||
398 | while (xics_ipi_message[cpu].value) { | ||
399 | if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, | ||
400 | &xics_ipi_message[cpu].value)) { | ||
401 | mb(); | ||
402 | smp_message_recv(PPC_MSG_CALL_FUNCTION); | ||
403 | } | ||
404 | if (test_and_clear_bit(PPC_MSG_RESCHEDULE, | ||
405 | &xics_ipi_message[cpu].value)) { | ||
406 | mb(); | ||
407 | smp_message_recv(PPC_MSG_RESCHEDULE); | ||
408 | } | ||
409 | if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, | ||
410 | &xics_ipi_message[cpu].value)) { | ||
411 | mb(); | ||
412 | smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); | ||
413 | } | ||
414 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | ||
415 | if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, | ||
416 | &xics_ipi_message[cpu].value)) { | ||
417 | mb(); | ||
418 | smp_message_recv(PPC_MSG_DEBUGGER_BREAK); | ||
419 | } | ||
420 | #endif | ||
421 | } | ||
422 | return IRQ_HANDLED; | ||
423 | } | ||
424 | |||
425 | static inline void smp_xics_do_message(int cpu, int msg) | ||
426 | { | ||
427 | set_bit(msg, &xics_ipi_message[cpu].value); | ||
428 | mb(); | ||
429 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
430 | lpar_qirr_info(cpu, IPI_PRIORITY); | ||
431 | else | ||
432 | direct_qirr_info(cpu, IPI_PRIORITY); | ||
433 | } | ||
434 | |||
435 | void smp_xics_message_pass(int target, int msg) | ||
436 | { | ||
437 | unsigned int i; | ||
438 | |||
439 | if (target < NR_CPUS) { | ||
440 | smp_xics_do_message(target, msg); | ||
441 | } else { | ||
442 | for_each_online_cpu(i) { | ||
443 | if (target == MSG_ALL_BUT_SELF | ||
444 | && i == smp_processor_id()) | ||
445 | continue; | ||
446 | smp_xics_do_message(i, msg); | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | |||
451 | |||
452 | static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) | ||
453 | { | 324 | { |
454 | int cpu = smp_processor_id(); | 325 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
455 | |||
456 | direct_qirr_info(cpu, 0xff); | ||
457 | 326 | ||
458 | return xics_ipi_dispatch(cpu); | 327 | iosync(); |
328 | direct_xirr_info_set((0xff << 24) | irq); | ||
459 | } | 329 | } |
460 | 330 | ||
461 | static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) | 331 | static void xics_eoi_lpar(unsigned int virq) |
462 | { | 332 | { |
463 | int cpu = smp_processor_id(); | 333 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
464 | |||
465 | lpar_qirr_info(cpu, 0xff); | ||
466 | |||
467 | return xics_ipi_dispatch(cpu); | ||
468 | } | ||
469 | #endif /* CONFIG_SMP */ | ||
470 | 334 | ||
471 | static void xics_set_cpu_priority(unsigned char cppr) | ||
472 | { | ||
473 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
474 | lpar_cppr_info(cppr); | ||
475 | else | ||
476 | direct_cppr_info(cppr); | ||
477 | iosync(); | 335 | iosync(); |
336 | lpar_xirr_info_set((0xff << 24) | irq); | ||
478 | } | 337 | } |
479 | 338 | ||
480 | static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | 339 | static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) |
@@ -519,22 +378,6 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | |||
519 | } | 378 | } |
520 | } | 379 | } |
521 | 380 | ||
522 | void xics_setup_cpu(void) | ||
523 | { | ||
524 | xics_set_cpu_priority(0xff); | ||
525 | |||
526 | /* | ||
527 | * Put the calling processor into the GIQ. This is really only | ||
528 | * necessary from a secondary thread as the OF start-cpu interface | ||
529 | * performs this function for us on primary threads. | ||
530 | * | ||
531 | * XXX: undo of teardown on kexec needs this too, as may hotplug | ||
532 | */ | ||
533 | rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, | ||
534 | (1UL << interrupt_server_size) - 1 - default_distrib_server, 1); | ||
535 | } | ||
536 | |||
537 | |||
538 | static struct irq_chip xics_pic_direct = { | 381 | static struct irq_chip xics_pic_direct = { |
539 | .typename = " XICS ", | 382 | .typename = " XICS ", |
540 | .startup = xics_startup, | 383 | .startup = xics_startup, |
@@ -544,7 +387,6 @@ static struct irq_chip xics_pic_direct = { | |||
544 | .set_affinity = xics_set_affinity | 387 | .set_affinity = xics_set_affinity |
545 | }; | 388 | }; |
546 | 389 | ||
547 | |||
548 | static struct irq_chip xics_pic_lpar = { | 390 | static struct irq_chip xics_pic_lpar = { |
549 | .typename = " XICS ", | 391 | .typename = " XICS ", |
550 | .startup = xics_startup, | 392 | .startup = xics_startup, |
@@ -554,6 +396,9 @@ static struct irq_chip xics_pic_lpar = { | |||
554 | .set_affinity = xics_set_affinity | 396 | .set_affinity = xics_set_affinity |
555 | }; | 397 | }; |
556 | 398 | ||
399 | |||
400 | /* Interface to arch irq controller subsystem layer */ | ||
401 | |||
557 | /* Points to the irq_chip we're actually using */ | 402 | /* Points to the irq_chip we're actually using */ |
558 | static struct irq_chip *xics_irq_chip; | 403 | static struct irq_chip *xics_irq_chip; |
559 | 404 | ||
@@ -613,6 +458,169 @@ static void __init xics_init_host(void) | |||
613 | irq_set_default_host(xics_host); | 458 | irq_set_default_host(xics_host); |
614 | } | 459 | } |
615 | 460 | ||
461 | |||
462 | /* Inter-processor interrupt support */ | ||
463 | |||
464 | #ifdef CONFIG_SMP | ||
465 | /* | ||
466 | * XICS only has a single IPI, so encode the messages per CPU | ||
467 | */ | ||
468 | struct xics_ipi_struct { | ||
469 | unsigned long value; | ||
470 | } ____cacheline_aligned; | ||
471 | |||
472 | static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; | ||
473 | |||
474 | static inline void smp_xics_do_message(int cpu, int msg) | ||
475 | { | ||
476 | set_bit(msg, &xics_ipi_message[cpu].value); | ||
477 | mb(); | ||
478 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
479 | lpar_qirr_info(cpu, IPI_PRIORITY); | ||
480 | else | ||
481 | direct_qirr_info(cpu, IPI_PRIORITY); | ||
482 | } | ||
483 | |||
484 | void smp_xics_message_pass(int target, int msg) | ||
485 | { | ||
486 | unsigned int i; | ||
487 | |||
488 | if (target < NR_CPUS) { | ||
489 | smp_xics_do_message(target, msg); | ||
490 | } else { | ||
491 | for_each_online_cpu(i) { | ||
492 | if (target == MSG_ALL_BUT_SELF | ||
493 | && i == smp_processor_id()) | ||
494 | continue; | ||
495 | smp_xics_do_message(i, msg); | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | static irqreturn_t xics_ipi_dispatch(int cpu) | ||
501 | { | ||
502 | WARN_ON(cpu_is_offline(cpu)); | ||
503 | |||
504 | while (xics_ipi_message[cpu].value) { | ||
505 | if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, | ||
506 | &xics_ipi_message[cpu].value)) { | ||
507 | mb(); | ||
508 | smp_message_recv(PPC_MSG_CALL_FUNCTION); | ||
509 | } | ||
510 | if (test_and_clear_bit(PPC_MSG_RESCHEDULE, | ||
511 | &xics_ipi_message[cpu].value)) { | ||
512 | mb(); | ||
513 | smp_message_recv(PPC_MSG_RESCHEDULE); | ||
514 | } | ||
515 | if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, | ||
516 | &xics_ipi_message[cpu].value)) { | ||
517 | mb(); | ||
518 | smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); | ||
519 | } | ||
520 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | ||
521 | if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, | ||
522 | &xics_ipi_message[cpu].value)) { | ||
523 | mb(); | ||
524 | smp_message_recv(PPC_MSG_DEBUGGER_BREAK); | ||
525 | } | ||
526 | #endif | ||
527 | } | ||
528 | return IRQ_HANDLED; | ||
529 | } | ||
530 | |||
531 | static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) | ||
532 | { | ||
533 | int cpu = smp_processor_id(); | ||
534 | |||
535 | direct_qirr_info(cpu, 0xff); | ||
536 | |||
537 | return xics_ipi_dispatch(cpu); | ||
538 | } | ||
539 | |||
540 | static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) | ||
541 | { | ||
542 | int cpu = smp_processor_id(); | ||
543 | |||
544 | lpar_qirr_info(cpu, 0xff); | ||
545 | |||
546 | return xics_ipi_dispatch(cpu); | ||
547 | } | ||
548 | |||
549 | static void xics_request_ipi(void) | ||
550 | { | ||
551 | unsigned int ipi; | ||
552 | int rc; | ||
553 | |||
554 | ipi = irq_create_mapping(xics_host, XICS_IPI); | ||
555 | BUG_ON(ipi == NO_IRQ); | ||
556 | |||
557 | /* | ||
558 | * IPIs are marked IRQF_DISABLED as they must run with irqs | ||
559 | * disabled | ||
560 | */ | ||
561 | set_irq_handler(ipi, handle_percpu_irq); | ||
562 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
563 | rc = request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED, | ||
564 | "IPI", NULL); | ||
565 | else | ||
566 | rc = request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED, | ||
567 | "IPI", NULL); | ||
568 | BUG_ON(rc); | ||
569 | } | ||
570 | |||
571 | int __init smp_xics_probe(void) | ||
572 | { | ||
573 | xics_request_ipi(); | ||
574 | |||
575 | return cpus_weight(cpu_possible_map); | ||
576 | } | ||
577 | |||
578 | #endif /* CONFIG_SMP */ | ||
579 | |||
580 | |||
581 | /* Initialization */ | ||
582 | |||
583 | static void xics_update_irq_servers(void) | ||
584 | { | ||
585 | int i, j; | ||
586 | struct device_node *np; | ||
587 | u32 ilen; | ||
588 | const u32 *ireg, *isize; | ||
589 | u32 hcpuid; | ||
590 | |||
591 | /* Find the server numbers for the boot cpu. */ | ||
592 | np = of_get_cpu_node(boot_cpuid, NULL); | ||
593 | BUG_ON(!np); | ||
594 | |||
595 | ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); | ||
596 | if (!ireg) { | ||
597 | of_node_put(np); | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | i = ilen / sizeof(int); | ||
602 | hcpuid = get_hard_smp_processor_id(boot_cpuid); | ||
603 | |||
604 | /* Global interrupt distribution server is specified in the last | ||
605 | * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last | ||
606 | * entry fom this property for current boot cpu id and use it as | ||
607 | * default distribution server | ||
608 | */ | ||
609 | for (j = 0; j < i; j += 2) { | ||
610 | if (ireg[j] == hcpuid) { | ||
611 | default_server = hcpuid; | ||
612 | default_distrib_server = ireg[j+1]; | ||
613 | |||
614 | isize = of_get_property(np, | ||
615 | "ibm,interrupt-server#-size", NULL); | ||
616 | if (isize) | ||
617 | interrupt_server_size = *isize; | ||
618 | } | ||
619 | } | ||
620 | |||
621 | of_node_put(np); | ||
622 | } | ||
623 | |||
616 | static void __init xics_map_one_cpu(int hw_id, unsigned long addr, | 624 | static void __init xics_map_one_cpu(int hw_id, unsigned long addr, |
617 | unsigned long size) | 625 | unsigned long size) |
618 | { | 626 | { |
@@ -716,39 +724,33 @@ void __init xics_init_IRQ(void) | |||
716 | ppc64_boot_msg(0x21, "XICS Done"); | 724 | ppc64_boot_msg(0x21, "XICS Done"); |
717 | } | 725 | } |
718 | 726 | ||
727 | /* Cpu startup, shutdown, and hotplug */ | ||
719 | 728 | ||
720 | #ifdef CONFIG_SMP | 729 | static void xics_set_cpu_priority(unsigned char cppr) |
721 | static void xics_request_ipi(void) | ||
722 | { | 730 | { |
723 | unsigned int ipi; | ||
724 | int rc; | ||
725 | |||
726 | ipi = irq_create_mapping(xics_host, XICS_IPI); | ||
727 | BUG_ON(ipi == NO_IRQ); | ||
728 | |||
729 | /* | ||
730 | * IPIs are marked IRQF_DISABLED as they must run with irqs | ||
731 | * disabled | ||
732 | */ | ||
733 | set_irq_handler(ipi, handle_percpu_irq); | ||
734 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 731 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
735 | rc = request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED, | 732 | lpar_cppr_info(cppr); |
736 | "IPI", NULL); | ||
737 | else | 733 | else |
738 | rc = request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED, | 734 | direct_cppr_info(cppr); |
739 | "IPI", NULL); | 735 | iosync(); |
740 | BUG_ON(rc); | ||
741 | } | 736 | } |
742 | 737 | ||
743 | int __init smp_xics_probe(void) | 738 | |
739 | void xics_setup_cpu(void) | ||
744 | { | 740 | { |
745 | xics_request_ipi(); | 741 | xics_set_cpu_priority(0xff); |
746 | 742 | ||
747 | return cpus_weight(cpu_possible_map); | 743 | /* |
744 | * Put the calling processor into the GIQ. This is really only | ||
745 | * necessary from a secondary thread as the OF start-cpu interface | ||
746 | * performs this function for us on primary threads. | ||
747 | * | ||
748 | * XXX: undo of teardown on kexec needs this too, as may hotplug | ||
749 | */ | ||
750 | rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, | ||
751 | (1UL << interrupt_server_size) - 1 - default_distrib_server, 1); | ||
748 | } | 752 | } |
749 | 753 | ||
750 | #endif /* CONFIG_SMP */ | ||
751 | |||
752 | void xics_teardown_cpu(void) | 754 | void xics_teardown_cpu(void) |
753 | { | 755 | { |
754 | int cpu = smp_processor_id(); | 756 | int cpu = smp_processor_id(); |