2008-10-26 01:33:59 +02:00
|
|
|
# HG changeset patch
|
|
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
|
|
# Date 1223459328 -3600
|
|
|
|
# Node ID ed398097c03e16dacb1f3af19fa8faddf2deae1f
|
|
|
|
# Parent 1f85f7b216b34bfda4911b6a46548478f0e5d682
|
|
|
|
x86: Move pirq logic to irq.c.
|
|
|
|
|
|
|
|
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
|
|
|
|
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
|
|
|
|
|
2008-11-08 20:32:12 +01:00
|
|
|
Index: xen-3.3.1-testing/xen/arch/x86/irq.c
|
|
|
|
===================================================================
|
|
|
|
--- xen-3.3.1-testing.orig/xen/arch/x86/irq.c
|
|
|
|
+++ xen-3.3.1-testing/xen/arch/x86/irq.c
|
2008-10-26 01:33:59 +02:00
|
|
|
@@ -14,8 +14,11 @@
|
|
|
|
#include <xen/sched.h>
|
|
|
|
#include <xen/keyhandler.h>
|
|
|
|
#include <xen/compat.h>
|
|
|
|
-#include <asm/current.h>
|
|
|
|
+#include <xen/iocap.h>
|
|
|
|
#include <xen/iommu.h>
|
|
|
|
+#include <asm/msi.h>
|
|
|
|
+#include <asm/current.h>
|
|
|
|
+#include <public/physdev.h>
|
|
|
|
|
|
|
|
/* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
|
|
|
|
int opt_noirqbalance = 0;
|
2008-11-08 20:32:12 +01:00
|
|
|
@@ -742,6 +745,157 @@ int pirq_guest_force_unbind(struct domai
|
2008-10-26 01:33:59 +02:00
|
|
|
return bound;
|
|
|
|
}
|
|
|
|
|
|
|
|
+int get_free_pirq(struct domain *d, int type, int index)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ ASSERT(spin_is_locked(&d->evtchn_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;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int map_domain_pirq(
|
|
|
|
+ struct domain *d, int pirq, int vector, int type, void *data)
|
|
|
|
+{
|
|
|
|
+ int ret = 0;
|
|
|
|
+ int old_vector, old_pirq;
|
|
|
|
+ irq_desc_t *desc;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ ASSERT(spin_is_locked(&d->evtchn_lock));
|
|
|
|
+
|
|
|
|
+ if ( !IS_PRIV(current->domain) )
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ if ( pirq < 0 || pirq >= NR_PIRQS || vector < 0 || vector >= NR_VECTORS )
|
|
|
|
+ {
|
|
|
|
+ dprintk(XENLOG_G_ERR, "dom%d: invalid pirq %d or vector %d\n",
|
|
|
|
+ d->domain_id, 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)) )
|
|
|
|
+ {
|
|
|
|
+ dprintk(XENLOG_G_ERR, "dom%d: pirq %d or vector %d already mapped\n",
|
|
|
|
+ d->domain_id, pirq, vector);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = irq_permit_access(d, pirq);
|
|
|
|
+ if ( ret )
|
|
|
|
+ {
|
|
|
|
+ dprintk(XENLOG_G_ERR, "dom%d: could not permit access to irq %d\n",
|
|
|
|
+ d->domain_id, pirq);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ desc = &irq_desc[vector];
|
|
|
|
+ spin_lock_irqsave(&desc->lock, flags);
|
|
|
|
+
|
|
|
|
+ if ( type == MAP_PIRQ_TYPE_MSI )
|
|
|
|
+ {
|
|
|
|
+ struct msi_info *msi = (struct msi_info *)data;
|
|
|
|
+ if ( desc->handler != &no_irq_type )
|
|
|
|
+ dprintk(XENLOG_G_ERR, "dom%d: vector %d in use\n",
|
|
|
|
+ d->domain_id, vector);
|
|
|
|
+ desc->handler = &pci_msi_type;
|
|
|
|
+ ret = pci_enable_msi(msi);
|
|
|
|
+ if ( ret )
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ d->arch.pirq_vector[pirq] = vector;
|
|
|
|
+ d->arch.vector_pirq[vector] = pirq;
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* The pirq should have been unbound before this call. */
|
|
|
|
+int unmap_domain_pirq(struct domain *d, int pirq)
|
|
|
|
+{
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ irq_desc_t *desc;
|
|
|
|
+ int vector, ret = 0;
|
|
|
|
+ bool_t forced_unbind;
|
|
|
|
+
|
|
|
|
+ if ( (pirq < 0) || (pirq >= NR_PIRQS) )
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if ( !IS_PRIV(current->domain) )
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ ASSERT(spin_is_locked(&d->evtchn_lock));
|
|
|
|
+
|
|
|
|
+ vector = d->arch.pirq_vector[pirq];
|
|
|
|
+ if ( vector <= 0 )
|
|
|
|
+ {
|
|
|
|
+ dprintk(XENLOG_G_ERR, "dom%d: pirq %d not mapped\n",
|
|
|
|
+ d->domain_id, pirq);
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ forced_unbind = pirq_guest_force_unbind(d, pirq);
|
|
|
|
+ if ( forced_unbind )
|
|
|
|
+ dprintk(XENLOG_G_WARNING, "dom%d: forcing unbind of pirq %d\n",
|
|
|
|
+ d->domain_id, pirq);
|
|
|
|
+
|
|
|
|
+ desc = &irq_desc[vector];
|
|
|
|
+ spin_lock_irqsave(&desc->lock, flags);
|
|
|
|
+
|
|
|
|
+ BUG_ON(vector != d->arch.pirq_vector[pirq]);
|
|
|
|
+
|
|
|
|
+ if ( desc->msi_desc )
|
|
|
|
+ pci_disable_msi(vector);
|
|
|
|
+
|
|
|
|
+ if ( desc->handler == &pci_msi_type )
|
|
|
|
+ desc->handler = &no_irq_type;
|
|
|
|
+
|
|
|
|
+ if ( !forced_unbind )
|
|
|
|
+ {
|
|
|
|
+ d->arch.pirq_vector[pirq] = 0;
|
|
|
|
+ d->arch.vector_pirq[vector] = 0;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ d->arch.pirq_vector[pirq] = -vector;
|
|
|
|
+ d->arch.vector_pirq[vector] = -pirq;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
|
+
|
|
|
|
+ ret = irq_deny_access(d, pirq);
|
|
|
|
+ if ( ret )
|
|
|
|
+ dprintk(XENLOG_G_ERR, "dom%d: could not deny access to irq %d\n",
|
|
|
|
+ d->domain_id, pirq);
|
|
|
|
+
|
|
|
|
+ done:
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
extern void dump_ioapic_irq_info(void);
|
|
|
|
|
|
|
|
static void dump_irqs(unsigned char key)
|
2008-11-08 20:32:12 +01:00
|
|
|
Index: xen-3.3.1-testing/xen/arch/x86/physdev.c
|
|
|
|
===================================================================
|
|
|
|
--- xen-3.3.1-testing.orig/xen/arch/x86/physdev.c
|
|
|
|
+++ xen-3.3.1-testing/xen/arch/x86/physdev.c
|
2008-10-26 01:33:59 +02:00
|
|
|
@@ -26,171 +26,12 @@ 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;
|
|
|
|
-
|
|
|
|
- ASSERT(spin_is_locked(&d->evtchn_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;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int map_domain_pirq(struct domain *d, int pirq, int vector,
|
|
|
|
- struct physdev_map_pirq *map)
|
|
|
|
-{
|
|
|
|
- int ret = 0;
|
|
|
|
- int old_vector, old_pirq;
|
|
|
|
- struct msi_info msi;
|
|
|
|
- irq_desc_t *desc;
|
|
|
|
- unsigned long flags;
|
|
|
|
-
|
|
|
|
- ASSERT(spin_is_locked(&d->evtchn_lock));
|
|
|
|
-
|
|
|
|
- if ( !IS_PRIV(current->domain) )
|
|
|
|
- return -EPERM;
|
|
|
|
-
|
|
|
|
- if ( pirq < 0 || pirq >= NR_PIRQS || vector < 0 || vector >= NR_VECTORS )
|
|
|
|
- {
|
|
|
|
- dprintk(XENLOG_G_ERR, "dom%d: invalid pirq %d or vector %d\n",
|
|
|
|
- d->domain_id, 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)) )
|
|
|
|
- {
|
|
|
|
- dprintk(XENLOG_G_ERR, "dom%d: pirq %d or vector %d already mapped\n",
|
|
|
|
- d->domain_id, pirq, vector);
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = irq_permit_access(d, pirq);
|
|
|
|
- if ( ret )
|
|
|
|
- {
|
|
|
|
- dprintk(XENLOG_G_ERR, "dom%d: could not permit access to irq %d\n",
|
|
|
|
- d->domain_id, pirq);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- desc = &irq_desc[vector];
|
|
|
|
- spin_lock_irqsave(&desc->lock, flags);
|
|
|
|
-
|
|
|
|
- if ( map && MAP_PIRQ_TYPE_MSI == map->type )
|
|
|
|
- {
|
|
|
|
- if ( desc->handler != &no_irq_type )
|
|
|
|
- dprintk(XENLOG_G_ERR, "dom%d: vector %d in use\n",
|
|
|
|
- d->domain_id, vector);
|
|
|
|
- desc->handler = &pci_msi_type;
|
|
|
|
-
|
|
|
|
- msi.bus = map->bus;
|
|
|
|
- msi.devfn = map->devfn;
|
|
|
|
- msi.entry_nr = map->entry_nr;
|
|
|
|
- msi.table_base = map->table_base;
|
|
|
|
- msi.vector = vector;
|
|
|
|
-
|
|
|
|
- ret = pci_enable_msi(&msi);
|
|
|
|
- if ( ret )
|
|
|
|
- goto done;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- d->arch.pirq_vector[pirq] = vector;
|
|
|
|
- d->arch.vector_pirq[vector] = pirq;
|
|
|
|
-
|
|
|
|
-done:
|
|
|
|
- spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* The pirq should have 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->evtchn_lock));
|
|
|
|
-
|
|
|
|
- vector = d->arch.pirq_vector[pirq];
|
|
|
|
-
|
|
|
|
- if ( vector <= 0 )
|
|
|
|
- {
|
|
|
|
- dprintk(XENLOG_G_ERR, "dom%d: pirq %d not mapped\n",
|
|
|
|
- d->domain_id, pirq);
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- unsigned long flags;
|
|
|
|
- irq_desc_t *desc;
|
|
|
|
- bool_t forced_unbind = pirq_guest_force_unbind(d, pirq);
|
|
|
|
-
|
|
|
|
- if ( forced_unbind )
|
|
|
|
- dprintk(XENLOG_G_WARNING, "dom%d: forcing unbind of pirq %d\n",
|
|
|
|
- d->domain_id, pirq);
|
|
|
|
-
|
|
|
|
- desc = &irq_desc[vector];
|
|
|
|
- spin_lock_irqsave(&desc->lock, flags);
|
|
|
|
-
|
|
|
|
- BUG_ON(vector != d->arch.pirq_vector[pirq]);
|
|
|
|
-
|
|
|
|
- if ( desc->msi_desc )
|
|
|
|
- pci_disable_msi(vector);
|
|
|
|
-
|
|
|
|
- if ( desc->handler == &pci_msi_type )
|
|
|
|
- desc->handler = &no_irq_type;
|
|
|
|
-
|
|
|
|
- if ( !forced_unbind )
|
|
|
|
- {
|
|
|
|
- d->arch.pirq_vector[pirq] = 0;
|
|
|
|
- d->arch.vector_pirq[vector] = 0;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- d->arch.pirq_vector[pirq] = -vector;
|
|
|
|
- d->arch.vector_pirq[vector] = -pirq;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = irq_deny_access(d, pirq);
|
|
|
|
-
|
|
|
|
- if ( ret )
|
|
|
|
- dprintk(XENLOG_G_ERR, "dom%d: could not deny access to irq %d\n",
|
|
|
|
- d->domain_id, pirq);
|
|
|
|
-
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int physdev_map_pirq(struct physdev_map_pirq *map)
|
|
|
|
{
|
|
|
|
struct domain *d;
|
|
|
|
int vector, pirq, ret = 0;
|
|
|
|
+ struct msi_info _msi;
|
|
|
|
+ void *map_data = NULL;
|
|
|
|
|
|
|
|
/* if msi_enable is not enabled, map always succeeds */
|
|
|
|
if ( !msi_enable )
|
|
|
|
@@ -213,6 +54,7 @@ static int physdev_map_pirq(struct physd
|
|
|
|
goto free_domain;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ /* Verify or get vector. */
|
|
|
|
switch ( map->type )
|
|
|
|
{
|
|
|
|
case MAP_PIRQ_TYPE_GSI:
|
|
|
|
@@ -227,15 +69,16 @@ static int physdev_map_pirq(struct physd
|
|
|
|
if ( !vector )
|
|
|
|
{
|
|
|
|
dprintk(XENLOG_G_ERR, "dom%d: map irq with no vector %d\n",
|
|
|
|
- d->domain_id, map->index);
|
|
|
|
+ d->domain_id, vector);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto free_domain;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
+
|
|
|
|
case MAP_PIRQ_TYPE_MSI:
|
|
|
|
vector = map->index;
|
|
|
|
- if ( vector == -1 )
|
|
|
|
- vector = assign_irq_vector(AUTO_ASSIGN);
|
|
|
|
+ if ( vector == -1 )
|
|
|
|
+ vector = assign_irq_vector(AUTO_ASSIGN);
|
|
|
|
|
|
|
|
if ( vector < 0 || vector >= NR_VECTORS )
|
|
|
|
{
|
|
|
|
@@ -244,13 +87,23 @@ static int physdev_map_pirq(struct physd
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto free_domain;
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+ _msi.bus = map->bus;
|
|
|
|
+ _msi.devfn = map->devfn;
|
|
|
|
+ _msi.entry_nr = map->entry_nr;
|
|
|
|
+ _msi.table_base = map->table_base;
|
|
|
|
+ _msi.vector = vector;
|
|
|
|
+ map_data = &_msi;
|
|
|
|
break;
|
|
|
|
+
|
|
|
|
default:
|
|
|
|
- dprintk(XENLOG_G_ERR, "dom%d: wrong map_pirq type %x\n", d->domain_id, map->type);
|
|
|
|
+ dprintk(XENLOG_G_ERR, "dom%d: wrong map_pirq type %x\n",
|
|
|
|
+ d->domain_id, map->type);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto free_domain;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ /* Verify or get pirq. */
|
|
|
|
spin_lock(&d->evtchn_lock);
|
|
|
|
if ( map->pirq < 0 )
|
|
|
|
{
|
|
|
|
@@ -292,10 +145,10 @@ static int physdev_map_pirq(struct physd
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- ret = map_domain_pirq(d, pirq, vector, map);
|
|
|
|
-
|
|
|
|
+ ret = map_domain_pirq(d, pirq, vector, map->type, map_data);
|
|
|
|
if ( !ret )
|
|
|
|
map->pirq = pirq;
|
|
|
|
+
|
|
|
|
done:
|
|
|
|
spin_unlock(&d->evtchn_lock);
|
|
|
|
free_domain:
|
|
|
|
@@ -462,7 +315,8 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
|
|
|
|
if ( msi_enable )
|
|
|
|
{
|
|
|
|
spin_lock(&dom0->evtchn_lock);
|
|
|
|
- ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector, NULL);
|
|
|
|
+ ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector,
|
|
|
|
+ MAP_PIRQ_TYPE_GSI, NULL);
|
|
|
|
spin_unlock(&dom0->evtchn_lock);
|
|
|
|
}
|
|
|
|
|
2008-11-08 20:32:12 +01:00
|
|
|
Index: xen-3.3.1-testing/xen/include/asm-x86/irq.h
|
|
|
|
===================================================================
|
|
|
|
--- xen-3.3.1-testing.orig/xen/include/asm-x86/irq.h
|
|
|
|
+++ xen-3.3.1-testing/xen/include/asm-x86/irq.h
|
2008-10-26 01:33:59 +02:00
|
|
|
@@ -52,6 +52,11 @@ extern atomic_t irq_mis_count;
|
|
|
|
int pirq_acktype(struct domain *d, int irq);
|
|
|
|
int pirq_shared(struct domain *d , int irq);
|
|
|
|
|
|
|
|
+int map_domain_pirq(struct domain *d, int pirq, int vector, int type,
|
|
|
|
+ void *data);
|
|
|
|
+int unmap_domain_pirq(struct domain *d, int pirq);
|
|
|
|
+int get_free_pirq(struct domain *d, int type, int index);
|
|
|
|
+
|
|
|
|
#define domain_irq_to_vector(d, irq) (msi_enable ? (d)->arch.pirq_vector[irq] : irq_to_vector(irq))
|
|
|
|
#define domain_vector_to_irq(d, vec) (msi_enable ? (d)->arch.vector_pirq[vec] : vector_to_irq(vec))
|
|
|
|
|