Commit 010b8f4e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'stable/irq.cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen

* 'stable/irq.cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen: events: remove dom0 specific xen_create_msi_irq
  xen: events: use xen_bind_pirq_msi_to_irq from xen_create_msi_irq
  xen: events: push set_irq_msi down into xen_create_msi_irq
  xen: events: update pirq_to_irq in xen_create_msi_irq
  xen: events: refactor xen_create_msi_irq slightly
  xen: events: separate MSI PIRQ allocation from PIRQ binding to IRQ
  xen: events: assume PHYSDEVOP_get_free_pirq exists
  xen: pci: collapse apic_register_gsi_xen_hvm and xen_hvm_register_pirq
  xen: events: return irq from xen_allocate_pirq_msi
  xen: events: drop XEN_ALLOC_IRQ flag to xen_allocate_pirq_msi
  xen: events: do not leak IRQ from xen_allocate_pirq_msi when no pirq available.
  xen: pci: only define xen_initdom_setup_msi_irqs if CONFIG_XEN_DOM0
parents 397fae08 71eef7d1
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
#include <asm/xen/pci.h> #include <asm/xen/pci.h>
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static int xen_hvm_register_pirq(u32 gsi, int triggering) static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
int trigger, int polarity)
{ {
int rc, irq; int rc, irq;
struct physdev_map_pirq map_irq; struct physdev_map_pirq map_irq;
...@@ -41,7 +42,7 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering) ...@@ -41,7 +42,7 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering)
return -1; return -1;
} }
if (triggering == ACPI_EDGE_SENSITIVE) { if (trigger == ACPI_EDGE_SENSITIVE) {
shareable = 0; shareable = 0;
name = "ioapic-edge"; name = "ioapic-edge";
} else { } else {
...@@ -55,12 +56,6 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering) ...@@ -55,12 +56,6 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering)
return irq; return irq;
} }
static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
int trigger, int polarity)
{
return xen_hvm_register_pirq(gsi, trigger);
}
#endif #endif
#if defined(CONFIG_PCI_MSI) #if defined(CONFIG_PCI_MSI)
...@@ -91,7 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, ...@@ -91,7 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{ {
int irq, pirq, ret = 0; int irq, pirq;
struct msi_desc *msidesc; struct msi_desc *msidesc;
struct msi_msg msg; struct msi_msg msg;
...@@ -99,39 +94,32 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ...@@ -99,39 +94,32 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
__read_msi_msg(msidesc, &msg); __read_msi_msg(msidesc, &msg);
pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) { if (msg.data != XEN_PIRQ_MSI_DATA ||
xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? xen_irq_from_pirq(pirq) < 0) {
"msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ); pirq = xen_allocate_pirq_msi(dev, msidesc);
if (irq < 0) if (pirq < 0)
goto error; goto error;
ret = set_irq_msi(irq, msidesc); xen_msi_compose_msg(dev, pirq, &msg);
if (ret < 0) __write_msi_msg(msidesc, &msg);
goto error_while; dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d" } else {
" pirq=%d\n", irq, pirq); dev_dbg(&dev->dev,
return 0; "xen: msi already bound to pirq=%d\n", pirq);
} }
xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
"msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ)); (type == PCI_CAP_ID_MSIX) ?
if (irq < 0 || pirq < 0) "msi-x" : "msi");
if (irq < 0)
goto error; goto error;
printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq); dev_dbg(&dev->dev,
xen_msi_compose_msg(dev, pirq, &msg); "xen: msi --> pirq=%d --> irq=%d\n", pirq, irq);
ret = set_irq_msi(irq, msidesc);
if (ret < 0)
goto error_while;
write_msi_msg(irq, &msg);
} }
return 0; return 0;
error_while:
unbind_from_irqhandler(irq, NULL);
error: error:
if (ret == -ENODEV) dev_err(&dev->dev,
dev_err(&dev->dev, "Xen PCI frontend has not registered" \ "Xen PCI frontend has not registered MSI/MSI-X support!\n");
" MSI/MSI-X support!\n"); return -ENODEV;
return ret;
} }
/* /*
...@@ -157,28 +145,19 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ...@@ -157,28 +145,19 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
goto error; goto error;
i = 0; i = 0;
list_for_each_entry(msidesc, &dev->msi_list, list) { list_for_each_entry(msidesc, &dev->msi_list, list) {
xen_allocate_pirq_msi( irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
(type == PCI_CAP_ID_MSIX) ? (type == PCI_CAP_ID_MSIX) ?
"pcifront-msi-x" : "pcifront-msi", "pcifront-msi-x" :
&irq, &v[i], XEN_ALLOC_IRQ); "pcifront-msi");
if (irq < 0) { if (irq < 0)
ret = -1;
goto free; goto free;
}
ret = set_irq_msi(irq, msidesc);
if (ret)
goto error_while;
i++; i++;
} }
kfree(v); kfree(v);
return 0; return 0;
error_while:
unbind_from_irqhandler(irq, NULL);
error: error:
if (ret == -ENODEV) dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
dev_err(&dev->dev, "Xen PCI frontend has not registered" \
" MSI/MSI-X support!\n");
free: free:
kfree(v); kfree(v);
return ret; return ret;
...@@ -203,27 +182,56 @@ static void xen_teardown_msi_irq(unsigned int irq) ...@@ -203,27 +182,56 @@ static void xen_teardown_msi_irq(unsigned int irq)
xen_destroy_irq(irq); xen_destroy_irq(irq);
} }
#ifdef CONFIG_XEN_DOM0
static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{ {
int irq, ret; int ret = 0;
struct msi_desc *msidesc; struct msi_desc *msidesc;
list_for_each_entry(msidesc, &dev->msi_list, list) { list_for_each_entry(msidesc, &dev->msi_list, list) {
irq = xen_create_msi_irq(dev, msidesc, type); struct physdev_map_pirq map_irq;
if (irq < 0)
return -1;
ret = set_irq_msi(irq, msidesc); memset(&map_irq, 0, sizeof(map_irq));
if (ret) map_irq.domid = DOMID_SELF;
goto error; map_irq.type = MAP_PIRQ_TYPE_MSI;
} map_irq.index = -1;
return 0; map_irq.pirq = -1;
map_irq.bus = dev->bus->number;
map_irq.devfn = dev->devfn;
error: if (type == PCI_CAP_ID_MSIX) {
xen_destroy_irq(irq); int pos;
u32 table_offset, bir;
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
pci_read_config_dword(dev, pos + PCI_MSIX_TABLE,
&table_offset);
bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
map_irq.table_base = pci_resource_start(dev, bir);
map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
}
ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
if (ret) {
dev_warn(&dev->dev, "xen map irq failed %d\n", ret);
goto out;
}
ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
map_irq.pirq, map_irq.index,
(type == PCI_CAP_ID_MSIX) ?
"msi-x" : "msi");
if (ret < 0)
goto out;
}
ret = 0;
out:
return ret; return ret;
} }
#endif #endif
#endif
static int xen_pcifront_enable_irq(struct pci_dev *dev) static int xen_pcifront_enable_irq(struct pci_dev *dev)
{ {
......
...@@ -644,104 +644,46 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) ...@@ -644,104 +644,46 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
} }
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
#include <linux/msi.h> int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
#include "../pci/msi.h"
static int find_unbound_pirq(int type)
{ {
int rc, i; int rc;
struct physdev_get_free_pirq op_get_free_pirq; struct physdev_get_free_pirq op_get_free_pirq;
op_get_free_pirq.type = type;
op_get_free_pirq.type = MAP_PIRQ_TYPE_MSI;
rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
if (!rc)
return op_get_free_pirq.pirq;
for (i = 0; i < nr_irqs; i++) {
if (pirq_to_irq[i] < 0)
return i;
}
return -1;
}
void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc)
{
spin_lock(&irq_mapping_update_lock);
if (alloc & XEN_ALLOC_IRQ) {
*irq = xen_allocate_irq_dynamic();
if (*irq == -1)
goto out;
}
if (alloc & XEN_ALLOC_PIRQ) {
*pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
if (*pirq == -1)
goto out;
}
set_irq_chip_and_handler_name(*irq, &xen_pirq_chip,
handle_level_irq, name);
irq_info[*irq] = mk_pirq_info(0, *pirq, 0, 0); WARN_ONCE(rc == -ENOSYS,
pirq_to_irq[*pirq] = *irq; "hypervisor does not support the PHYSDEVOP_get_free_pirq interface\n");
out: return rc ? -1 : op_get_free_pirq.pirq;
spin_unlock(&irq_mapping_update_lock);
} }
int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type) int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int pirq, int vector, const char *name)
{ {
int irq = -1; int irq, ret;
struct physdev_map_pirq map_irq;
int rc;
int pos;
u32 table_offset, bir;
memset(&map_irq, 0, sizeof(map_irq));
map_irq.domid = DOMID_SELF;
map_irq.type = MAP_PIRQ_TYPE_MSI;
map_irq.index = -1;
map_irq.pirq = -1;
map_irq.bus = dev->bus->number;
map_irq.devfn = dev->devfn;
if (type == PCI_CAP_ID_MSIX) {
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
pci_read_config_dword(dev, msix_table_offset_reg(pos),
&table_offset);
bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
map_irq.table_base = pci_resource_start(dev, bir);
map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
}
spin_lock(&irq_mapping_update_lock); spin_lock(&irq_mapping_update_lock);
irq = xen_allocate_irq_dynamic(); irq = xen_allocate_irq_dynamic();
if (irq == -1) if (irq == -1)
goto out; goto out;
rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
if (rc) {
printk(KERN_WARNING "xen map irq failed %d\n", rc);
xen_free_irq(irq);
irq = -1;
goto out;
}
irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index);
set_irq_chip_and_handler_name(irq, &xen_pirq_chip, set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
handle_level_irq, handle_level_irq, name);
(type == PCI_CAP_ID_MSIX) ? "msi-x":"msi");
irq_info[irq] = mk_pirq_info(0, pirq, 0, vector);
pirq_to_irq[pirq] = irq;
ret = set_irq_msi(irq, msidesc);
if (ret < 0)
goto error_irq;
out: out:
spin_unlock(&irq_mapping_update_lock); spin_unlock(&irq_mapping_update_lock);
return irq; return irq;
error_irq:
spin_unlock(&irq_mapping_update_lock);
xen_free_irq(irq);
return -1;
} }
#endif #endif
......
...@@ -75,11 +75,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name); ...@@ -75,11 +75,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
/* Allocate an irq and a pirq to be used with MSIs. */ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
#define XEN_ALLOC_PIRQ (1 << 0) int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
#define XEN_ALLOC_IRQ (1 << 1) int pirq, int vector, const char *name);
void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask);
int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
#endif #endif
/* De-allocates the above mentioned physical interrupt. */ /* De-allocates the above mentioned physical interrupt. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment