diff options
author | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2010-07-01 12:08:14 -0400 |
---|---|---|
committer | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2010-10-22 16:25:40 -0400 |
commit | 7a043f119c0e4b460306f868d9638ac55c6afa6f (patch) | |
tree | 6642df09a1bf509ee553bef0ab9e6032ba832271 /drivers | |
parent | 67ba37293e938208795d6a3562201bdb0cf43393 (diff) |
xen: support pirq != irq
PHYSDEVOP_map_pirq might return a pirq different from what we asked if
we are running as an HVM guest, so we need to be able to support pirqs
that are different from linux irqs.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/xen/events.c | 64 |
1 files changed, 48 insertions, 16 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 3df53de6b43a..018a96275ee4 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -90,6 +90,7 @@ struct irq_info | |||
90 | unsigned short virq; | 90 | unsigned short virq; |
91 | enum ipi_vector ipi; | 91 | enum ipi_vector ipi; |
92 | struct { | 92 | struct { |
93 | unsigned short pirq; | ||
93 | unsigned short gsi; | 94 | unsigned short gsi; |
94 | unsigned char vector; | 95 | unsigned char vector; |
95 | unsigned char flags; | 96 | unsigned char flags; |
@@ -100,6 +101,7 @@ struct irq_info | |||
100 | #define PIRQ_SHAREABLE (1 << 1) | 101 | #define PIRQ_SHAREABLE (1 << 1) |
101 | 102 | ||
102 | static struct irq_info *irq_info; | 103 | static struct irq_info *irq_info; |
104 | static int *pirq_to_irq; | ||
103 | 105 | ||
104 | static int *evtchn_to_irq; | 106 | static int *evtchn_to_irq; |
105 | struct cpu_evtchn_s { | 107 | struct cpu_evtchn_s { |
@@ -147,11 +149,12 @@ static struct irq_info mk_virq_info(unsigned short evtchn, unsigned short virq) | |||
147 | .cpu = 0, .u.virq = virq }; | 149 | .cpu = 0, .u.virq = virq }; |
148 | } | 150 | } |
149 | 151 | ||
150 | static struct irq_info mk_pirq_info(unsigned short evtchn, | 152 | static struct irq_info mk_pirq_info(unsigned short evtchn, unsigned short pirq, |
151 | unsigned short gsi, unsigned short vector) | 153 | unsigned short gsi, unsigned short vector) |
152 | { | 154 | { |
153 | return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn, | 155 | return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn, |
154 | .cpu = 0, .u.pirq = { .gsi = gsi, .vector = vector } }; | 156 | .cpu = 0, |
157 | .u.pirq = { .pirq = pirq, .gsi = gsi, .vector = vector } }; | ||
155 | } | 158 | } |
156 | 159 | ||
157 | /* | 160 | /* |
@@ -193,6 +196,16 @@ static unsigned virq_from_irq(unsigned irq) | |||
193 | return info->u.virq; | 196 | return info->u.virq; |
194 | } | 197 | } |
195 | 198 | ||
199 | static unsigned pirq_from_irq(unsigned irq) | ||
200 | { | ||
201 | struct irq_info *info = info_for_irq(irq); | ||
202 | |||
203 | BUG_ON(info == NULL); | ||
204 | BUG_ON(info->type != IRQT_PIRQ); | ||
205 | |||
206 | return info->u.pirq.pirq; | ||
207 | } | ||
208 | |||
196 | static unsigned gsi_from_irq(unsigned irq) | 209 | static unsigned gsi_from_irq(unsigned irq) |
197 | { | 210 | { |
198 | struct irq_info *info = info_for_irq(irq); | 211 | struct irq_info *info = info_for_irq(irq); |
@@ -365,6 +378,16 @@ static int get_nr_hw_irqs(void) | |||
365 | return ret; | 378 | return ret; |
366 | } | 379 | } |
367 | 380 | ||
381 | static int find_unbound_pirq(void) | ||
382 | { | ||
383 | int i; | ||
384 | for (i = 0; i < nr_irqs; i++) { | ||
385 | if (pirq_to_irq[i] < 0) | ||
386 | return i; | ||
387 | } | ||
388 | return -1; | ||
389 | } | ||
390 | |||
368 | static int find_unbound_irq(void) | 391 | static int find_unbound_irq(void) |
369 | { | 392 | { |
370 | struct irq_data *data; | 393 | struct irq_data *data; |
@@ -410,7 +433,7 @@ static bool identity_mapped_irq(unsigned irq) | |||
410 | 433 | ||
411 | static void pirq_unmask_notify(int irq) | 434 | static void pirq_unmask_notify(int irq) |
412 | { | 435 | { |
413 | struct physdev_eoi eoi = { .irq = irq }; | 436 | struct physdev_eoi eoi = { .irq = pirq_from_irq(irq) }; |
414 | 437 | ||
415 | if (unlikely(pirq_needs_eoi(irq))) { | 438 | if (unlikely(pirq_needs_eoi(irq))) { |
416 | int rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); | 439 | int rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); |
@@ -425,7 +448,7 @@ static void pirq_query_unmask(int irq) | |||
425 | 448 | ||
426 | BUG_ON(info->type != IRQT_PIRQ); | 449 | BUG_ON(info->type != IRQT_PIRQ); |
427 | 450 | ||
428 | irq_status.irq = irq; | 451 | irq_status.irq = pirq_from_irq(irq); |
429 | if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status)) | 452 | if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status)) |
430 | irq_status.flags = 0; | 453 | irq_status.flags = 0; |
431 | 454 | ||
@@ -453,7 +476,7 @@ static unsigned int startup_pirq(unsigned int irq) | |||
453 | if (VALID_EVTCHN(evtchn)) | 476 | if (VALID_EVTCHN(evtchn)) |
454 | goto out; | 477 | goto out; |
455 | 478 | ||
456 | bind_pirq.pirq = irq; | 479 | bind_pirq.pirq = pirq_from_irq(irq); |
457 | /* NB. We are happy to share unless we are probing. */ | 480 | /* NB. We are happy to share unless we are probing. */ |
458 | bind_pirq.flags = info->u.pirq.flags & PIRQ_SHAREABLE ? | 481 | bind_pirq.flags = info->u.pirq.flags & PIRQ_SHAREABLE ? |
459 | BIND_PIRQ__WILL_SHARE : 0; | 482 | BIND_PIRQ__WILL_SHARE : 0; |
@@ -556,28 +579,32 @@ static int find_irq_by_gsi(unsigned gsi) | |||
556 | return -1; | 579 | return -1; |
557 | } | 580 | } |
558 | 581 | ||
559 | /* xen_allocate_irq might allocate irqs from the top down, as a | 582 | int xen_allocate_pirq(unsigned gsi, int shareable, char *name) |
583 | { | ||
584 | return xen_map_pirq_gsi(gsi, gsi, shareable, name); | ||
585 | } | ||
586 | |||
587 | /* xen_map_pirq_gsi might allocate irqs from the top down, as a | ||
560 | * consequence don't assume that the irq number returned has a low value | 588 | * consequence don't assume that the irq number returned has a low value |
561 | * or can be used as a pirq number unless you know otherwise. | 589 | * or can be used as a pirq number unless you know otherwise. |
562 | * | 590 | * |
563 | * One notable exception is when xen_allocate_irq is called passing an | 591 | * One notable exception is when xen_map_pirq_gsi is called passing an |
564 | * hardware gsi as argument, in that case the irq number returned | 592 | * hardware gsi as argument, in that case the irq number returned |
565 | * matches the gsi number passed as first argument. | 593 | * matches the gsi number passed as second argument. |
566 | 594 | * | |
567 | * Note: We don't assign an | 595 | * Note: We don't assign an event channel until the irq actually started |
568 | * event channel until the irq actually started up. Return an | 596 | * up. Return an existing irq if we've already got one for the gsi. |
569 | * existing irq if we've already got one for the gsi. | ||
570 | */ | 597 | */ |
571 | int xen_allocate_pirq(unsigned gsi, int shareable, char *name) | 598 | int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) |
572 | { | 599 | { |
573 | int irq; | 600 | int irq = 0; |
574 | struct physdev_irq irq_op; | 601 | struct physdev_irq irq_op; |
575 | 602 | ||
576 | spin_lock(&irq_mapping_update_lock); | 603 | spin_lock(&irq_mapping_update_lock); |
577 | 604 | ||
578 | irq = find_irq_by_gsi(gsi); | 605 | irq = find_irq_by_gsi(gsi); |
579 | if (irq != -1) { | 606 | if (irq != -1) { |
580 | printk(KERN_INFO "xen_allocate_pirq: returning irq %d for gsi %u\n", | 607 | printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n", |
581 | irq, gsi); | 608 | irq, gsi); |
582 | goto out; /* XXX need refcount? */ | 609 | goto out; /* XXX need refcount? */ |
583 | } | 610 | } |
@@ -606,8 +633,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name) | |||
606 | goto out; | 633 | goto out; |
607 | } | 634 | } |
608 | 635 | ||
609 | irq_info[irq] = mk_pirq_info(0, gsi, irq_op.vector); | 636 | irq_info[irq] = mk_pirq_info(0, pirq, gsi, irq_op.vector); |
610 | irq_info[irq].u.pirq.flags |= shareable ? PIRQ_SHAREABLE : 0; | 637 | irq_info[irq].u.pirq.flags |= shareable ? PIRQ_SHAREABLE : 0; |
638 | pirq_to_irq[pirq] = irq; | ||
611 | 639 | ||
612 | out: | 640 | out: |
613 | spin_unlock(&irq_mapping_update_lock); | 641 | spin_unlock(&irq_mapping_update_lock); |
@@ -1327,6 +1355,10 @@ void __init xen_init_IRQ(void) | |||
1327 | GFP_KERNEL); | 1355 | GFP_KERNEL); |
1328 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); | 1356 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); |
1329 | 1357 | ||
1358 | pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL); | ||
1359 | for (i = 0; i < nr_irqs; i++) | ||
1360 | pirq_to_irq[i] = -1; | ||
1361 | |||
1330 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), | 1362 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), |
1331 | GFP_KERNEL); | 1363 | GFP_KERNEL); |
1332 | for (i = 0; i < NR_EVENT_CHANNELS; i++) | 1364 | for (i = 0; i < NR_EVENT_CHANNELS; i++) |