[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 4/7] amd-iommu: reduce code duplication...
...by calling update_paging_mode() inside iommu_pde_from_dfn(). Also have iommu_pde_from_dfn() return -EFAULT if pt_mfn[1] is zero, to avoid the callers having to explictly test it. NOTE: The return value of iommu_pde_from_dfn() is ignored by amd_iommu_map_page(). Instead, to preserve the existing return semantics, -EFAULT is returned regardless of the actual error. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- Cc: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx> Cc: Brian Woods <brian.woods@xxxxxxx> --- xen/drivers/passthrough/amd/iommu_map.c | 276 ++++++++++++++++---------------- 1 file changed, 138 insertions(+), 138 deletions(-) diff --git a/xen/drivers/passthrough/amd/iommu_map.c b/xen/drivers/passthrough/amd/iommu_map.c index d7df8b9161..a186c8d28b 100644 --- a/xen/drivers/passthrough/amd/iommu_map.c +++ b/xen/drivers/passthrough/amd/iommu_map.c @@ -431,6 +431,102 @@ static int iommu_merge_pages(struct domain *d, unsigned long pt_mfn, return 0; } +static int update_paging_mode(struct domain *d, unsigned long dfn) +{ + uint16_t bdf; + void *device_entry; + unsigned int req_id, level, offset; + unsigned long flags; + struct pci_dev *pdev; + struct amd_iommu *iommu = NULL; + struct page_info *new_root = NULL; + struct page_info *old_root = NULL; + void *new_root_vaddr; + unsigned long old_root_mfn; + struct domain_iommu *hd = dom_iommu(d); + + ASSERT(dfn != dfn_x(INVALID_DFN)); + ASSERT(!(dfn >> DEFAULT_DOMAIN_ADDRESS_WIDTH)); + + level = hd->arch.paging_mode; + old_root = hd->arch.root_table; + offset = dfn >> (PTE_PER_TABLE_SHIFT * (level - 1)); + + ASSERT(spin_is_locked(&hd->arch.mapping_lock) && is_hvm_domain(d)); + + while ( offset >= PTE_PER_TABLE_SIZE ) + { + /* + * Allocate and install a new root table. + * Only upper I/O page table grows, no need to fix next level bits. + */ + new_root = alloc_amd_iommu_pgtable(); + if ( !new_root ) + { + AMD_IOMMU_DEBUG("%s Cannot allocate I/O page table\n", + __func__); + return -ENOMEM; + } + + new_root_vaddr = __map_domain_page(new_root); + old_root_mfn = mfn_x(page_to_mfn(old_root)); + set_iommu_pde_present(new_root_vaddr, old_root_mfn, level, + !!IOMMUF_writable, !!IOMMUF_readable); + + level++; + old_root = new_root; + offset >>= PTE_PER_TABLE_SHIFT; + unmap_domain_page(new_root_vaddr); + } + + if ( new_root ) + { + hd->arch.paging_mode = level; + hd->arch.root_table = new_root; + + if ( !pcidevs_locked() ) + AMD_IOMMU_DEBUG("%s Try to access pdev_list " + "without aquiring pcidevs_lock.\n", __func__); + + /* + * Update device table entries using new root table and paging + * mode. + */ + for_each_pdev ( d, pdev ) + { + bdf = PCI_BDF2(pdev->bus, pdev->devfn); + iommu = find_iommu_for_device(pdev->seg, bdf); + if ( !iommu ) + { + AMD_IOMMU_DEBUG("%s Fail to find iommu.\n", __func__); + return -ENODEV; + } + + spin_lock_irqsave(&iommu->lock, flags); + do { + req_id = get_dma_requestor_id(pdev->seg, bdf); + device_entry = iommu->dev_table.buffer + + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE); + + /* valid = 0 only works for dom0 passthrough mode */ + amd_iommu_set_root_page_table( + device_entry, page_to_maddr(hd->arch.root_table), + d->domain_id, hd->arch.paging_mode, 1); + + amd_iommu_flush_device(iommu, req_id); + bdf += pdev->phantom_stride; + } while ( PCI_DEVFN2(bdf) != pdev->devfn && + PCI_SLOT(bdf) == PCI_SLOT(pdev->devfn) ); + spin_unlock_irqrestore(&iommu->lock, flags); + } + + /* For safety, invalidate all entries */ + amd_iommu_flush_all_pages(d); + } + + return 0; +} + /* Walk io page tables and build level page tables if necessary * {Re, un}mapping super page frames causes re-allocation of io * page tables. @@ -445,23 +541,37 @@ static int iommu_pde_from_dfn(struct domain *d, unsigned long dfn, struct page_info *table; const struct domain_iommu *hd = dom_iommu(d); + /* + * Since HVM domain is initialized with 2 level IO page table, + * we might need a deeper page table for wider dfn now. + */ + if ( is_hvm_domain(d) ) + { + int rc = update_paging_mode(d, dfn); + + if ( rc ) + { + AMD_IOMMU_DEBUG("Update page mode failed dfn = %"PRI_dfn"\n", + dfn); + return rc; + } + } + table = hd->arch.root_table; level = hd->arch.paging_mode; - BUG_ON( table == NULL || level < IOMMU_PAGING_MODE_LEVEL_1 || + BUG_ON( !table || level < IOMMU_PAGING_MODE_LEVEL_1 || level > IOMMU_PAGING_MODE_LEVEL_6 ); next_table_mfn = mfn_x(page_to_mfn(table)); if ( level == IOMMU_PAGING_MODE_LEVEL_1 ) - { - pt_mfn[level] = next_table_mfn; - return 0; - } + goto out; while ( level > IOMMU_PAGING_MODE_LEVEL_1 ) { unsigned int next_level = level - 1; + pt_mfn[level] = next_table_mfn; next_table_vaddr = map_domain_page(_mfn(next_table_mfn)); @@ -485,11 +595,11 @@ static int iommu_pde_from_dfn(struct domain *d, unsigned long dfn, /* allocate lower level page table */ table = alloc_amd_iommu_pgtable(); - if ( table == NULL ) + if ( !table ) { AMD_IOMMU_DEBUG("Cannot allocate I/O page table\n"); unmap_domain_page(next_table_vaddr); - return 1; + return -EFAULT; } next_table_mfn = mfn_x(page_to_mfn(table)); @@ -510,14 +620,14 @@ static int iommu_pde_from_dfn(struct domain *d, unsigned long dfn, /* Install lower level page table for non-present entries */ else if ( !iommu_is_pte_present(pde) ) { - if ( next_table_mfn == 0 ) + if ( !next_table_mfn ) { table = alloc_amd_iommu_pgtable(); if ( table == NULL ) { AMD_IOMMU_DEBUG("Cannot allocate I/O page table\n"); unmap_domain_page(next_table_vaddr); - return 1; + return -EFAULT; } next_table_mfn = mfn_x(page_to_mfn(table)); set_iommu_pde_present(pde, next_table_mfn, next_level, @@ -526,7 +636,7 @@ static int iommu_pde_from_dfn(struct domain *d, unsigned long dfn, else /* should never reach here */ { unmap_domain_page(next_table_vaddr); - return 1; + return -EFAULT; } } @@ -534,99 +644,17 @@ static int iommu_pde_from_dfn(struct domain *d, unsigned long dfn, level--; } - /* mfn of level 1 page table */ - pt_mfn[level] = next_table_mfn; - return 0; -} - -static int update_paging_mode(struct domain *d, unsigned long dfn) -{ - uint16_t bdf; - void *device_entry; - unsigned int req_id, level, offset; - unsigned long flags; - struct pci_dev *pdev; - struct amd_iommu *iommu = NULL; - struct page_info *new_root = NULL; - struct page_info *old_root = NULL; - void *new_root_vaddr; - unsigned long old_root_mfn; - struct domain_iommu *hd = dom_iommu(d); - - if ( dfn == dfn_x(INVALID_DFN) ) - return -EADDRNOTAVAIL; - ASSERT(!(dfn >> DEFAULT_DOMAIN_ADDRESS_WIDTH)); - - level = hd->arch.paging_mode; - old_root = hd->arch.root_table; - offset = dfn >> (PTE_PER_TABLE_SHIFT * (level - 1)); - - ASSERT(spin_is_locked(&hd->arch.mapping_lock) && is_hvm_domain(d)); - - while ( offset >= PTE_PER_TABLE_SIZE ) + out: + if ( !next_table_mfn ) { - /* Allocate and install a new root table. - * Only upper I/O page table grows, no need to fix next level bits */ - new_root = alloc_amd_iommu_pgtable(); - if ( new_root == NULL ) - { - AMD_IOMMU_DEBUG("%s Cannot allocate I/O page table\n", - __func__); - return -ENOMEM; - } - - new_root_vaddr = __map_domain_page(new_root); - old_root_mfn = mfn_x(page_to_mfn(old_root)); - set_iommu_pde_present(new_root_vaddr, old_root_mfn, level, - !!IOMMUF_writable, !!IOMMUF_readable); - level++; - old_root = new_root; - offset >>= PTE_PER_TABLE_SHIFT; - unmap_domain_page(new_root_vaddr); + AMD_IOMMU_DEBUG("Invalid IO pagetable entry dfn = %"PRI_dfn"\n", + dfn); + return -EFAULT; } - if ( new_root != NULL ) - { - hd->arch.paging_mode = level; - hd->arch.root_table = new_root; - - if ( !pcidevs_locked() ) - AMD_IOMMU_DEBUG("%s Try to access pdev_list " - "without aquiring pcidevs_lock.\n", __func__); - - /* Update device table entries using new root table and paging mode */ - for_each_pdev( d, pdev ) - { - bdf = PCI_BDF2(pdev->bus, pdev->devfn); - iommu = find_iommu_for_device(pdev->seg, bdf); - if ( !iommu ) - { - AMD_IOMMU_DEBUG("%s Fail to find iommu.\n", __func__); - return -ENODEV; - } - - spin_lock_irqsave(&iommu->lock, flags); - do { - req_id = get_dma_requestor_id(pdev->seg, bdf); - device_entry = iommu->dev_table.buffer + - (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE); - - /* valid = 0 only works for dom0 passthrough mode */ - amd_iommu_set_root_page_table(device_entry, - page_to_maddr(hd->arch.root_table), - d->domain_id, - hd->arch.paging_mode, 1); - - amd_iommu_flush_device(iommu, req_id); - bdf += pdev->phantom_stride; - } while ( PCI_DEVFN2(bdf) != pdev->devfn && - PCI_SLOT(bdf) == PCI_SLOT(pdev->devfn) ); - spin_unlock_irqrestore(&iommu->lock, flags); - } + ASSERT(level == IOMMU_PAGING_MODE_LEVEL_1); + pt_mfn[level] = next_table_mfn; - /* For safety, invalidate all entries */ - amd_iommu_flush_all_pages(d); - } return 0; } @@ -636,13 +664,14 @@ int amd_iommu_map_page(struct domain *d, dfn_t dfn, mfn_t mfn, bool need_flush = false; struct domain_iommu *hd = dom_iommu(d); int rc; - unsigned long pt_mfn[7]; + unsigned long pt_mfn[7] = {}; unsigned int merge_level; if ( iommu_use_hap_pt(d) ) return 0; - memset(pt_mfn, 0, sizeof(pt_mfn)); + if ( dfn_eq(dfn, INVALID_DFN) ) + return -EFAULT; spin_lock(&hd->arch.mapping_lock); @@ -655,24 +684,9 @@ int amd_iommu_map_page(struct domain *d, dfn_t dfn, mfn_t mfn, return rc; } - /* Since HVM domain is initialized with 2 level IO page table, - * we might need a deeper page table for wider dfn now */ - if ( is_hvm_domain(d) ) - { - if ( update_paging_mode(d, dfn_x(dfn)) ) - { - spin_unlock(&hd->arch.mapping_lock); - AMD_IOMMU_DEBUG("Update page mode failed dfn = %"PRI_dfn"\n", - dfn_x(dfn)); - return -EFAULT; - } - } - - if ( iommu_pde_from_dfn(d, dfn_x(dfn), pt_mfn) || (pt_mfn[1] == 0) ) + if ( iommu_pde_from_dfn(d, dfn_x(dfn), pt_mfn) ) { spin_unlock(&hd->arch.mapping_lock); - AMD_IOMMU_DEBUG("Invalid IO pagetable entry dfn = %"PRI_dfn"\n", - dfn_x(dfn)); return -EFAULT; } @@ -721,13 +735,15 @@ out: int amd_iommu_unmap_page(struct domain *d, dfn_t dfn) { - unsigned long pt_mfn[7]; + unsigned long pt_mfn[7] = {}; struct domain_iommu *hd = dom_iommu(d); + int rc; if ( iommu_use_hap_pt(d) ) return 0; - memset(pt_mfn, 0, sizeof(pt_mfn)); + if ( dfn_eq(dfn, INVALID_DFN) ) + return -EADDRNOTAVAIL; spin_lock(&hd->arch.mapping_lock); @@ -737,27 +753,11 @@ int amd_iommu_unmap_page(struct domain *d, dfn_t dfn) return 0; } - /* Since HVM domain is initialized with 2 level IO page table, - * we might need a deeper page table for lager dfn now */ - if ( is_hvm_domain(d) ) - { - int rc = update_paging_mode(d, dfn_x(dfn)); - - if ( rc ) - { - spin_unlock(&hd->arch.mapping_lock); - AMD_IOMMU_DEBUG("Update page mode failed dfn = %"PRI_dfn"\n", - dfn_x(dfn)); - return rc; - } - } - - if ( iommu_pde_from_dfn(d, dfn_x(dfn), pt_mfn) || (pt_mfn[1] == 0) ) + rc = iommu_pde_from_dfn(d, dfn_x(dfn), pt_mfn); + if ( rc ) { spin_unlock(&hd->arch.mapping_lock); - AMD_IOMMU_DEBUG("Invalid IO pagetable entry dfn = %"PRI_dfn"\n", - dfn_x(dfn)); - return -EFAULT; + return rc; } /* mark PTE as 'page not present' */ -- 2.11.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |