Commit a7391ad3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'iomm-fixes-v5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu fixes from Joerg Roedel:
 "IOMMU core:

   - Fix for a regression which could cause NULL-ptr dereferences

  Arm SMMU:

   - Fix off-by-one in SMMUv3 SVA TLB invalidation

   - Disable large mappings to workaround nvidia erratum

  Intel VT-d:

   - Handle PCI stop marker messages in IOMMU driver to meet the
     requirement of I/O page fault handling framework.

   - Calculate a feasible mask for non-aligned page-selective IOTLB
     invalidation.

  Apple DART IOMMU:

   - Fix potential NULL-ptr dereference

   - Set module owner"

* tag 'iomm-fixes-v5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu: Make sysfs robust for non-API groups
  iommu/dart: Add missing module owner to ops structure
  iommu/dart: check return value after calling platform_get_resource()
  iommu/vt-d: Drop stop marker messages
  iommu/vt-d: Calculate mask for non-aligned flushes
  iommu: arm-smmu: disable large page mappings for Nvidia arm-smmu
  iommu/arm-smmu-v3: Fix size calculation in arm_smmu_mm_invalidate_range()
parents 3118d7ab 392bf519
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -773,6 +773,7 @@ static const struct iommu_ops apple_dart_iommu_ops = {
	.get_resv_regions = apple_dart_get_resv_regions,
	.put_resv_regions = generic_iommu_put_resv_regions,
	.pgsize_bitmap = -1UL, /* Restricted during dart probe */
	.owner = THIS_MODULE,
	.default_domain_ops = &(const struct iommu_domain_ops) {
		.attach_dev	= apple_dart_attach_dev,
		.detach_dev	= apple_dart_detach_dev,
@@ -859,16 +860,15 @@ static int apple_dart_probe(struct platform_device *pdev)
	dart->dev = dev;
	spin_lock_init(&dart->lock);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	dart->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
	if (IS_ERR(dart->regs))
		return PTR_ERR(dart->regs);

	if (resource_size(res) < 0x4000) {
		dev_err(dev, "MMIO region too small (%pr)\n", res);
		return -EINVAL;
	}

	dart->regs = devm_ioremap_resource(dev, res);
	if (IS_ERR(dart->regs))
		return PTR_ERR(dart->regs);

	dart->irq = platform_get_irq(pdev, 0);
	if (dart->irq < 0)
		return -ENODEV;
+8 −1
Original line number Diff line number Diff line
@@ -183,7 +183,14 @@ static void arm_smmu_mm_invalidate_range(struct mmu_notifier *mn,
{
	struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn);
	struct arm_smmu_domain *smmu_domain = smmu_mn->domain;
	size_t size = end - start + 1;
	size_t size;

	/*
	 * The mm_types defines vm_end as the first byte after the end address,
	 * different from IOMMU subsystem using the last address of an address
	 * range. So do a simple translation here by calculating size correctly.
	 */
	size = end - start;

	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_BTM))
		arm_smmu_tlb_inv_range_asid(start, size, smmu_mn->cd->asid,
+30 −0
Original line number Diff line number Diff line
@@ -258,6 +258,34 @@ static void nvidia_smmu_probe_finalize(struct arm_smmu_device *smmu, struct devi
			dev_name(dev), err);
}

static int nvidia_smmu_init_context(struct arm_smmu_domain *smmu_domain,
				    struct io_pgtable_cfg *pgtbl_cfg,
				    struct device *dev)
{
	struct arm_smmu_device *smmu = smmu_domain->smmu;
	const struct device_node *np = smmu->dev->of_node;

	/*
	 * Tegra194 and Tegra234 SoCs have the erratum that causes walk cache
	 * entries to not be invalidated correctly. The problem is that the walk
	 * cache index generated for IOVA is not same across translation and
	 * invalidation requests. This is leading to page faults when PMD entry
	 * is released during unmap and populated with new PTE table during
	 * subsequent map request. Disabling large page mappings avoids the
	 * release of PMD entry and avoid translations seeing stale PMD entry in
	 * walk cache.
	 * Fix this by limiting the page mappings to PAGE_SIZE on Tegra194 and
	 * Tegra234.
	 */
	if (of_device_is_compatible(np, "nvidia,tegra234-smmu") ||
	    of_device_is_compatible(np, "nvidia,tegra194-smmu")) {
		smmu->pgsize_bitmap = PAGE_SIZE;
		pgtbl_cfg->pgsize_bitmap = smmu->pgsize_bitmap;
	}

	return 0;
}

static const struct arm_smmu_impl nvidia_smmu_impl = {
	.read_reg = nvidia_smmu_read_reg,
	.write_reg = nvidia_smmu_write_reg,
@@ -268,10 +296,12 @@ static const struct arm_smmu_impl nvidia_smmu_impl = {
	.global_fault = nvidia_smmu_global_fault,
	.context_fault = nvidia_smmu_context_fault,
	.probe_finalize = nvidia_smmu_probe_finalize,
	.init_context = nvidia_smmu_init_context,
};

static const struct arm_smmu_impl nvidia_smmu_single_impl = {
	.probe_finalize = nvidia_smmu_probe_finalize,
	.init_context = nvidia_smmu_init_context,
};

struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu)
+24 −3
Original line number Diff line number Diff line
@@ -1588,7 +1588,8 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
				  unsigned long pfn, unsigned int pages,
				  int ih, int map)
{
	unsigned int mask = ilog2(__roundup_pow_of_two(pages));
	unsigned int aligned_pages = __roundup_pow_of_two(pages);
	unsigned int mask = ilog2(aligned_pages);
	uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
	u16 did = domain->iommu_did[iommu->seq_id];

@@ -1600,10 +1601,30 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
	if (domain_use_first_level(domain)) {
		qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr, pages, ih);
	} else {
		unsigned long bitmask = aligned_pages - 1;

		/*
		 * PSI masks the low order bits of the base address. If the
		 * address isn't aligned to the mask, then compute a mask value
		 * needed to ensure the target range is flushed.
		 */
		if (unlikely(bitmask & pfn)) {
			unsigned long end_pfn = pfn + pages - 1, shared_bits;

			/*
			 * Since end_pfn <= pfn + bitmask, the only way bits
			 * higher than bitmask can differ in pfn and end_pfn is
			 * by carrying. This means after masking out bitmask,
			 * high bits starting with the first set bit in
			 * shared_bits are all equal in both pfn and end_pfn.
			 */
			shared_bits = ~(pfn ^ end_pfn) & ~bitmask;
			mask = shared_bits ? __ffs(shared_bits) : BITS_PER_LONG;
		}

		/*
		 * Fallback to domain selective flush if no PSI support or
		 * the size is too big. PSI requires page size to be 2 ^ x,
		 * and the base address is naturally aligned to the size.
		 * the size is too big.
		 */
		if (!cap_pgsel_inv(iommu->cap) ||
		    mask > cap_max_amask_val(iommu->cap))
+4 −0
Original line number Diff line number Diff line
@@ -757,6 +757,10 @@ static irqreturn_t prq_event_thread(int irq, void *d)
			goto bad_req;
		}

		/* Drop Stop Marker message. No need for a response. */
		if (unlikely(req->lpig && !req->rd_req && !req->wr_req))
			goto prq_advance;

		if (!svm || svm->pasid != req->pasid) {
			/*
			 * It can't go away, because the driver is not permitted
Loading