From: Joerg Roedel Date: Fri, 28 Nov 2025 07:44:21 +0000 (+0100) Subject: Merge branches 'arm/smmu/updates', 'arm/smmu/bindings', 'mediatek', 'nvidia/tegra... X-Git-Url: https://gentwo.org/gitweb/?a=commitdiff_plain;h=0d081b16946ef449fcb35b6edc1ef6f9fea6f0a0;p=linux%2F.git Merge branches 'arm/smmu/updates', 'arm/smmu/bindings', 'mediatek', 'nvidia/tegra', 'intel/vt-d', 'amd/amd-vi' and 'core' into next --- 0d081b16946ef449fcb35b6edc1ef6f9fea6f0a0 diff --cc drivers/iommu/amd/iommu.c index 2e1865daa1ce,2e1865daa1ce,2e1865daa1ce,2e1865daa1ce,2e1865daa1ce,2e1865daa1ce,a5fb6af4fd2d,273951b4501c..9f1d56a5e145 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@@@@@@@@ -2500,29 -2500,29 -2500,29 -2500,29 -2500,29 -2500,29 -2526,29 -2489,66 +2515,66 @@@@@@@@@ struct protection_domain *protection_do return domain; } ------- static int pdom_setup_pgtable(struct protection_domain *domain, ------- struct device *dev) +++++++ static bool amd_iommu_hd_support(struct amd_iommu *iommu) ++++++ { - struct io_pgtable_ops *pgtbl_ops; - enum io_pgtable_fmt fmt; +++++++ if (amd_iommu_hatdis) +++++++ return false; ++++++ - switch (domain->pd_mode) { - case PD_MODE_V1: - fmt = AMD_IOMMU_V1; - break; - case PD_MODE_V2: - fmt = AMD_IOMMU_V2; - break; - case PD_MODE_NONE: - WARN_ON_ONCE(1); - return -EPERM; +++++++ return iommu && (iommu->features & FEATURE_HDSUP); +++++++ } +++++++ +++++++ static spinlock_t *amd_iommu_get_top_lock(struct pt_iommu *iommupt) + { ------ struct io_pgtable_ops *pgtbl_ops; ------ enum io_pgtable_fmt fmt; +++++++ struct protection_domain *pdom = +++++++ container_of(iommupt, struct protection_domain, iommu); + ------ switch (domain->pd_mode) { ------ case PD_MODE_V1: ------ fmt = AMD_IOMMU_V1; ------ break; ------ case PD_MODE_V2: ------ fmt = AMD_IOMMU_V2; ------ break; ------ case PD_MODE_NONE: ------ WARN_ON_ONCE(1); ------ return -EPERM; +++++++ return &pdom->lock; +++++++ } +++++++ +++++++ /* +++++++ * Update all HW references to the domain with a new pgtable configuration. +++++++ */ +++++++ static void amd_iommu_change_top(struct pt_iommu *iommu_table, +++++++ phys_addr_t top_paddr, unsigned int top_level) +++++++ { +++++++ struct protection_domain *pdom = +++++++ container_of(iommu_table, struct protection_domain, iommu); +++++++ struct iommu_dev_data *dev_data; +++++++ +++++++ lockdep_assert_held(&pdom->lock); +++++++ +++++++ /* Update the DTE for all devices attached to this domain */ +++++++ list_for_each_entry(dev_data, &pdom->dev_list, list) { +++++++ struct amd_iommu *iommu = rlookup_amd_iommu(dev_data->dev); +++++++ +++++++ /* Update the HW references with the new level and top ptr */ +++++++ set_dte_entry(iommu, dev_data, top_paddr, top_level); +++++++ clone_aliases(iommu, dev_data->dev); } ------- domain->iop.pgtbl.cfg.amd.nid = dev_to_node(dev); ------- pgtbl_ops = alloc_io_pgtable_ops(fmt, &domain->iop.pgtbl.cfg, domain); ------- if (!pgtbl_ops) ------- return -ENOMEM; +++++++ list_for_each_entry(dev_data, &pdom->dev_list, list) +++++++ device_flush_dte(dev_data); +++++++ +++++++ domain_flush_complete(pdom); +++++++ } ++++++ +++++++ /* +++++++ * amd_iommu_iotlb_sync_map() is used to generate flushes for non-present to +++++++ * present (ie mapping) operations. It is a NOP if the IOMMU doesn't have non +++++++ * present caching (like hypervisor shadowing). +++++++ */ +++++++ static int amd_iommu_iotlb_sync_map(struct iommu_domain *dom, +++++++ unsigned long iova, size_t size) +++++++ { +++++++ struct protection_domain *domain = to_pdomain(dom); +++++++ unsigned long flags; + +++++++ if (likely(!amd_iommu_np_cache)) +++++++ return 0; +++++++ +++++++ spin_lock_irqsave(&domain->lock, flags); +++++++ amd_iommu_domain_flush_pages(domain, iova, size); +++++++ spin_unlock_irqrestore(&domain->lock, flags); return 0; } @@@@@@@@@ -2577,17 -2577,17 -2577,17 -2577,17 -2577,17 -2577,17 -2603,17 -2650,79 +2676,79 @@@@@@@@@ static struct iommu_domain *amd_iommu_d return ERR_PTR(ret); } ------- domain->domain.geometry.aperture_start = 0; ------- domain->domain.geometry.aperture_end = dma_max_address(pgtable); ------- domain->domain.geometry.force_aperture = true; ------- domain->domain.pgsize_bitmap = domain->iop.pgtbl.cfg.pgsize_bitmap; +++++++ /* +++++++ * Narrow the supported page sizes to those selected by the kernel +++++++ * command line. +++++++ */ +++++++ domain->domain.pgsize_bitmap &= amd_iommu_pgsize_bitmap; +++++++ return &domain->domain; +++++++ } + ------ domain->domain.type = IOMMU_DOMAIN_UNMANAGED; ------ domain->domain.ops = iommu->iommu.ops->default_domain_ops; +++++++ static const struct iommu_domain_ops amdv2_ops = { +++++++ IOMMU_PT_DOMAIN_OPS(x86_64), +++++++ .iotlb_sync_map = amd_iommu_iotlb_sync_map, +++++++ .flush_iotlb_all = amd_iommu_flush_iotlb_all, +++++++ .iotlb_sync = amd_iommu_iotlb_sync, +++++++ .attach_dev = amd_iommu_attach_device, +++++++ .free = amd_iommu_domain_free, +++++++ /* +++++++ * Note the AMDv2 page table format does not support a Force Coherency +++++++ * bit, so enforce_cache_coherency should not be set. However VFIO is +++++++ * not prepared to handle a case where some domains will support +++++++ * enforcement and others do not. VFIO and iommufd will have to be fixed +++++++ * before it can fully use the V2 page table. See the comment in +++++++ * iommufd_hwpt_paging_alloc(). For now leave things as they have +++++++ * historically been and lie about enforce_cache_coherencey. +++++++ */ +++++++ .enforce_cache_coherency = amd_iommu_enforce_cache_coherency, +++++++ }; ------ if (dirty_tracking) ------ domain->domain.dirty_ops = &amd_dirty_ops; - domain->domain.type = IOMMU_DOMAIN_UNMANAGED; - domain->domain.ops = iommu->iommu.ops->default_domain_ops; +++++++ static struct iommu_domain *amd_iommu_domain_alloc_paging_v2(struct device *dev, +++++++ u32 flags) +++++++ { +++++++ struct pt_iommu_x86_64_cfg cfg = {}; +++++++ struct protection_domain *domain; +++++++ int ret; - if (dirty_tracking) - domain->domain.dirty_ops = &amd_dirty_ops; +++++++ if (!amd_iommu_v2_pgtbl_supported()) +++++++ return ERR_PTR(-EOPNOTSUPP); ++++++ +++++++ domain = protection_domain_alloc(); +++++++ if (!domain) +++++++ return ERR_PTR(-ENOMEM); +++++++ +++++++ domain->pd_mode = PD_MODE_V2; +++++++ domain->iommu.nid = dev_to_node(dev); +++++++ +++++++ cfg.common.features = BIT(PT_FEAT_X86_64_AMD_ENCRYPT_TABLES); +++++++ if (amd_iommu_np_cache) +++++++ cfg.common.features |= BIT(PT_FEAT_FLUSH_RANGE_NO_GAPS); +++++++ else +++++++ cfg.common.features |= BIT(PT_FEAT_FLUSH_RANGE); +++++++ +++++++ /* +++++++ * The v2 table behaves differently if it is attached to PASID 0 vs a +++++++ * non-zero PASID. On PASID 0 it has no sign extension and the full +++++++ * 57/48 bits decode the lower addresses. Otherwise it behaves like a +++++++ * normal sign extended x86 page table. Since we want the domain to work +++++++ * in both modes the top bit is removed and PT_FEAT_SIGN_EXTEND is not +++++++ * set which creates a table that is compatible in both modes. +++++++ */ +++++++ if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) { +++++++ cfg.common.hw_max_vasz_lg2 = 56; +++++++ cfg.top_level = 4; +++++++ } else { +++++++ cfg.common.hw_max_vasz_lg2 = 47; +++++++ cfg.top_level = 3; +++++++ } +++++++ cfg.common.hw_max_oasz_lg2 = 52; +++++++ domain->domain.ops = &amdv2_ops; +++++++ +++++++ ret = pt_iommu_x86_64_init(&domain->amdv2, &cfg, GFP_KERNEL); +++++++ if (ret) { +++++++ amd_iommu_domain_free(&domain->domain); +++++++ return ERR_PTR(ret); +++++++ } return &domain->domain; }