WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] VT-d: Free unused interrupt remapping tab

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] VT-d: Free unused interrupt remapping table entry
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 27 Nov 2009 00:40:18 -0800
Delivery-date: Fri, 27 Nov 2009 00:41:19 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1259309118 0
# Node ID 8b73b7840c550011166088e8e6436cf199cd0f14
# Parent  e2a8483d57f74737c934e1115d8ae6d126e2de8f
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@xxxxxxxxx>
---
 xen/arch/x86/msi.c                     |    5 +
 xen/drivers/passthrough/vtd/intremap.c |  153 ++++++++++++++++++++++++---------
 xen/drivers/passthrough/vtd/iommu.h    |   16 +++
 xen/drivers/passthrough/vtd/utils.c    |   17 ++-
 4 files changed, 144 insertions(+), 47 deletions(-)

diff -r e2a8483d57f7 -r 8b73b7840c55 xen/arch/x86/msi.c
--- a/xen/arch/x86/msi.c        Fri Nov 27 07:56:38 2009 +0000
+++ b/xen/arch/x86/msi.c        Fri Nov 27 08:05:18 2009 +0000
@@ -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;
diff -r e2a8483d57f7 -r 8b73b7840c55 xen/drivers/passthrough/vtd/intremap.c
--- a/xen/drivers/passthrough/vtd/intremap.c    Fri Nov 27 07:56:38 2009 +0000
+++ b/xen/drivers/passthrough/vtd/intremap.c    Fri Nov 27 08:05:18 2009 +0000
@@ -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 )
-    {
-        dprintk(XENLOG_ERR VTDPREFIX,
-                "%s: index (%d) is larger than remap table entry size (%d)!\n",
-                __func__, index, ir_ctrl->iremap_index);
+    if ( index < 0 || index > IREMAP_ENTRY_NR - 1 )
+    {
+        dprintk(XENLOG_ERR VTDPREFIX,
+                "%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 )
-    {
-        dprintk(XENLOG_ERR VTDPREFIX,
-                "%s: index (%d) is larger than remap table entry size (%d)\n",
-                __func__, index, ir_ctrl->iremap_index);
+    if ( index < 0 || index > IREMAP_ENTRY_NR - 1 )
+    {
+        dprintk(XENLOG_ERR VTDPREFIX,
+                "%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
diff -r e2a8483d57f7 -r 8b73b7840c55 xen/drivers/passthrough/vtd/iommu.h
--- a/xen/drivers/passthrough/vtd/iommu.h       Fri Nov 27 07:56:38 2009 +0000
+++ b/xen/drivers/passthrough/vtd/iommu.h       Fri Nov 27 08:05:18 2009 +0000
@@ -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 */
 };
 
diff -r e2a8483d57f7 -r 8b73b7840c55 xen/drivers/passthrough/vtd/utils.c
--- a/xen/drivers/passthrough/vtd/utils.c       Fri Nov 27 07:56:38 2009 +0000
+++ b/xen/drivers/passthrough/vtd/utils.c       Fri Nov 27 08:05:18 2009 +0000
@@ -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);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] VT-d: Free unused interrupt remapping table entry, Xen patchbot-unstable <=