# HG changeset patch # User Keir Fraser # Date 1223463099 -3600 # Node ID 51a05fb4c6014059058de48b83a9431e7474a456 # Parent ed398097c03e16dacb1f3af19fa8faddf2deae1f x86: Free MSI vector when a pirq is unmapped. Signed-off-by: Yunhong Jiang Signed-off-by: Keir Fraser 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))