[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [HVM] Allow PV-on-HVM callback irq to be identified by PCI device.
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1168441500 0 # Node ID 5c5d9692f559ab6b8f7cddc32d6f656e1ed3b888 # Parent 36fd53b2e3b4a41b4664be1abc059e25622e2ee3 [HVM] Allow PV-on-HVM callback irq to be identified by PCI device. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- unmodified_drivers/linux-2.6/platform-pci/platform-pci.c | 24 + unmodified_drivers/linux-2.6/platform-pci/platform-pci.h | 4 xen/arch/x86/hvm/hvm.c | 2 xen/arch/x86/hvm/irq.c | 187 +++++++++------ xen/include/asm-x86/hvm/irq.h | 16 - xen/include/public/hvm/params.h | 22 + 6 files changed, 175 insertions(+), 80 deletions(-) diff -r 36fd53b2e3b4 -r 5c5d9692f559 unmodified_drivers/linux-2.6/platform-pci/platform-pci.c --- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c Wed Jan 10 14:14:30 2007 +0000 +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c Wed Jan 10 15:05:00 2007 +0000 @@ -179,7 +179,7 @@ static int get_hypercall_stubs(void) #define get_hypercall_stubs() (0) #endif -static int get_callback_irq(struct pci_dev *pdev) +static uint64_t get_callback_via(struct pci_dev *pdev) { #ifdef __ia64__ int irq; @@ -189,16 +189,24 @@ static int get_callback_irq(struct pci_d } return 0; #else /* !__ia64__ */ - return pdev->irq; + if (pdev->irq < 16) + return pdev->irq; /* ISA IRQ */ + /* We don't know the GSI. Specify the PCI INTx line instead. */ + return (((uint64_t)0x01 << 56) | /* PCI INTx identifier */ + ((uint64_t)pci_domain_nr(pdev->bus) << 32) | + ((uint64_t)pdev->bus->number << 16) | + ((uint64_t)(pdev->devfn & 0xff) << 8) | + ((uint64_t)(pdev->pin - 1) & 3)); #endif } static int __devinit platform_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) { - int i, ret, callback_irq; + int i, ret; long ioaddr, iolen; long mmio_addr, mmio_len; + uint64_t callback_via; i = pci_enable_device(pdev); if (i) @@ -210,9 +218,9 @@ static int __devinit platform_pci_init(s mmio_addr = pci_resource_start(pdev, 1); mmio_len = pci_resource_len(pdev, 1); - callback_irq = get_callback_irq(pdev); - - if (mmio_addr == 0 || ioaddr == 0 || callback_irq == 0) { + callback_via = get_callback_via(pdev); + + if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) { printk(KERN_WARNING DRV_NAME ":no resources found\n"); return -ENOENT; } @@ -247,7 +255,7 @@ static int __devinit platform_pci_init(s goto out; } - if ((ret = set_callback_irq(callback_irq))) + if ((ret = set_callback_via(callback_via))) goto out; out: @@ -297,7 +305,7 @@ static void __exit platform_pci_module_c { printk(KERN_INFO DRV_NAME ":Do platform module cleanup\n"); /* disable hypervisor for callback irq */ - set_callback_irq(0); + set_callback_via(0); if (pci_device_registered) pci_unregister_driver(&platform_driver); } diff -r 36fd53b2e3b4 -r 5c5d9692f559 unmodified_drivers/linux-2.6/platform-pci/platform-pci.h --- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h Wed Jan 10 14:14:30 2007 +0000 +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h Wed Jan 10 15:05:00 2007 +0000 @@ -24,13 +24,13 @@ #include <linux/interrupt.h> #include <xen/interface/hvm/params.h> -static inline int set_callback_irq(int irq) +static inline int set_callback_via(uint64_t via) { struct xen_hvm_param a; a.domid = DOMID_SELF; a.index = HVM_PARAM_CALLBACK_IRQ; - a.value = irq; + a.value = via; return HYPERVISOR_hvm_op(HVMOP_set_param, &a); } diff -r 36fd53b2e3b4 -r 5c5d9692f559 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Wed Jan 10 14:14:30 2007 +0000 +++ b/xen/arch/x86/hvm/hvm.c Wed Jan 10 15:05:00 2007 +0000 @@ -800,7 +800,7 @@ long do_hvm_op(unsigned long op, XEN_GUE d->arch.hvm_domain.buffered_io_va = (unsigned long)p; break; case HVM_PARAM_CALLBACK_IRQ: - hvm_set_callback_gsi(d, a.value); + hvm_set_callback_via(d, a.value); break; } d->arch.hvm_domain.params[a.index] = a.value; diff -r 36fd53b2e3b4 -r 5c5d9692f559 xen/arch/x86/hvm/irq.c --- a/xen/arch/x86/hvm/irq.c Wed Jan 10 14:14:30 2007 +0000 +++ b/xen/arch/x86/hvm/irq.c Wed Jan 10 15:05:00 2007 +0000 @@ -25,7 +25,7 @@ #include <xen/sched.h> #include <asm/hvm/domain.h> -void hvm_pci_intx_assert( +static void __hvm_pci_intx_assert( struct domain *d, unsigned int device, unsigned int intx) { struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; @@ -33,10 +33,8 @@ void hvm_pci_intx_assert( ASSERT((device <= 31) && (intx <= 3)); - spin_lock(&hvm_irq->lock); - if ( __test_and_set_bit(device*4 + intx, &hvm_irq->pci_intx) ) - goto out; + return; gsi = hvm_pci_intx_gsi(device, intx); if ( hvm_irq->gsi_assert_count[gsi]++ == 0 ) @@ -50,12 +48,19 @@ void hvm_pci_intx_assert( vioapic_irq_positive_edge(d, isa_irq); vpic_irq_positive_edge(d, isa_irq); } - - out: - spin_unlock(&hvm_irq->lock); -} - -void hvm_pci_intx_deassert( +} + +void hvm_pci_intx_assert( + struct domain *d, unsigned int device, unsigned int intx) +{ + struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; + + spin_lock(&hvm_irq->lock); + __hvm_pci_intx_assert(d, device, intx); + spin_unlock(&hvm_irq->lock); +} + +static void __hvm_pci_intx_deassert( struct domain *d, unsigned int device, unsigned int intx) { struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; @@ -63,10 +68,8 @@ void hvm_pci_intx_deassert( ASSERT((device <= 31) && (intx <= 3)); - spin_lock(&hvm_irq->lock); - if ( !__test_and_clear_bit(device*4 + intx, &hvm_irq->pci_intx) ) - goto out; + return; gsi = hvm_pci_intx_gsi(device, intx); --hvm_irq->gsi_assert_count[gsi]; @@ -76,8 +79,15 @@ void hvm_pci_intx_deassert( if ( (--hvm_irq->pci_link_assert_count[link] == 0) && isa_irq && (--hvm_irq->gsi_assert_count[isa_irq] == 0) ) vpic_irq_negative_edge(d, isa_irq); - - out: +} + +void hvm_pci_intx_deassert( + struct domain *d, unsigned int device, unsigned int intx) +{ + struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; + + spin_lock(&hvm_irq->lock); + __hvm_pci_intx_deassert(d, device, intx); spin_unlock(&hvm_irq->lock); } @@ -123,37 +133,47 @@ void hvm_set_callback_irq_level(void) struct vcpu *v = current; struct domain *d = v->domain; struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; - unsigned int gsi = hvm_irq->callback_gsi; + unsigned int gsi, pdev, pintx, asserted; /* Fast lock-free tests. */ - if ( (v->vcpu_id != 0) || (gsi == 0) ) + if ( (v->vcpu_id != 0) || + (hvm_irq->callback_via_type == HVMIRQ_callback_none) ) return; spin_lock(&hvm_irq->lock); - gsi = hvm_irq->callback_gsi; - if ( gsi == 0 ) + /* NB. Do not check the evtchn_upcall_mask. It is not used in HVM mode. */ + asserted = !!vcpu_info(v, evtchn_upcall_pending); + if ( hvm_irq->callback_via_asserted == asserted ) goto out; - - /* NB. Do not check the evtchn_upcall_mask. It is not used in HVM mode. */ - if ( vcpu_info(v, evtchn_upcall_pending) ) - { - if ( !__test_and_set_bit(0, &hvm_irq->callback_irq_wire) && - (hvm_irq->gsi_assert_count[gsi]++ == 0) ) + hvm_irq->callback_via_asserted = asserted; + + /* Callback status has changed. Update the callback via. */ + switch ( hvm_irq->callback_via_type ) + { + case HVMIRQ_callback_gsi: + gsi = hvm_irq->callback_via.gsi; + if ( asserted && (hvm_irq->gsi_assert_count[gsi]++ == 0) ) { vioapic_irq_positive_edge(d, gsi); if ( gsi <= 15 ) vpic_irq_positive_edge(d, gsi); } - } - else - { - if ( __test_and_clear_bit(0, &hvm_irq->callback_irq_wire) && - (--hvm_irq->gsi_assert_count[gsi] == 0) ) + else if ( !asserted && (--hvm_irq->gsi_assert_count[gsi] == 0) ) { if ( gsi <= 15 ) vpic_irq_negative_edge(d, gsi); } + break; + case HVMIRQ_callback_pci_intx: + pdev = hvm_irq->callback_via.pci.dev; + pintx = hvm_irq->callback_via.pci.intx; + if ( asserted ) + __hvm_pci_intx_assert(d, pdev, pintx); + else + __hvm_pci_intx_deassert(d, pdev, pintx); + default: + break; } out: @@ -193,40 +213,79 @@ void hvm_set_pci_link_route(struct domai d->domain_id, link, old_isa_irq, isa_irq); } -void hvm_set_callback_gsi(struct domain *d, unsigned int gsi) -{ - struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; - unsigned int old_gsi; - - if ( gsi >= ARRAY_SIZE(hvm_irq->gsi_assert_count) ) - gsi = 0; - - spin_lock(&hvm_irq->lock); - - old_gsi = hvm_irq->callback_gsi; - if ( old_gsi == gsi ) - goto out; - hvm_irq->callback_gsi = gsi; - - if ( !test_bit(0, &hvm_irq->callback_irq_wire) ) - goto out; - - if ( old_gsi && (--hvm_irq->gsi_assert_count[old_gsi] == 0) ) - if ( old_gsi <= 15 ) - vpic_irq_negative_edge(d, old_gsi); - - if ( gsi && (hvm_irq->gsi_assert_count[gsi]++ == 0) ) - { - vioapic_irq_positive_edge(d, gsi); - if ( gsi <= 15 ) - vpic_irq_positive_edge(d, gsi); - } - - out: - spin_unlock(&hvm_irq->lock); - - dprintk(XENLOG_G_INFO, "Dom%u callback GSI changed %u -> %u\n", - d->domain_id, old_gsi, gsi); +void hvm_set_callback_via(struct domain *d, uint64_t via) +{ + struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; + unsigned int gsi=0, pdev=0, pintx=0; + uint8_t via_type; + + via_type = (uint8_t)(via >> 56) + 1; + if ( ((via_type == HVMIRQ_callback_gsi) && (via == 0)) || + (via_type > HVMIRQ_callback_pci_intx) ) + via_type = HVMIRQ_callback_none; + + spin_lock(&hvm_irq->lock); + + /* Tear down old callback via. */ + if ( hvm_irq->callback_via_asserted ) + { + switch ( hvm_irq->callback_via_type ) + { + case HVMIRQ_callback_gsi: + gsi = hvm_irq->callback_via.gsi; + if ( (--hvm_irq->gsi_assert_count[gsi] == 0) && (gsi <= 15) ) + vpic_irq_negative_edge(d, gsi); + break; + case HVMIRQ_callback_pci_intx: + pdev = hvm_irq->callback_via.pci.dev; + pintx = hvm_irq->callback_via.pci.intx; + __hvm_pci_intx_deassert(d, pdev, pintx); + break; + default: + break; + } + } + + /* Set up new callback via. */ + switch ( hvm_irq->callback_via_type = via_type ) + { + case HVMIRQ_callback_gsi: + gsi = hvm_irq->callback_via.gsi = (uint8_t)via; + if ( (gsi == 0) || (gsi >= ARRAY_SIZE(hvm_irq->gsi_assert_count)) ) + hvm_irq->callback_via_type = HVMIRQ_callback_none; + else if ( hvm_irq->callback_via_asserted && + (hvm_irq->gsi_assert_count[gsi]++ == 0) ) + { + vioapic_irq_positive_edge(d, gsi); + if ( gsi <= 15 ) + vpic_irq_positive_edge(d, gsi); + } + break; + case HVMIRQ_callback_pci_intx: + pdev = hvm_irq->callback_via.pci.dev = (uint8_t)(via >> 11) & 31; + pintx = hvm_irq->callback_via.pci.intx = (uint8_t)via & 3; + if ( hvm_irq->callback_via_asserted ) + __hvm_pci_intx_assert(d, pdev, pintx); + break; + default: + break; + } + + spin_unlock(&hvm_irq->lock); + + dprintk(XENLOG_G_INFO, "Dom%u callback via changed to ", d->domain_id); + switch ( via_type ) + { + case HVMIRQ_callback_gsi: + printk("GSI %u\n", gsi); + break; + case HVMIRQ_callback_pci_intx: + printk("PCI INTx Dev 0x%02x Int%c\n", pdev, 'A' + pintx); + break; + default: + printk("None\n"); + break; + } } int cpu_has_pending_irq(struct vcpu *v) diff -r 36fd53b2e3b4 -r 5c5d9692f559 xen/include/asm-x86/hvm/irq.h --- a/xen/include/asm-x86/hvm/irq.h Wed Jan 10 14:14:30 2007 +0000 +++ b/xen/include/asm-x86/hvm/irq.h Wed Jan 10 15:05:00 2007 +0000 @@ -43,9 +43,17 @@ struct hvm_irq { */ DECLARE_BITMAP(isa_irq, 16); - /* Virtual interrupt wire and GSI link for paravirtual platform driver. */ - DECLARE_BITMAP(callback_irq_wire, 1); - unsigned int callback_gsi; + /* Virtual interrupt and via-link for paravirtual platform driver. */ + unsigned int callback_via_asserted; + enum { + HVMIRQ_callback_none, + HVMIRQ_callback_gsi, + HVMIRQ_callback_pci_intx + } callback_via_type; + union { + unsigned int gsi; + struct { uint8_t dev, intx; } pci; + } callback_via; /* * PCI-ISA interrupt router. @@ -105,7 +113,7 @@ void hvm_set_pci_link_route(struct domai void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq); void hvm_set_callback_irq_level(void); -void hvm_set_callback_gsi(struct domain *d, unsigned int gsi); +void hvm_set_callback_via(struct domain *d, uint64_t via); int cpu_get_interrupt(struct vcpu *v, int *type); int cpu_has_pending_irq(struct vcpu *v); diff -r 36fd53b2e3b4 -r 5c5d9692f559 xen/include/public/hvm/params.h --- a/xen/include/public/hvm/params.h Wed Jan 10 14:14:30 2007 +0000 +++ b/xen/include/public/hvm/params.h Wed Jan 10 15:05:00 2007 +0000 @@ -24,13 +24,33 @@ #include "hvm_op.h" -/* Parameter space for HVMOP_{set,get}_param. */ +/* + * Parameter space for HVMOP_{set,get}_param. + */ + +/* + * How should CPU0 event-channel notifications be delivered? + * val[63:56] == 0: val[55:0] is a delivery GSI (Global System Interrupt). + * val[63:56] == 1: val[55:0] is a delivery PCI INTx line, as follows: + * Domain = val[47:32], Bus = val[31:16], + * DevFn = val[15: 8], IntX = val[ 1: 0] + * If val == 0 then CPU0 event-channel notifications are not delivered. + */ #define HVM_PARAM_CALLBACK_IRQ 0 + +/* + * These are not used by Xen. They are here for convenience of HVM-guest + * xenbus implementations. + */ #define HVM_PARAM_STORE_PFN 1 #define HVM_PARAM_STORE_EVTCHN 2 + #define HVM_PARAM_PAE_ENABLED 4 + #define HVM_PARAM_IOREQ_PFN 5 + #define HVM_PARAM_BUFIOREQ_PFN 6 + #define HVM_NR_PARAMS 7 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |