[PATCH 5/5] vtd: Move intremap table to xenheap
Teddy Astie <[email protected]> Wed, 29 Jul 2026 11:59:47 +0200
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <1785319343.8631fc262581453bbf619ec5b2062170.19fad5345fc000e099@vates.tech> |
Interrupt remapping entries often needs to be accessed, and we're creating pointers to it on demand, which brings a lot of complexity (e.g GET_IREMAP_ENTRY() macro), move it to xenheap such that it's persistently mapped and we won't have to worry about mapping and unmapping individual intremap table pages. Signed-off-by: Teddy Astie <[email protected]> --- xen/drivers/passthrough/vtd/intremap.c | 61 +++++++++----------------- xen/drivers/passthrough/vtd/iommu.h | 16 +------ xen/drivers/passthrough/vtd/utils.c | 22 +++------- 3 files changed, 26 insertions(+), 73 deletions(-) diff --git a/xen/drivers/passthrough/vtd/intremap.c b/xen/drivers/passthrough/vtd/intremap.c index dd2788efd7..fc683516cb 100644 --- a/xen/drivers/passthrough/vtd/intremap.c +++ b/xen/drivers/passthrough/vtd/intremap.c @@ -17,6 +17,7 @@ * Copyright (C) Xiaohui Xin <[email protected]> */ +#include <xen/mm.h> #include <xen/irq.h> #include <xen/sched.h> #include <xen/iommu.h> @@ -208,21 +209,19 @@ static void update_irte(struct vtd_iommu *iommu, struct iremap_entry *entry, /* Mark specified intr remap entry as free */ static void free_remap_entry(struct vtd_iommu *iommu, int index) { - struct iremap_entry *iremap_entry = NULL, *iremap_entries, new_ire = { }; + struct iremap_entry *iremap_entry = NULL, new_ire = { }; if ( index < 0 || index > IREMAP_ENTRY_NR - 1 ) return; ASSERT(spin_is_locked(&iommu->intremap.lock)); - GET_IREMAP_ENTRY(iommu->intremap.maddr, index, - iremap_entries, iremap_entry); + iremap_entry = &iommu->intremap.entries[index]; update_irte(iommu, iremap_entry, &new_ire, false); iommu_sync_cache(iremap_entry, sizeof(*iremap_entry)); iommu_flush_iec_index(iommu, 0, index); - unmap_vtd_domain_page(iremap_entries); iommu->intremap.num--; } @@ -232,25 +231,13 @@ static void free_remap_entry(struct vtd_iommu *iommu, int index) */ static unsigned int alloc_remap_entry(struct vtd_iommu *iommu, unsigned int nr) { - struct iremap_entry *iremap_entries = NULL; unsigned int i, found; ASSERT(spin_is_locked(&iommu->intremap.lock)); for ( found = 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(iommu->intremap.maddr, i, - iremap_entries, p); - } - else - p = &iremap_entries[i % (1 << IREMAP_ENTRY_ORDER)]; + struct iremap_entry *p = &iommu->intremap.entries[i]; if ( p->val ) /* not a free entry */ found = 0; @@ -258,9 +245,6 @@ static unsigned int alloc_remap_entry(struct vtd_iommu *iommu, unsigned int nr) break; } - if ( iremap_entries ) - unmap_vtd_domain_page(iremap_entries); - if ( i < IREMAP_ENTRY_NR ) iommu->intremap.num += nr; @@ -270,7 +254,7 @@ static unsigned int alloc_remap_entry(struct vtd_iommu *iommu, unsigned int nr) static int remap_entry_to_ioapic_rte( struct vtd_iommu *iommu, int index, struct IO_APIC_route_entry *old_rte) { - struct iremap_entry *iremap_entry = NULL, *iremap_entries; + struct iremap_entry *iremap_entry = NULL; unsigned long flags; if ( index < 0 || index > IREMAP_ENTRY_NR - 1 ) @@ -283,15 +267,13 @@ static int remap_entry_to_ioapic_rte( spin_lock_irqsave(&iommu->intremap.lock, flags); - GET_IREMAP_ENTRY(iommu->intremap.maddr, index, - iremap_entries, iremap_entry); + iremap_entry = &iommu->intremap.entries[index]; if ( iremap_entry->val == 0 ) { dprintk(XENLOG_ERR VTDPREFIX, "IO-APIC index (%d) has an empty entry\n", index); - unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&iommu->intremap.lock, flags); return -EFAULT; } @@ -309,7 +291,6 @@ static int remap_entry_to_ioapic_rte( old_rte->dest.logical.logical_dest = iremap_entry->remap.dst >> 8; } - unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&iommu->intremap.lock, flags); return 0; @@ -319,7 +300,7 @@ static int ioapic_rte_to_remap_entry(struct vtd_iommu *iommu, int apic, unsigned int ioapic_pin, struct IO_APIC_route_entry *old_rte, struct IO_APIC_route_entry new_rte) { - struct iremap_entry *iremap_entry = NULL, *iremap_entries; + struct iremap_entry *iremap_entry = NULL; struct iremap_entry new_ire; struct IO_APIC_route_remap_entry *remap_rte; int index; @@ -347,8 +328,7 @@ static int ioapic_rte_to_remap_entry(struct vtd_iommu *iommu, return -EFAULT; } - GET_IREMAP_ENTRY(iommu->intremap.maddr, index, - iremap_entries, iremap_entry); + iremap_entry = &iommu->intremap.entries[index]; new_ire = *iremap_entry; @@ -388,7 +368,6 @@ static int ioapic_rte_to_remap_entry(struct vtd_iommu *iommu, iommu_sync_cache(iremap_entry, sizeof(*iremap_entry)); iommu_flush_iec_index(iommu, 0, index); - unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&iommu->intremap.lock, flags); return 0; } @@ -500,7 +479,7 @@ static int msi_msg_to_remap_entry( struct vtd_iommu *iommu, struct pci_dev *pdev, struct msi_desc *msi_desc, struct msi_msg *msg) { - struct iremap_entry *iremap_entry = NULL, *iremap_entries, new_ire = { }; + struct iremap_entry *iremap_entry = NULL, new_ire = { }; struct msi_msg_remap_entry *remap_rte; unsigned int index, i, nr = 1; unsigned long flags; @@ -556,8 +535,7 @@ static int msi_msg_to_remap_entry( return -EFAULT; } - GET_IREMAP_ENTRY(iommu->intremap.maddr, index, - iremap_entries, iremap_entry); + iremap_entry = &iommu->intremap.entries[index]; if ( !pi_desc ) { @@ -604,7 +582,6 @@ static int msi_msg_to_remap_entry( iommu_sync_cache(iremap_entry, sizeof(*iremap_entry)); iommu_flush_iec_index(iommu, 0, index); - unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&iommu->intremap.lock, flags); return alloc; @@ -628,7 +605,7 @@ int __init cf_check intel_setup_hpet_msi(struct msi_desc *msi_desc) unsigned long flags; int rc = 0; - if ( !iommu->intremap.maddr ) + if ( !iommu->intremap.entries ) return 0; spin_lock_irqsave(&iommu->intremap.lock, flags); @@ -663,7 +640,7 @@ int enable_intremap(struct vtd_iommu *iommu, int eim) sts = dmar_readl(iommu->reg, DMAR_GSTS_REG); /* Return if already enabled by Xen */ - if ( (sts & DMA_GSTS_IRES) && iommu->intremap.maddr ) + if ( (sts & DMA_GSTS_IRES) && iommu->intremap.entries ) return 0; if ( !(sts & DMA_GSTS_QIES) ) @@ -679,16 +656,18 @@ int enable_intremap(struct vtd_iommu *iommu, int eim) " Compatibility Format Interrupts permitted on IOMMU #%u:" " Device pass-through will be insecure\n", iommu->index); - if ( iommu->intremap.maddr == 0 ) + if ( !iommu->intremap.entries ) { - iommu->intremap.maddr = alloc_pgtable_maddr(IREMAP_ARCH_PAGE_NR, - iommu->node); - if ( iommu->intremap.maddr == 0 ) + iommu->intremap.entries = + alloc_xenheap_pages(get_order_from_pages(IREMAP_ARCH_PAGE_NR), + MEMF_node(iommu->node)); + if ( !iommu->intremap.entries ) { dprintk(XENLOG_WARNING VTDPREFIX, - "Cannot allocate memory for ir_ctrl->iremap_maddr\n"); + "Cannot allocate memory for iommu->intremap.entries\n"); return -ENOMEM; } + memset(iommu->intremap.entries, 0, IREMAP_ARCH_PAGE_NR * PAGE_SIZE); iommu->intremap.num = 0; } @@ -700,7 +679,7 @@ int enable_intremap(struct vtd_iommu *iommu, int eim) * Interrupt Mode. */ dmar_writeq(iommu->reg, DMAR_IRTA_REG, - iommu->intremap.maddr | IRTA_REG_TABLE_SIZE | + virt_to_maddr(iommu->intremap.entries) | IRTA_REG_TABLE_SIZE | (eim ? IRTA_EIME : 0)); /* set SIRTP */ diff --git a/xen/drivers/passthrough/vtd/iommu.h b/xen/drivers/passthrough/vtd/iommu.h index ccb00889d7..0cd2c2ef3a 100644 --- a/xen/drivers/passthrough/vtd/iommu.h +++ b/xen/drivers/passthrough/vtd/iommu.h @@ -357,20 +357,6 @@ 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 { @@ -491,7 +477,7 @@ struct vtd_iommu { uint64_t qinval_maddr; /* queue invalidation page machine address */ struct { - uint64_t maddr; /* interrupt remap table machine address */ + struct iremap_entry *entries; /* interrupt remap table entries */ unsigned int num; /* total num of used interrupt remap entry */ spinlock_t lock; /* lock for irq remapping table */ } intremap; diff --git a/xen/drivers/passthrough/vtd/utils.c b/xen/drivers/passthrough/vtd/utils.c index 7c4d032f4f..3ae4d35e2d 100644 --- a/xen/drivers/passthrough/vtd/utils.c +++ b/xen/drivers/passthrough/vtd/utils.c @@ -187,11 +187,12 @@ void cf_check vtd_dump_iommu_info(unsigned char key) { /* Dump interrupt remapping table. */ uint64_t irta = dmar_readq(iommu->reg, DMAR_IRTA_REG); - uint64_t iremap_maddr = irta & PAGE_MASK; unsigned int nr_entry = 1 << ((irta & 0xF) + 1); - struct iremap_entry *iremap_entries = NULL; unsigned int print_cnt = 0; + /* Hardware must be using the same table as us. */ + ASSERT((irta & PAGE_MASK) == virt_to_maddr(iommu->intremap.entries)); + printk(" Interrupt remapping table (nr_entry=%#x. " "Only dump P=1 entries here):\n", nr_entry); printk("R means remapped format, P means posted format.\n"); @@ -199,18 +200,7 @@ void cf_check vtd_dump_iommu_info(unsigned char key) printk("P: SVT SQ SID V AVL FPD PDA URG P\n"); for ( i = 0; i < nr_entry; 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(iremap_maddr, i, - iremap_entries, p); - } - else - p = &iremap_entries[i % (1 << IREMAP_ENTRY_ORDER)]; + struct iremap_entry *p = &iommu->intremap.entries[i]; if ( !p->remap.p ) continue; @@ -231,8 +221,6 @@ void cf_check vtd_dump_iommu_info(unsigned char key) print_cnt++; } - if ( iremap_entries ) - unmap_vtd_domain_page(iremap_entries); if ( iommu->intremap.num != print_cnt ) printk("Warning: Print %u IRTE (actually have %u)!\n", print_cnt, iommu->intremap.num); @@ -251,7 +239,7 @@ void cf_check vtd_dump_iommu_info(unsigned char key) { iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid); - if ( !iommu->intremap.maddr || !iommu->intremap.num ) + if ( !iommu->intremap.entries || !iommu->intremap.num ) continue; printk( "\nRedirection table of IOAPIC %x:\n", apic); -- 2.54.0 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech