Add Tegra241 (Grace) CMDQV Support (part 1/2)
Subsystems (4)
v14 cover Add Tegra241 (Grace) CMDQV Support (part 1/2)
NVIDIA's Tegra241 (Grace) SoC has a CMDQ-Virtualization (CMDQV) hardware that extends standard ARM SMMUv3 to support multiple command queues with virtualization capabilities. Though this is similar to the ECMDQ in SMMU v3.3, CMDQV provides additional Virtual Interfaces (VINTFs) allowing VMs to have their own VINTFs and Virtual Command Queues (VCMDQs). The VCMDQs can only execute a limited set of commands, mainly invalidation commands when exclusively used by the VMs, compared to the standard SMMUv3 CMDQ.
Thus, there are two parts of patch series to add its support: the basic in-kernel support as part 1, and the user-space support as part 2.
The in-kernel support is to detect/configure the CMDQV hardware and then allocate a VINTF with some VCMDQs for the kernel/hypervisor to use. Like ECMDQ, CMDQV also allows the kernel to use multiple VCMDQs, giving some limited performance improvement: up to 20% reduction of TLB invalidation time was measured by a multi-threaded DMA unmap benchmark, compared to a single queue.
The user-space support is to provide uAPIs (via IOMMUFD) for hypervisors in user space to passthrough VCMDQs to VMs, allowing these VMs to access the VCMDQs directly without trappings, i.e. no VM Exits. This gives huge performance improvements: 70% to 90% reductions of TLB invalidation time were measured by various DMA unmap tests running in a guest OS, compared to a nested SMMU CMDQ (with trappings).
This is the part-1 series:
- Preparatory changes to share the existing SMMU functions
- A new CMDQV driver and extending the SMMUv3 driver to interact with the new driver
- Limit the commands for a guest kernel.
It's available on Github:
https://github.com/nicolinc/iommufd/commits/vcmdq_in_kernel-v14
And the part-2 RFC series is also sent for discussion:
https://lore.kernel.org/all/[email protected]/
Note that this in-kernel support isn't confined to host kernels running on Grace-powered servers, but is also used by guest kernels running on VMs virtualized on those servers. So, those VMs must install the driver, ideally before the part 2 is merged. So, later those servers would only need to upgrade their host kernels without bothering the VMs.
Thank you!
Changelog
v14:
* Rebased on Will's for-joerg/arm-smmu/updates
* Added a missed kdoc for "dev" in struct tegra241_cmdqv
* Corrected typo-ed function names in the impl commit message
v13:
https://lore.kernel.org/all/[email protected]/
* Rebased on 6.11-rc4
* Fixed the lidx calculation in the isr()
* Dropped the arm_smmu_get_iort_node from v12
* Dropped the WARN_ON_ONCE in arm_smmu_cmdq_batch_init()
* Replaced ARM_SMMU_OPT_SECONDARY_CMDQ_CS_NONE_ONLY with ARM_SMMU_OPT_TEGRA241_CMDQV for impl-level probe
* Split the minimal cmdqv dsdt probe part from the tegra241_cmdqv to the common driver since it might run on other platforms too
* Added an impl_dev to forward the device node to cmdqv driver so it can use it for prints and HW resources probe
* Switched to the open-code approach provided by Will, replacing the patch "Enforce arm_smmu_cmdq_build_sync_cmd"
* Added a supports_cmd op in the struct arm_smmu_cmdq, so as to scan the command at each arm_smmu_cmdq_batch_add call
v12:
https://lore.kernel.org/all/[email protected]/
* Rebased on 6.11-rc3
* Added Jason's Reviewed-by
* Added an arm_smmu_impl_probe helper
* Added an arm_smmu_get_iort_node helper
* Slightly updated the CMDQV acpi probe()
* Added a static_assert() for smmu in struct tegra241_cmdqv
v11:
https://lore.kernel.org/all/[email protected]/
* Rebased on 6.11-rc2
* Fixed "vtinfs" typo in kdoc
* Maxed out the max_n_shift to hardware allowed value
v10:
https://lore.kernel.org/all/[email protected]/
* Rebased on 6.11-rc1
* Added impl design mimicing arm-smmu (v2) driver
* Replaced the CS_NONE quirk with a new smmu option
* Fixed misaligned 64-bit register reading in the isr()
* Explicitly assign opcode to arm_smmu_cmdq_batch_init() where cmd/ent might potentially not be initialized.
v9:
https://lore.kernel.org/all/[email protected]/
* Rebased on 6.10-rc3
* Replaced "base + offset" in write_config() with REG helpers
* Added "Reviewed-by" line from Jason, to the remaining PATCH-5
v8:
https://lore.kernel.org/all/[email protected]/
* Added "Reviewed-by" lines from Jason
* Replaced memset with a simple "cmd[1] = 0"
* Replaced MMIO read/write helpers with REG_* macros
* Dropped the racy static string in lvcmdq_error_header()
* Added a few lines of comments to arm_smmu_get_cmdq at the line calling tegra241_cmdqv_get_cmdq()
v7:
https://lore.kernel.org/all/[email protected]/
* Moved all public symbols into one single patch
* Enforced a command batch to use the same cmdq
* Enforced the use of arm_smmu_cmdq_build_sync_cmd()
* Reworked the tegra241-cmdqv driver patch
- Dropped logging macros, cmdqv->dev, and atomic
- Dropped devm_* and added tegra241_cmdqv_device_remove()
- Moved all structure allocations to cmdqv's probe() from device_reset() where only register configurations remains
- Switched the config macros to inline functions
- Optimized ISR routine with 64-bit reading MMIO
- Scan once per batch against command list
- Reorganized function locations
- Minor readability changes
v6:
https://lore.kernel.org/all/[email protected]/
* Reordered the patch sequence to fix git-bisect break
* Added a status cache to cmdqv/vintf/vcmdq structure
* Added gerror/gerrorn value match in hw_deinit()
* Minimized changes in __arm_smmu_cmdq_skip_err()
* Preallocated VCMDQs to VINTFs for stablility
v5:
https://lore.kernel.org/all/[email protected]/
* Improved print/mmio helpers
* Added proper register reset routines
* Reorganized init/deinit functions to share with VIOMMU callbacks in the upcoming part-2 user-space series (RFC)
v4:
https://lore.kernel.org/all/[email protected]/
* Rebased on v6.9-rc1
* Renamed to "tegra241-cmdqv", following other Grace kernel patches
* Added a set of print and MMIO helpers
* Reworked the guest limitation patch
v3:
https://lore.kernel.org/all/[email protected]/
* Dropped VMID and mdev patches to redesign later based on IOMMUFD
* Separated HYP_OWN part for guest support into a new patch
* Added new preparatory changes
v2:
https://lore.kernel.org/all/[email protected]/
* Added mdev interface support for hypervisor and VMs
* Added preparatory changes for mdev interface implementation
* PATCH-12 Changed ->issue_cmdlist() to ->get_cmdq() for a better integration with recently merged ECMDQ-related changes
v1:
https://lore.kernel.org/all/[email protected]/
Jason Gunthorpe (1):
iommu/arm-smmu-v3: Add struct arm_smmu_impl_ops
Nate Watterson (1):
iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace)
CMDQV
Nicolin Chen (8):
iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq iommu/arm-smmu-v3: Pass in cmdq pointer to
arm_smmu_cmdq_build_sync_cmd
iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_init iommu/arm-smmu-v3: Make symbols public for CONFIG_TEGRA241_CMDQV iommu/arm-smmu-v3: Add ARM_SMMU_OPT_TEGRA241_CMDQV iommu/arm-smmu-v3: Add acpi_smmu_iort_probe_model for impl iommu/arm-smmu-v3: Start a new batch if new command is not supported iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF
MAINTAINERS | 1 + drivers/iommu/Kconfig | 11 + drivers/iommu/arm/arm-smmu-v3/Makefile | 1 + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 201 +++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 40 + .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 890 ++++++++++++++++++ 6 files changed, 1101 insertions(+), 43 deletions(-) create mode 100644 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
Signature · 1 line
2.43.0
PATCH v14 1/10 iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq
The driver calls in different places the arm_smmu_get_cmdq() helper, and it's fine to do so since the helper always returns the single SMMU CMDQ. However, with NVIDIA CMDQV extension or SMMU ECMDQ, there can be multiple cmdqs in the system to select one from. And either case requires a batch of commands to be issued to the same cmdq. Thus, a cmdq has to be decided in the higher-level callers.
Add a cmdq pointer in arm_smmu_cmdq_batch structure, and decide the cmdq when initializing the batch. Pass its pointer down to the bottom function. Update __arm_smmu_cmdq_issue_cmd() accordingly for single command issuers.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 48 +++++++++++++-------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 + 2 files changed, 31 insertions(+), 18 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +30 -18
@@ -592,11 +592,11 @@ static void arm_smmu_cmdq_poll_valid_map(struct arm_smmu_cmdq *cmdq,/* Wait for the command queue to become non-full */ static int arm_smmu_cmdq_poll_until_not_full (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq,struct arm_smmu_ll_queue *llq) {unsigned long flags;struct arm_smmu_queue_poll qp; -struct arm_smmu_cmdq *cmdq =arm_smmu_get_cmdq (smmu);int ret =0 ;/*
@@ -627,11 +627,11 @@ static int arm_smmu_cmdq_poll_until_not_full(struct arm_smmu_device *smmu,* Must be called with the cmdq lock held in some capacity. */ static int __arm_smmu_cmdq_poll_until_msi (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq,struct arm_smmu_ll_queue *llq) {int ret =0 ;struct arm_smmu_queue_poll qp; -struct arm_smmu_cmdq *cmdq =arm_smmu_get_cmdq (smmu);u32 *cmd = (u32 *)(Q_ENT (&cmdq->q, llq->prod));queue_poll_init (smmu, &qp);
@@ -651,10 +651,10 @@ static int __arm_smmu_cmdq_poll_until_msi(struct arm_smmu_device *smmu,* Must be called with the cmdq lock held in some capacity. */ static int __arm_smmu_cmdq_poll_until_consumed (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq,struct arm_smmu_ll_queue *llq) {struct arm_smmu_queue_poll qp; -struct arm_smmu_cmdq *cmdq =arm_smmu_get_cmdq (smmu);u32 prod = llq->prod;int ret =0 ;
@@ -701,12 +701,13 @@ static int __arm_smmu_cmdq_poll_until_consumed(struct arm_smmu_device *smmu, }static int arm_smmu_cmdq_poll_until_sync (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq,struct arm_smmu_ll_queue *llq) {if (smmu->options &ARM_SMMU_OPT_MSIPOLL ) -return __arm_smmu_cmdq_poll_until_msi (smmu, llq); +return __arm_smmu_cmdq_poll_until_msi (smmu, cmdq, llq); -return __arm_smmu_cmdq_poll_until_consumed (smmu, llq); +return __arm_smmu_cmdq_poll_until_consumed (smmu, cmdq, llq); } static void arm_smmu_cmdq_write_entries(struct arm_smmu_cmdq *cmdq, u64 *cmds,
@@ -743,13 +744,13 @@ static void arm_smmu_cmdq_write_entries(struct arm_smmu_cmdq *cmdq, u64 *cmds,* CPU will appear before any of the commands from the other CPU. */ static int arm_smmu_cmdq_issue_cmdlist (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq,u64 *cmds,int n,bool sync) {u64 cmd_sync[CMDQ_ENT_DWORDS ];u32 prod;unsigned long flags;bool owner; -struct arm_smmu_cmdq *cmdq =arm_smmu_get_cmdq (smmu);struct arm_smmu_ll_queue llq, head;int ret =0 ;
@@ -763,7 +764,7 @@ static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,while (!queue_has_space (&llq, n + sync)) {local_irq_restore (flags); -if (arm_smmu_cmdq_poll_until_not_full (smmu, &llq)) +if (arm_smmu_cmdq_poll_until_not_full (smmu, cmdq, &llq))dev_err_ratelimited (smmu->dev,"CMDQ timeout\n" );local_irq_save (flags); }
@@ -839,7 +840,7 @@ static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,/* 5. If we are inserting a CMD_SYNC, we must wait for it to complete */ if (sync) { llq.prod =queue_inc_prod_n (&llq, n); - ret =arm_smmu_cmdq_poll_until_sync (smmu, &llq); + ret =arm_smmu_cmdq_poll_until_sync (smmu, cmdq, &llq);if (ret) { dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout at 0x%08x [hwprod 0x%08x, hwcons 0x%08x]\n",
@@ -874,7 +875,8 @@ static int __arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,return -EINVAL ; } -return arm_smmu_cmdq_issue_cmdlist (smmu, cmd,1 , sync); +return arm_smmu_cmdq_issue_cmdlist ( + smmu,arm_smmu_get_cmdq (smmu), cmd,1 , sync); } static int arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
@@ -889,6 +891,13 @@ static int arm_smmu_cmdq_issue_cmd_with_sync(struct arm_smmu_device *smmu,return __arm_smmu_cmdq_issue_cmd (smmu, ent, true); } +static void arm_smmu_cmdq_batch_init (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq_batch *cmds) +{ + cmds->num =0 ; + cmds->cmdq =arm_smmu_get_cmdq (smmu); +} +static void arm_smmu_cmdq_batch_add (struct arm_smmu_device *smmu,struct arm_smmu_cmdq_batch *cmds,struct arm_smmu_cmdq_ent *cmd)
@@ -897,13 +906,15 @@ static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,if (cmds->num ==CMDQ_BATCH_ENTRIES -1 && (smmu->options &ARM_SMMU_OPT_CMDQ_FORCE_SYNC )) { -arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmds, cmds->num, true); - cmds->num =0 ; +arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, + cmds->num, true); +arm_smmu_cmdq_batch_init (smmu, cmds); }if (cmds->num ==CMDQ_BATCH_ENTRIES ) { -arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmds, cmds->num, false); - cmds->num =0 ; +arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, + cmds->num, false); +arm_smmu_cmdq_batch_init (smmu, cmds); } index = cmds->num *CMDQ_ENT_DWORDS ;
@@ -919,7 +930,8 @@ static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,static int arm_smmu_cmdq_batch_submit (struct arm_smmu_device *smmu,struct arm_smmu_cmdq_batch *cmds) { -return arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmds, cmds->num, true); +return arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, + cmds->num, true); } static void arm_smmu_page_response(struct device *dev, struct iopf_fault *unused,
@@ -1170,7 +1182,7 @@ static void arm_smmu_sync_cd(struct arm_smmu_master *master, }, }; - cmds.num =0 ; +arm_smmu_cmdq_batch_init (smmu, &cmds);for (i =0 ; i < master->num_streams; i++) { cmd.cfgi.sid = master->streams[i].id;arm_smmu_cmdq_batch_add (smmu, &cmds, &cmd);
@@ -2021,7 +2033,7 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,arm_smmu_atc_inv_to_cmd (ssid,0 ,0 , &cmd); - cmds.num =0 ; +arm_smmu_cmdq_batch_init (master->smmu, &cmds);for (i =0 ; i < master->num_streams; i++) { cmd.atc.sid = master->streams[i].id;arm_smmu_cmdq_batch_add (master->smmu, &cmds, &cmd);
@@ -2059,7 +2071,7 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,if (!atomic_read (&smmu_domain->nr_ats_masters))return 0 ; - cmds.num =0 ; +arm_smmu_cmdq_batch_init (smmu_domain->smmu, &cmds);spin_lock_irqsave (&smmu_domain->devices_lock, flags); list_for_each_entry(master_domain, &smmu_domain->devices,
@@ -2141,7 +2153,7 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd, num_pages++; } - cmds.num =0 ; +arm_smmu_cmdq_batch_init (smmu, &cmds);while (iova < end) {if (smmu->features &ARM_SMMU_FEAT_RANGE_INV ) {
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +1 -0
@@ -570,6 +570,7 @@ struct arm_smmu_cmdq {struct arm_smmu_cmdq_batch {u64 cmds[CMDQ_BATCH_ENTRIES *CMDQ_ENT_DWORDS ]; +struct arm_smmu_cmdq *cmdq;int num; };
Signature · 1 line
2.43.0
PATCH v14 2/10 iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_build_sync_cmd
In reply to Nicolin ChenThe CMDQV extension on NVIDIA Tegra241 SoC only supports CS_NONE in the CS field of CMD_SYNC, v.s. standard SMMU CMDQ. Pass in the cmdq pointer directly, so the function can identify a different cmdq implementation.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +6 -4
@@ -352,8 +352,9 @@ static struct arm_smmu_cmdq *arm_smmu_get_cmdq(struct arm_smmu_device *smmu) }static void arm_smmu_cmdq_build_sync_cmd (u64 *cmd,struct arm_smmu_device *smmu, -struct arm_smmu_queue *q,u32 prod) +struct arm_smmu_cmdq *cmdq,u32 prod) { +struct arm_smmu_queue *q = &cmdq->q;struct arm_smmu_cmdq_ent ent = { .opcode =CMDQ_OP_CMD_SYNC , };
@@ -371,7 +372,7 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu, }static void __arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu, -struct arm_smmu_queue *q) +struct arm_smmu_cmdq *cmdq) {static const char *const cerror_str[] = { [CMDQ_ERR_CERROR_NONE_IDX ] ="No error" ,
@@ -379,6 +380,7 @@ static void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu, [CMDQ_ERR_CERROR_ABT_IDX] = "Abort on command fetch", [CMDQ_ERR_CERROR_ATC_INV_IDX] = "ATC invalidate timeout", }; +struct arm_smmu_queue *q = &cmdq->q;int i;u64 cmd[CMDQ_ENT_DWORDS ];
@@ -427,7 +429,7 @@ static void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,static void arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu) { -__arm_smmu_cmdq_skip_err (smmu, &smmu->cmdq.q); +__arm_smmu_cmdq_skip_err (smmu, &smmu->cmdq); }/*
@@ -790,7 +792,7 @@ static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,arm_smmu_cmdq_write_entries (cmdq, cmds, llq.prod, n);if (sync) { prod =queue_inc_prod_n (&llq, n); -arm_smmu_cmdq_build_sync_cmd (cmd_sync, smmu, &cmdq->q, prod); +arm_smmu_cmdq_build_sync_cmd (cmd_sync, smmu, cmdq, prod);queue_write (Q_ENT (&cmdq->q, prod), cmd_sync,CMDQ_ENT_DWORDS );/*
Signature · 1 line
2.43.0
PATCH v14 3/10 iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_init
In reply to Nicolin ChenSo that this function can be used by other cmdqs than &smmu->cmdq only.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +3 -3
@@ -3564,9 +3564,9 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,return 0 ; } -static int arm_smmu_cmdq_init (struct arm_smmu_device *smmu) +static int arm_smmu_cmdq_init (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq) { -struct arm_smmu_cmdq *cmdq = &smmu->cmdq;unsigned int nents =1 << cmdq->q.llq.max_n_shift;atomic_set (&cmdq->owner_prod,0 );
@@ -3591,7 +3591,7 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu)if (ret)return ret; - ret =arm_smmu_cmdq_init (smmu); + ret =arm_smmu_cmdq_init (smmu, &smmu->cmdq);if (ret)return ret;
Signature · 1 line
2.43.0
PATCH v14 4/10 iommu/arm-smmu-v3: Make symbols public for CONFIG_TEGRA241_CMDQV
In reply to Nicolin ChenThe symbols __arm_smmu_cmdq_skip_err(), arm_smmu_init_one_queue(), and arm_smmu_cmdq_init() need to be used by the tegra241-cmdqv compilation unit in a following patch.
Remove the static and put prototypes in the header.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 18 ++++++++---------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 9 +++++++++ 2 files changed, 17 insertions(+), 10 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +8 -10
@@ -371,8 +371,8 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,arm_smmu_cmdq_build_cmd (cmd, &ent); } -static void __arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu, -struct arm_smmu_cmdq *cmdq) +void __arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq) {static const char *const cerror_str[] = { [CMDQ_ERR_CERROR_NONE_IDX ] ="No error" ,
@@ -3521,12 +3521,10 @@ static struct iommu_dirty_ops arm_smmu_dirty_ops = { };/* Probing and initialisation functions */ -static int arm_smmu_init_one_queue (struct arm_smmu_device *smmu, -struct arm_smmu_queue *q, -void __iomem *page, -unsigned long prod_off, -unsigned long cons_off, -size_t dwords,const char *name) +int arm_smmu_init_one_queue (struct arm_smmu_device *smmu, +struct arm_smmu_queue *q,void __iomem *page, +unsigned long prod_off,unsigned long cons_off, +size_t dwords,const char *name) {size_t qsz;
@@ -3564,8 +3562,8 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,return 0 ; } -static int arm_smmu_cmdq_init (struct arm_smmu_device *smmu, -struct arm_smmu_cmdq *cmdq) +int arm_smmu_cmdq_init (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq) {unsigned int nents =1 << cmdq->q.llq.max_n_shift;
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +9 -0
@@ -816,6 +816,15 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,int arm_smmu_atc_inv_domain (struct arm_smmu_domain *smmu_domain,unsigned long iova,size_t size); +void __arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq); +int arm_smmu_init_one_queue (struct arm_smmu_device *smmu, +struct arm_smmu_queue *q,void __iomem *page, +unsigned long prod_off,unsigned long cons_off, +size_t dwords,const char *name); +int arm_smmu_cmdq_init (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq); +#ifdef CONFIG_ARM_SMMU_V3_SVA bool arm_smmu_sva_supported (struct arm_smmu_device *smmu);bool arm_smmu_master_sva_supported (struct arm_smmu_master *master);
Signature · 1 line
2.43.0
PATCH v14 5/10 iommu/arm-smmu-v3: Add ARM_SMMU_OPT_TEGRA241_CMDQV
In reply to Nicolin ChenThe CMDQV extension in NVIDIA Tegra241 SoC only supports CS_NONE in the CS field of CMD_SYNC. Add a new SMMU option to accommodate that.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 16 +++++++++++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +15 -1
@@ -351,6 +351,15 @@ static struct arm_smmu_cmdq *arm_smmu_get_cmdq(struct arm_smmu_device *smmu)return &smmu->cmdq; } +static bool arm_smmu_cmdq_needs_busy_polling (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq *cmdq) +{ +if (cmdq == &smmu->cmdq) +return false; + +return smmu->options &ARM_SMMU_OPT_TEGRA241_CMDQV ; +} +static void arm_smmu_cmdq_build_sync_cmd (u64 *cmd,struct arm_smmu_device *smmu,struct arm_smmu_cmdq *cmdq,u32 prod) {
@@ -369,6 +378,8 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu, }arm_smmu_cmdq_build_cmd (cmd, &ent); +if (arm_smmu_cmdq_needs_busy_polling (smmu, cmdq)) +u64p_replace_bits (cmd,CMDQ_SYNC_0_CS_NONE ,CMDQ_SYNC_0_CS ); } void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,
@@ -423,6 +434,8 @@ void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,/* Convert the erroneous command into a CMD_SYNC */ arm_smmu_cmdq_build_cmd (cmd, &cmd_sync); +if (arm_smmu_cmdq_needs_busy_polling (smmu, cmdq)) +u64p_replace_bits (cmd,CMDQ_SYNC_0_CS_NONE ,CMDQ_SYNC_0_CS );queue_write (Q_ENT (q, cons), cmd, q->ent_dwords); }
@@ -706,7 +719,8 @@ static int arm_smmu_cmdq_poll_until_sync(struct arm_smmu_device *smmu, struct arm_smmu_cmdq *cmdq, struct arm_smmu_ll_queue *llq) { -if (smmu->options &ARM_SMMU_OPT_MSIPOLL ) +if (smmu->options &ARM_SMMU_OPT_MSIPOLL && + !arm_smmu_cmdq_needs_busy_polling (smmu, cmdq))return __arm_smmu_cmdq_poll_until_msi (smmu, cmdq, llq);return __arm_smmu_cmdq_poll_until_consumed (smmu, cmdq, llq);
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +1 -0
@@ -665,6 +665,7 @@ struct arm_smmu_device {#define ARM_SMMU_OPT_PAGE0_REGS_ONLY (1 << 1)#define ARM_SMMU_OPT_MSIPOLL (1 << 2)#define ARM_SMMU_OPT_CMDQ_FORCE_SYNC (1 << 3) +#define ARM_SMMU_OPT_TEGRA241_CMDQV (1 << 4)u32 options;struct arm_smmu_cmdq cmdq;
Signature · 1 line
2.43.0
PATCH v14 6/10 iommu/arm-smmu-v3: Add acpi_smmu_iort_probe_model for impl
In reply to Nicolin ChenFor model-specific implementation, repurpose the acpi_smmu_get_options() to a wider acpi_smmu_acpi_probe_model(). A new model can add to the list in this new function.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +13 -5
@@ -4341,18 +4341,28 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) }#ifdef CONFIG_ACPI -static void acpi_smmu_get_options (u32 model,struct arm_smmu_device *smmu) +static int acpi_smmu_iort_probe_model (struct acpi_iort_node *node, +struct arm_smmu_device *smmu) { -switch (model) { +struct acpi_iort_smmu_v3 *iort_smmu = + (struct acpi_iort_smmu_v3 *)node->node_data; + +switch (iort_smmu->model) {case ACPI_IORT_SMMU_V3_CAVIUM_CN99XX : smmu->options |=ARM_SMMU_OPT_PAGE0_REGS_ONLY ;break ;case ACPI_IORT_SMMU_V3_HISILICON_HI161X : smmu->options |=ARM_SMMU_OPT_SKIP_PREFETCH ;break ; +case ACPI_IORT_SMMU_V3_GENERIC : +break ; +default : +dev_err (smmu->dev,"Unknown/unsupported IORT model!\n" ); +return -ENXIO ; }dev_notice (smmu->dev,"option mask 0x%x\n" , smmu->options); +return 0 ; } static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
@@ -4367,8 +4377,6 @@ static int arm_smmu_device_acpi_probe(struct platform_device *pdev,/* Retrieve SMMUv3 specific data */ iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data; -acpi_smmu_get_options (iort_smmu->model, smmu); -if (iort_smmu->flags &ACPI_IORT_SMMU_V3_COHACC_OVERRIDE ) smmu->features |=ARM_SMMU_FEAT_COHERENCY ;
@@ -4380,7 +4388,7 @@ static int arm_smmu_device_acpi_probe(struct platform_device *pdev, smmu->features |= ARM_SMMU_FEAT_HA; } -return 0 ; +return acpi_smmu_iort_probe_model (node, smmu); }#else static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
Signature · 1 line
2.43.0
PATCH v14 7/10 iommu/arm-smmu-v3: Add struct arm_smmu_impl_ops
In reply to Nicolin ChenFrom: Jason Gunthorpe <[email protected]>
Mimicing the arm-smmu (v2) driver, introduce a struct arm_smmu_impl_ops to accommodate impl routines.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 51 ++++++++++++++++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 10 ++++ 2 files changed, 60 insertions(+), 1 deletion(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +50 -1
@@ -348,7 +348,12 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)static struct arm_smmu_cmdq *arm_smmu_get_cmdq (struct arm_smmu_device *smmu) { -return &smmu->cmdq; +struct arm_smmu_cmdq *cmdq =NULL ; + +if (smmu->impl_ops && smmu->impl_ops->get_secondary_cmdq) + cmdq = smmu->impl_ops->get_secondary_cmdq (smmu); + +return cmdq ?: &smmu->cmdq; } static bool arm_smmu_cmdq_needs_busy_polling(struct arm_smmu_device *smmu,
@@ -4052,6 +4057,14 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)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 ; }
@@ -4469,6 +4482,38 @@ static void arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device *smmu)iort_put_rmr_sids (dev_fwnode (smmu->dev), &rmr_list); } +static void arm_smmu_impl_remove (void *data) +{ +struct arm_smmu_device *smmu = data; + +if (smmu->impl_ops && smmu->impl_ops->device_remove) + smmu->impl_ops->device_remove (smmu); +} + +/* +* Probe all the compiled in implementations. Each one checks to see if it +* matches this HW and if so returns a devm_krealloc'd arm_smmu_device which +* replaces the callers. Otherwise the original is returned or ERR_PTR. +*/ +static struct arm_smmu_device *arm_smmu_impl_probe (struct arm_smmu_device *smmu) +{ +struct arm_smmu_device *new_smmu =ERR_PTR (-ENODEV ); +int ret; + +/* Add impl probe */ + +if (new_smmu ==ERR_PTR (-ENODEV )) +return smmu; +if (IS_ERR (new_smmu)) +return new_smmu; + + ret =devm_add_action_or_reset (new_smmu->dev, arm_smmu_impl_remove, + new_smmu); +if (ret) +return ERR_PTR (ret); +return new_smmu; +} +static int arm_smmu_device_probe (struct platform_device *pdev) {int irq, ret;
@@ -4490,6 +4535,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)if (ret)return ret; + smmu =arm_smmu_impl_probe (smmu); +if (IS_ERR (smmu)) +return PTR_ERR (smmu); +/* Base address */ res =platform_get_resource (pdev,IORESOURCE_MEM ,0 );if (!res)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +10 -0
@@ -14,6 +14,8 @@#include <linux/mmzone.h> #include <linux/sizes.h> +struct arm_smmu_device ; +/* MMIO registers */ #define ARM_SMMU_IDR0 0x0#define IDR0_ST_LVL GENMASK(28, 27)
@@ -630,9 +632,17 @@ struct arm_smmu_strtab_cfg {u32 strtab_base_cfg; }; +struct arm_smmu_impl_ops { +int (*device_reset)(struct arm_smmu_device *smmu); +void (*device_remove)(struct arm_smmu_device *smmu); +struct arm_smmu_cmdq *(*get_secondary_cmdq)(struct arm_smmu_device *smmu); +}; +/* An SMMUv3 instance */ struct arm_smmu_device {struct device *dev; +const struct arm_smmu_impl_ops *impl_ops; +void __iomem *base;void __iomem *page1;
Signature · 1 line
2.43.0
PATCH v14 8/10 iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
In reply to Nicolin ChenFrom: Nate Watterson <[email protected]>
NVIDIA's Tegra241 Soc has a CMDQ-Virtualization (CMDQV) hardware, extending the standard ARM SMMU v3 IP to support multiple VCMDQs with virtualization capabilities. In terms of command queue, they are very like a standard SMMU CMDQ (or ECMDQs), but only support CS_NONE in the CS field of CMD_SYNC.
Add a new tegra241-cmdqv driver, and insert its structure pointer into the existing arm_smmu_device, and then add related function calls in the SMMUv3 driver to interact with the CMDQV driver.
In the CMDQV driver, add a minimal part for the in-kernel support: reserve VINTF0 for in-kernel use, and assign some of the VCMDQs to the VINTF0, and select one VCMDQ based on the current CPU ID to execute supported commands. This multi-queue design for in-kernel use gives some limited improvements:
up to 20% reduction of invalidation time was measured by a multi-threaded DMA unmap benchmark, compared to a single queue.
The other part of the CMDQV driver will be user-space support that gives a hypervisor running on the host OS to talk to the driver for virtualization use cases, allowing VMs to use VCMDQs without trappings, i.e. no VM Exits. This is designed based on IOMMUFD, and its RFC series is also under review. It will provide a guest OS a bigger improvement: 70% to 90% reductions of TLB invalidation time were measured by DMA unmap tests running in a guest, compared to nested SMMU CMDQ (with trappings).
As the initial version, the CMDQV driver only supports ACPI configurations.
--- MAINTAINERS | 1 + drivers/iommu/Kconfig | 11 + drivers/iommu/arm/arm-smmu-v3/Makefile | 1 + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 28 +- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 11 + .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 858 ++++++++++++++++++ 6 files changed, 909 insertions(+), 1 deletion(-) create mode 100644 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
MAINTAINERS +1 -0
@@ -22474,6 +22474,7 @@ M: Thierry Reding <[email protected]> R: Krishna Reddy <[email protected]> L: [email protected] S: Supported +F: drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c F: drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c F: drivers/iommu/tegra*
drivers/iommu/Kconfig +11 -0
@@ -424,6 +424,17 @@ config ARM_SMMU_V3_KUNIT_TEST Enable this option to unit-test arm-smmu-v3 driver functions. If unsure, say N. + +config TEGRA241_CMDQV + bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3" + depends on ACPI + help + Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The + CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues + support, except with virtualization capabilities. + + Say Y here if your system is NVIDIA Tegra241 (Grace) or it has the same + CMDQ-V extension. endif config S390_IOMMU
drivers/iommu/arm/arm-smmu-v3/Makefile +1 -0
@@ -2,5 +2,6 @@ obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o arm_smmu_v3-y := arm-smmu-v3.o arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o +arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o obj-$(CONFIG_ARM_SMMU_V3_KUNIT_TEST) += arm-smmu-v3-test.o
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +27 -1
@@ -4354,6 +4354,26 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) }#ifdef CONFIG_ACPI +static void acpi_smmu_dsdt_probe_tegra241_cmdqv (struct acpi_iort_node *node, +struct arm_smmu_device *smmu) +{ +#ifdef CONFIG_TEGRA241_CMDQV +const char *uid =kasprintf (GFP_KERNEL ,"%u" , node->identifier); +struct acpi_device *adev; + +/* Look for an NVDA200C node whose _UID matches the SMMU node ID */ + adev =acpi_dev_get_first_match_dev ("NVDA200C" , uid,-1 ); +if (adev) { +/* Tegra241 CMDQV driver is responsible for put_device() */ + smmu->impl_dev = &adev->dev; + smmu->options |=ARM_SMMU_OPT_TEGRA241_CMDQV ; +dev_info (smmu->dev,"found companion CMDQV device: %s\n" , +dev_name (smmu->impl_dev)); + } +kfree (uid); +#endif +} +static int acpi_smmu_iort_probe_model (struct acpi_iort_node *node,struct arm_smmu_device *smmu) {
@@ -4368,6 +4388,11 @@ static int acpi_smmu_iort_probe_model(struct acpi_iort_node *node, smmu->options |=ARM_SMMU_OPT_SKIP_PREFETCH ;break ;case ACPI_IORT_SMMU_V3_GENERIC : +/* +* Tegra241 implementation stores its SMMU options and impl_dev +* in DSDT. Thus, go through the ACPI tables unconditionally. +*/ +acpi_smmu_dsdt_probe_tegra241_cmdqv (node, smmu);break ;default :dev_err (smmu->dev,"Unknown/unsupported IORT model!\n" );
@@ -4500,7 +4525,8 @@ static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu)struct arm_smmu_device *new_smmu =ERR_PTR (-ENODEV );int ret; -/* Add impl probe */ +if (smmu->impl_dev && (smmu->options &ARM_SMMU_OPT_TEGRA241_CMDQV )) + new_smmu =tegra241_cmdqv_probe (smmu);if (new_smmu ==ERR_PTR (-ENODEV ))return smmu;
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +11 -0
@@ -641,6 +641,7 @@ struct arm_smmu_impl_ops {/* An SMMUv3 instance */ struct arm_smmu_device {struct device *dev; +struct device *impl_dev;const struct arm_smmu_impl_ops *impl_ops;void __iomem *base;
@@ -882,4 +883,14 @@ static inline void arm_smmu_sva_notifier_synchronize(void) {}#define arm_smmu_sva_domain_alloc NULL#endif /* CONFIG_ARM_SMMU_V3_SVA */ + +#ifdef CONFIG_TEGRA241_CMDQV +struct arm_smmu_device *tegra241_cmdqv_probe (struct arm_smmu_device *smmu); +#else /* CONFIG_TEGRA241_CMDQV */ +static inline struct arm_smmu_device * +tegra241_cmdqv_probe (struct arm_smmu_device *smmu) +{ +return ERR_PTR (-ENODEV ); +} +#endif /* CONFIG_TEGRA241_CMDQV */ #endif /* _ARM_SMMU_V3_H */
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +858 -0
858 lines not on this page · raw message
Signature · 1 line
2.43.0
Re: [PATCH v14 08/10] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
I was reviewing Smatch warnings:
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:616 tegra241_cmdqv_init_vintf()
error: Calling ida_alloc_max() with a 'max' argument which is a power of 2. -1 missing?
The problem is that we're calling ida_alloc_max() where max is always zero.
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c line 587
Quoted 11 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +11
-0+static int tegra241_cmdqv_init_vintf (struct tegra241_cmdqv *cmdqv,u16 max_idx, +struct tegra241_vintf *vintf) +{ + +u16 idx; +int ret; + + ret =ida_alloc_max (&cmdqv->vintf_ids, max_idx,GFP_KERNEL ); +if (ret <0 ) +return ret; + idx = ret;
max_idx is always zero so idx is always zero.
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c line 600
Quoted 13 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +13
-0+ + vintf->idx = idx; + vintf->cmdqv = cmdqv; + vintf->base = cmdqv->base +TEGRA241_VINTF (idx); + + vintf->lvcmdqs =kcalloc (cmdqv->num_lvcmdqs_per_vintf, +sizeof (*vintf->lvcmdqs),GFP_KERNEL ); +if (!vintf->lvcmdqs) { +ida_free (&cmdqv->vintf_ids, idx); +return -ENOMEM ; + } + + cmdqv->vintfs[idx] = vintf;
We only use the first element of this array.
Review
Quoted 2 lines
(quoted diff) +2
-0+ return ret; +}
We could get rid of the ida_ stuff and change the cmdqv->vintfs[] array to a pointer. It would simplify the code.
regards,
dan carpenter
Re: [PATCH v14 08/10] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
Hi Dan,
Quoted 7 lines · Dan Carpenter
I was reviewing Smatch warnings:
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:616tegra241_cmdqv_init_vintf()
error: Callingida_alloc_max()with a 'max' argument which is a power of 2. -1 missing?The problem is that we're calling
ida_alloc_max()where max is always zero.
Quoted 13 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c line 587
Quoted 11 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +11
-0+static int tegra241_cmdqv_init_vintf (struct tegra241_cmdqv *cmdqv,u16 max_idx, +struct tegra241_vintf *vintf) +{ + +u16 idx; +int ret; + + ret =ida_alloc_max (&cmdqv->vintf_ids, max_idx,GFP_KERNEL ); +if (ret <0 ) +return ret; + idx = ret;
max_idxis always zero so idx is always zero.
There is a followup series adding support for max[1, max_vintf]. And I guess that would make Smatch happy. I'd personally prefer keep this by ignoring the Smatch warning. But if you think the common practice is to drop it and add back, I'd be okay with it.
Quoted 16 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c line 600
Quoted 13 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +13
-0+ + vintf->idx = idx; + vintf->cmdqv = cmdqv; + vintf->base = cmdqv->base +TEGRA241_VINTF (idx); + + vintf->lvcmdqs =kcalloc (cmdqv->num_lvcmdqs_per_vintf, +sizeof (*vintf->lvcmdqs),GFP_KERNEL ); +if (!vintf->lvcmdqs) { +ida_free (&cmdqv->vintf_ids, idx); +return -ENOMEM ; + } + + cmdqv->vintfs[idx] = vintf;We only use the first element of this array.
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ return ret; +}We could get rid of the
ida_stuff and change the cmdqv->vintfs[] array to a pointer. It would simplify the code.
As mentioned above, a following series is adding other vintfs. There is no warning/error to this array, I'd prefer we keep it as is.
Thanks
Nicolin
Re: [PATCH v14 08/10] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
Quoted 25 lines · Nicolin Chen
Hi Dan,
Quoted 7 lines · Dan Carpenter
I was reviewing Smatch warnings:
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:616tegra241_cmdqv_init_vintf()
error: Callingida_alloc_max()with a 'max' argument which is a power of 2. -1 missing?The problem is that we're calling
ida_alloc_max()where max is always zero.Quoted 13 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c line 587
Quoted 11 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +11
-0+static int tegra241_cmdqv_init_vintf (struct tegra241_cmdqv *cmdqv,u16 max_idx, +struct tegra241_vintf *vintf) +{ + +u16 idx; +int ret; + + ret =ida_alloc_max (&cmdqv->vintf_ids, max_idx,GFP_KERNEL ); +if (ret <0 ) +return ret; + idx = ret;
max_idxis always zero so idx is always zero.
Quoted 5 lines
There is a followup series adding support for max[1,
max_vintf]. And I guess that would make Smatch happy. I'd personally prefer keep this by ignoring the Smatch warning. But if you think the common practice is to drop it and add back, I'd be okay with it.
I'm just reviewing static checker warnings so I don't know the back story... How long are we going to have to wait for the follow on patchset?
Generally if someone had noticed this in review they would have asked that it be dropped but now that it's in, you're probably in the clear. No one else is going to volunteer to refactor this code if you don't. ;)
With regards, to ignoring static checker warnings. These are one time emails. There is always going to be a certain percent of false positives. You're *encouraged* to ignore static checker warnings unless it's a bug or it makes the code cleaner. The goal is never to silence the checker.
regards,
dan carpenter
Re: [PATCH v14 08/10] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
Quoted 26 lines · Dan Carpenter
Quoted 25 lines · Nicolin Chen
Hi Dan,
Quoted 20 lines · Dan Carpenter
I was reviewing Smatch warnings:
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:616tegra241_cmdqv_init_vintf()
error: Callingida_alloc_max()with a 'max' argument which is a power of 2. -1 missing?The problem is that we're calling
ida_alloc_max()where max is always zero.drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c line 587
Quoted 11 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +11
-0+static int tegra241_cmdqv_init_vintf (struct tegra241_cmdqv *cmdqv,u16 max_idx, +struct tegra241_vintf *vintf) +{ + +u16 idx; +int ret; + + ret =ida_alloc_max (&cmdqv->vintf_ids, max_idx,GFP_KERNEL ); +if (ret <0 ) +return ret; + idx = ret;
max_idxis always zero so idx is always zero.
Quoted 8 lines
Quoted 5 lines
There is a followup series adding support for max[1,
max_vintf]. And I guess that would make Smatch happy. I'd personally prefer keep this by ignoring the Smatch warning. But if you think the common practice is to drop it and add back, I'd be okay with it.I'm just reviewing static checker warnings so I don't know the back story... How long are we going to have to wait for the follow on patchset?
There are a couple of dependencies we need to get merged first. So, it might take a few months I think.
Perhaps I can make a small patch by changing the ida_alloc_max in the common place here to iad_alloc_range(.., 1, max,..) in the caller of the followup series. Then the existing caller for vintf0 wouldn't need an ida_alloc().
Quoted 8 lines
Generally if someone had noticed this in review they would have asked that it be dropped but now that it's in, you're probably in the clear. No one else is going to volunteer to refactor this code if you don't. ;)
With regards, to ignoring static checker warnings. These are one time emails. There is always going to be a certain percent of false positives. You're *encouraged* to ignore static checker warnings unless it's a bug or it makes the code cleaner. The goal is never to silence the checker.
I see. Thanks for the note!
Nicolin
Re: [PATCH v14 08/10] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
Quoted 37 lines · Nicolin Chen
Quoted 26 lines · Dan Carpenter
Quoted 25 lines · Nicolin Chen
Hi Dan,
Quoted 20 lines · Dan Carpenter
I was reviewing Smatch warnings:
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:616tegra241_cmdqv_init_vintf()
error: Callingida_alloc_max()with a 'max' argument which is a power of 2. -1 missing?The problem is that we're calling
ida_alloc_max()where max is always zero.drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c line 587
Quoted 11 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +11
-0+static int tegra241_cmdqv_init_vintf (struct tegra241_cmdqv *cmdqv,u16 max_idx, +struct tegra241_vintf *vintf) +{ + +u16 idx; +int ret; + + ret =ida_alloc_max (&cmdqv->vintf_ids, max_idx,GFP_KERNEL ); +if (ret <0 ) +return ret; + idx = ret;
max_idxis always zero so idx is always zero.Quoted 8 lines
Quoted 5 lines
There is a followup series adding support for max[1,
max_vintf]. And I guess that would make Smatch happy. I'd personally prefer keep this by ignoring the Smatch warning. But if you think the common practice is to drop it and add back, I'd be okay with it.I'm just reviewing static checker warnings so I don't know the back story... How long are we going to have to wait for the follow on patchset?
Quoted 7 lines
There are a couple of dependencies we need to get merged first. So, it might take a few months I think.
Perhaps I can make a small patch by changing the
ida_alloc_maxin the common place here toiad_alloc_range(.., 1, max,..)in the caller of the followup series. Then the existing caller for vintf0 wouldn't need anida_alloc().
Nah, forget about it. We can wait for a few months.
regards,
dan carpenter
PATCH v14 9/10 iommu/arm-smmu-v3: Start a new batch if new command is not supported
In reply to Nicolin ChenThe VCMDQ in the tegra241-cmdqv driver has a guest mode that supports only a few invalidation commands. A batch is initialized with a cmdq, so it has to confirm whether a new command is supported or not.
Add a supports_cmd function pointer to the cmdq structure, where the vcmdq driver should hook a command scan function. Add an inline helper too so it can be used by both sides.
If a new command is not supported, simply issue the existing batch and re- init it as a new batch.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 6 ++++-- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +4 -2
@@ -923,10 +923,12 @@ static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,struct arm_smmu_cmdq_batch *cmds, struct arm_smmu_cmdq_ent *cmd) { + bool unsupported_cmd = !arm_smmu_cmdq_supports_cmd(cmds->cmdq, cmd); +bool force_sync = (cmds->num ==CMDQ_BATCH_ENTRIES -1 ) && + (smmu->options &ARM_SMMU_OPT_CMDQ_FORCE_SYNC );int index; -if (cmds->num ==CMDQ_BATCH_ENTRIES -1 && - (smmu->options &ARM_SMMU_OPT_CMDQ_FORCE_SYNC )) { +if (force_sync || unsupported_cmd) {arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, cmds->num, true);arm_smmu_cmdq_batch_init (smmu, cmds);
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +7 -0
@@ -568,8 +568,15 @@ struct arm_smmu_cmdq {atomic_long_t *valid_map;atomic_t owner_prod;atomic_t lock; +bool (*supports_cmd)(struct arm_smmu_cmdq_ent *ent); }; +static inline bool arm_smmu_cmdq_supports_cmd (struct arm_smmu_cmdq *cmdq, +struct arm_smmu_cmdq_ent *ent) +{ +return cmdq->supports_cmd ? cmdq->supports_cmd (ent) : true; +} +struct arm_smmu_cmdq_batch {u64 cmds[CMDQ_BATCH_ENTRIES *CMDQ_ENT_DWORDS ];struct arm_smmu_cmdq *cmdq;
Signature · 1 line
2.43.0
PATCH v14 10/10 iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF
In reply to Nicolin ChenWhen VCMDQs are assigned to a VINTF owned by a guest (HYP_OWN bit unset), only TLB and ATC invalidation commands are supported by the VCMDQ HW. So, implement the new cmdq->supports_cmd op to scan the input cmd in order to make sure that it is supported by the selected queue.
Note that the guest VM shouldn't have HYP_OWN bit being set regardless of guest kernel driver writing it or not, i.e. the hypervisor running in the host OS should wire this bit to zero when trapping a write access to this VINTF_CONFIG register from a guest kernel.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 28 ++++++++------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +- .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 34 ++++++++++++++++++- 3 files changed, 51 insertions(+), 14 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +16 -12
@@ -346,12 +346,13 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)return 0 ; } -static struct arm_smmu_cmdq *arm_smmu_get_cmdq (struct arm_smmu_device *smmu) +static struct arm_smmu_cmdq *arm_smmu_get_cmdq (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq_ent *ent) {struct arm_smmu_cmdq *cmdq =NULL ;if (smmu->impl_ops && smmu->impl_ops->get_secondary_cmdq) - cmdq = smmu->impl_ops->get_secondary_cmdq (smmu); + cmdq = smmu->impl_ops->get_secondary_cmdq (smmu, ent);return cmdq ?: &smmu->cmdq; }
@@ -897,7 +898,7 @@ static int __arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu, }return arm_smmu_cmdq_issue_cmdlist ( - smmu,arm_smmu_get_cmdq (smmu), cmd,1 , sync); + smmu,arm_smmu_get_cmdq (smmu, ent), cmd,1 , sync); } static int arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
@@ -913,10 +914,11 @@ static int arm_smmu_cmdq_issue_cmd_with_sync(struct arm_smmu_device *smmu, }static void arm_smmu_cmdq_batch_init (struct arm_smmu_device *smmu, -struct arm_smmu_cmdq_batch *cmds) +struct arm_smmu_cmdq_batch *cmds, +struct arm_smmu_cmdq_ent *ent) { cmds->num =0 ; - cmds->cmdq =arm_smmu_get_cmdq (smmu); + cmds->cmdq =arm_smmu_get_cmdq (smmu, ent); } static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,
@@ -931,13 +933,13 @@ static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,if (force_sync || unsupported_cmd) {arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, cmds->num, true); -arm_smmu_cmdq_batch_init (smmu, cmds); +arm_smmu_cmdq_batch_init (smmu, cmds, cmd); }if (cmds->num ==CMDQ_BATCH_ENTRIES ) {arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, cmds->num, false); -arm_smmu_cmdq_batch_init (smmu, cmds); +arm_smmu_cmdq_batch_init (smmu, cmds, cmd); } index = cmds->num *CMDQ_ENT_DWORDS ;
@@ -1205,7 +1207,7 @@ static void arm_smmu_sync_cd(struct arm_smmu_master *master, }, }; -arm_smmu_cmdq_batch_init (smmu, &cmds); +arm_smmu_cmdq_batch_init (smmu, &cmds, &cmd);for (i =0 ; i < master->num_streams; i++) { cmd.cfgi.sid = master->streams[i].id;arm_smmu_cmdq_batch_add (smmu, &cmds, &cmd);
@@ -2056,7 +2058,7 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,arm_smmu_atc_inv_to_cmd (ssid,0 ,0 , &cmd); -arm_smmu_cmdq_batch_init (master->smmu, &cmds); +arm_smmu_cmdq_batch_init (master->smmu, &cmds, &cmd);for (i =0 ; i < master->num_streams; i++) { cmd.atc.sid = master->streams[i].id;arm_smmu_cmdq_batch_add (master->smmu, &cmds, &cmd);
@@ -2071,7 +2073,9 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,struct arm_smmu_master_domain *master_domain;int i;unsigned long flags; -struct arm_smmu_cmdq_ent cmd; +struct arm_smmu_cmdq_ent cmd = { + .opcode =CMDQ_OP_ATC_INV , + };struct arm_smmu_cmdq_batch cmds;if (!(smmu_domain->smmu->features &ARM_SMMU_FEAT_ATS ))
@@ -2094,7 +2098,7 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,if (!atomic_read (&smmu_domain->nr_ats_masters))return 0 ; -arm_smmu_cmdq_batch_init (smmu_domain->smmu, &cmds); +arm_smmu_cmdq_batch_init (smmu_domain->smmu, &cmds, &cmd);spin_lock_irqsave (&smmu_domain->devices_lock, flags); list_for_each_entry(master_domain, &smmu_domain->devices,
@@ -2176,7 +2180,7 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd, num_pages++; } -arm_smmu_cmdq_batch_init (smmu, &cmds); +arm_smmu_cmdq_batch_init (smmu, &cmds, cmd);while (iova < end) {if (smmu->features &ARM_SMMU_FEAT_RANGE_INV ) {
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +2 -1
@@ -642,7 +642,8 @@ struct arm_smmu_strtab_cfg {struct arm_smmu_impl_ops {int (*device_reset)(struct arm_smmu_device *smmu);void (*device_remove)(struct arm_smmu_device *smmu); -struct arm_smmu_cmdq *(*get_secondary_cmdq)(struct arm_smmu_device *smmu); +struct arm_smmu_cmdq *(*get_secondary_cmdq)( +struct arm_smmu_device *smmu,struct arm_smmu_cmdq_ent *ent); };/* An SMMUv3 instance */
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +33 -1
@@ -142,6 +142,7 @@ struct tegra241_vcmdq {* struct tegra241_vintf - Virtual Interface * @idx: Global index in the CMDQV * @enabled: Enable status +* @hyp_own: Owned by hypervisor (in-kernel) * @cmdqv: Parent CMDQV pointer * @lvcmdqs: List of logical VCMDQ pointers * @base: MMIO base address
@@ -150,6 +151,7 @@ struct tegra241_vintf {u16 idx;bool enabled; +bool hyp_own;struct tegra241_cmdqv *cmdqv;struct tegra241_vcmdq **lvcmdqs;
@@ -301,8 +303,21 @@ static irqreturn_t tegra241_cmdqv_isr(int irq, void *devid)/* Command Queue Function */ +static bool tegra241_guest_vcmdq_supports_cmd (struct arm_smmu_cmdq_ent *ent) +{ +switch (ent->opcode) { +case CMDQ_OP_TLBI_NH_ASID : +case CMDQ_OP_TLBI_NH_VA : +case CMDQ_OP_ATC_INV : +return true; +default : +return false; + } +} +static struct arm_smmu_cmdq * -tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu) +tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu, +struct arm_smmu_cmdq_ent *ent) {struct tegra241_cmdqv *cmdqv = container_of(smmu, struct tegra241_cmdqv, smmu);
@@ -328,6 +343,10 @@ tegra241_cmdqv_get_cmdq(struct arm_smmu_device *smmu) vcmdq = vintf->lvcmdqs[lidx];if (!vcmdq || !READ_ONCE (vcmdq->enabled))return NULL ; + +/* Unsupported CMD goes for smmu->cmdq pathway */ +if (!arm_smmu_cmdq_supports_cmd (&vcmdq->cmdq, ent)) +return NULL ;return &vcmdq->cmdq; }
@@ -406,12 +425,22 @@ static int tegra241_vintf_hw_init(struct tegra241_vintf *vintf, bool hyp_own)tegra241_vintf_hw_deinit (vintf);/* Configure and enable VINTF */ +/* +* Note that HYP_OWN bit is wired to zero when running in guest kernel, +* whether enabling it here or not, as !HYP_OWN cmdq HWs only support a +* restricted set of supported commands. +*/ regval =FIELD_PREP (VINTF_HYP_OWN , hyp_own);writel (regval,REG_VINTF (vintf,CONFIG )); ret =vintf_write_config (vintf, regval |VINTF_EN );if (ret)return ret; +/* +* As being mentioned above, HYP_OWN bit is wired to zero for a guest +* kernel, so read it back from HW to ensure that reflects in hyp_own +*/ + vintf->hyp_own = !!(VINTF_HYP_OWN &readl (REG_VINTF (vintf,CONFIG )));for (lidx =0 ; lidx < vintf->cmdqv->num_lvcmdqs_per_vintf; lidx++) {if (vintf->lvcmdqs && vintf->lvcmdqs[lidx]) {
@@ -493,6 +522,9 @@ static int tegra241_vcmdq_alloc_smmu_cmdq(struct tegra241_vcmdq *vcmdq) q->q_base = q->base_dma &VCMDQ_ADDR ; q->q_base |=FIELD_PREP (VCMDQ_LOG2SIZE , q->llq.max_n_shift); +if (!vcmdq->vintf->hyp_own) + cmdq->supports_cmd = tegra241_guest_vcmdq_supports_cmd; +return arm_smmu_cmdq_init (smmu, cmdq); }
Signature · 1 line
2.43.0
Quoted 9 lines · Nicolin Chen
NVIDIA's Tegra241 (Grace) SoC has a CMDQ-Virtualization (CMDQV) hardware that extends standard ARM SMMUv3 to support multiple command queues with virtualization capabilities. Though this is similar to the ECMDQ in SMMU v3.3, CMDQV provides additional Virtual Interfaces (VINTFs) allowing VMs to have their own VINTFs and Virtual Command Queues (VCMDQs). The VCMDQs can only execute a limited set of commands, mainly invalidation commands when exclusively used by the VMs, compared to the standard SMMUv3 CMDQ.
[...]
Thanks for this, Nicolin! I did drop the 'default' statement in the end, as I think it's a bit overkill to fail the probe in that case.
Applied to will (for-joerg/arm-smmu/updates), thanks!
[01/10] iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq
https://git.kernel.org/will/c/56ae8866f3b4 [02/10] iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_build_sync_cmd https://git.kernel.org/will/c/2ea1f0120f90 [03/10] iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_init https://git.kernel.org/will/c/e736c895c45b [04/10] iommu/arm-smmu-v3: Make symbols public for CONFIG_TEGRA241_CMDQV https://git.kernel.org/will/c/a7a08b857a32 [05/10] iommu/arm-smmu-v3: Add ARM_SMMU_OPT_TEGRA241_CMDQV https://git.kernel.org/will/c/b935a5b1c670 [06/10] iommu/arm-smmu-v3: Add acpi_smmu_iort_probe_model for impl https://git.kernel.org/will/c/6f3f9ff43d00 [07/10] iommu/arm-smmu-v3: Add struct arm_smmu_impl_ops https://git.kernel.org/will/c/6de80d619203 [08/10] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV https://git.kernel.org/will/c/918eb5c856f6 [09/10] iommu/arm-smmu-v3: Start a new batch if new command is not supported https://git.kernel.org/will/c/f59e85490712 [10/10] iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF https://git.kernel.org/will/c/a9d40285bdef
Cheers,
Signature · 5 lines
Will https://fixes.arm64.dev https://next.arm64.dev https://will.arm64.dev
Quoted 37 lines · Will Deacon
Quoted 9 lines · Nicolin Chen
NVIDIA's Tegra241 (Grace) SoC has a CMDQ-Virtualization (CMDQV) hardware that extends standard ARM SMMUv3 to support multiple command queues with virtualization capabilities. Though this is similar to the ECMDQ in SMMU v3.3, CMDQV provides additional Virtual Interfaces (VINTFs) allowing VMs to have their own VINTFs and Virtual Command Queues (VCMDQs). The VCMDQs can only execute a limited set of commands, mainly invalidation commands when exclusively used by the VMs, compared to the standard SMMUv3 CMDQ.
[...]
Thanks for this, Nicolin! I did drop the 'default' statement in the end, as I think it's a bit overkill to fail the probe in that case.
Applied to will (for-joerg/arm-smmu/updates), thanks!
[01/10] iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq
https://git.kernel.org/will/c/56ae8866f3b4 [02/10] iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_build_sync_cmd https://git.kernel.org/will/c/2ea1f0120f90 [03/10] iommu/arm-smmu-v3: Pass in cmdq pointer to arm_smmu_cmdq_init https://git.kernel.org/will/c/e736c895c45b [04/10] iommu/arm-smmu-v3: Make symbols public for CONFIG_TEGRA241_CMDQV https://git.kernel.org/will/c/a7a08b857a32 [05/10] iommu/arm-smmu-v3: Add ARM_SMMU_OPT_TEGRA241_CMDQV https://git.kernel.org/will/c/b935a5b1c670 [06/10] iommu/arm-smmu-v3: Add acpi_smmu_iort_probe_model for impl https://git.kernel.org/will/c/6f3f9ff43d00 [07/10] iommu/arm-smmu-v3: Add struct arm_smmu_impl_ops https://git.kernel.org/will/c/6de80d619203 [08/10] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV https://git.kernel.org/will/c/918eb5c856f6 [09/10] iommu/arm-smmu-v3: Start a new batch if new command is not supported https://git.kernel.org/will/c/f59e85490712 [10/10] iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF https://git.kernel.org/will/c/a9d40285bdef
Quoted 1 line
Cheers,
This makes my day :)
Cheers!
Nicolin