10 Commits

Author SHA1 Message Date
Ashish Mhetre
a34ad11c0a arm64: configs: Enable CMDQV
Enable CMDQV in defconfigs

Bug 5158829
Bug 5111712
Bug 5419379

Change-Id: I93fdc23c3590091016f1a6f99157a4d1cb2fb638
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3439904
(cherry-picked from commit a9e268cc859f893579b1071d31451f1511cc1e65)
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3495589
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-11-20 08:13:30 -08:00
Ashish Mhetre
e3677b3425 Merge 'drivers/iommu' from dev-main into rel-38
Relevant changes:
9fc5b88382e6 DOWNSTREAM: iommu/arm-smmu-v3: Fix arm_smmu_impl_ops
75436e3f13e4 [DOWNSTREAM] iommu/arm-smmu-v3: Retain prod and cons after resume
b82c7a458d43 [DOWNSTREAM]: iommu/tegra241-cmdqv: WAR for 64-bit writes on NV HV
61d9b92ef30a [UPSTREAM PENDING] iommu/arm-smmu-v3: Add device-tree support in tegra241-cmdqv driver
d4303ed2cb0d DOWNSTREAM: iommu/arm-smmu-v3: Add pm suspend op
69677a732a7d [UPSTREAM PENDING] iommu/arm-smmu-v3: add suspend/resume support
15a4351b19b6 Revert "NVIDIA: SAUCE: iommu/arm-smmu-v3: add suspend/resume support"
415c7fb8e350 [DOWNSTREAM]iommu/arm-smmu-v3: use reserved memory for allocations
0d90af2451b4 iommu/tegra241-cmdqv: Fix warnings due to dmam_free_coherent()
680d181b9007 iommu/tegra241-cmdqv: Read SMMU IDR1.CMDQS instead of hardcoding
2553592d2c24 iommu/tegra241-cmdqv: do not use smp_processor_id in preemptible context
7f390db97e23 iommu/tegra241-cmdqv: Fix alignment failure at max_n_shift
0695cfe98a97 iommu/tegra241-cmdqv: Fix unused variable warning
b266c532562d iommu/tegra241-cmdqv: Staticize cmdqv_debugfs_dir
d5bdc04d1988 iommu/tegra241-cmdqv: Do not allocate vcmdq until dma_set_mask_and_coherent
0c7291931d8c iommu/tegra241-cmdqv: Drop static at local variable
aa469aa3dfa5 iommu/tegra241-cmdqv: Fix ioremap() error handling in probe()
d639d2b0554b iommu/tegra241-cmdqv: Fix -Wformat-truncation warnings in lvcmdq_error_header
2215e2358dff iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF
eefc77955d2e iommu/arm-smmu-v3: Start a new batch if new command is not supported
f70fe98429c7 iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
44a9231b800b iommu/arm-smmu-v3: Add struct arm_smmu_impl_ops
b66ffedc113c iommu/arm-smmu-v3: Add acpi_smmu_iort_probe_model for impl
33f689e1cecd iommu/arm-smmu-v3: Add ARM_SMMU_OPT_TEGRA241_CMDQV
fb85f6f304f2 iommu/arm-smmu-v3: Make symbols public for CONFIG_TEGRA241_CMDQV
8e3c873d5ab3 iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_init
4fae6fb536f6 iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_build_sync_cmd
3c255f7d9cbd iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq

Change-Id: I3e28a37c04d9bbfb6e22a1bc51771bc83db11b07
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
2025-11-20 10:25:56 +00:00
Ashish Mhetre
5865348c39 DOWNSTREAM: iommu/arm-smmu-v3: Fix arm_smmu_impl_ops
While backporting the upstream commit:
44a9231b800b454befac069d468e2f2b71827474
(iommu/arm-smmu-v3: Add struct arm_smmu_impl_ops)

it didn't apply correctly causing cmdqv reset not getting invoked during
resume. Fix it by moving the device reset in arm_smmu_device_reset as
in upstream commit.

Bug 5419379
Bug 5111712

