# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1223463099 -3600
# Node ID 51a05fb4c6014059058de48b83a9431e7474a456
# Parent ed398097c03e16dacb1f3af19fa8faddf2deae1f
x86: Free MSI vector when a pirq is unmapped.
Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/domain.c | 1
xen/arch/x86/i8259.c | 4 +++
xen/arch/x86/io_apic.c | 49 ++++++++++++++++++++++++------------------
xen/arch/x86/irq.c | 18 +++++++++++++++
xen/arch/x86/physdev.c | 7 +++---
xen/include/asm-x86/io_apic.h | 1
xen/include/asm-x86/irq.h | 5 +++-
7 files changed, 60 insertions(+), 25 deletions(-)
diff -r ed398097c03e -r 51a05fb4c601 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Wed Oct 08 10:48:48 2008 +0100
+++ b/xen/arch/x86/domain.c Wed Oct 08 11:51:39 2008 +0100
@@ -459,6 +459,7 @@ void arch_domain_destroy(struct domain *
hvm_domain_destroy(d);
pci_release_devices(d);
+ free_domain_pirqs(d);
if ( !is_idle_domain(d) )
iommu_domain_destroy(d);
diff -r ed398097c03e -r 51a05fb4c601 xen/arch/x86/i8259.c
--- a/xen/arch/x86/i8259.c Wed Oct 08 10:48:48 2008 +0100
+++ b/xen/arch/x86/i8259.c Wed Oct 08 11:51:39 2008 +0100
@@ -408,6 +408,10 @@ void __init init_IRQ(void)
irq_desc[LEGACY_VECTOR(i)].handler = &i8259A_irq_type;
}
+ /* Never allocate the hypercall vector or Linux/BSD fast-trap vector. */
+ vector_irq[HYPERCALL_VECTOR] = NEVER_ASSIGN;
+ vector_irq[0x80] = NEVER_ASSIGN;
+
apic_intr_init();
/* Set the clock to HZ Hz */
diff -r ed398097c03e -r 51a05fb4c601 xen/arch/x86/io_apic.c
--- a/xen/arch/x86/io_apic.c Wed Oct 08 10:48:48 2008 +0100
+++ b/xen/arch/x86/io_apic.c Wed Oct 08 11:51:39 2008 +0100
@@ -87,7 +87,8 @@ static struct irq_pin_list {
} irq_2_pin[PIN_MAP_SIZE];
static int irq_2_pin_free_entry = NR_IRQS;
-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
+int vector_irq[NR_VECTORS] __read_mostly = {
+ [0 ... NR_VECTORS - 1] = FREE_TO_ASSIGN};
/*
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are
@@ -666,40 +667,46 @@ static inline int IO_APIC_irq_trigger(in
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
u8 irq_vector[NR_IRQ_VECTORS] __read_mostly;
+int free_irq_vector(int vector)
+{
+ int irq;
+
+ BUG_ON((vector > LAST_DYNAMIC_VECTOR) || (vector < FIRST_DYNAMIC_VECTOR));
+
+ spin_lock(&vector_lock);
+ if ((irq = vector_irq[vector]) == AUTO_ASSIGN)
+ vector_irq[vector] = FREE_TO_ASSIGN;
+ spin_unlock(&vector_lock);
+
+ return (irq == AUTO_ASSIGN) ? 0 : -EINVAL;
+}
+
int assign_irq_vector(int irq)
{
- static unsigned current_vector = FIRST_DYNAMIC_VECTOR, offset = 0;
+ static unsigned current_vector = FIRST_DYNAMIC_VECTOR;
unsigned vector;
BUG_ON(irq >= NR_IRQ_VECTORS);
+
spin_lock(&vector_lock);
- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
+ if ((irq != AUTO_ASSIGN) && (IO_APIC_VECTOR(irq) > 0)) {
spin_unlock(&vector_lock);
return IO_APIC_VECTOR(irq);
}
-next:
- current_vector += 8;
-
- /* Skip the hypercall vector. */
- if (current_vector == HYPERCALL_VECTOR)
- goto next;
-
- /* Skip the Linux/BSD fast-trap vector. */
- if (current_vector == 0x80)
- goto next;
-
- if (current_vector > LAST_DYNAMIC_VECTOR) {
- offset++;
- if (!(offset%8)) {
+ vector = current_vector;
+ while (vector_irq[vector] != FREE_TO_ASSIGN) {
+ if (++vector > LAST_DYNAMIC_VECTOR)
+ vector = FIRST_DYNAMIC_VECTOR;
+
+ if (vector == current_vector) {
spin_unlock(&vector_lock);
return -ENOSPC;
}
- current_vector = FIRST_DYNAMIC_VECTOR + offset;
- }
-
- vector = current_vector;
+ }
+
+ current_vector = vector;
vector_irq[vector] = irq;
if (irq != AUTO_ASSIGN)
IO_APIC_VECTOR(irq) = vector;
diff -r ed398097c03e -r 51a05fb4c601 xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c Wed Oct 08 10:48:48 2008 +0100
+++ b/xen/arch/x86/irq.c Wed Oct 08 11:51:39 2008 +0100
@@ -861,7 +861,10 @@ int unmap_domain_pirq(struct domain *d,
pci_disable_msi(vector);
if ( desc->handler == &pci_msi_type )
+ {
desc->handler = &no_irq_type;
+ free_irq_vector(vector);
+ }
if ( !forced_unbind )
{
@@ -883,6 +886,21 @@ int unmap_domain_pirq(struct domain *d,
done:
return ret;
+}
+
+void free_domain_pirqs(struct domain *d)
+{
+ int i;
+
+ ASSERT(d->is_dying == DOMDYING_dying);
+
+ spin_lock(&d->evtchn_lock);
+
+ for ( i = 0; i < NR_PIRQS; i++ )
+ if ( d->arch.pirq_vector[i] > 0 )
+ unmap_domain_pirq(d, i);
+
+ spin_unlock(&d->evtchn_lock);
}
extern void dump_ioapic_irq_info(void);
diff -r ed398097c03e -r 51a05fb4c601 xen/arch/x86/physdev.c
--- a/xen/arch/x86/physdev.c Wed Oct 08 10:48:48 2008 +0100
+++ b/xen/arch/x86/physdev.c Wed Oct 08 11:51:39 2008 +0100
@@ -79,7 +79,7 @@ static int physdev_map_pirq(struct physd
if ( vector < 0 || vector >= NR_VECTORS )
{
dprintk(XENLOG_G_ERR, "dom%d: map irq with wrong vector %d\n",
- d->domain_id, map->index);
+ d->domain_id, vector);
ret = -EINVAL;
goto free_domain;
}
@@ -140,13 +140,14 @@ static int physdev_map_pirq(struct physd
pirq = map->pirq;
}
-
ret = map_domain_pirq(d, pirq, vector, map->type, map_data);
- if ( !ret )
+ if ( ret == 0 )
map->pirq = pirq;
done:
spin_unlock(&d->evtchn_lock);
+ if ( (ret != 0) && (map->type == MAP_PIRQ_TYPE_MSI) && (map->index == -1) )
+ free_irq_vector(vector);
free_domain:
rcu_unlock_domain(d);
return ret;
diff -r ed398097c03e -r 51a05fb4c601 xen/include/asm-x86/io_apic.h
--- a/xen/include/asm-x86/io_apic.h Wed Oct 08 10:48:48 2008 +0100
+++ b/xen/include/asm-x86/io_apic.h Wed Oct 08 11:51:39 2008 +0100
@@ -190,5 +190,6 @@ static inline int ioapic_resume(void) {r
#endif
extern int assign_irq_vector(int irq);
+extern int free_irq_vector(int vector);
#endif
diff -r ed398097c03e -r 51a05fb4c601 xen/include/asm-x86/irq.h
--- a/xen/include/asm-x86/irq.h Wed Oct 08 10:48:48 2008 +0100
+++ b/xen/include/asm-x86/irq.h Wed Oct 08 11:51:39 2008 +0100
@@ -19,7 +19,9 @@
extern int vector_irq[NR_VECTORS];
extern u8 irq_vector[NR_IRQ_VECTORS];
-#define AUTO_ASSIGN -1
+#define AUTO_ASSIGN -1
+#define NEVER_ASSIGN -2
+#define FREE_TO_ASSIGN -3
#define platform_legacy_irq(irq) ((irq) < 16)
@@ -56,6 +58,7 @@ int map_domain_pirq(struct domain *d, in
void *data);
int unmap_domain_pirq(struct domain *d, int pirq);
int get_free_pirq(struct domain *d, int type, int index);
+void free_domain_pirqs(struct domain *d);
#define domain_irq_to_vector(d, irq) ((d)->arch.pirq_vector[(irq)])
#define domain_vector_to_irq(d, vec) ((d)->arch.vector_pirq[(vec)])
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|