mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
VT-d: Free unused interrupt remapping table entry
This patch changes the IRTE allocation method, and frees unused IRTE when device is de-assigned. Signed-Off-By: Zhai Edwin <edwin.zhai@intel.com>
This commit is contained in:
1 parent
dd14c75ad4
commit
d210b9fc62
4 files changed
+140
-43
No files matched your search
@@ -438,6 +438,11 @@ int msi_free_irq(struct msi_desc *entry)
|
||||
start = (unsigned long)entry->mask_base & ~(PAGE_SIZE - 1);
|
||||
msix_put_fixmap(entry->dev, virt_to_fix(start));
|
||||
}
|
||||
|
||||
/* Free the unused IRTE if intr remap enabled */
|
||||
if ( iommu_enabled )
|
||||
iommu_update_ire_from_msi(entry, NULL);
|
||||
|
||||
list_del(&entry->list);
|
||||
xfree(entry);
|
||||
return 0;
|
||||
|
||||
@@ -140,13 +140,72 @@ int iommu_supports_eim(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mark specified intr remap entry as free */
|
||||
static void free_remap_entry(struct iommu *iommu, int index)
|
||||
{
|
||||
struct iremap_entry *iremap_entry = NULL, *iremap_entries;
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
|
||||
if ( index < 0 || index > IREMAP_ENTRY_NR - 1 )
|
||||
return;
|
||||
|
||||
ASSERT( spin_is_locked(&ir_ctrl->iremap_lock) );
|
||||
|
||||
GET_IREMAP_ENTRY(ir_ctrl->iremap_maddr, index,
|
||||
iremap_entries, iremap_entry);
|
||||
|
||||
memset(iremap_entry, 0, sizeof(struct iremap_entry));
|
||||
iommu_flush_cache_entry(iremap_entry);
|
||||
iommu_flush_iec_index(iommu, 0, index);
|
||||
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
ir_ctrl->iremap_num--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a free intr remap entry.
|
||||
* Need hold iremap_lock, and setup returned entry before releasing lock.
|
||||
*/
|
||||
static int alloc_remap_entry(struct iommu *iommu)
|
||||
{
|
||||
struct iremap_entry *iremap_entries = NULL;
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
int i;
|
||||
|
||||
ASSERT( spin_is_locked(&ir_ctrl->iremap_lock) );
|
||||
|
||||
for ( i = 0; i < IREMAP_ENTRY_NR; i++ )
|
||||
{
|
||||
struct iremap_entry *p;
|
||||
if ( i % (1 << IREMAP_ENTRY_ORDER) == 0 )
|
||||
{
|
||||
/* This entry across page boundry */
|
||||
if ( iremap_entries )
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
|
||||
GET_IREMAP_ENTRY(ir_ctrl->iremap_maddr, i,
|
||||
iremap_entries, p);
|
||||
}
|
||||
else
|
||||
p = &iremap_entries[i % (1 << IREMAP_ENTRY_ORDER)];
|
||||
|
||||
if ( p->lo_val == 0 && p->hi_val == 0 ) /* a free entry */
|
||||
break;
|
||||
}
|
||||
|
||||
if ( iremap_entries )
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
|
||||
ir_ctrl->iremap_num++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int remap_entry_to_ioapic_rte(
|
||||
struct iommu *iommu, int index, struct IO_xAPIC_route_entry *old_rte)
|
||||
{
|
||||
struct iremap_entry *iremap_entry = NULL, *iremap_entries;
|
||||
unsigned long flags;
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
u64 entry_base;
|
||||
|
||||
if ( ir_ctrl == NULL )
|
||||
{
|
||||
@@ -155,21 +214,26 @@ static int remap_entry_to_ioapic_rte(
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if ( index > ir_ctrl->iremap_index )
|
||||
if ( index < 0 || index > IREMAP_ENTRY_NR - 1 )
|
||||
{
|
||||
dprintk(XENLOG_ERR VTDPREFIX,
|
||||
"%s: index (%d) is larger than remap table entry size (%d)!\n",
|
||||
__func__, index, ir_ctrl->iremap_index);
|
||||
"%s: index (%d) for remap table is invalid !\n",
|
||||
__func__, index);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
|
||||
|
||||
entry_base = ir_ctrl->iremap_maddr +
|
||||
(( index >> IREMAP_ENTRY_ORDER ) << PAGE_SHIFT );
|
||||
iremap_entries =
|
||||
(struct iremap_entry *)map_vtd_domain_page(entry_base);
|
||||
iremap_entry = &iremap_entries[index % (1 << IREMAP_ENTRY_ORDER)];
|
||||
GET_IREMAP_ENTRY(ir_ctrl->iremap_maddr, index,
|
||||
iremap_entries, iremap_entry);
|
||||
|
||||
if ( iremap_entry->hi_val == 0 && iremap_entry->lo_val == 0 )
|
||||
{
|
||||
dprintk(XENLOG_ERR VTDPREFIX,
|
||||
"%s: index (%d) get an empty entry!\n",
|
||||
__func__, index);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
old_rte->vector = iremap_entry->lo.vector;
|
||||
old_rte->delivery_mode = iremap_entry->lo.dlm;
|
||||
@@ -195,7 +259,6 @@ static int ioapic_rte_to_remap_entry(struct iommu *iommu,
|
||||
int index;
|
||||
unsigned long flags;
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
u64 entry_base;
|
||||
|
||||
remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
|
||||
spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
|
||||
@@ -203,8 +266,7 @@ static int ioapic_rte_to_remap_entry(struct iommu *iommu,
|
||||
index = apic_pin_2_ir_idx[apic][ioapic_pin];
|
||||
if ( index < 0 )
|
||||
{
|
||||
ir_ctrl->iremap_index++;
|
||||
index = ir_ctrl->iremap_index;
|
||||
index = alloc_remap_entry(iommu);
|
||||
apic_pin_2_ir_idx[apic][ioapic_pin] = index;
|
||||
}
|
||||
|
||||
@@ -218,11 +280,8 @@ static int ioapic_rte_to_remap_entry(struct iommu *iommu,
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
entry_base = ir_ctrl->iremap_maddr +
|
||||
(( index >> IREMAP_ENTRY_ORDER ) << PAGE_SHIFT );
|
||||
iremap_entries =
|
||||
(struct iremap_entry *)map_vtd_domain_page(entry_base);
|
||||
iremap_entry = &iremap_entries[index % (1 << IREMAP_ENTRY_ORDER)];
|
||||
GET_IREMAP_ENTRY(ir_ctrl->iremap_maddr, index,
|
||||
iremap_entries, iremap_entry);
|
||||
|
||||
memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
|
||||
|
||||
@@ -291,7 +350,7 @@ unsigned int io_apic_read_remap_rte(
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
|
||||
if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ||
|
||||
(ir_ctrl->iremap_index == -1) ||
|
||||
(ir_ctrl->iremap_num == 0) ||
|
||||
( (index = apic_pin_2_ir_idx[apic][ioapic_pin]) < 0 ) )
|
||||
{
|
||||
*IO_APIC_BASE(apic) = reg;
|
||||
@@ -431,7 +490,6 @@ static int remap_entry_to_msi_msg(
|
||||
int index;
|
||||
unsigned long flags;
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
u64 entry_base;
|
||||
|
||||
if ( ir_ctrl == NULL )
|
||||
{
|
||||
@@ -444,21 +502,26 @@ static int remap_entry_to_msi_msg(
|
||||
index = (remap_rte->address_lo.index_15 << 15) |
|
||||
remap_rte->address_lo.index_0_14;
|
||||
|
||||
if ( index > ir_ctrl->iremap_index )
|
||||
if ( index < 0 || index > IREMAP_ENTRY_NR - 1 )
|
||||
{
|
||||
dprintk(XENLOG_ERR VTDPREFIX,
|
||||
"%s: index (%d) is larger than remap table entry size (%d)\n",
|
||||
__func__, index, ir_ctrl->iremap_index);
|
||||
"%s: index (%d) for remap table is invalid !\n",
|
||||
__func__, index);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
|
||||
|
||||
entry_base = ir_ctrl->iremap_maddr +
|
||||
(( index >> IREMAP_ENTRY_ORDER ) << PAGE_SHIFT );
|
||||
iremap_entries =
|
||||
(struct iremap_entry *)map_vtd_domain_page(entry_base);
|
||||
iremap_entry = &iremap_entries[index % (1 << IREMAP_ENTRY_ORDER)];
|
||||
GET_IREMAP_ENTRY(ir_ctrl->iremap_maddr, index,
|
||||
iremap_entries, iremap_entry);
|
||||
|
||||
if ( iremap_entry->hi_val == 0 && iremap_entry->lo_val == 0 )
|
||||
{
|
||||
dprintk(XENLOG_ERR VTDPREFIX,
|
||||
"%s: index (%d) get an empty entry!\n",
|
||||
__func__, index);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
msg->address_hi = MSI_ADDR_BASE_HI;
|
||||
msg->address_lo =
|
||||
@@ -498,15 +561,27 @@ static int msi_msg_to_remap_entry(
|
||||
int index;
|
||||
unsigned long flags;
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
u64 entry_base;
|
||||
|
||||
remap_rte = (struct msi_msg_remap_entry *) msg;
|
||||
spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
|
||||
|
||||
if ( msg == NULL )
|
||||
{
|
||||
/* Free specified unused IRTE */
|
||||
free_remap_entry(iommu, msi_desc->remap_index);
|
||||
spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( msi_desc->remap_index < 0 )
|
||||
{
|
||||
ir_ctrl->iremap_index++;
|
||||
index = ir_ctrl->iremap_index;
|
||||
/*
|
||||
* TODO: Multiple-vector MSI requires allocating multiple continuous
|
||||
* entries and configuring addr/data of msi_msg in different way. So
|
||||
* alloca_remap_entry will be changed if enabling multiple-vector MSI
|
||||
* in future.
|
||||
*/
|
||||
index = alloc_remap_entry(iommu);
|
||||
msi_desc->remap_index = index;
|
||||
}
|
||||
else
|
||||
@@ -523,11 +598,9 @@ static int msi_msg_to_remap_entry(
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
entry_base = ir_ctrl->iremap_maddr +
|
||||
(( index >> IREMAP_ENTRY_ORDER ) << PAGE_SHIFT );
|
||||
iremap_entries =
|
||||
(struct iremap_entry *)map_vtd_domain_page(entry_base);
|
||||
iremap_entry = &iremap_entries[index % (1 << IREMAP_ENTRY_ORDER)];
|
||||
GET_IREMAP_ENTRY(ir_ctrl->iremap_maddr, index,
|
||||
iremap_entries, iremap_entry);
|
||||
|
||||
memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
|
||||
|
||||
/* Set interrupt remapping table entry */
|
||||
@@ -642,7 +715,7 @@ int enable_intremap(struct iommu *iommu)
|
||||
"Cannot allocate memory for ir_ctrl->iremap_maddr\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ir_ctrl->iremap_index = -1;
|
||||
ir_ctrl->iremap_num = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
|
||||
@@ -325,6 +325,20 @@ struct iremap_entry {
|
||||
#define iremap_set_present(v) do {(v).lo |= 1;} while(0)
|
||||
#define iremap_clear_present(v) do {(v).lo &= ~1;} while(0)
|
||||
|
||||
/*
|
||||
* Get the intr remap entry:
|
||||
* maddr - machine addr of the table
|
||||
* index - index of the entry
|
||||
* entries - return addr of the page holding this entry, need unmap it
|
||||
* entry - return required entry
|
||||
*/
|
||||
#define GET_IREMAP_ENTRY(maddr, index, entries, entry) \
|
||||
do { \
|
||||
entries = (struct iremap_entry *)map_vtd_domain_page( \
|
||||
(maddr) + (( (index) >> IREMAP_ENTRY_ORDER ) << PAGE_SHIFT ) ); \
|
||||
entry = &entries[(index) % (1 << IREMAP_ENTRY_ORDER)]; \
|
||||
} while(0)
|
||||
|
||||
/* queue invalidation entry */
|
||||
struct qinval_entry {
|
||||
union {
|
||||
@@ -472,7 +486,7 @@ struct qi_ctrl {
|
||||
|
||||
struct ir_ctrl {
|
||||
u64 iremap_maddr; /* interrupt remap table machine address */
|
||||
int iremap_index; /* interrupt remap index */
|
||||
int iremap_num; /* total num of used interrupt remap entry */
|
||||
spinlock_t iremap_lock; /* lock for irq remappping table */
|
||||
};
|
||||
|
||||
|
||||
@@ -227,6 +227,7 @@ static void dump_iommu_info(unsigned char key)
|
||||
u64 iremap_maddr = dmar_readq(iommu->reg, DMAR_IRTA_REG);
|
||||
int nr_entry = 1 << ((iremap_maddr & 0xF) + 1);
|
||||
struct iremap_entry *iremap_entries = NULL;
|
||||
int print_cnt = 0;
|
||||
|
||||
printk(" Interrupt remapping table (nr_entry=0x%x. "
|
||||
"Only dump P=1 entries here):\n", nr_entry);
|
||||
@@ -238,14 +239,14 @@ static void dump_iommu_info(unsigned char key)
|
||||
if ( i % (1 << IREMAP_ENTRY_ORDER) == 0 )
|
||||
{
|
||||
/* This entry across page boundry */
|
||||
u64 entry_base = iremap_maddr +
|
||||
(( i >> IREMAP_ENTRY_ORDER ) << PAGE_SHIFT );
|
||||
if ( iremap_entries )
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
iremap_entries =
|
||||
(struct iremap_entry *)map_vtd_domain_page(entry_base);
|
||||
|
||||
GET_IREMAP_ENTRY(iremap_maddr, i,
|
||||
iremap_entries, p);
|
||||
}
|
||||
p = &iremap_entries[i % (1 << IREMAP_ENTRY_ORDER)];
|
||||
else
|
||||
p = &iremap_entries[i % (1 << IREMAP_ENTRY_ORDER)];
|
||||
|
||||
if ( !p->lo.p )
|
||||
continue;
|
||||
@@ -255,9 +256,13 @@ static void dump_iommu_info(unsigned char key)
|
||||
(u32)p->lo.dst, (u32)p->lo.vector, (u32)p->lo.avail,
|
||||
(u32)p->lo.dlm, (u32)p->lo.tm, (u32)p->lo.rh,
|
||||
(u32)p->lo.dm, (u32)p->lo.fpd, (u32)p->lo.p);
|
||||
print_cnt++;
|
||||
}
|
||||
if ( iremap_entries )
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
if ( iommu_ir_ctrl(iommu)->iremap_num != print_cnt )
|
||||
printk("Warning: Print %d IRTE (actually have %d)!\n",
|
||||
print_cnt, iommu_ir_ctrl(iommu)->iremap_num);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -276,7 +281,7 @@ static void dump_iommu_info(unsigned char key)
|
||||
iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
|
||||
ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ||
|
||||
ir_ctrl->iremap_index == -1 )
|
||||
ir_ctrl->iremap_num == 0 )
|
||||
continue;
|
||||
|
||||
printk( "\nRedirection table of IOAPIC %x:\n", apic);
|
||||
|
||||