[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>
This commit is contained in:
parent
10397e4069
commit
b80e699812
|
@ -643,27 +643,42 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
|
||||||
|
|
||||||
unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
|
unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
|
||||||
{
|
{
|
||||||
unsigned long sysino, hv_err;
|
struct irq_handler_data *data;
|
||||||
unsigned int virq;
|
struct ino_bucket *bucket;
|
||||||
|
unsigned long hv_err, cookie;
|
||||||
|
|
||||||
BUG_ON(devhandle & devino);
|
bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
|
||||||
|
if (unlikely(!bucket))
|
||||||
|
return 0;
|
||||||
|
|
||||||
sysino = devhandle | devino;
|
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
|
||||||
BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
|
set_irq_chip(bucket->virt_irq, &sun4v_virq);
|
||||||
|
|
||||||
hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
|
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
|
||||||
|
if (unlikely(!data))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
set_irq_chip_data(bucket->virt_irq, data);
|
||||||
|
|
||||||
|
/* Catch accidental accesses to these things. IMAP/ICLR handling
|
||||||
|
* is done by hypervisor calls on sun4v platforms, not by direct
|
||||||
|
* register accesses.
|
||||||
|
*/
|
||||||
|
data->imap = ~0UL;
|
||||||
|
data->iclr = ~0UL;
|
||||||
|
|
||||||
|
cookie = ~__pa(bucket);
|
||||||
|
hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie);
|
||||||
if (hv_err) {
|
if (hv_err) {
|
||||||
prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
|
prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
|
||||||
"err=%lu\n", devhandle, devino, hv_err);
|
"err=%lu\n", devhandle, devino, hv_err);
|
||||||
prom_halt();
|
prom_halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
virq = sun4v_build_common(sysino, &sun4v_virq);
|
virt_to_real_irq_table[bucket->virt_irq].dev_handle = devhandle;
|
||||||
|
virt_to_real_irq_table[bucket->virt_irq].dev_ino = devino;
|
||||||
|
|
||||||
virt_to_real_irq_table[virq].dev_handle = devhandle;
|
return bucket->virt_irq;
|
||||||
virt_to_real_irq_table[virq].dev_ino = devino;
|
|
||||||
|
|
||||||
return virq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ack_bad_irq(unsigned int virt_irq)
|
void ack_bad_irq(unsigned int virt_irq)
|
||||||
|
|
|
@ -98,13 +98,17 @@ sun4v_dev_mondo:
|
||||||
|
|
||||||
TRAP_LOAD_IRQ_WORK_PA(%g1, %g4)
|
TRAP_LOAD_IRQ_WORK_PA(%g1, %g4)
|
||||||
|
|
||||||
|
/* For VIRQs, cookie is encoded as ~bucket_phys_addr */
|
||||||
|
brlz,pt %g3, 1f
|
||||||
|
xnor %g3, %g0, %g4
|
||||||
|
|
||||||
/* Get __pa(&ivector_table[IVEC]) into %g4. */
|
/* Get __pa(&ivector_table[IVEC]) into %g4. */
|
||||||
sethi %hi(ivector_table_pa), %g4
|
sethi %hi(ivector_table_pa), %g4
|
||||||
ldx [%g4 + %lo(ivector_table_pa)], %g4
|
ldx [%g4 + %lo(ivector_table_pa)], %g4
|
||||||
sllx %g3, 4, %g3
|
sllx %g3, 4, %g3
|
||||||
add %g4, %g3, %g4
|
add %g4, %g3, %g4
|
||||||
|
|
||||||
ldx [%g1], %g2
|
1: ldx [%g1], %g2
|
||||||
stxa %g2, [%g4] ASI_PHYS_USE_EC
|
stxa %g2, [%g4] ASI_PHYS_USE_EC
|
||||||
stx %g4, [%g1]
|
stx %g4, [%g1]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue