2008-10-26 01:33:59 +02:00
|
|
|
# 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>
|
|
|
|
|
2008-11-08 20:32:12 +01:00
|
|
|
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
|
2008-10-26 01:33:59 +02:00
|
|
|
@@ -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);
|
|
|
|
|
2008-11-08 20:32:12 +01:00
|
|
|
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
|
2008-10-26 01:33:59 +02:00
|
|
|
@@ -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 */
|
2008-11-08 20:32:12 +01:00
|
|
|
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
|
2008-10-26 01:33:59 +02:00
|
|
|
@@ -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;
|
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
|
|
|
|
@@ -872,7 +872,10 @@ int unmap_domain_pirq(struct domain *d,
|
2008-10-26 01:33:59 +02:00
|
|
|
pci_disable_msi(vector);
|
|
|
|
|
|
|
|
if ( desc->handler == &pci_msi_type )
|
|
|
|
+ {
|
|
|
|
desc->handler = &no_irq_type;
|
|
|
|
+ free_irq_vector(vector);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if ( !forced_unbind )
|
|
|
|
{
|
2008-11-08 20:32:12 +01:00
|
|
|
@@ -896,6 +899,24 @@ int unmap_domain_pirq(struct domain *d,
|
2008-10-26 01:33:59 +02:00
|
|
|
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)
|
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
|
|
|
@@ -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;
|
2008-11-08 20:32:12 +01:00
|
|
|
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
|
2008-10-26 01:33:59 +02:00
|
|
|
@@ -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
|
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
|
|
|
@@ -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))
|