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
 -----BEGIN PGP SIGNATURE-----
 
 iQFEBAABCgAuFiEEPxTL6PPUbjXGY88ct6xw3ITBYzQFAmJ6eJ0QHHdpbGxAa2Vy
 bmVsLm9yZwAKCRC3rHDchMFjNNroB/92+cfwPyDnA8qdsSCAbyRU2ChrcZvHfKom
 0YxnN6mxQxevcFcLEg8NfbueVgcpZuogrVmBy2ES7s/yJwyFbHk9Pxsq8WO1oMNC
 idIZHjpS9AC4yItgHPzmZd0sUEzmOgINMjHFxdXVnVz4F6EpfrPfRucaBBDe4y1M
 QjKKkjFhMuKjiZWBbQYxRjTJR2LelpK3c2rWhdBxqOLpFJ+XoEcBcaPqiLU5BLcE
 Lbzg88ldneFfM8ixAv0fFY+agxv0vorWXS7GDFOg0nRStMqOeI6Y1mOSKnskVtcD
 dc+Gm8tX7ObeDu/59l+2BsebSemMYapdy7QCEAQDKmna6SayFFA4
 =Z0YK
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Joerg Roedel 2022-05-13 15:17:33 +02:00
commit e3b9bf145c
7 changed files with 82 additions and 9 deletions

View File

@ -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:

View File

@ -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 @@ out_free_cd:
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,

View File

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

View File

@ -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);

View File

@ -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)

View File

@ -408,6 +408,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = {
{ .compatible = "qcom,sc7180-smmu-500" },
{ .compatible = "qcom,sc7280-smmu-500" },
{ .compatible = "qcom,sc8180x-smmu-500" },
{ .compatible = "qcom,sc8280xp-smmu-500" },
{ .compatible = "qcom,sdm630-smmu-v2" },
{ .compatible = "qcom,sdm845-smmu-500" },
{ .compatible = "qcom,sm6125-smmu-500" },

View File

@ -1574,6 +1574,9 @@ static int arm_smmu_def_domain_type(struct device *dev)
struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev);
const struct arm_smmu_impl *impl = cfg->smmu->impl;
if (using_legacy_binding)
return IOMMU_DOMAIN_IDENTITY;
if (impl && impl->def_domain_type)
return impl->def_domain_type(dev);
@ -2092,11 +2095,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (err)
return err;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ioaddr = res->start;
smmu->base = devm_ioremap_resource(dev, res);
smmu->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(smmu->base))
return PTR_ERR(smmu->base);
ioaddr = res->start;
/*
* The resource size should effectively match the value of SMMU_TOP;
* stash that temporarily until we know PAGESIZE to validate it with.