From 44a879dae8c246cd52fa754e99a1d43bc019c757 Mon Sep 17 00:00:00 2001 From: James Sewart Date: Mon, 11 Mar 2019 14:55:01 +0000 Subject: [PATCH 9/9] iommu/vt-d: Remove lazy allocation of domains The generic IOMMU code will allocate and attach a default domain to each device that comes online. This patch removes the lazy domain allocation and early reserved region mapping that is now redundant. Signed-off-by: James Sewart diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 2055c11f5978..4bf719a82b64 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2463,21 +2463,6 @@ static void domain_remove_dev_info(struct dmar_domain *domain) spin_unlock_irqrestore(&device_domain_lock, flags); } -/* - * find_domain - * Note: we use struct device->archdata.iommu stores the info - */ -static struct dmar_domain *find_domain(struct device *dev) -{ - struct device_domain_info *info; - - /* No lock here, assumes no domain exit in normal case */ - info = dev->archdata.iommu; - if (likely(info)) - return info->domain; - return NULL; -} - static inline struct device_domain_info * dmar_search_domain_by_dev_info(int segment, int bus, int devfn) { @@ -2539,8 +2524,11 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, } spin_lock_irqsave(&device_domain_lock, flags); - if (dev) - found = find_domain(dev); + if (dev) { + struct iommu_domain *io_domain = iommu_get_domain_for_dev(dev); + if (io_domain) + found = to_dmar_domain(io_domain); + } if (!found) { struct device_domain_info *info2; @@ -2608,118 +2596,6 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, return domain; } -static int get_last_alias(struct pci_dev *pdev, u16 alias, void *opaque) -{ - *(u16 *)opaque = alias; - return 0; -} - -static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw) -{ - struct device_domain_info *info; - struct dmar_domain *domain = NULL; - struct intel_iommu *iommu; - u16 dma_alias; - unsigned long flags; - u8 bus, devfn; - - iommu = device_to_iommu(dev, &bus, &devfn); - if (!iommu) - return NULL; - - if (dev_is_pci(dev)) { - struct pci_dev *pdev = to_pci_dev(dev); - - pci_for_each_dma_alias(pdev, get_last_alias, &dma_alias); - - spin_lock_irqsave(&device_domain_lock, flags); - info = dmar_search_domain_by_dev_info(pci_domain_nr(pdev->bus), - PCI_BUS_NUM(dma_alias), - dma_alias & 0xff); - if (info) { - iommu = info->iommu; - domain = info->domain; - } - spin_unlock_irqrestore(&device_domain_lock, flags); - - /* DMA alias already has a domain, use it */ - if (info) - goto out; - } - - /* Allocate and initialize new domain for the device */ - domain = alloc_domain(0); - if (!domain) - return NULL; - if (domain_init(domain, iommu, gaw)) { - domain_exit(domain); - return NULL; - } - -out: - - return domain; -} - -static struct dmar_domain *set_domain_for_dev(struct device *dev, - struct dmar_domain *domain) -{ - struct intel_iommu *iommu; - struct dmar_domain *tmp; - u16 req_id, dma_alias; - u8 bus, devfn; - - iommu = device_to_iommu(dev, &bus, &devfn); - if (!iommu) - return NULL; - - req_id = ((u16)bus << 8) | devfn; - - if (dev_is_pci(dev)) { - struct pci_dev *pdev = to_pci_dev(dev); - - pci_for_each_dma_alias(pdev, get_last_alias, &dma_alias); - - /* register PCI DMA alias device */ - if (req_id != dma_alias) { - tmp = dmar_insert_one_dev_info(iommu, PCI_BUS_NUM(dma_alias), - dma_alias & 0xff, NULL, domain); - - if (!tmp || tmp != domain) - return tmp; - } - } - - tmp = dmar_insert_one_dev_info(iommu, bus, devfn, dev, domain); - if (!tmp || tmp != domain) - return tmp; - - return domain; -} - -static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw) -{ - struct dmar_domain *domain, *tmp; - - domain = find_domain(dev); - if (domain) - goto out; - - domain = find_or_alloc_domain(dev, gaw); - if (!domain) - goto out; - - tmp = set_domain_for_dev(dev, domain); - if (!tmp || domain != tmp) { - domain_exit(domain); - domain = tmp; - } - -out: - - return domain; -} - static int iommu_domain_identity_map(struct dmar_domain *domain, unsigned long long start, unsigned long long end) @@ -2745,72 +2621,6 @@ static int iommu_domain_identity_map(struct dmar_domain *domain, DMA_PTE_READ|DMA_PTE_WRITE); } -static int domain_prepare_identity_map(struct device *dev, - struct dmar_domain *domain, - unsigned long long start, - unsigned long long end) -{ - /* For _hardware_ passthrough, don't bother. But for software - passthrough, we do it anyway -- it may indicate a memory - range which is reserved in E820, so which didn't get set - up to start with in si_domain */ - if (domain == si_domain && hw_pass_through) { - dev_warn(dev, "Ignoring identity map for HW passthrough [0x%Lx - 0x%Lx]\n", - start, end); - return 0; - } - - dev_info(dev, "Setting identity map [0x%Lx - 0x%Lx]\n", start, end); - - if (end < start) { - WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n" - "BIOS vendor: %s; Ver: %s; Product Version: %s\n", - dmi_get_system_info(DMI_BIOS_VENDOR), - dmi_get_system_info(DMI_BIOS_VERSION), - dmi_get_system_info(DMI_PRODUCT_VERSION)); - return -EIO; - } - - if (end >> agaw_to_width(domain->agaw)) { - WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n" - "BIOS vendor: %s; Ver: %s; Product Version: %s\n", - agaw_to_width(domain->agaw), - dmi_get_system_info(DMI_BIOS_VENDOR), - dmi_get_system_info(DMI_BIOS_VERSION), - dmi_get_system_info(DMI_PRODUCT_VERSION)); - return -EIO; - } - - return iommu_domain_identity_map(domain, start, end); -} - -static int iommu_prepare_identity_map(struct device *dev, - unsigned long long start, - unsigned long long end) -{ - struct dmar_domain *domain; - int ret; - - domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH); - if (!domain) - return -ENOMEM; - - ret = domain_prepare_identity_map(dev, domain, start, end); - if (ret) - domain_exit(domain); - - return ret; -} - -static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr, - struct device *dev) -{ - if (dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO) - return 0; - return iommu_prepare_identity_map(dev, rmrr->base_address, - rmrr->end_address); -} - static inline struct iommu_resv_region *iommu_get_isa_resv_region(void) { if (!isa_resv_region) @@ -2821,29 +2631,6 @@ static inline struct iommu_resv_region *iommu_get_isa_resv_region(void) return isa_resv_region; } -#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA -static inline void iommu_prepare_isa(struct pci_dev *pdev) -{ - int ret; - struct iommu_resv_region *reg = iommu_get_isa_resv_region(); - - if (!reg) - return; - - pr_info("Prepare 0-16MiB unity mapping for LPC\n"); - ret = iommu_prepare_identity_map(&pdev->dev, reg->start, - reg->start + reg->length - 1); - - if (ret) - pr_err("Failed to create 0-16MiB identity map - floppy might not work\n"); -} -#else -static inline void iommu_prepare_isa(struct pci_dev *pdev) -{ - return; -} -#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */ - static int md_domain_init(struct dmar_domain *domain, int guest_width); static int __init si_domain_init(int hw) @@ -3066,18 +2853,10 @@ static int __init dev_prepare_static_identity_mapping(struct device *dev, int hw static int __init iommu_prepare_static_identity_mapping(int hw) { - struct pci_dev *pdev = NULL; struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; struct device *dev; - int i; - int ret = 0; - - for_each_pci_dev(pdev) { - ret = dev_prepare_static_identity_mapping(&pdev->dev, hw); - if (ret) - return ret; - } + int i, ret = 0; for_each_active_iommu(iommu, drhd) for_each_active_dev_scope(drhd->devices, drhd->devices_cnt, i, dev) { @@ -3324,12 +3103,9 @@ static int copy_translation_tables(struct intel_iommu *iommu) static int __init init_dmars(void) { struct dmar_drhd_unit *drhd; - struct dmar_rmrr_unit *rmrr; bool copied_tables = false; - struct device *dev; - struct pci_dev *pdev; struct intel_iommu *iommu; - int i, ret; + int ret; /* * for each drhd @@ -3483,36 +3259,6 @@ static int __init init_dmars(void) goto free_iommu; } } - /* - * For each rmrr - * for each dev attached to rmrr - * do - * locate drhd for dev, alloc domain for dev - * allocate free domain - * allocate page table entries for rmrr - * if context not allocated for bus - * allocate and init context - * set present in root table for this bus - * init context with domain, translation etc - * endfor - * endfor - */ - pr_info("Setting RMRR:\n"); - for_each_rmrr_units(rmrr) { - /* some BIOS lists non-exist devices in DMAR table. */ - for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, - i, dev) { - ret = iommu_prepare_rmrr_dev(rmrr, dev); - if (ret) - pr_err("Mapping reserved region failed\n"); - } - } - - pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); - if (pdev) { - iommu_prepare_isa(pdev); - pci_dev_put(pdev); - } domains_done: @@ -3595,53 +3341,6 @@ static unsigned long intel_alloc_iova(struct device *dev, return iova_pfn; } -struct dmar_domain *get_valid_domain_for_dev(struct device *dev) -{ - struct dmar_domain *domain, *tmp; - struct dmar_rmrr_unit *rmrr; - struct device *i_dev; - int i, ret; - - domain = find_domain(dev); - if (domain) - goto out; - - domain = find_or_alloc_domain(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH); - if (!domain) - goto out; - - /* We have a new domain - setup possible RMRRs for the device */ - rcu_read_lock(); - for_each_rmrr_units(rmrr) { - for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, - i, i_dev) { - if (i_dev != dev) - continue; - - ret = domain_prepare_identity_map(dev, domain, - rmrr->base_address, - rmrr->end_address); - if (ret) - dev_err(dev, "Mapping reserved region failed\n"); - } - } - rcu_read_unlock(); - - tmp = set_domain_for_dev(dev, domain); - if (!tmp || domain != tmp) { - domain_exit(domain); - domain = tmp; - } - -out: - - if (!domain) - dev_err(dev, "Allocating domain failed\n"); - - - return domain; -} - /* Check if the dev needs to go through non-identity map and unmap process.*/ static int iommu_no_mapping(struct device *dev) { @@ -3688,6 +3387,7 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir, u64 dma_mask) { struct dmar_domain *domain; + struct iommu_domain *io_domain; phys_addr_t start_paddr; unsigned long iova_pfn; int prot = 0; @@ -3700,9 +3400,10 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr, if (iommu_no_mapping(dev)) return paddr; - domain = get_valid_domain_for_dev(dev); - if (!domain) + io_domain = iommu_get_domain_for_dev(dev); + if (!io_domain) return DMA_MAPPING_ERROR; + domain = to_dmar_domain(io_domain); iommu = domain_get_iommu(domain); size = aligned_nrpages(paddr, size); @@ -3762,6 +3463,7 @@ static dma_addr_t intel_map_resource(struct device *dev, phys_addr_t phys_addr, static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size) { struct dmar_domain *domain; + struct iommu_domain *io_domain; unsigned long start_pfn, last_pfn; unsigned long nrpages; unsigned long iova_pfn; @@ -3771,8 +3473,9 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size) if (iommu_no_mapping(dev)) return; - domain = find_domain(dev); - BUG_ON(!domain); + io_domain = iommu_get_domain_for_dev(dev); + BUG_ON(!io_domain); + domain = to_dmar_domain(io_domain); iommu = domain_get_iommu(domain); @@ -3906,6 +3609,7 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele { int i; struct dmar_domain *domain; + struct iommu_domain *io_domain; size_t size = 0; int prot = 0; unsigned long iova_pfn; @@ -3918,9 +3622,10 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele if (iommu_no_mapping(dev)) return intel_nontranslate_map_sg(dev, sglist, nelems, dir); - domain = get_valid_domain_for_dev(dev); - if (!domain) + io_domain = iommu_get_domain_for_dev(dev); + if (!io_domain) return 0; + domain = to_dmar_domain(io_domain); iommu = domain_get_iommu(domain); @@ -4611,9 +4316,11 @@ static int device_notifier(struct notifier_block *nb, return 0; if (action == BUS_NOTIFY_REMOVED_DEVICE) { - domain = find_domain(dev); - if (!domain) + struct iommu_domain *io_domain; + io_domain = iommu_get_domain_for_dev(dev); + if (!io_domain) return 0; + domain = to_dmar_domain(io_domain); dmar_remove_one_dev_info(dev); if (!domain_managed_externally(domain) && @@ -5143,9 +4850,11 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, /* normally dev is not mapped */ if (unlikely(domain_context_mapped(dev))) { struct dmar_domain *old_domain; + struct iommu_domain *old_io_domain; - old_domain = find_domain(dev); - if (old_domain) { + old_io_domain = iommu_get_domain_for_dev(dev); + if (old_io_domain) { + old_domain = to_dmar_domain(old_io_domain); rcu_read_lock(); dmar_remove_one_dev_info(dev); rcu_read_unlock(); @@ -5416,13 +5125,15 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd struct device_domain_info *info; struct context_entry *context; struct dmar_domain *domain; + struct iommu_domain *io_domain; unsigned long flags; u64 ctx_lo; int ret; - domain = get_valid_domain_for_dev(sdev->dev); - if (!domain) + io_domain = iommu_get_domain_for_dev(sdev->dev); + if (!io_domain) return -EINVAL; + domain = to_dmar_domain(io_domain); spin_lock_irqsave(&device_domain_lock, flags); spin_lock(&iommu->lock); -- 2.17.1