aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/irq.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-10-11 06:16:13 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-14 00:53:13 -0400
commit759f89e03c9e5656ff18c02e21b439506f7c0cdc (patch)
tree6e7703c0672210f2c0a1168de161d15c7470081d /arch/sparc64/kernel/irq.c
parenta2cd15586e630b0870bf34783568d83901890743 (diff)
[SPARC64]: Consolidate MSI support code.
This also makes us use the MSI queues correctly. Each MSI queue is serviced by a normal sun4u/sun4v INO interrupt handler. This handler runs the MSI queue and dispatches the virtual interrupts indicated by arriving MSIs in that MSI queue. All of the common logic is placed in pci_msi.c, with callbacks to handle the PCI controller specific aspects of the operations. This common infrastructure will make it much easier to add MSG support. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r--arch/sparc64/kernel/irq.c230
1 files changed, 23 insertions, 207 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 7f5a4c77e3e4..045ab27d4271 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -21,7 +21,6 @@
21#include <linux/seq_file.h> 21#include <linux/seq_file.h>
22#include <linux/bootmem.h> 22#include <linux/bootmem.h>
23#include <linux/irq.h> 23#include <linux/irq.h>
24#include <linux/msi.h>
25 24
26#include <asm/ptrace.h> 25#include <asm/ptrace.h>
27#include <asm/processor.h> 26#include <asm/processor.h>
@@ -92,39 +91,46 @@ static struct {
92 unsigned int dev_handle; 91 unsigned int dev_handle;
93 unsigned int dev_ino; 92 unsigned int dev_ino;
94} virt_to_real_irq_table[NR_IRQS]; 93} virt_to_real_irq_table[NR_IRQS];
94static DEFINE_SPINLOCK(virt_irq_alloc_lock);
95 95
96static unsigned char virt_irq_alloc(unsigned int real_irq) 96unsigned char virt_irq_alloc(unsigned int real_irq)
97{ 97{
98 unsigned long flags;
98 unsigned char ent; 99 unsigned char ent;
99 100
100 BUILD_BUG_ON(NR_IRQS >= 256); 101 BUILD_BUG_ON(NR_IRQS >= 256);
101 102
103 spin_lock_irqsave(&virt_irq_alloc_lock, flags);
104
102 for (ent = 1; ent < NR_IRQS; ent++) { 105 for (ent = 1; ent < NR_IRQS; ent++) {
103 if (!virt_to_real_irq_table[ent].irq) 106 if (!virt_to_real_irq_table[ent].irq)
104 break; 107 break;
105 } 108 }
106 if (ent >= NR_IRQS) { 109 if (ent >= NR_IRQS) {
107 printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); 110 printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
108 return 0; 111 ent = 0;
112 } else {
113 virt_to_real_irq_table[ent].irq = real_irq;
109 } 114 }
110 115
111 virt_to_real_irq_table[ent].irq = real_irq; 116 spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
112 117
113 return ent; 118 return ent;
114} 119}
115 120
116#ifdef CONFIG_PCI_MSI 121#ifdef CONFIG_PCI_MSI
117static void virt_irq_free(unsigned int virt_irq) 122void virt_irq_free(unsigned int virt_irq)
118{ 123{
119 unsigned int real_irq; 124 unsigned long flags;
120 125
121 if (virt_irq >= NR_IRQS) 126 if (virt_irq >= NR_IRQS)
122 return; 127 return;
123 128
124 real_irq = virt_to_real_irq_table[virt_irq].irq; 129 spin_lock_irqsave(&virt_irq_alloc_lock, flags);
130
125 virt_to_real_irq_table[virt_irq].irq = 0; 131 virt_to_real_irq_table[virt_irq].irq = 0;
126 132
127 __bucket(real_irq)->virt_irq = 0; 133 spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
128} 134}
129#endif 135#endif
130 136
@@ -217,27 +223,8 @@ struct irq_handler_data {
217 void (*pre_handler)(unsigned int, void *, void *); 223 void (*pre_handler)(unsigned int, void *, void *);
218 void *pre_handler_arg1; 224 void *pre_handler_arg1;
219 void *pre_handler_arg2; 225 void *pre_handler_arg2;
220
221 u32 msi;
222}; 226};
223 227
224void sparc64_set_msi(unsigned int virt_irq, u32 msi)
225{
226 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
227
228 if (data)
229 data->msi = msi;
230}
231
232u32 sparc64_get_msi(unsigned int virt_irq)
233{
234 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
235
236 if (data)
237 return data->msi;
238 return 0xffffffff;
239}
240
241static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) 228static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq)
242{ 229{
243 unsigned int real_irq = virt_to_real_irq(virt_irq); 230 unsigned int real_irq = virt_to_real_irq(virt_irq);
@@ -405,32 +392,6 @@ static void sun4v_irq_disable(unsigned int virt_irq)
405 } 392 }
406} 393}
407 394
408#ifdef CONFIG_PCI_MSI
409static void sun4u_msi_enable(unsigned int virt_irq)
410{
411 sun4u_irq_enable(virt_irq);
412 unmask_msi_irq(virt_irq);
413}
414
415static void sun4u_msi_disable(unsigned int virt_irq)
416{
417 mask_msi_irq(virt_irq);
418 sun4u_irq_disable(virt_irq);
419}
420
421static void sun4v_msi_enable(unsigned int virt_irq)
422{
423 sun4v_irq_enable(virt_irq);
424 unmask_msi_irq(virt_irq);
425}
426
427static void sun4v_msi_disable(unsigned int virt_irq)
428{
429 mask_msi_irq(virt_irq);
430 sun4v_irq_disable(virt_irq);
431}
432#endif
433
434static void sun4v_irq_end(unsigned int virt_irq) 395static void sun4v_irq_end(unsigned int virt_irq)
435{ 396{
436 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 397 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
@@ -585,39 +546,6 @@ static struct irq_chip sun4v_irq = {
585 .set_affinity = sun4v_set_affinity, 546 .set_affinity = sun4v_set_affinity,
586}; 547};
587 548
588static struct irq_chip sun4v_irq_ack = {
589 .typename = "sun4v+ack",
590 .enable = sun4v_irq_enable,
591 .disable = sun4v_irq_disable,
592 .ack = run_pre_handler,
593 .end = sun4v_irq_end,
594 .set_affinity = sun4v_set_affinity,
595};
596
597#ifdef CONFIG_PCI_MSI
598static struct irq_chip sun4u_msi = {
599 .typename = "sun4u+msi",
600 .mask = mask_msi_irq,
601 .unmask = unmask_msi_irq,
602 .enable = sun4u_msi_enable,
603 .disable = sun4u_msi_disable,
604 .ack = run_pre_handler,
605 .end = sun4u_irq_end,
606 .set_affinity = sun4u_set_affinity,
607};
608
609static struct irq_chip sun4v_msi = {
610 .typename = "sun4v+msi",
611 .mask = mask_msi_irq,
612 .unmask = unmask_msi_irq,
613 .enable = sun4v_msi_enable,
614 .disable = sun4v_msi_disable,
615 .ack = run_pre_handler,
616 .end = sun4v_irq_end,
617 .set_affinity = sun4v_set_affinity,
618};
619#endif
620
621static struct irq_chip sun4v_virq = { 549static struct irq_chip sun4v_virq = {
622 .typename = "vsun4v", 550 .typename = "vsun4v",
623 .enable = sun4v_virq_enable, 551 .enable = sun4v_virq_enable,
@@ -626,42 +554,27 @@ static struct irq_chip sun4v_virq = {
626 .set_affinity = sun4v_virt_set_affinity, 554 .set_affinity = sun4v_virt_set_affinity,
627}; 555};
628 556
629static struct irq_chip sun4v_virq_ack = {
630 .typename = "vsun4v+ack",
631 .enable = sun4v_virq_enable,
632 .disable = sun4v_virq_disable,
633 .ack = run_pre_handler,
634 .end = sun4v_virq_end,
635 .set_affinity = sun4v_virt_set_affinity,
636};
637
638void irq_install_pre_handler(int virt_irq, 557void irq_install_pre_handler(int virt_irq,
639 void (*func)(unsigned int, void *, void *), 558 void (*func)(unsigned int, void *, void *),
640 void *arg1, void *arg2) 559 void *arg1, void *arg2)
641{ 560{
642 struct irq_handler_data *data = get_irq_chip_data(virt_irq); 561 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
643 struct irq_chip *chip; 562 struct irq_chip *chip = get_irq_chip(virt_irq);
563
564 if (WARN_ON(chip == &sun4v_irq || chip == &sun4v_virq)) {
565 printk(KERN_ERR "IRQ: Trying to install pre-handler on "
566 "sun4v irq %u\n", virt_irq);
567 return;
568 }
644 569
645 data->pre_handler = func; 570 data->pre_handler = func;
646 data->pre_handler_arg1 = arg1; 571 data->pre_handler_arg1 = arg1;
647 data->pre_handler_arg2 = arg2; 572 data->pre_handler_arg2 = arg2;
648 573
649 chip = get_irq_chip(virt_irq); 574 if (chip == &sun4u_irq_ack)
650 if (chip == &sun4u_irq_ack ||
651 chip == &sun4v_irq_ack ||
652 chip == &sun4v_virq_ack
653#ifdef CONFIG_PCI_MSI
654 || chip == &sun4u_msi
655 || chip == &sun4v_msi
656#endif
657 )
658 return; 575 return;
659 576
660 chip = (chip == &sun4u_irq ? 577 set_irq_chip(virt_irq, &sun4u_irq_ack);
661 &sun4u_irq_ack :
662 (chip == &sun4v_irq ?
663 &sun4v_irq_ack : &sun4v_virq_ack));
664 set_irq_chip(virt_irq, chip);
665} 578}
666 579
667unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) 580unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
@@ -765,103 +678,6 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
765 return virq; 678 return virq;
766} 679}
767 680
768#ifdef CONFIG_PCI_MSI
769unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
770 unsigned int msi_start, unsigned int msi_end)
771{
772 struct ino_bucket *bucket;
773 struct irq_handler_data *data;
774 unsigned long sysino;
775 unsigned int devino;
776
777 BUG_ON(tlb_type != hypervisor);
778
779 /* Find a free devino in the given range. */
780 for (devino = msi_start; devino < msi_end; devino++) {
781 sysino = sun4v_devino_to_sysino(devhandle, devino);
782 bucket = &ivector_table[sysino];
783 if (!bucket->virt_irq)
784 break;
785 }
786 if (devino >= msi_end)
787 return -ENOSPC;
788
789 sysino = sun4v_devino_to_sysino(devhandle, devino);
790 bucket = &ivector_table[sysino];
791 bucket->virt_irq = virt_irq_alloc(__irq(bucket));
792 *virt_irq_p = bucket->virt_irq;
793 set_irq_chip(bucket->virt_irq, &sun4v_msi);
794
795 data = get_irq_chip_data(bucket->virt_irq);
796 if (unlikely(data))
797 return devino;
798
799 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
800 if (unlikely(!data)) {
801 virt_irq_free(*virt_irq_p);
802 return -ENOMEM;
803 }
804 set_irq_chip_data(bucket->virt_irq, data);
805
806 data->imap = ~0UL;
807 data->iclr = ~0UL;
808
809 return devino;
810}
811
812void sun4v_destroy_msi(unsigned int virt_irq)
813{
814 virt_irq_free(virt_irq);
815}
816
817unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
818 unsigned int msi_start, unsigned int msi_end,
819 unsigned long imap_base, unsigned long iclr_base)
820{
821 struct ino_bucket *bucket;
822 struct irq_handler_data *data;
823 unsigned long sysino;
824 unsigned int devino;
825
826 /* Find a free devino in the given range. */
827 for (devino = msi_start; devino < msi_end; devino++) {
828 sysino = (portid << 6) | devino;
829 bucket = &ivector_table[sysino];
830 if (!bucket->virt_irq)
831 break;
832 }
833 if (devino >= msi_end)
834 return -ENOSPC;
835
836 sysino = (portid << 6) | devino;
837 bucket = &ivector_table[sysino];
838 bucket->virt_irq = virt_irq_alloc(__irq(bucket));
839 *virt_irq_p = bucket->virt_irq;
840 set_irq_chip(bucket->virt_irq, &sun4u_msi);
841
842 data = get_irq_chip_data(bucket->virt_irq);
843 if (unlikely(data))
844 return devino;
845
846 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
847 if (unlikely(!data)) {
848 virt_irq_free(*virt_irq_p);
849 return -ENOMEM;
850 }
851 set_irq_chip_data(bucket->virt_irq, data);
852
853 data->imap = (imap_base + (devino * 0x8UL));
854 data->iclr = (iclr_base + (devino * 0x8UL));
855
856 return devino;
857}
858
859void sun4u_destroy_msi(unsigned int virt_irq)
860{
861 virt_irq_free(virt_irq);
862}
863#endif
864
865void ack_bad_irq(unsigned int virt_irq) 681void ack_bad_irq(unsigned int virt_irq)
866{ 682{
867 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 683 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);