[PATCH 4 of 5] Linux pvops: pci passthrough support

From: Stefano Stabellini
Date: Tue Mar 09 2010 - 11:02:19 EST


Hi all,
this patch makes few changes to the xen pci functions to handle pirq
remapping of interrupts belonging to pci passthrough devices:

- disable pcifront and MSIs when running on HVM
the former is not meant to be used while the latter are not supported
yet

- change xen_allocate_pirq to take the pirq as a parameter
this is necessary because with pt devices the pirq returned by
PHYSDEVOP_map_pirq may be different from the one we passed as an
argument


Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>

---

diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index e138053..6a857eb 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -25,7 +25,7 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev)
if (dev->irq < 0)
return -EINVAL;

- rc = xen_allocate_pirq(dev->irq, 0, "pcifront");
+ rc = xen_allocate_pirq(dev->irq, dev->irq, 0, "pcifront");
if (rc < 0) {
dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
dev->irq, rc);
diff --git a/arch/x86/xen/pci.c b/arch/x86/xen/pci.c
index ac7e6bd..84d4904 100644
--- a/arch/x86/xen/pci.c
+++ b/arch/x86/xen/pci.c
@@ -37,36 +37,34 @@ int xen_register_gsi(u32 gsi, int triggering, int polarity)
name = "ioapic-level";
}

- irq = xen_allocate_pirq(gsi, shareable, name);
-
- printk(KERN_DEBUG "xen: --> irq=%d\n", irq);
-
- if (irq >= 0) {
- setup_gsi.gsi = gsi;
- setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ?
- 0 : 1);
- setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
-
- rc = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi);
- if (rc == -EEXIST)
- printk(KERN_INFO "Already setup the GSI :%d\n", gsi);
- else if (rc) {
- printk(KERN_ERR "Failed to setup GSI :%d, err_code:%d\n",
- gsi, rc);
- BUG();
- }
-
- map_irq.domid = DOMID_SELF;
- map_irq.type = MAP_PIRQ_TYPE_GSI;
- map_irq.index = gsi;
- map_irq.pirq = irq;
-
- rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
- if (rc) {
- printk(KERN_WARNING "xen map irq failed %d\n", rc);
- irq = -1;
- }
+ setup_gsi.gsi = gsi;
+ setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ?
+ 0 : 1);
+ setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
+
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi);
+ if (rc == -EEXIST)
+ printk(KERN_INFO "Already setup the GSI :%d\n", gsi);
+ else if (rc) {
+ printk(KERN_ERR "Failed to setup GSI :%d, err_code:%d\n",
+ gsi, rc);
+ BUG();
}
+
+ map_irq.domid = DOMID_SELF;
+ map_irq.type = MAP_PIRQ_TYPE_GSI;
+ map_irq.index = gsi;
+ map_irq.pirq = gsi;
+
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+ if (rc) {
+ printk(KERN_WARNING "xen map irq failed %d\n", rc);
+ return -1;
+ }
+ irq = xen_allocate_pirq(map_irq.pirq, gsi, shareable, name);
+
+ printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
+
return irq;
}

@@ -76,7 +74,7 @@ void __init xen_setup_pirqs(void)

if (0 == nr_ioapics) {
for (irq = 0; irq < NR_IRQS_LEGACY; irq++)
- xen_allocate_pirq(irq, 0, "xt-pic");
+ xen_allocate_pirq(irq, irq, 0, "xt-pic");
return;
}

@@ -100,6 +98,10 @@ int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
struct msi_desc *msidesc;
int *v;

+ /* PV on HVM domains do not support MSI at the moment */
+ if (xen_hvm_domain())
+ return -EINVAL;
+
v = kzalloc(sizeof(int) * min(1, nvec), GFP_KERNEL);
if (!v)
return -ENOMEM;
@@ -135,7 +137,7 @@ error:
void xen_teardown_msi_dev(struct pci_dev *dev)
{
/* Only do this when were are in non-privileged mode.*/
- if (!xen_initial_domain()) {
+ if (!xen_initial_domain() && !xen_hvm_domain()) {
struct msi_desc *msidesc;

msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index cc3b51b..5f5c2fa 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -1116,7 +1116,7 @@ static struct xenbus_driver xenbus_pcifront_driver = {

static int __init pcifront_init(void)
{
- if (!xen_domain())
+ if (!xen_domain() || xen_hvm_domain())
return -ENODEV;

return xenbus_register_frontend(&xenbus_pcifront_driver);
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 29a399d..21c0d8c 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -538,7 +538,7 @@ static int find_irq_by_gsi(unsigned gsi)
* until the irq actually started up. Return an
* existing irq if we've already got one for the gsi.
*/
-int xen_allocate_pirq(unsigned gsi, int shareable, char *name)
+int xen_allocate_pirq(unsigned pirq, unsigned gsi, int shareable, char *name)
{
int irq;

@@ -563,7 +563,7 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name)
set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
handle_level_irq, name);

- irq_info[irq] = mk_pirq_info(0, gsi);
+ irq_info[irq] = mk_pirq_info(0, pirq);
irq_info[irq].u.pirq.flags |= shareable ? PIRQ_SHAREABLE : 0;
out:
spin_unlock(&irq_mapping_update_lock);
diff --git a/include/xen/events.h b/include/xen/events.h
index cbe3218..eccc87b 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -72,7 +72,7 @@ unsigned irq_from_evtchn(unsigned int evtchn);
/* Allocate an irq for a physical interrupt, given a gsi. "Legacy"
GSIs are identity mapped; others are dynamically allocated as
usual. */
-int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
+int xen_allocate_pirq(unsigned pirq, unsigned gsi, int shareable, char *name);

/* Return vector allocated to pirq */
int xen_vector_from_irq(unsigned pirq);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/