From: "Zhai, Edwin" <edwin.zhai@intel.com>
To: Keir Fraser <keir.fraser@eu.citrix.com>
Cc: xen-devel@lists.xensource.com, "Zhai, Edwin" <edwin.zhai@intel.com>
Subject: [PATCH][IOMMU] Free unused interrupt remapping table entry
Date: Fri, 27 Nov 2009 14:06:54 +0800 [thread overview]
Message-ID: <4B0F6C7E.7000507@intel.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 149 bytes --]
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>
[-- Attachment #2: free_irte.patch --]
[-- Type: application/octet-stream, Size: 13166 bytes --]
Index: xen-dev/xen/arch/x86/msi.c
===================================================================
--- xen-dev.orig/xen/arch/x86/msi.c
+++ xen-dev/xen/arch/x86/msi.c
@@ -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;
Index: xen-dev/xen/drivers/passthrough/vtd/intremap.c
===================================================================
--- xen-dev.orig/xen/drivers/passthrough/vtd/intremap.c
+++ xen-dev/xen/drivers/passthrough/vtd/intremap.c
@@ -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(str
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(str
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(str
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
Index: xen-dev/xen/drivers/passthrough/vtd/iommu.h
===================================================================
--- xen-dev.orig/xen/drivers/passthrough/vtd/iommu.h
+++ xen-dev/xen/drivers/passthrough/vtd/iommu.h
@@ -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 */
};
Index: xen-dev/xen/drivers/passthrough/vtd/utils.c
===================================================================
--- xen-dev.orig/xen/drivers/passthrough/vtd/utils.c
+++ xen-dev/xen/drivers/passthrough/vtd/utils.c
@@ -227,6 +227,7 @@ static void dump_iommu_info(unsigned cha
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 cha
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 cha
(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 cha
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);
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
reply other threads:[~2009-11-27 6:06 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B0F6C7E.7000507@intel.com \
--to=edwin.zhai@intel.com \
--cc=keir.fraser@eu.citrix.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.