Commit e3b9bf14 authored by Joerg Roedel's avatar Joerg Roedel
Browse files

Merge tag 'arm-smmu-updates' of...

Merge tag 'arm-smmu-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into arm/smmu

Arm SMMU updates for 5.19

- Add new Qualcomm device-tree compatible strings

- Add new Nvidia device-tree compatible string for Tegra234

- Fix UAF in SMMUv3 shared virtual addressing code

- Force identity-mapped domains for users of ye olde SMMU legacy binding

- Minor cleanups
parents af2d861d 628bf55b
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -37,8 +37,10 @@ properties:
              - qcom,sc7180-smmu-500
              - qcom,sc7280-smmu-500
              - qcom,sc8180x-smmu-500
              - qcom,sc8280xp-smmu-500
              - qcom,sdm845-smmu-500
              - qcom,sdx55-smmu-500
              - qcom,sdx65-smmu-500
              - qcom,sm6350-smmu-500
              - qcom,sm8150-smmu-500
              - qcom,sm8250-smmu-500
@@ -62,8 +64,9 @@ properties:
          for improved performance.
        items:
          - enum:
              - nvidia,tegra194-smmu
              - nvidia,tegra186-smmu
              - nvidia,tegra194-smmu
              - nvidia,tegra234-smmu
          - const: nvidia,smmu-500
      - items:
          - const: arm,mmu-500
@@ -157,6 +160,17 @@ properties:
  power-domains:
    maxItems: 1

  nvidia,memory-controller:
    description: |
      A phandle to the memory controller on NVIDIA Tegra186 and later SoCs.
      The memory controller needs to be programmed with a mapping of memory
      client IDs to ARM SMMU stream IDs.

      If this property is absent, the mapping programmed by early firmware
      will be used and it is not guaranteed that IOMMU translations will be
      enabled for any given device.
    $ref: /schemas/types.yaml#/definitions/phandle

required:
  - compatible
  - reg
@@ -172,13 +186,20 @@ allOf:
        compatible:
          contains:
            enum:
              - nvidia,tegra194-smmu
              - nvidia,tegra186-smmu
              - nvidia,tegra194-smmu
              - nvidia,tegra234-smmu
    then:
      properties:
        reg:
          minItems: 1
          maxItems: 2

      # The reference to the memory controller is required to ensure that the
      # memory client to stream ID mapping can be done synchronously with the
      # IOMMU attachment.
      required:
        - nvidia,memory-controller
    else:
      properties:
        reg:
+19 −3
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include <linux/mm.h>
#include <linux/mmu_context.h>
#include <linux/mmu_notifier.h>
#include <linux/sched/mm.h>
#include <linux/slab.h>

#include "arm-smmu-v3.h"
@@ -96,9 +97,14 @@ static struct arm_smmu_ctx_desc *arm_smmu_alloc_shared_cd(struct mm_struct *mm)
	struct arm_smmu_ctx_desc *cd;
	struct arm_smmu_ctx_desc *ret = NULL;

	/* Don't free the mm until we release the ASID */
	mmgrab(mm);

	asid = arm64_mm_context_get(mm);
	if (!asid)
		return ERR_PTR(-ESRCH);
	if (!asid) {
		err = -ESRCH;
		goto out_drop_mm;
	}

	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
	if (!cd) {
@@ -165,6 +171,8 @@ static struct arm_smmu_ctx_desc *arm_smmu_alloc_shared_cd(struct mm_struct *mm)
	kfree(cd);
out_put_context:
	arm64_mm_context_put(mm);
out_drop_mm:
	mmdrop(mm);
	return err < 0 ? ERR_PTR(err) : ret;
}

@@ -173,6 +181,7 @@ static void arm_smmu_free_shared_cd(struct arm_smmu_ctx_desc *cd)
	if (arm_smmu_free_asid(cd)) {
		/* Unpin ASID */
		arm64_mm_context_put(cd->mm);
		mmdrop(cd->mm);
		kfree(cd);
	}
}
@@ -183,7 +192,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,
+2 −0
Original line number Diff line number Diff line
@@ -3770,6 +3770,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)

	/* Base address */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -EINVAL;
	if (resource_size(res) < arm_smmu_resource_size(smmu)) {
		dev_err(dev, "MMIO region too small (%pr)\n", res);
		return -EINVAL;
+2 −1
Original line number Diff line number Diff line
@@ -211,7 +211,8 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
	if (of_property_read_bool(np, "calxeda,smmu-secure-config-access"))
		smmu->impl = &calxeda_impl;

	if (of_device_is_compatible(np, "nvidia,tegra194-smmu") ||
	if (of_device_is_compatible(np, "nvidia,tegra234-smmu") ||
	    of_device_is_compatible(np, "nvidia,tegra194-smmu") ||
	    of_device_is_compatible(np, "nvidia,tegra186-smmu"))
		return nvidia_smmu_impl_init(smmu);

+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)
Loading