xen/18574-msi-free-vector.patch

220 lines
6.9 KiB
Diff

# HG changeset patch
# User Keir Fraser <keir.fraser@citrix.com>
# Date 1223463099 -3600
# Node ID 51a05fb4c6014059058de48b83a9431e7474a456
# Parent ed398097c03e16dacb1f3af19fa8faddf2deae1f
x86: Free MSI vector when a pirq is unmapped.
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Index: xen-3.3.1-testing/xen/arch/x86/domain.c
===================================================================
--- xen-3.3.1-testing.orig/xen/arch/x86/domain.c
+++ xen-3.3.1-testing/xen/arch/x86/domain.c
@@ -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);
Index: xen-3.3.1-testing/xen/arch/x86/i8259.c
===================================================================
--- xen-3.3.1-testing.orig/xen/arch/x86/i8259.c
+++ xen-3.3.1-testing/xen/arch/x86/i8259.c
@@ -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 */
Index: xen-3.3.1-testing/xen/arch/x86/io_apic.c
===================================================================
--- xen-3.3.1-testing.orig/xen/arch/x86/io_apic.c
+++ xen-3.3.1-testing/xen/arch/x86/io_apic.c
@@ -90,7 +90,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
@@ -669,40 +670,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;
+ vector = current_vector;
+ while (vector_irq[vector] != FREE_TO_ASSIGN) {
+ if (++vector > LAST_DYNAMIC_VECTOR)
+ vector = FIRST_DYNAMIC_VECTOR;
- /* 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)) {
+ 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;
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
@@ -872,7 +872,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 )
{
@@ -896,6 +899,24 @@ int unmap_domain_pirq(struct domain *d,
return ret;
}
+void free_domain_pirqs(struct domain *d)
+{
+ int i;
+
+ ASSERT(d->is_dying == DOMDYING_dying);
+
+ if ( !msi_enable )
+ return;
+
+ 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);
static void dump_irqs(unsigned char key)
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
@@ -83,7 +83,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;
}
@@ -144,13 +144,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;
Index: xen-3.3.1-testing/xen/include/asm-x86/io_apic.h
===================================================================
--- xen-3.3.1-testing.orig/xen/include/asm-x86/io_apic.h
+++ xen-3.3.1-testing/xen/include/asm-x86/io_apic.h
@@ -192,5 +192,6 @@ static inline int ioapic_resume(void) {r
#endif
extern int assign_irq_vector(int irq);
+extern int free_irq_vector(int vector);
#endif
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
@@ -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) (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))