aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-05-01 10:30:22 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-05-01 10:30:22 +0100
commitca0074e519fdc29c8574356b1ba551c8a1b235bb (patch)
tree4d65accb82731b261759c982e39a6a4ad78e9fc1
parent154c5516cb1264c9630f6100b28a7c7ed138430a (diff)
downloadxen-ca0074e519fdc29c8574356b1ba551c8a1b235bb.tar.gz
xen-ca0074e519fdc29c8574356b1ba551c8a1b235bb.tar.bz2
xen-ca0074e519fdc29c8574356b1ba551c8a1b235bb.zip
MSI 2/6: change the pirq to be per-domain
Signed-off-by: Jiang Yunhong <yunhong.jiang@intel.com> Signed-off-by: Shan Haitao <haitao.shan@intel.com>
-rw-r--r--tools/ioemu/hw/pass-through.c14
-rw-r--r--tools/libxc/xc_physdev.c40
-rw-r--r--tools/libxc/xc_private.h30
-rw-r--r--tools/libxc/xenctrl.h11
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c29
-rw-r--r--tools/python/xen/xend/server/irqif.py7
-rw-r--r--tools/python/xen/xend/server/pciif.py6
-rw-r--r--xen/arch/x86/domain.c2
-rw-r--r--xen/arch/x86/hvm/vmx/intr.c4
-rw-r--r--xen/arch/x86/io_apic.c19
-rw-r--r--xen/arch/x86/irq.c27
-rw-r--r--xen/arch/x86/physdev.c302
-rw-r--r--xen/drivers/passthrough/io.c12
-rw-r--r--xen/drivers/passthrough/vtd/x86/vtd.c2
-rw-r--r--xen/include/asm-x86/domain.h5
-rw-r--r--xen/include/asm-x86/irq.h6
-rw-r--r--xen/include/asm-x86/pirq.h11
-rw-r--r--xen/include/public/physdev.h27
18 files changed, 529 insertions, 25 deletions
diff --git a/tools/ioemu/hw/pass-through.c b/tools/ioemu/hw/pass-through.c
index 29ffda451e..0da7176d44 100644
--- a/tools/ioemu/hw/pass-through.c
+++ b/tools/ioemu/hw/pass-through.c
@@ -519,7 +519,21 @@ struct pt_dev * register_real_device(PCIBus *e_bus,
e_intx = assigned_device->dev.config[0x3d]-1;
if ( PT_MACHINE_IRQ_AUTO == machine_irq )
+ {
+ int pirq = pci_dev->irq;
+
machine_irq = pci_dev->irq;
+ rc = xc_physdev_map_pirq(xc_handle, domid, MAP_PIRQ_TYPE_GSI,
+ machine_irq, &pirq);
+
+ if ( rc )
+ {
+ /* TBD: unregister device in case of an error */
+ PT_LOG("Error: Mapping irq failed, rc = %d\n", rc);
+ }
+ else
+ machine_irq = pirq;
+ }
/* bind machine_irq to device */
if ( 0 != machine_irq )
diff --git a/tools/libxc/xc_physdev.c b/tools/libxc/xc_physdev.c
index 43ea7ff53f..1c5e8cb5da 100644
--- a/tools/libxc/xc_physdev.c
+++ b/tools/libxc/xc_physdev.c
@@ -19,3 +19,43 @@ int xc_physdev_pci_access_modify(int xc_handle,
errno = ENOSYS;
return -1;
}
+
+int xc_physdev_map_pirq(int xc_handle,
+ int domid,
+ int type,
+ int index,
+ int *pirq)
+{
+ int rc;
+ struct physdev_map_pirq map;
+
+ if ( !pirq )
+ return -EINVAL;
+
+ map.domid = domid;
+ map.type = type;
+ map.index = index;
+ map.pirq = *pirq;
+
+ rc = do_physdev_op(xc_handle, PHYSDEVOP_map_pirq, &map);
+
+ if ( !rc )
+ *pirq = map.pirq;
+
+ return rc;
+}
+
+int xc_physdev_unmap_pirq(int xc_handle,
+ int domid,
+ int pirq)
+{
+ int rc;
+ struct physdev_unmap_pirq unmap;
+
+ unmap.domid = domid;
+ unmap.pirq = pirq;
+
+ rc = do_physdev_op(xc_handle, PHYSDEVOP_unmap_pirq, &unmap);
+
+ return rc;
+}
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index b068e45dbe..0570e62dfb 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -24,10 +24,12 @@
#define DECLARE_HYPERCALL privcmd_hypercall_t hypercall = { 0 }
#define DECLARE_DOMCTL struct xen_domctl domctl = { 0 }
#define DECLARE_SYSCTL struct xen_sysctl sysctl = { 0 }
+#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op = { 0 }
#else
#define DECLARE_HYPERCALL privcmd_hypercall_t hypercall
#define DECLARE_DOMCTL struct xen_domctl domctl
#define DECLARE_SYSCTL struct xen_sysctl sysctl
+#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op
#endif
#undef PAGE_SHIFT
@@ -96,6 +98,34 @@ static inline int do_xen_version(int xc_handle, int cmd, void *dest)
return do_xen_hypercall(xc_handle, &hypercall);
}
+static inline int do_physdev_op(int xc_handle, int cmd, void *op)
+{
+ int ret = -1;
+
+ DECLARE_HYPERCALL;
+ hypercall.op = __HYPERVISOR_physdev_op;
+ hypercall.arg[0] = (unsigned long) cmd;
+ hypercall.arg[1] = (unsigned long) op;
+
+ if ( lock_pages(op, sizeof(*op)) != 0 )
+ {
+ PERROR("Could not lock memory for Xen hypercall");
+ goto out1;
+ }
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ DPRINTF("physdev operation failed -- need to"
+ " rebuild the user-space tool set?\n");
+ }
+
+ unlock_pages(op, sizeof(*op));
+
+out1:
+ return ret;
+}
+
static inline int do_domctl(int xc_handle, struct xen_domctl *domctl)
{
int ret = -1;
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index e05df73162..09e7becea3 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <xen/xen.h>
#include <xen/domctl.h>
+#include <xen/physdev.h>
#include <xen/sysctl.h>
#include <xen/version.h>
#include <xen/event_channel.h>
@@ -849,6 +850,16 @@ int xc_gnttab_munmap(int xcg_handle,
int xc_gnttab_set_max_grants(int xcg_handle,
uint32_t count);
+int xc_physdev_map_pirq(int xc_handle,
+ int domid,
+ int type,
+ int index,
+ int *pirq);
+
+int xc_physdev_unmap_pirq(int xc_handle,
+ int domid,
+ int pirq);
+
int xc_hvm_set_pci_intx_level(
int xc_handle, domid_t dom,
uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx,
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 53a26eed6b..709bbba62b 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -799,6 +799,26 @@ static PyObject *pyxc_evtchn_reset(XcObject *self,
return zero;
}
+static PyObject *pyxc_physdev_map_pirq(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ uint32_t dom;
+ int index, pirq, ret;
+
+ static char *kwd_list[] = {"domid", "index", "pirq", NULL};
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwd_list,
+ &dom, &index, &pirq) )
+ return NULL;
+ ret = xc_physdev_map_pirq(xc->xc_handle, dom, MAP_PIRQ_TYPE_GSI,
+ index, &pirq);
+ if ( ret != 0 )
+ return pyxc_error_to_exception();
+ return PyLong_FromUnsignedLong(pirq);
+}
+
static PyObject *pyxc_physdev_pci_access_modify(XcObject *self,
PyObject *args,
PyObject *kwds)
@@ -1589,6 +1609,15 @@ static PyMethodDef pyxc_methods[] = {
"Reset all connections.\n"
" dom [int]: Domain to reset.\n" },
+ { "physdev_map_pirq",
+ (PyCFunction)pyxc_physdev_map_pirq,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "map physical irq to guest pirq.\n"
+ " dom [int]: Identifier of domain to map for.\n"
+ " index [int]: physical irq.\n"
+ " pirq [int]: guest pirq.\n"
+ "Returns: [long] value of the param.\n" },
+
{ "physdev_pci_access_modify",
(PyCFunction)pyxc_physdev_pci_access_modify,
METH_VARARGS | METH_KEYWORDS, "\n"
diff --git a/tools/python/xen/xend/server/irqif.py b/tools/python/xen/xend/server/irqif.py
index 7e96726834..db4b1deedd 100644
--- a/tools/python/xen/xend/server/irqif.py
+++ b/tools/python/xen/xend/server/irqif.py
@@ -69,5 +69,10 @@ class IRQController(DevController):
#todo non-fatal
raise VmError(
'irq: Failed to configure irq: %d' % (pirq))
-
+ rc = xc.physdev_map_pirq(domid = self.getDomid(),
+ index = pirq,
+ pirq = pirq)
+ if rc < 0:
+ raise VmError(
+ 'irq: Failed to map irq %x' % (pirq))
return (None, {}, {})
diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py
index e616ebfe11..6f08e77e7c 100644
--- a/tools/python/xen/xend/server/pciif.py
+++ b/tools/python/xen/xend/server/pciif.py
@@ -271,6 +271,12 @@ class PciController(DevController):
if rc<0:
raise VmError(('pci: failed to configure I/O memory on device '+
'%s - errno=%d')%(dev.name,rc))
+ rc = xc.physdev_map_pirq(domid = fe_domid,
+ index = dev.irq,
+ pirq = dev.irq)
+ if rc < 0:
+ raise VmError(('pci: failed to map irq on device '+
+ '%s - errno=%d')%(dev.name,rc))
if dev.irq>0:
log.debug('pci: enabling irq %d'%dev.irq)
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 4fd1ac1f51..85ff65eadc 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -525,6 +525,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
goto fail;
}
+ spin_lock_init(&d->arch.irq_lock);
+
if ( is_hvm_domain(d) )
{
if ( (rc = hvm_domain_initialise(d)) != 0 )
diff --git a/xen/arch/x86/hvm/vmx/intr.c b/xen/arch/x86/hvm/vmx/intr.c
index 3fcfc52175..72dfd1d6ac 100644
--- a/xen/arch/x86/hvm/vmx/intr.c
+++ b/xen/arch/x86/hvm/vmx/intr.c
@@ -121,7 +121,7 @@ static void vmx_dirq_assist(struct vcpu *v)
if ( !test_and_clear_bit(irq, &hvm_irq_dpci->dirq_mask) )
continue;
- stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]);
+ stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)]);
list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list )
{
@@ -140,7 +140,7 @@ static void vmx_dirq_assist(struct vcpu *v)
* guest will never deal with the irq, then the physical interrupt line
* will never be deasserted.
*/
- set_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)],
+ set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)],
NOW() + PT_IRQ_TIME_OUT);
}
}
diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
index b7e50ae8f1..67cfed78b6 100644
--- a/xen/arch/x86/io_apic.c
+++ b/xen/arch/x86/io_apic.c
@@ -41,6 +41,25 @@
int (*ioapic_renumber_irq)(int ioapic, int irq);
atomic_t irq_mis_count;
+int msi_irq_enable = 0;
+boolean_param("msi_irq_enable", msi_irq_enable);
+
+int domain_irq_to_vector(struct domain *d, int irq)
+{
+ if ( !msi_irq_enable )
+ return irq_to_vector(irq);
+ else
+ return d->arch.pirq_vector[irq];
+}
+
+int domain_vector_to_irq(struct domain *d, int vector)
+{
+ if ( !msi_irq_enable )
+ return vector_to_irq(vector);
+ else
+ return d->arch.vector_pirq[vector];
+}
+
/* Where if anywhere is the i8259 connect in external int mode */
static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index fc050d7d60..ea840dfbdd 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -203,7 +203,6 @@ static DEFINE_PER_CPU(struct pending_eoi, pending_eoi[NR_VECTORS]);
static void __do_IRQ_guest(int vector)
{
- unsigned int irq = vector_to_irq(vector);
irq_desc_t *desc = &irq_desc[vector];
irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
struct domain *d;
@@ -232,7 +231,9 @@ static void __do_IRQ_guest(int vector)
for ( i = 0; i < action->nr_guests; i++ )
{
+ unsigned int irq;
d = action->guest[i];
+ irq = domain_vector_to_irq(d, vector);
if ( (action->ack_type != ACKTYPE_NONE) &&
!test_and_set_bit(irq, d->pirq_mask) )
action->in_flight++;
@@ -305,8 +306,10 @@ static void __pirq_guest_eoi(struct domain *d, int irq)
irq_desc_t *desc;
irq_guest_action_t *action;
cpumask_t cpu_eoi_map;
+ int vector;
- desc = &irq_desc[irq_to_vector(irq)];
+ vector = domain_irq_to_vector(d, irq);
+ desc = &irq_desc[vector];
action = (irq_guest_action_t *)desc->action;
spin_lock_irq(&desc->lock);
@@ -324,7 +327,7 @@ static void __pirq_guest_eoi(struct domain *d, int irq)
if ( action->ack_type == ACKTYPE_UNMASK )
{
ASSERT(cpus_empty(action->cpu_eoi_map));
- desc->handler->end(irq_to_vector(irq));
+ desc->handler->end(vector);
spin_unlock_irq(&desc->lock);
return;
}
@@ -375,12 +378,12 @@ int pirq_guest_unmask(struct domain *d)
}
extern int ioapic_ack_new;
-int pirq_acktype(int irq)
+int pirq_acktype(struct domain *d, int irq)
{
irq_desc_t *desc;
unsigned int vector;
- vector = irq_to_vector(irq);
+ vector = domain_irq_to_vector(d, irq);
if ( vector == 0 )
return ACKTYPE_NONE;
@@ -421,7 +424,7 @@ int pirq_acktype(int irq)
return 0;
}
-int pirq_shared(int irq)
+int pirq_shared(struct domain *d, int irq)
{
unsigned int vector;
irq_desc_t *desc;
@@ -429,7 +432,7 @@ int pirq_shared(int irq)
unsigned long flags;
int shared;
- vector = irq_to_vector(irq);
+ vector = domain_irq_to_vector(d, irq);
if ( vector == 0 )
return 0;
@@ -453,7 +456,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
cpumask_t cpumask = CPU_MASK_NONE;
retry:
- vector = irq_to_vector(irq);
+ vector = domain_irq_to_vector(v->domain, irq);
if ( vector == 0 )
return -EINVAL;
@@ -487,7 +490,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
action->nr_guests = 0;
action->in_flight = 0;
action->shareable = will_share;
- action->ack_type = pirq_acktype(irq);
+ action->ack_type = pirq_acktype(v->domain, irq);
cpus_clear(action->cpu_eoi_map);
desc->depth = 0;
@@ -538,13 +541,15 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
int pirq_guest_unbind(struct domain *d, int irq)
{
- unsigned int vector = irq_to_vector(irq);
- irq_desc_t *desc = &irq_desc[vector];
+ unsigned int vector;
+ irq_desc_t *desc;
irq_guest_action_t *action;
cpumask_t cpu_eoi_map;
unsigned long flags;
int i;
+ vector = domain_irq_to_vector(d, irq);
+ desc = &irq_desc[vector];
BUG_ON(vector == 0);
spin_lock_irqsave(&desc->lock, flags);
diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c
index e42379d4ac..dd396fed07 100644
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -7,6 +7,7 @@
#include <xen/irq.h>
#include <xen/event.h>
#include <xen/guest_access.h>
+#include <xen/iocap.h>
#include <asm/current.h>
#include <asm/hypercall.h>
#include <public/xen.h>
@@ -24,6 +25,263 @@ int
ioapic_guest_write(
unsigned long physbase, unsigned int reg, u32 pval);
+static int get_free_pirq(struct domain *d, int type, int index)
+{
+ int i;
+
+ if ( d == NULL )
+ return -EINVAL;
+
+ ASSERT(spin_is_locked(&d->arch.irq_lock));
+
+ if ( type == MAP_PIRQ_TYPE_GSI )
+ {
+ for ( i = 16; i < NR_PIRQS; i++ )
+ if ( !d->arch.pirq_vector[i] )
+ break;
+ if ( i == NR_PIRQS )
+ return -ENOSPC;
+ }
+ else
+ {
+ for ( i = NR_PIRQS - 1; i >= 16; i-- )
+ if ( !d->arch.pirq_vector[i] )
+ break;
+ if ( i == 16 )
+ return -ENOSPC;
+ }
+
+ return i;
+}
+
+/*
+ * Caller hold the irq_lock
+ */
+static int map_domain_pirq(struct domain *d, int pirq, int vector, int type)
+{
+ int ret = 0;
+ int old_vector, old_pirq;
+
+ if ( d == NULL )
+ return -EINVAL;
+
+ ASSERT(spin_is_locked(&d->arch.irq_lock));
+
+ if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( pirq < 0 || pirq >= NR_PIRQS || vector < 0 || vector >= NR_VECTORS )
+ {
+ gdprintk(XENLOG_G_ERR,
+ "invalid pirq %x or vector %x\n", pirq, vector);
+ return -EINVAL;
+ }
+
+ old_vector = d->arch.pirq_vector[pirq];
+ old_pirq = d->arch.vector_pirq[vector];
+
+ if ( (old_vector && (old_vector != vector) ) ||
+ (old_pirq && (old_pirq != pirq)) )
+ {
+ gdprintk(XENLOG_G_ERR, "remap pirq %x vector %x while not unmap\n",
+ pirq, vector);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = irq_permit_access(d, pirq);
+ if ( ret )
+ {
+ gdprintk(XENLOG_G_ERR, "add irq permit access %x failed\n", pirq);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ d->arch.pirq_vector[pirq] = vector;
+ d->arch.vector_pirq[vector] = pirq;
+
+done:
+ return ret;
+}
+
+/*
+ * The pirq should has been unbound before this call
+ */
+static int unmap_domain_pirq(struct domain *d, int pirq)
+{
+ int ret = 0;
+ int vector;
+
+ if ( d == NULL || pirq < 0 || pirq > NR_PIRQS )
+ return -EINVAL;
+
+ if ( !IS_PRIV(current->domain) )
+ return -EINVAL;
+
+ ASSERT(spin_is_locked(&d->arch.irq_lock));
+
+ vector = d->arch.pirq_vector[pirq];
+
+ if ( !vector )
+ {
+ gdprintk(XENLOG_G_ERR, "domain %X: pirq %x not mapped still\n",
+ d->domain_id, pirq);
+ ret = -EINVAL;
+ }
+ else
+ d->arch.pirq_vector[pirq] = d->arch.vector_pirq[vector] = 0;
+ ret = irq_deny_access(d, pirq);
+
+ if ( ret )
+ gdprintk(XENLOG_G_ERR, "deny irq %x access failed\n", pirq);
+
+ return ret;
+}
+
+extern int msi_irq_enable;
+static int physdev_map_pirq(struct physdev_map_pirq *map)
+{
+ struct domain *d;
+ int vector, pirq, ret = 0;
+ unsigned long flags;
+
+ /* if msi_irq_enable is not enabled,map always success */
+ if ( !msi_irq_enable )
+ return 0;
+
+ if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( !map )
+ return -EINVAL;
+
+ if ( map->domid == DOMID_SELF )
+ d = rcu_lock_domain(current->domain);
+ else
+ d = rcu_lock_domain_by_id(map->domid);
+
+ if ( d == NULL )
+ {
+ ret = -ESRCH;
+ goto free_domain;
+ }
+
+ switch ( map->type )
+ {
+ case MAP_PIRQ_TYPE_GSI:
+ if ( map->index >= NR_IRQS )
+ {
+ ret = -EINVAL;
+ gdprintk(XENLOG_G_ERR,
+ "map invalid irq %x\n", map->index);
+ goto free_domain;
+ }
+ vector = IO_APIC_VECTOR(map->index);
+ if ( !vector )
+ {
+ ret = -EINVAL;
+ gdprintk(XENLOG_G_ERR,
+ "map irq with no vector %x\n", map->index);
+ goto free_domain;
+ }
+ break;
+ case MAP_PIRQ_TYPE_MSI:
+ vector = map->index;
+ if ( vector < 0 || vector >= NR_VECTORS )
+ {
+ ret = -EINVAL;
+ gdprintk(XENLOG_G_ERR,
+ "map_pirq with wrong vector %x\n", map->index);
+ goto free_domain;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ gdprintk(XENLOG_G_ERR, "wrong map_pirq type %x\n", map->type);
+ goto free_domain;
+ break;
+ }
+
+ spin_lock_irqsave(&d->arch.irq_lock, flags);
+ if ( map->pirq == -1 )
+ {
+ if ( d->arch.vector_pirq[vector] )
+ {
+ gdprintk(XENLOG_G_ERR, "%x %x mapped already%x\n",
+ map->index, map->pirq,
+ d->arch.vector_pirq[vector]);
+ pirq = d->arch.vector_pirq[vector];
+ }
+ else
+ {
+ pirq = get_free_pirq(d, map->type, map->index);
+ if ( pirq < 0 )
+ {
+ ret = pirq;
+ gdprintk(XENLOG_G_ERR, "No free pirq\n");
+ goto done;
+ }
+ }
+ }
+ else
+ {
+ if ( d->arch.vector_pirq[vector] &&
+ d->arch.vector_pirq[vector] != map->pirq )
+ {
+ gdprintk(XENLOG_G_ERR, "%x conflict with %x\n",
+ map->index, map->pirq);
+ ret = -EEXIST;
+ goto done;
+ }
+ else
+ pirq = map->pirq;
+ }
+
+ ret = map_domain_pirq(d, pirq, vector, map->type);
+
+ if ( !ret )
+ map->pirq = pirq;
+done:
+ spin_unlock_irqrestore(&d->arch.irq_lock, flags);
+free_domain:
+ rcu_unlock_domain(d);
+ return ret;
+}
+
+static int physdev_unmap_pirq(struct physdev_unmap_pirq *unmap)
+{
+ struct domain *d;
+ unsigned long flags;
+ int ret;
+
+ if ( !msi_irq_enable )
+ return 0;
+
+ if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( !unmap )
+ return -EINVAL;
+
+ if ( unmap->domid == DOMID_SELF )
+ d = rcu_lock_domain(current->domain);
+ else
+ d = rcu_lock_domain_by_id(unmap->domid);
+
+ if ( d == NULL )
+ {
+ rcu_unlock_domain(d);
+ return -ESRCH;
+ }
+
+ spin_lock_irqsave(&d->arch.irq_lock, flags);
+ ret = unmap_domain_pirq(d, unmap->pirq);
+ spin_unlock_irqrestore(&d->arch.irq_lock, flags);
+ rcu_unlock_domain(d);
+
+ return ret;
+}
+
ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
{
int irq;
@@ -57,14 +315,38 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
if ( (irq < 0) || (irq >= NR_IRQS) )
break;
irq_status_query.flags = 0;
- if ( pirq_acktype(irq) != 0 )
+ if ( pirq_acktype(v->domain, irq) != 0 )
irq_status_query.flags |= XENIRQSTAT_needs_eoi;
- if ( pirq_shared(irq) )
+ if ( pirq_shared(v->domain, irq) )
irq_status_query.flags |= XENIRQSTAT_shared;
ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0;
break;
}
+ case PHYSDEVOP_map_pirq: {
+ struct physdev_map_pirq map;
+
+ ret = -EFAULT;
+ if ( copy_from_guest(&map, arg, 1) != 0 )
+ break;
+
+ ret = physdev_map_pirq(&map);
+ if ( copy_to_guest(arg, &map, 1) != 0 )
+ ret = -EFAULT;
+ break;
+ }
+
+ case PHYSDEVOP_unmap_pirq: {
+ struct physdev_unmap_pirq unmap;
+
+ ret = -EFAULT;
+ if ( copy_from_guest(&unmap, arg, 1) != 0 )
+ break;
+
+ ret = physdev_unmap_pirq(&unmap);
+ break;
+ }
+
case PHYSDEVOP_apic_read: {
struct physdev_apic apic;
ret = -EFAULT;
@@ -99,6 +381,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
case PHYSDEVOP_alloc_irq_vector: {
struct physdev_irq irq_op;
+ unsigned long flags;
ret = -EFAULT;
if ( copy_from_guest(&irq_op, arg, 1) != 0 )
@@ -118,7 +401,20 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
break;
irq_op.vector = assign_irq_vector(irq);
- ret = copy_to_guest(arg, &irq_op, 1) ? -EFAULT : 0;
+
+ ret = 0;
+
+ if ( msi_irq_enable )
+ {
+ spin_lock_irqsave(&dom0->arch.irq_lock, flags);
+ if ( irq != AUTO_ASSIGN )
+ ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector,
+ MAP_PIRQ_TYPE_GSI);
+ spin_unlock_irqrestore(&dom0->arch.irq_lock, flags);
+ }
+
+ if ( copy_to_guest(arg, &irq_op, 1) != 0 )
+ ret = -EFAULT;
break;
}
diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c
index 528839550b..b0f55bc802 100644
--- a/xen/drivers/passthrough/io.c
+++ b/xen/drivers/passthrough/io.c
@@ -25,6 +25,7 @@ static void pt_irq_time_out(void *data)
{
struct hvm_mirq_dpci_mapping *irq_map = data;
unsigned int guest_gsi, machine_gsi = 0;
+ int vector;
struct hvm_irq_dpci *dpci = domain_get_irq_dpci(irq_map->dom);
struct dev_intx_gsi_link *digl;
uint32_t device, intx;
@@ -39,7 +40,8 @@ static void pt_irq_time_out(void *data)
}
clear_bit(machine_gsi, dpci->dirq_mask);
- stop_timer(&dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+ vector = domain_irq_to_vector(irq_map->dom, machine_gsi);
+ stop_timer(&dpci->hvm_timer[vector]);
spin_lock(&dpci->dirq_lock);
dpci->mirq[machine_gsi].pending = 0;
spin_unlock(&dpci->dirq_lock);
@@ -98,7 +100,7 @@ int pt_irq_create_bind_vtd(
hvm_irq_dpci->mirq[machine_gsi].valid = 1;
hvm_irq_dpci->mirq[machine_gsi].dom = d;
- init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
+ init_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)],
pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
/* Deal with gsi for legacy devices */
pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
@@ -157,7 +159,7 @@ int pt_irq_destroy_bind_vtd(
if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
{
pirq_guest_unbind(d, machine_gsi);
- kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+ kill_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
hvm_irq_dpci->mirq[machine_gsi].valid = 0;
}
@@ -185,7 +187,7 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
* PIC) and we need to detect that.
*/
set_bit(mirq, dpci->dirq_mask);
- set_timer(&dpci->hvm_timer[irq_to_vector(mirq)],
+ set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
NOW() + PT_IRQ_TIME_OUT);
vcpu_kick(d->vcpu[0]);
@@ -221,7 +223,7 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
gdprintk(XENLOG_INFO VTDPREFIX,
"hvm_dpci_eoi:: mirq = %x\n", machine_gsi);
- stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+ stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
if ( (ent == NULL) || !ent->fields.mask )
pirq_guest_eoi(d, machine_gsi);
}
diff --git a/xen/drivers/passthrough/vtd/x86/vtd.c b/xen/drivers/passthrough/vtd/x86/vtd.c
index b78bce80ed..098a1b949a 100644
--- a/xen/drivers/passthrough/vtd/x86/vtd.c
+++ b/xen/drivers/passthrough/vtd/x86/vtd.c
@@ -114,7 +114,7 @@ void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)
if ( --dpci->mirq[i].pending == 0 )
{
spin_unlock(&dpci->dirq_lock);
- stop_timer(&dpci->hvm_timer[irq_to_vector(i)]);
+ stop_timer(&dpci->hvm_timer[domain_irq_to_vector(d, i)]);
pirq_guest_eoi(d, i);
}
else
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 8c4ee649b4..106a90656e 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -6,6 +6,7 @@
#include <asm/hvm/vcpu.h>
#include <asm/hvm/domain.h>
#include <asm/e820.h>
+#include <asm/pirq.h>
#define has_32bit_shinfo(d) ((d)->arch.has_32bit_shinfo)
#define is_pv_32bit_domain(d) ((d)->arch.is_32bit_pv)
@@ -222,6 +223,10 @@ struct arch_domain
/* Shadow translated domain: P2M mapping */
pagetable_t phys_table;
+ spinlock_t irq_lock;
+ int vector_pirq[NR_VECTORS];
+ int pirq_vector[NR_PIRQS];
+
/* Pseudophysical e820 map (XENMEM_memory_map). */
struct e820entry e820[3];
unsigned int nr_e820;
diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h
index e92e775945..8858b4eb95 100644
--- a/xen/include/asm-x86/irq.h
+++ b/xen/include/asm-x86/irq.h
@@ -49,7 +49,9 @@ extern unsigned long io_apic_irqs;
extern atomic_t irq_err_count;
extern atomic_t irq_mis_count;
-int pirq_acktype(int irq);
-int pirq_shared(int irq);
+int pirq_acktype(struct domain *d, int irq);
+int pirq_shared(struct domain *d , int irq);
+extern int domain_irq_to_vector(struct domain *d, int irq);
+extern int domain_vector_to_irq(struct domain *d, int vector);
#endif /* _ASM_HW_IRQ_H */
diff --git a/xen/include/asm-x86/pirq.h b/xen/include/asm-x86/pirq.h
new file mode 100644
index 0000000000..2041262134
--- /dev/null
+++ b/xen/include/asm-x86/pirq.h
@@ -0,0 +1,11 @@
+#ifndef __XEN_PIRQ_H
+#define __XEN_PIRQ_H
+
+#define PIRQ_BASE 0
+#define NR_PIRQS 256
+
+#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS)
+#define NR_DYNIRQS 256
+
+#endif /* __XEN_PIRQ_H */
+
diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h
index 75990545b2..fdf6c2bf16 100644
--- a/xen/include/public/physdev.h
+++ b/xen/include/public/physdev.h
@@ -121,6 +121,33 @@ struct physdev_irq {
};
typedef struct physdev_irq physdev_irq_t;
DEFINE_XEN_GUEST_HANDLE(physdev_irq_t);
+
+#define MAP_PIRQ_TYPE_MSI 0x0
+#define MAP_PIRQ_TYPE_GSI 0x1
+#define MAP_PIRQ_TYPE_UNKNOWN 0x2
+
+#define PHYSDEVOP_map_pirq 13
+struct physdev_map_pirq {
+ domid_t domid;
+ /* IN */
+ int type;
+ /* IN */
+ int index;
+ /* IN or OUT */
+ int pirq;
+};
+typedef struct physdev_map_pirq physdev_map_pirq_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t);
+
+#define PHYSDEVOP_unmap_pirq 14
+struct physdev_unmap_pirq {
+ domid_t domid;
+ /* IN */
+ int pirq;
+};
+
+typedef struct physdev_unmap_pirq physdev_unmap_pirq_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_unmap_pirq_t);
/*
* Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()