Re: [PATCH v10 3/5] iommu/arm-smmu: add NVIDIA implementation for ARM MMU-500 usage
On Tue, Jul 07, 2020 at 10:00:15PM -0700, Krishna Reddy wrote: > NVIDIA's Tegra194 SoC has three ARM MMU-500 instances. > It uses two of the ARM MMU-500s together to interleave IOVA > accesses across them and must be programmed identically. > This implementation supports programming the two ARM MMU-500s > that must be programmed identically. > > The third ARM MMU-500 instance is supported by standard > arm-smmu.c driver itself. > > Signed-off-by: Krishna Reddy Reviewed-by: Nicolin Chen ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v10 3/5] iommu/arm-smmu: add NVIDIA implementation for ARM MMU-500 usage
On 08/07/2020 06:00, Krishna Reddy wrote: > NVIDIA's Tegra194 SoC has three ARM MMU-500 instances. > It uses two of the ARM MMU-500s together to interleave IOVA > accesses across them and must be programmed identically. > This implementation supports programming the two ARM MMU-500s > that must be programmed identically. > > The third ARM MMU-500 instance is supported by standard > arm-smmu.c driver itself. > > Signed-off-by: Krishna Reddy > --- > MAINTAINERS | 2 + > drivers/iommu/Makefile | 2 +- > drivers/iommu/arm-smmu-impl.c | 3 + > drivers/iommu/arm-smmu-nvidia.c | 179 > drivers/iommu/arm-smmu.c| 1 + > drivers/iommu/arm-smmu.h| 1 + > 6 files changed, 187 insertions(+), 1 deletion(-) > create mode 100644 drivers/iommu/arm-smmu-nvidia.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index c23352059a6b..534cedaf8e55 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -16811,8 +16811,10 @@ F: drivers/i2c/busses/i2c-tegra.c > > TEGRA IOMMU DRIVERS > M: Thierry Reding > +R: Krishna Reddy > L: linux-te...@vger.kernel.org > S: Supported > +F: drivers/iommu/arm-smmu-nvidia.c > F: drivers/iommu/tegra* > > TEGRA KBC DRIVER > diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile > index 342190196dfb..2b8203db73ec 100644 > --- a/drivers/iommu/Makefile > +++ b/drivers/iommu/Makefile > @@ -15,7 +15,7 @@ obj-$(CONFIG_AMD_IOMMU) += amd/iommu.o amd/init.o > amd/quirks.o > obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd/debugfs.o > obj-$(CONFIG_AMD_IOMMU_V2) += amd/iommu_v2.o > obj-$(CONFIG_ARM_SMMU) += arm_smmu.o > -arm_smmu-objs += arm-smmu.o arm-smmu-impl.o arm-smmu-qcom.o > +arm_smmu-objs += arm-smmu.o arm-smmu-impl.o arm-smmu-nvidia.o arm-smmu-qcom.o > obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o > obj-$(CONFIG_DMAR_TABLE) += intel/dmar.o > obj-$(CONFIG_INTEL_IOMMU) += intel/iommu.o intel/pasid.o > diff --git a/drivers/iommu/arm-smmu-impl.c b/drivers/iommu/arm-smmu-impl.c > index c75b9d957b70..f15571d05474 100644 > --- a/drivers/iommu/arm-smmu-impl.c > +++ b/drivers/iommu/arm-smmu-impl.c > @@ -171,6 +171,9 @@ 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 = _impl; > > + if (of_device_is_compatible(np, "nvidia,tegra194-smmu")) > + return nvidia_smmu_impl_init(smmu); > + I wonder if we should be matching nvidia,smmu-500 here as well because any device that has that we want to call nvidia_smmu_impl_init(). I understand that there is only tegra194 today, but seems funny to match nvidia,smmu-500 below and then nvidia,tegra194-smmu here. That said ... > if (of_device_is_compatible(np, "qcom,sdm845-smmu-500") || > of_device_is_compatible(np, "qcom,sc7180-smmu-500")) > return qcom_smmu_impl_init(smmu); > diff --git a/drivers/iommu/arm-smmu-nvidia.c b/drivers/iommu/arm-smmu-nvidia.c > new file mode 100644 > index ..2f55e5793d34 > --- /dev/null > +++ b/drivers/iommu/arm-smmu-nvidia.c > @@ -0,0 +1,179 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +// Copyright (C) 2019-2020 NVIDIA CORPORATION. All rights reserved. > + > +#include > +#include > +#include > +#include > +#include > + > +#include "arm-smmu.h" > + > +/* > + * Tegra194 has three ARM MMU-500 Instances. > + * Two of them are used together and must be programmed identically for > + * interleaved IOVA accesses across them and translates accesses from > + * non-isochronous HW devices. > + * Third one is used for translating accesses from isochronous HW devices. > + * This implementation supports programming of the two instances that must > + * be programmed identically. > + * The third instance usage is through standard arm-smmu driver itself and > + * is out of scope of this implementation. > + */ > +#define NUM_SMMU_INSTANCES 2 > + > +struct nvidia_smmu { > + struct arm_smmu_device smmu; > + void __iomem*bases[NUM_SMMU_INSTANCES]; > +}; > + > +static inline void __iomem *nvidia_smmu_page(struct arm_smmu_device *smmu, > + unsigned int inst, int page) > +{ > + struct nvidia_smmu *nvidia_smmu; > + > + nvidia_smmu = container_of(smmu, struct nvidia_smmu, smmu); > + return nvidia_smmu->bases[inst] + (page << smmu->pgshift); > +} > + > +static u32 nvidia_smmu_read_reg(struct arm_smmu_device *smmu, > + int page, int offset) > +{ > + void __iomem *reg = nvidia_smmu_page(smmu, 0, page) + offset; > + > + return readl_relaxed(reg); > +} > + > +static void nvidia_smmu_write_reg(struct arm_smmu_device *smmu, > + int page, int offset, u32 val) > +{ > + unsigned int i; > + > + for (i = 0; i < NUM_SMMU_INSTANCES; i++) { > + void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset; > + > +
[PATCH v10 3/5] iommu/arm-smmu: add NVIDIA implementation for ARM MMU-500 usage
NVIDIA's Tegra194 SoC has three ARM MMU-500 instances. It uses two of the ARM MMU-500s together to interleave IOVA accesses across them and must be programmed identically. This implementation supports programming the two ARM MMU-500s that must be programmed identically. The third ARM MMU-500 instance is supported by standard arm-smmu.c driver itself. Signed-off-by: Krishna Reddy --- MAINTAINERS | 2 + drivers/iommu/Makefile | 2 +- drivers/iommu/arm-smmu-impl.c | 3 + drivers/iommu/arm-smmu-nvidia.c | 179 drivers/iommu/arm-smmu.c| 1 + drivers/iommu/arm-smmu.h| 1 + 6 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 drivers/iommu/arm-smmu-nvidia.c diff --git a/MAINTAINERS b/MAINTAINERS index c23352059a6b..534cedaf8e55 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16811,8 +16811,10 @@ F: drivers/i2c/busses/i2c-tegra.c TEGRA IOMMU DRIVERS M: Thierry Reding +R: Krishna Reddy L: linux-te...@vger.kernel.org S: Supported +F: drivers/iommu/arm-smmu-nvidia.c F: drivers/iommu/tegra* TEGRA KBC DRIVER diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 342190196dfb..2b8203db73ec 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_AMD_IOMMU) += amd/iommu.o amd/init.o amd/quirks.o obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd/debugfs.o obj-$(CONFIG_AMD_IOMMU_V2) += amd/iommu_v2.o obj-$(CONFIG_ARM_SMMU) += arm_smmu.o -arm_smmu-objs += arm-smmu.o arm-smmu-impl.o arm-smmu-qcom.o +arm_smmu-objs += arm-smmu.o arm-smmu-impl.o arm-smmu-nvidia.o arm-smmu-qcom.o obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o obj-$(CONFIG_DMAR_TABLE) += intel/dmar.o obj-$(CONFIG_INTEL_IOMMU) += intel/iommu.o intel/pasid.o diff --git a/drivers/iommu/arm-smmu-impl.c b/drivers/iommu/arm-smmu-impl.c index c75b9d957b70..f15571d05474 100644 --- a/drivers/iommu/arm-smmu-impl.c +++ b/drivers/iommu/arm-smmu-impl.c @@ -171,6 +171,9 @@ 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 = _impl; + if (of_device_is_compatible(np, "nvidia,tegra194-smmu")) + return nvidia_smmu_impl_init(smmu); + if (of_device_is_compatible(np, "qcom,sdm845-smmu-500") || of_device_is_compatible(np, "qcom,sc7180-smmu-500")) return qcom_smmu_impl_init(smmu); diff --git a/drivers/iommu/arm-smmu-nvidia.c b/drivers/iommu/arm-smmu-nvidia.c new file mode 100644 index ..2f55e5793d34 --- /dev/null +++ b/drivers/iommu/arm-smmu-nvidia.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2019-2020 NVIDIA CORPORATION. All rights reserved. + +#include +#include +#include +#include +#include + +#include "arm-smmu.h" + +/* + * Tegra194 has three ARM MMU-500 Instances. + * Two of them are used together and must be programmed identically for + * interleaved IOVA accesses across them and translates accesses from + * non-isochronous HW devices. + * Third one is used for translating accesses from isochronous HW devices. + * This implementation supports programming of the two instances that must + * be programmed identically. + * The third instance usage is through standard arm-smmu driver itself and + * is out of scope of this implementation. + */ +#define NUM_SMMU_INSTANCES 2 + +struct nvidia_smmu { + struct arm_smmu_device smmu; + void __iomem*bases[NUM_SMMU_INSTANCES]; +}; + +static inline void __iomem *nvidia_smmu_page(struct arm_smmu_device *smmu, +unsigned int inst, int page) +{ + struct nvidia_smmu *nvidia_smmu; + + nvidia_smmu = container_of(smmu, struct nvidia_smmu, smmu); + return nvidia_smmu->bases[inst] + (page << smmu->pgshift); +} + +static u32 nvidia_smmu_read_reg(struct arm_smmu_device *smmu, + int page, int offset) +{ + void __iomem *reg = nvidia_smmu_page(smmu, 0, page) + offset; + + return readl_relaxed(reg); +} + +static void nvidia_smmu_write_reg(struct arm_smmu_device *smmu, + int page, int offset, u32 val) +{ + unsigned int i; + + for (i = 0; i < NUM_SMMU_INSTANCES; i++) { + void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset; + + writel_relaxed(val, reg); + } +} + +static u64 nvidia_smmu_read_reg64(struct arm_smmu_device *smmu, + int page, int offset) +{ + void __iomem *reg = nvidia_smmu_page(smmu, 0, page) + offset; + + return readq_relaxed(reg); +} + +static void nvidia_smmu_write_reg64(struct arm_smmu_device *smmu, + int page, int offset, u64 val) +{ + unsigned int i; + + for (i = 0; i < NUM_SMMU_INSTANCES; i++) { + void