aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-10-14 00:51:37 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-14 00:53:16 -0400
commitb80e6998120eecec00781658bc43702494117ea8 (patch)
tree7923d42de2f1248549b0cb35900953b78b570caf
parent10397e4069bbcc8219537e7c1e0d6a6935432156 (diff)
[SPARC64]: Use sun4v VIRQ interfaces as intended.
We were simply concatenating the devhandle and devino and using that as the cookie, which defeats the entire purpose of the VIRQ hypervisor interfaces. Now that we use physical addresses for the INO buckets, we can allocate them dynamically for VIRQs and encode the cookies as ~__pa(bucket). This allows us to test for and decode the cookie with a simple: brlz $reg1, 1f xnor $reg1, %g0, $reg2 sequence. This works because bit 64 is never set in traditional INO vectors, and it is also never set in a physical address. So xnor'ing the physical address of the bucket always gives us a negative number, and thus a unique condition we can test cheaply. Inspired by ideas from Greg Onufer. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc64/kernel/irq.c37
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S6
2 files changed, 31 insertions, 12 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 5a92851296c0..4e9537c96778 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -643,27 +643,42 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
643 643
644unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) 644unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
645{ 645{
646 unsigned long sysino, hv_err; 646 struct irq_handler_data *data;
647 unsigned int virq; 647 struct ino_bucket *bucket;
648 unsigned long hv_err, cookie;
649
650 bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
651 if (unlikely(!bucket))
652 return 0;
653
654 bucket->virt_irq = virt_irq_alloc(__irq(bucket));
655 set_irq_chip(bucket->virt_irq, &sun4v_virq);
648 656
649 BUG_ON(devhandle & devino); 657 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
658 if (unlikely(!data))
659 return 0;
650 660
651 sysino = devhandle | devino; 661 set_irq_chip_data(bucket->virt_irq, data);
652 BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
653 662
654 hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino); 663 /* Catch accidental accesses to these things. IMAP/ICLR handling
664 * is done by hypervisor calls on sun4v platforms, not by direct
665 * register accesses.
666 */
667 data->imap = ~0UL;
668 data->iclr = ~0UL;
669
670 cookie = ~__pa(bucket);
671 hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie);
655 if (hv_err) { 672 if (hv_err) {
656 prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] " 673 prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
657 "err=%lu\n", devhandle, devino, hv_err); 674 "err=%lu\n", devhandle, devino, hv_err);
658 prom_halt(); 675 prom_halt();
659 } 676 }
660 677
661 virq = sun4v_build_common(sysino, &sun4v_virq); 678 virt_to_real_irq_table[bucket->virt_irq].dev_handle = devhandle;
662 679 virt_to_real_irq_table[bucket->virt_irq].dev_ino = devino;
663 virt_to_real_irq_table[virq].dev_handle = devhandle;
664 virt_to_real_irq_table[virq].dev_ino = devino;
665 680
666 return virq; 681 return bucket->virt_irq;
667} 682}
668 683
669void ack_bad_irq(unsigned int virt_irq) 684void ack_bad_irq(unsigned int virt_irq)
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index 16d306445912..e2f8e1b4882a 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -98,13 +98,17 @@ sun4v_dev_mondo:
98 98
99 TRAP_LOAD_IRQ_WORK_PA(%g1, %g4) 99 TRAP_LOAD_IRQ_WORK_PA(%g1, %g4)
100 100
101 /* For VIRQs, cookie is encoded as ~bucket_phys_addr */
102 brlz,pt %g3, 1f
103 xnor %g3, %g0, %g4
104
101 /* Get __pa(&ivector_table[IVEC]) into %g4. */ 105 /* Get __pa(&ivector_table[IVEC]) into %g4. */
102 sethi %hi(ivector_table_pa), %g4 106 sethi %hi(ivector_table_pa), %g4
103 ldx [%g4 + %lo(ivector_table_pa)], %g4 107 ldx [%g4 + %lo(ivector_table_pa)], %g4
104 sllx %g3, 4, %g3 108 sllx %g3, 4, %g3
105 add %g4, %g3, %g4 109 add %g4, %g3, %g4
106 110
107 ldx [%g1], %g2 1111: ldx [%g1], %g2
108 stxa %g2, [%g4] ASI_PHYS_USE_EC 112 stxa %g2, [%g4] ASI_PHYS_USE_EC
109 stx %g4, [%g1] 113 stx %g4, [%g1]
110 114