aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries
diff options
context:
space:
mode:
authorMilton Miller <miltonm@bga.com>2008-10-09 21:56:30 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-13 01:24:17 -0400
commit0641cc91b08937578263589feb15182b9ad2b0fc (patch)
tree0aa0e9d35041faaef04ddc7eb709ec70390e6f14 /arch/powerpc/platforms/pseries
parentd13f7208b211dd3613bdb04e2647081a5160d68f (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.c432
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
37static 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
51static unsigned int default_server = 0xFF;
52static unsigned int default_distrib_server = 0;
53static unsigned int interrupt_server_size = 8;
54
55/* RTAS service tokens */
56static int ibm_get_xive;
57static int ibm_set_xive;
58static int ibm_int_on;
59static 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 */
50struct xics_ipl { 65struct xics_ipl {
51 union { 66 union {
52 u32 word; 67 u32 word;
@@ -65,22 +80,6 @@ struct xics_ipl {
65 80
66static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; 81static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];
67 82
68static unsigned int default_server = 0xFF;
69static unsigned int default_distrib_server = 0;
70static unsigned int interrupt_server_size = 8;
71
72static struct irq_host *xics_host;
73
74/* RTAS service tokens */
75static int ibm_get_xive;
76static int ibm_set_xive;
77static int ibm_int_on;
78static int ibm_int_off;
79
80
81/* Direct HW low level accessors */
82
83
84static inline unsigned int direct_xirr_info_get(void) 83static 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
114static inline unsigned int lpar_xirr_info_get(void) 112static 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
157static 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 */
202struct xics_ipi_struct {
203 unsigned long value;
204 } ____cacheline_aligned;
205
206static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
207
208static int get_irq_server(unsigned int virq, unsigned int strict_check) 156static 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
243static void xics_unmask_irq(unsigned int virq) 190static 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
223static unsigned int xics_startup(unsigned int virq)
224{
225 /* unmask it */
226 xics_unmask_irq(virq);
227 return 0;
228}
229
276static void xics_mask_real_irq(unsigned int irq) 230static 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
312static unsigned int xics_startup(unsigned int virq) 266static void xics_mask_unknown_vec(unsigned int vec)
313{
314 /* unmask it */
315 xics_unmask_irq(virq);
316 return 0;
317}
318
319static 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
328static 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
336static inline unsigned int xics_xirr_vector(unsigned int xirr) 272static 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
345static 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
351static unsigned int xics_get_irq_direct(void) 281static 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 323static void xics_eoi_direct(unsigned int virq)
394static 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
425static 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
435void 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
452static 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
461static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) 331static 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
471static 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
480static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) 339static 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
522void 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
538static struct irq_chip xics_pic_direct = { 381static 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
548static struct irq_chip xics_pic_lpar = { 390static 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 */
558static struct irq_chip *xics_irq_chip; 403static 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 */
468struct xics_ipi_struct {
469 unsigned long value;
470 } ____cacheline_aligned;
471
472static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
473
474static 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
484void 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
500static 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
531static 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
540static 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
549static 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
571int __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
583static 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
616static void __init xics_map_one_cpu(int hw_id, unsigned long addr, 624static 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 729static void xics_set_cpu_priority(unsigned char cppr)
721static 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
743int __init smp_xics_probe(void) 738
739void 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
752void xics_teardown_cpu(void) 754void xics_teardown_cpu(void)
753{ 755{
754 int cpu = smp_processor_id(); 756 int cpu = smp_processor_id();