Change-Id: Ifc873bccd0b43b4e6890ac5d6672b4ea3e71cc88
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3452819
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
2025-11-20 10:22:55 +00:00
Ashish Mhetre
c79ae7acb3 [DOWNSTREAM] iommu/arm-smmu-v3: Retain prod and cons after resume
Set PROD and CONS registers of VCMDQs with retained values from
prod and cons variables after SC7 resume.

Bug 5117507

Change-Id: Ida34bb04ce669fdc7901fa935e2a2eff806e3d1e
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3447044
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-11-20 10:22:55 +00:00
Ashish Mhetre
c16f161cd7 [DOWNSTREAM]: iommu/tegra241-cmdqv: WAR for 64-bit writes on NV HV
NVIDIA’s hypervisor does not support 64-bit writes to consecutive
two 32-bit registers e.g., VCMDQ_BASE_LO and VCMDQ_BASE_HI. The driver
currently issues a 64-bit write to such registers, which works fine on
real hardware but fails under NV HV.
This is not a functional bug in the driver, but rather a quirk of the
hypervisor which does not fully emulate the HW behavior. Add a workaround
to split the write into two 32-bit accesses.

Bug 5111712

Change-Id: I6fb6a926a80326e2d7a8a2ec9e475106af843f7c
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3439898
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-11-20 10:22:55 +00:00
Ashish Mhetre
9cbafdf4c3 [UPSTREAM PENDING] iommu/arm-smmu-v3: Add device-tree support in tegra241-cmdqv driver
Add support for initialization from device-tree in CMDQV driver required
for T264 which mimics the current ACPI probe.
Drop ACPI dependency in Kconfig since the inline ifdef would be enough
to depend on ACPI

Bug 4900238

Change-Id: I4ff0996c9ee0688a0ea795892e2fe59133303658
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3439897
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
2025-11-20 10:22:54 +00:00
Ashish Mhetre
a7ae04815b DOWNSTREAM: iommu/arm-smmu-v3: Add pm suspend op
- Issue CMD_OP_CFGI and CMD_OP_TBI_ALL to ensure all pending
transactions are complete before going into suspend and then disable
SMMU device so that there won't be any new map/unmap requests.
- Change to sleep ops to late sleep ops so that SMMU will suspend
late after clients and resume early before clients.
- Add few debug prints

Bug 5117507
Bug 5165373

Change-Id: I108861e6288fd63cebd6d2da2aa93ece071d419f
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3447041
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
2025-11-20 10:22:54 +00:00
Pritesh Raithatha
09c630f285 [UPSTREAM PENDING] iommu/arm-smmu-v3: add suspend/resume support
Add suspend/resume support for arm-smmu-v3. Move irq initialization
to probe and re-use the reset function for restoring registers in
resume.

Bug 4267541

Change-Id: I7bf410f0b69b56f1e1c138e9802449bcd3634a1e
Signed-off-by: Pritesh Raithatha <praithatha@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-stable/+/3112738
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3447965
Tested-by: Ashish Mhetre <amhetre@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-11-20 10:22:54 +00:00
Ashish Mhetre
a0eab0226d Revert "NVIDIA: SAUCE: iommu/arm-smmu-v3: add suspend/resume support"
There is other similar commit added for suspend/resume on K6.1.
Using that commit e6edc95c25dc52fcebf985206ce61fbf817abc98

This reverts commit be979fd7a1.

Bug 5506739

Change-Id: I32d88bc63d9f94d4eb6efdac298e7c2932b7b6e3
Signed-off-by: Ashish Mhetre <amhetre@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3449096
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-11-20 10:22:54 +00:00
Pritesh Raithatha
56a7b340cd [DOWNSTREAM]iommu/arm-smmu-v3: use reserved memory for allocations
CMA allocations are reusable. When not allocated, it can be used
for temporary allocations. When there is allocation request,
temporary allocations will be reclaimed and that takes time.

SMMU uses CMA allocations and causing boot time increase. To avoid
this, add reserved memory pool and use for SMMU allocations instead
of CMA.

