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
|