[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH][RFC] Support S3 for MSI interrupt in latest kernel dom0



In latest kernel, the pci_save_state will not try to save msi/x_state anymore, 
instead, it will try to restore msi state when resume using kernel's msi data 
structure. This cause trouble for us, since thoese MSI data structure is 
meaningless in Xen environment. 

Several option to resolve this issue:
a) Change the latest kernel (as dom0) to still to save/restore the msi content
b) Add a new hypercall, so when dom0 try to restore dom0, it will instruct Xen 
HV to restore the content based on Xen's MSI data structure
c) In Dom0's pci_restore_msi/x_state, try to call map_domain_pirq again. Xen HV 
will found there is a vector assigned already, then it will try to re_startup 
the interrupt.

We try to cook a patch for option c) as following (it is still not fully tested 
because my environment is broken and I send to mailing list to get some 
feedback in advance), but I suspect this option is not so good because it mix 
the function of map_domain_pirq and pirq_guest_bind more (it is very un-clear 
of the boundary between these two function now). And I'm not sure if the 
re-startup will cause potential issue for non-S3 situation.

Any suggestion?

Thanks
Yunhong Jiang

diff -r 045f70d1acdb xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c        Sat Dec 13 17:44:20 2008 +0000
+++ b/xen/arch/x86/irq.c        Wed Dec 17 12:49:18 2008 +0800
@@ -896,12 +896,23 @@ int map_domain_pirq(
         spin_lock_irqsave(&desc->lock, flags);
 
         if ( desc->handler != &no_irq_type )
-            dprintk(XENLOG_G_ERR, "dom%d: vector %d in use\n",
+            dprintk(XENLOG_G_INFO, "dom%d: vector %d in use\n",
               d->domain_id, vector);
         desc->handler = &pci_msi_type;
         d->arch.pirq_vector[pirq] = vector;
         d->arch.vector_pirq[vector] = pirq;
         setup_msi_irq(pdev, msi_desc);
+
+        /* If the vector has been bound, re-startup it again for S3 situation 
*/
+        if (desc->status & IRQ_GUEST)
+        {
+            irq_guest_action_t *action;
+
+            action = (irq_guest_action_t *)desc->action;
+
+            if ((action->nr_guests == 1) && (action->guest[0] == d))
+                desc->handler->startup(vector);
+        }
         spin_unlock_irqrestore(&desc->lock, flags);
     } else
     {
diff -r 045f70d1acdb xen/arch/x86/msi.c
--- a/xen/arch/x86/msi.c        Sat Dec 13 17:44:20 2008 +0000
+++ b/xen/arch/x86/msi.c        Wed Dec 17 14:52:59 2008 +0800
@@ -147,6 +147,9 @@ static int set_vector_msi(struct msi_des
         return -EINVAL;
     }
 
+    BUG_ON( (irq_desc[entry->vector].msi_desc)
+             &&(irq_desc[entry->vector].msi_desc != entry) );
+
     irq_desc[entry->vector].msi_desc = entry;
     return 0;
 }
@@ -573,17 +576,19 @@ static int __pci_enable_msi(struct msi_i
 {
     int status;
     struct pci_dev *pdev;
+    struct msi_desc *msi_desc = NULL;
 
     ASSERT(rw_is_locked(&pcidevs_lock));
     pdev = pci_get_pdev(msi->bus, msi->devfn);
     if ( !pdev )
         return -ENODEV;
 
-    if ( find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSI) )
+    if ( (msi_desc = find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSI) ))
     {
         dprintk(XENLOG_WARNING, "vector %d has already mapped to MSI on "
                 "device %02x:%02x.%01x.\n", msi->vector, msi->bus,
                 PCI_SLOT(msi->devfn), PCI_FUNC(msi->devfn));
+        *desc = msi_desc;
         return 0;
     }
 
@@ -633,6 +638,7 @@ static int __pci_enable_msix(struct msi_
     u16 control;
     u8 slot = PCI_SLOT(msi->devfn);
     u8 func = PCI_FUNC(msi->devfn);
+    struct msi_desc *msi_desc;
 
     ASSERT(rw_is_locked(&pcidevs_lock));
     pdev = pci_get_pdev(msi->bus, msi->devfn);
@@ -645,11 +651,12 @@ static int __pci_enable_msix(struct msi_
     if (msi->entry_nr >= nr_entries)
         return -EINVAL;
 
-    if ( find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSIX) )
+    if ( (msi_desc = find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSIX)))
     {
         dprintk(XENLOG_WARNING, "vector %d has already mapped to MSIX on "
                 "device %02x:%02x.%01x.\n", msi->vector, msi->bus,
                 PCI_SLOT(msi->devfn), PCI_FUNC(msi->devfn));
+        *desc = msi_desc;
         return 0;
     }
 
diff -r 045f70d1acdb xen/arch/x86/physdev.c
--- a/xen/arch/x86/physdev.c    Sat Dec 13 17:44:20 2008 +0000
+++ b/xen/arch/x86/physdev.c    Wed Dec 17 10:10:36 2008 +0800
@@ -51,6 +51,9 @@ static int physdev_map_pirq(struct physd
         goto free_domain;
     }
 
+    read_lock(&pcidevs_lock);
+    spin_lock(&d->event_lock);
+
     /* Verify or get vector. */
     switch ( map->type )
     {
@@ -60,7 +63,7 @@ static int physdev_map_pirq(struct physd
                 dprintk(XENLOG_G_ERR, "dom%d: map invalid irq %d\n",
                         d->domain_id, map->index);
                 ret = -EINVAL;
-                goto free_domain;
+                goto vector_fail;
             }
             vector = IO_APIC_VECTOR(map->index);
             if ( !vector )
@@ -68,21 +71,27 @@ static int physdev_map_pirq(struct physd
                 dprintk(XENLOG_G_ERR, "dom%d: map irq with no vector %d\n",
                         d->domain_id, vector);
                 ret = -EINVAL;
-                goto free_domain;
+                goto vector_fail;
             }
             break;
 
         case MAP_PIRQ_TYPE_MSI:
             vector = map->index;
+
             if ( vector == -1 )
-                vector = assign_irq_vector(AUTO_ASSIGN);
+            {
+                if (map->pirq >= 0)
+                    vector = d->arch.pirq_vector[map->pirq];
+                else
+                    vector = assign_irq_vector(AUTO_ASSIGN);
+            }
 
             if ( vector < 0 || vector >= NR_VECTORS )
             {
                 dprintk(XENLOG_G_ERR, "dom%d: map irq with wrong vector %d\n",
                         d->domain_id, vector);
                 ret = -EINVAL;
-                goto free_domain;
+                goto vector_fail;
             }
 
             _msi.bus = map->bus;
@@ -97,12 +106,10 @@ static int physdev_map_pirq(struct physd
             dprintk(XENLOG_G_ERR, "dom%d: wrong map_pirq type %x\n",
                     d->domain_id, map->type);
             ret = -EINVAL;
-            goto free_domain;
-    }
-
-    read_lock(&pcidevs_lock);
+            goto vector_fail;
+    }
+
     /* Verify or get pirq. */
-    spin_lock(&d->event_lock);
     if ( map->pirq < 0 )
     {
         if ( d->arch.vector_pirq[vector] )
@@ -147,11 +154,12 @@ static int physdev_map_pirq(struct physd
         map->pirq = pirq;
 
 done:
+    if ( (ret != 0) && (map->type == MAP_PIRQ_TYPE_MSI) && (map->index == -1) )
+        free_irq_vector(vector);
+vector_fail:
     spin_unlock(&d->event_lock);
     read_unlock(&pcidevs_lock);
-    if ( (ret != 0) && (map->type == MAP_PIRQ_TYPE_MSI) && (map->index == -1) )
-        free_irq_vector(vector);
-free_domain:
+free_domain:    
     rcu_unlock_domain(d);
     return ret;
 }

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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