With reserved memory 1MB allocation time is reduced from 17999343ns
to 166037ns.

Bug 5115195

Change-Id: I34febac4235da68027908969b9348cbfd2feffc4
Signed-off-by: Pritesh Raithatha <praithatha@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/3rdparty/canonical/linux-noble/+/3446227
Reviewed-by: svcacv <svcacv@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
2025-11-20 10:22:54 +00:00
6 changed files with 157 additions and 67 deletions

View File

@@ -1425,6 +1425,7 @@ CONFIG_TEGRA_IOMMU_SMMU=y
CONFIG_ARM_SMMU=y CONFIG_ARM_SMMU=y
CONFIG_ARM_SMMU_V3=y CONFIG_ARM_SMMU_V3=y
CONFIG_ARM_SMMU_V3_SVA=y CONFIG_ARM_SMMU_V3_SVA=y
CONFIG_TEGRA241_CMDQV=y
CONFIG_MTK_IOMMU=y CONFIG_MTK_IOMMU=y
CONFIG_QCOM_IOMMU=y CONFIG_QCOM_IOMMU=y
CONFIG_REMOTEPROC=y CONFIG_REMOTEPROC=y

View File

@@ -483,6 +483,7 @@ CONFIG_PLATFORM_MHU=y
CONFIG_TEGRA_IOMMU_SMMU=y CONFIG_TEGRA_IOMMU_SMMU=y
CONFIG_ARM_SMMU=y CONFIG_ARM_SMMU=y
CONFIG_ARM_SMMU_V3=y CONFIG_ARM_SMMU_V3=y
CONFIG_TEGRA241_CMDQV=y
CONFIG_MTK_IOMMU=y CONFIG_MTK_IOMMU=y
CONFIG_REMOTEPROC=y CONFIG_REMOTEPROC=y
CONFIG_MTK_PMIC_WRAP=y CONFIG_MTK_PMIC_WRAP=y

View File

@@ -409,7 +409,7 @@ config ARM_SMMU_V3_SVA
config TEGRA241_CMDQV config TEGRA241_CMDQV
bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3" bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
depends on ACPI depends on ARM_SMMU_V3
help help
Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues

View File

