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;
}
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;
}