Skip to content

Commit

Permalink
[SPARC64]: Use sun4v VIRQ interfaces as intended.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David S. Miller committed Oct 14, 2007
1 parent 10397e4 commit b80e699
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 12 deletions.
37 changes: 26 additions & 11 deletions arch/sparc64/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 long sysino, hv_err;
unsigned int virq;
struct irq_handler_data *data;
struct ino_bucket *bucket;
unsigned long hv_err, cookie;

bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
if (unlikely(!bucket))
return 0;

bucket->virt_irq = virt_irq_alloc(__irq(bucket));
set_irq_chip(bucket->virt_irq, &sun4v_virq);

BUG_ON(devhandle & devino);
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
if (unlikely(!data))
return 0;

sysino = devhandle | devino;
BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
set_irq_chip_data(bucket->virt_irq, data);

hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
/* 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) {
prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
"err=%lu\n", devhandle, devino, hv_err);
prom_halt();
}

virq = sun4v_build_common(sysino, &sun4v_virq);

virt_to_real_irq_table[virq].dev_handle = devhandle;
virt_to_real_irq_table[virq].dev_ino = devino;
virt_to_real_irq_table[bucket->virt_irq].dev_handle = devhandle;
virt_to_real_irq_table[bucket->virt_irq].dev_ino = devino;

return virq;
return bucket->virt_irq;
}

void ack_bad_irq(unsigned int virt_irq)
Expand Down
6 changes: 5 additions & 1 deletion arch/sparc64/kernel/sun4v_ivec.S
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,17 @@ sun4v_dev_mondo:

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. */
sethi %hi(ivector_table_pa), %g4
ldx [%g4 + %lo(ivector_table_pa)], %g4
sllx %g3, 4, %g3
add %g4, %g3, %g4

ldx [%g1], %g2
1: ldx [%g1], %g2
stxa %g2, [%g4] ASI_PHYS_USE_EC
stx %g4, [%g1]

Expand Down

0 comments on commit b80e699

Please sign in to comment.