[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.