@@ -2,7 +2,8 @@
/* /*
* IOMMU API for ARM architected SMMUv3 implementations. * IOMMU API for ARM architected SMMUv3 implementations.
* *
* Copyright (C) 2015 ARM Limited * SPDX-FileCopyrightText: Copyright (C) 2015 ARM Limited
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
* *
* Author: Will Deacon <will.deacon@arm.com> * Author: Will Deacon <will.deacon@arm.com>
* *
@@ -23,6 +24,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ats.h> #include <linux/pci-ats.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
@@ -3194,6 +3196,15 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
int ret, nvec = ARM_SMMU_MAX_MSIS; int ret, nvec = ARM_SMMU_MAX_MSIS;
struct device *dev = smmu->dev; struct device *dev = smmu->dev;
/* Clear the MSI address regs */
writeq_relaxed(0, smmu->base + ARM_SMMU_GERROR_IRQ_CFG0);
writeq_relaxed(0, smmu->base + ARM_SMMU_EVTQ_IRQ_CFG0);
if (smmu->features & ARM_SMMU_FEAT_PRI)
writeq_relaxed(0, smmu->base + ARM_SMMU_PRIQ_IRQ_CFG0);
else
nvec--;
if (!(smmu->features & ARM_SMMU_FEAT_MSI)) if (!(smmu->features & ARM_SMMU_FEAT_MSI))
return; return;
@@ -3202,9 +3213,6 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
return; return;
} }
if (!(smmu->features & ARM_SMMU_FEAT_PRI))
nvec--;
/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */ /* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg); ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
if (ret) { if (ret) {
@@ -3266,9 +3274,9 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
} }
} }
static int arm_smmu_reset_irqs(struct arm_smmu_device *smmu) static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
{ {
int ret; int ret, irq;
u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN; u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
/* Disable IRQs first */ /* Disable IRQs first */
@@ -3279,35 +3287,7 @@ static int arm_smmu_reset_irqs(struct arm_smmu_device *smmu)
return ret; return ret;
} }
if (!smmu->combined_irq) { irq = smmu->combined_irq;
/*
* Clear the MSI address regs. These registers will be reset
* in arm_smmu_write_msi_msg callback function by irq_domain
* upon a new MSI message.
*/
writeq_relaxed(0, smmu->base + ARM_SMMU_GERROR_IRQ_CFG0);
writeq_relaxed(0, smmu->base + ARM_SMMU_EVTQ_IRQ_CFG0);
if (smmu->features & ARM_SMMU_FEAT_PRI)
writeq_relaxed(0, smmu->base + ARM_SMMU_PRIQ_IRQ_CFG0);
}
if (smmu->features & ARM_SMMU_FEAT_PRI)
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
/* Enable interrupt generation on the SMMU */
ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK);
if (ret)
dev_warn(smmu->dev, "failed to enable irqs\n");
return ret;
}
static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
{
int ret = 0, irq = smmu->combined_irq;
if (irq) { if (irq) {
/* /*
* Cavium ThunderX2 implementation doesn't support unique irq * Cavium ThunderX2 implementation doesn't support unique irq
@@ -3323,7 +3303,16 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
} else } else
arm_smmu_setup_unique_irqs(smmu); arm_smmu_setup_unique_irqs(smmu);
return ret; if (smmu->features & ARM_SMMU_FEAT_PRI)
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
/* Enable interrupt generation on the SMMU */
ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK);
if (ret)
dev_warn(smmu->dev, "failed to enable irqs\n");
return 0;
} }
static int arm_smmu_device_disable(struct arm_smmu_device *smmu) static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
@@ -3337,7 +3326,7 @@ static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
return ret; return ret;
} }
static int arm_smmu_device_reset(struct arm_smmu_device *smmu) static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
{ {
int ret; int ret;
u32 reg, enables; u32 reg, enables;
@@ -3445,17 +3434,11 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
} }
} }
ret = arm_smmu_reset_irqs(smmu);
if (ret) {
dev_err(smmu->dev, "failed to reset irqs\n");
return ret;
}
if (is_kdump_kernel()) if (is_kdump_kernel())
enables &= ~(CR0_EVTQEN | CR0_PRIQEN); enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
/* Enable the SMMU interface, or ensure bypass */ /* Enable the SMMU interface, or ensure bypass */
if (!smmu->bypass || disable_bypass) { if (!bypass || disable_bypass) {
enables |= CR0_SMMUEN; enables |= CR0_SMMUEN;
} else { } else {
ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT); ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
@@ -3469,6 +3452,14 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
return ret; return ret;
} }
if (smmu->impl_ops && smmu->impl_ops->device_reset) {
ret = smmu->impl_ops->device_reset(smmu);
if (ret) {
dev_err(smmu->dev, "failed to reset impl\n");
return ret;
}
}
return 0; return 0;
} }
@@ -3730,6 +3721,34 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
return 0; return 0;
} }
#ifdef CONFIG_TEGRA241_CMDQV
static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
struct arm_smmu_device *smmu)
{
struct platform_device *pdev;
struct device_node *np;
np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
if (!np)
return;
pdev = of_find_device_by_node(np);
of_node_put(np);
if (!pdev)
return;
smmu->impl_dev = &pdev->dev;
smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
dev_info(smmu->dev, "found companion CMDQV device: %s\n",
dev_name(smmu->impl_dev));
}
#else
static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
struct arm_smmu_device *smmu)
{
}
#endif
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
#ifdef CONFIG_TEGRA241_CMDQV #ifdef CONFIG_TEGRA241_CMDQV
static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node, static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
@@ -3814,6 +3833,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
u32 cells; u32 cells;
int ret = -EINVAL; int ret = -EINVAL;
if (!of_reserved_mem_device_init(dev))
dev_info(dev, "using device-specific reserved memory\n");
if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells)) if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
dev_err(dev, "missing #iommu-cells property\n"); dev_err(dev, "missing #iommu-cells property\n");
else if (cells != 1) else if (cells != 1)
@@ -3826,6 +3848,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
if (of_dma_is_coherent(dev->of_node)) if (of_dma_is_coherent(dev->of_node))
smmu->features |= ARM_SMMU_FEAT_COHERENCY; smmu->features |= ARM_SMMU_FEAT_COHERENCY;
tegra_cmdqv_dt_probe(dev->of_node, smmu);
return ret; return ret;
} }
@@ -3996,15 +4020,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
/* Check for RMRs and install bypass STEs if any */ /* Check for RMRs and install bypass STEs if any */
arm_smmu_rmr_install_bypass_ste(smmu); arm_smmu_rmr_install_bypass_ste(smmu);
ret = arm_smmu_setup_irqs(smmu);
if (ret)
return ret;
/* Reset the device */ /* Reset the device */
ret = arm_smmu_device_reset(smmu); ret = arm_smmu_device_reset(smmu, smmu->bypass);
if (ret) if (ret)
goto err_disable; goto err_disable;
ret = arm_smmu_setup_irqs(smmu);
if (ret) {
dev_err(smmu->dev, "failed to setup irqs\n");
return ret;
}
/* And we're up. Go go go! */ /* And we're up. Go go go! */
ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL, ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
"smmu3.%pa", &ioaddr); "smmu3.%pa", &ioaddr);
@@ -4017,14 +4043,6 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
goto err_free_sysfs; goto err_free_sysfs;
} }
if (smmu->impl_ops && smmu->impl_ops->device_reset) {
ret = smmu->impl_ops->device_reset(smmu);
if (ret) {
dev_err(smmu->dev, "failed to reset impl\n");
return ret;
}
}
return 0; return 0;
err_free_sysfs: err_free_sysfs:
@@ -4070,11 +4088,32 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
{ {
struct arm_smmu_device *smmu = dev_get_drvdata(dev); struct arm_smmu_device *smmu = dev_get_drvdata(dev);
return arm_smmu_device_reset(smmu); dev_dbg(dev, "Resuming\n");
arm_smmu_device_reset(smmu, smmu->bypass);
return 0;
}
static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
{
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
struct arm_smmu_cmdq_ent cmd;
cmd.opcode = CMDQ_OP_CFGI_ALL;
arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
cmd.opcode = CMDQ_OP_TLBI_NSNH_ALL;
arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
dev_dbg(dev, "Disabling\n");
arm_smmu_device_disable(smmu);
dev_dbg(dev, "Suspending\n");
return 0;
} }
static const struct dev_pm_ops arm_smmu_pm_ops = { static const struct dev_pm_ops arm_smmu_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(NULL, arm_smmu_runtime_resume) SET_LATE_SYSTEM_SLEEP_PM_OPS(arm_smmu_runtime_suspend, arm_smmu_runtime_resume)
}; };
static struct platform_driver arm_smmu_driver = { static struct platform_driver arm_smmu_driver = {

View File

@@ -9,6 +9,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <acpi/acpixf.h> #include <acpi/acpixf.h>
@@ -81,7 +83,9 @@
#define VCMDQ_LOG2SIZE GENMASK(4, 0) #define VCMDQ_LOG2SIZE GENMASK(4, 0)
#define TEGRA241_VCMDQ_BASE 0x00000 #define TEGRA241_VCMDQ_BASE 0x00000
#define TEGRA241_VCMDQ_BASE_H 0x00004
#define TEGRA241_VCMDQ_CONS_INDX_BASE 0x00008 #define TEGRA241_VCMDQ_CONS_INDX_BASE 0x00008
#define TEGRA241_VCMDQ_CONS_INDX_BASE_H 0x0000C
/* VINTF logical-VCMDQ pages */ /* VINTF logical-VCMDQ pages */
#define TEGRA241_VINTFi_PAGE0(i) (TEGRA241_VINTF_PAGE_BASE + SZ_128K*(i)) #define TEGRA241_VINTFi_PAGE0(i) (TEGRA241_VINTF_PAGE_BASE + SZ_128K*(i))
@@ -365,8 +369,10 @@ static void tegra241_vcmdq_hw_deinit(struct tegra241_vcmdq *vcmdq)
} }
writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, PROD)); writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, PROD));
writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, CONS)); writel_relaxed(0, REG_VCMDQ_PAGE0(vcmdq, CONS));
writeq_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, BASE)); writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, BASE_H));
writeq_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, CONS_INDX_BASE)); writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, BASE));
writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, CONS_INDX_BASE_H));
writel_relaxed(0, REG_VCMDQ_PAGE1(vcmdq, CONS_INDX_BASE));
gerrorn = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERRORN)); gerrorn = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERRORN));
gerror = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERROR)); gerror = readl_relaxed(REG_VCMDQ_PAGE0(vcmdq, GERROR));
@@ -388,7 +394,10 @@ static int tegra241_vcmdq_hw_init(struct tegra241_vcmdq *vcmdq)
tegra241_vcmdq_hw_deinit(vcmdq); tegra241_vcmdq_hw_deinit(vcmdq);
/* Configure and enable VCMDQ */ /* Configure and enable VCMDQ */
writeq_relaxed(vcmdq->cmdq.q.q_base, REG_VCMDQ_PAGE1(vcmdq, BASE)); writel_relaxed(upper_32_bits(vcmdq->cmdq.q.q_base), REG_VCMDQ_PAGE1(vcmdq, BASE_H));
writel_relaxed(lower_32_bits(vcmdq->cmdq.q.q_base), REG_VCMDQ_PAGE1(vcmdq, BASE));
writel_relaxed(vcmdq->cmdq.q.llq.prod, REG_VCMDQ_PAGE0(vcmdq, PROD));
writel_relaxed(vcmdq->cmdq.q.llq.cons, REG_VCMDQ_PAGE0(vcmdq, CONS));
ret = vcmdq_write_config(vcmdq, VCMDQ_EN); ret = vcmdq_write_config(vcmdq, VCMDQ_EN);
if (ret) { if (ret) {
@@ -748,6 +757,26 @@ free_list:
return res; return res;
} }
static struct resource *
tegra241_cmdqv_find_dt_resource(struct device *dev, int *irq)
{
struct platform_device *pdev = to_platform_device(dev);
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "no memory resource found for CMDQV\n");
return NULL;
}
if (irq)
*irq = platform_get_irq_byname_optional(pdev, "cmdqv");
if (!irq || *irq <= 0)
dev_warn(dev, "no interrupt. errors will not be reported\n");
return res;
}
static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu) static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
{ {
struct tegra241_cmdqv *cmdqv = struct tegra241_cmdqv *cmdqv =
@@ -875,10 +904,13 @@ struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
if (!smmu->dev->of_node) if (!smmu->dev->of_node)
res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq); res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
else
res = tegra241_cmdqv_find_dt_resource(smmu->impl_dev, &irq);
if (!res) if (!res)
goto out_fallback; goto out_fallback;
new_smmu = __tegra241_cmdqv_probe(smmu, res, irq); new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
if (!smmu->dev->of_node)
kfree(res); kfree(res);
if (new_smmu) if (new_smmu)
@@ -890,3 +922,20 @@ out_fallback:
put_device(smmu->impl_dev); put_device(smmu->impl_dev);
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static const struct of_device_id tegra241_cmdqv_of_match[] = {
{ .compatible = "nvidia,tegra264-cmdqv" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, tegra241_cmdqv_of_match);
static struct platform_driver tegra241_cmdqv_driver = {
.driver = {
.name = "tegra241-cmdqv",
.of_match_table = tegra241_cmdqv_of_match,
},
};
module_platform_driver(tegra241_cmdqv_driver);
MODULE_DESCRIPTION("NVIDIA Tegra241 Command Queue Virtualization Driver");
MODULE_LICENSE("GPL v2");