xen: remap MSIs into pirqs when running as initial domain
Implement xen_create_msi_irq to create an msi and remap it as pirq. Use xen_create_msi_irq to implement an initial domain specific version of setup_msi_irqs. Signed-off-by: Qing He <qing.he@intel.com> Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
This commit is contained in:
parent
38aa66fcb7
commit
f731e3ef02
3 changed files with 101 additions and 18 deletions
|
@ -135,14 +135,12 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
|||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!xen_initial_domain()) {
|
||||
if (type == PCI_CAP_ID_MSIX)
|
||||
ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
|
||||
else
|
||||
ret = xen_pci_frontend_enable_msi(dev, &v);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
if (type == PCI_CAP_ID_MSIX)
|
||||
ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
|
||||
else
|
||||
ret = xen_pci_frontend_enable_msi(dev, &v);
|
||||
if (ret)
|
||||
goto error;
|
||||
i = 0;
|
||||
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
||||
irq = xen_allocate_pirq(v[i], 0, /* not sharable */
|
||||
|
@ -172,23 +170,40 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
|||
|
||||
static void xen_teardown_msi_irqs(struct pci_dev *dev)
|
||||
{
|
||||
/* Only do this when were are in non-privileged mode.*/
|
||||
if (!xen_initial_domain()) {
|
||||
struct msi_desc *msidesc;
|
||||
|
||||
msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
|
||||
if (msidesc->msi_attrib.is_msix)
|
||||
xen_pci_frontend_disable_msix(dev);
|
||||
else
|
||||
xen_pci_frontend_disable_msi(dev);
|
||||
}
|
||||
struct msi_desc *msidesc;
|
||||
|
||||
msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
|
||||
if (msidesc->msi_attrib.is_msix)
|
||||
xen_pci_frontend_disable_msix(dev);
|
||||
else
|
||||
xen_pci_frontend_disable_msi(dev);
|
||||
}
|
||||
|
||||
static void xen_teardown_msi_irq(unsigned int irq)
|
||||
{
|
||||
xen_destroy_irq(irq);
|
||||
}
|
||||
|
||||
static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
{
|
||||
int irq, ret;
|
||||
struct msi_desc *msidesc;
|
||||
|
||||
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
||||
irq = xen_create_msi_irq(dev, msidesc, type);
|
||||
if (irq < 0)
|
||||
return -1;
|
||||
|
||||
ret = set_irq_msi(irq, msidesc);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
xen_destroy_irq(irq);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int xen_pcifront_enable_irq(struct pci_dev *dev)
|
||||
|
@ -362,6 +377,10 @@ static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
|
|||
|
||||
static int __init pci_xen_initial_domain(void)
|
||||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
|
||||
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
|
||||
#endif
|
||||
xen_setup_acpi_sci();
|
||||
__acpi_register_gsi = acpi_register_gsi_xen;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/bootmem.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irqnr.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/desc.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
@ -656,6 +657,10 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
|
|||
return irq;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
#include <linux/msi.h>
|
||||
#include "../pci/msi.h"
|
||||
|
||||
void xen_allocate_pirq_msi(char *name, int *irq, int *pirq)
|
||||
{
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
@ -678,6 +683,61 @@ void xen_allocate_pirq_msi(char *name, int *irq, int *pirq)
|
|||
spin_unlock(&irq_mapping_update_lock);
|
||||
}
|
||||
|
||||
int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
|
||||
{
|
||||
int irq = -1;
|
||||
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);
|
||||
|
||||
irq = find_unbound_irq();
|
||||
|
||||
if (irq == -1)
|
||||
goto out;
|
||||
|
||||
rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "xen map irq failed %d\n", rc);
|
||||
|
||||
irq_free_desc(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,
|
||||
handle_level_irq,
|
||||
(type == PCI_CAP_ID_MSIX) ? "msi-x":"msi");
|
||||
|
||||
out:
|
||||
spin_unlock(&irq_mapping_update_lock);
|
||||
return irq;
|
||||
}
|
||||
#endif
|
||||
|
||||
int xen_destroy_irq(int irq)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
|
|
|
@ -72,8 +72,12 @@ void xen_hvm_evtchn_do_upcall(void);
|
|||
* usual. */
|
||||
int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
|
||||
int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
/* Allocate an irq and a pirq to be used with MSIs. */
|
||||
void xen_allocate_pirq_msi(char *name, int *irq, int *pirq);
|
||||
int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
|
||||
#endif
|
||||
|
||||
/* De-allocates the above mentioned physical interrupt. */
|
||||
int xen_destroy_irq(int irq);
|
||||
|
|
Loading…
Reference in a new issue