Add Tegra241 (Grace) CMDQV Support (part 1/2)
Subsystems (4)
v9 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-v9
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
v9:
* 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]/
Nate Watterson (1):
iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace)
CMDQV
Nicolin Chen (5):
iommu/arm-smmu-v3: Make symbols public for CONFIG_TEGRA241_CMDQV iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq iommu/arm-smmu-v3: Enforce arm_smmu_cmdq_build_sync_cmd iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV iommu/tegra241-cmdqv: Limit CMDs for 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 | 175 ++-- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 67 +- .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 876 ++++++++++++++++++ 6 files changed, 1064 insertions(+), 67 deletions(-) create mode 100644 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
Signature · 1 line
2.43.0
PATCH v9 1/6 iommu/arm-smmu-v3: Make symbols public for CONFIG_TEGRA241_CMDQV
The 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. Also allow to pass in a different cmdq pointer to arm_smmu_cmdq_init.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 20 +++++++++----------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 9 +++++++++ 2 files changed, 18 insertions(+), 11 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +9 -11
@@ -366,8 +366,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_queue *q) +void __arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu, +struct arm_smmu_queue *q) {static const char *const cerror_str[] = { [CMDQ_ERR_CERROR_NONE_IDX ] ="No error" ,
@@ -3124,12 +3124,10 @@ static struct iommu_ops arm_smmu_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;
@@ -3167,9 +3165,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) +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 );
@@ -3194,7 +3192,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;
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +9 -0
@@ -794,6 +794,15 @@ bool arm_smmu_free_asid(struct arm_smmu_ctx_desc *cd);int arm_smmu_atc_inv_domain (struct arm_smmu_domain *smmu_domain,int ssid,unsigned long iova,size_t size); +void __arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu, +struct arm_smmu_queue *q); +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 v9 2/6 iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq
In reply to Nicolin ChenThe 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 | 44 +++++++++++++-------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 + 2 files changed, 29 insertions(+), 16 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +28 -16
@@ -588,11 +588,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 ;/*
@@ -623,11 +623,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);
@@ -647,10 +647,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 ;
@@ -697,12 +697,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,
@@ -739,13 +740,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 ;
@@ -759,7 +760,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); }
@@ -835,7 +836,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",
@@ -870,7 +871,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,
@@ -885,6 +887,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)
@@ -893,12 +902,14 @@ 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); +arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, + cmds->num, true); cmds->num =0 ; }if (cmds->num ==CMDQ_BATCH_ENTRIES ) { -arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmds, cmds->num, false); +arm_smmu_cmdq_issue_cmdlist (smmu, cmds->cmdq, cmds->cmds, + cmds->num, false); cmds->num =0 ; }
@@ -915,7 +926,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,
@@ -1158,7 +1170,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);
@@ -2003,7 +2015,7 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master)arm_smmu_atc_inv_to_cmd (IOMMU_NO_PASID ,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);
@@ -2043,7 +2055,7 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid,arm_smmu_atc_inv_to_cmd (ssid, iova, size, &cmd); - 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, &smmu_domain->devices, domain_head) {
@@ -2120,7 +2132,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
@@ -564,6 +564,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 v9 3/6 iommu/arm-smmu-v3: Enforce arm_smmu_cmdq_build_sync_cmd
In reply to Nicolin ChenThere is an existing arm_smmu_cmdq_build_sync_cmd() so the driver should call it at all places other than going through arm_smmu_cmdq_build_cmd() separately. This helps the following patch that adds a CS_NONE quirk for tegra241-cmdqv driver.
Note that this changes the type of CMD_SYNC in __arm_smmu_cmdq_skip_err, in ARM_SMMU_OPT_MSIPOLL=true case, from previously a non-MSI one to now an MSI one that is proven to still work using a hacking test:
nvme: Adding to iommu group 10
nvme: --------hacking-----------
arm-smmu-v3: unexpected global error reported (0x00000001),
this could be serious
arm-smmu-v3: CMDQ error (cons 0x01000022): Illegal command
arm-smmu-v3: skipping command in error state:
arm-smmu-v3: 0x0000000000000000
arm-smmu-v3: 0x0000000000000000
nvme: -------recovered----------
nvme nvme0: 72/0/0 default/read/poll queues
nvme0n1: p1 p2
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 36 ++++++++------------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 -- 2 files changed, 13 insertions(+), 26 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +13 -23
@@ -325,16 +325,6 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) cmd[0 ] |=FIELD_PREP (CMDQ_RESUME_0_RESP , ent->resume.resp); cmd[1 ] |=FIELD_PREP (CMDQ_RESUME_1_STAG , ent->resume.stag);break ; -case CMDQ_OP_CMD_SYNC : -if (ent->sync.msiaddr) { - cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_IRQ ); - cmd[1 ] |= ent->sync.msiaddr &CMDQ_SYNC_1_MSIADDR_MASK ; - }else { - cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV ); - } - cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ); - cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); -break ;default :return -ENOENT ; }
@@ -350,20 +340,23 @@ 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_ent ent = { - .opcode =CMDQ_OP_CMD_SYNC , - }; + cmd[1 ] =0 ; + cmd[0 ] =FIELD_PREP (CMDQ_0_OP ,CMDQ_OP_CMD_SYNC ) | +FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) | +FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); + +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV ); +return ; + }/* * Beware that Hi16xx adds an extra 32 bits of goodness to its MSI * payload, so the write will zero the entire command on that platform. */ -if (smmu->options &ARM_SMMU_OPT_MSIPOLL ) { - ent.sync.msiaddr = q->base_dma +Q_IDX (&q->llq, prod) * - q->ent_dwords *8 ; - } - -arm_smmu_cmdq_build_cmd (cmd, &ent); + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_IRQ ); + cmd[1 ] |= (q->base_dma +Q_IDX (&q->llq, prod) * q->ent_dwords *8 ) & +CMDQ_SYNC_1_MSIADDR_MASK ; } void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,
@@ -380,9 +373,6 @@ void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,u64 cmd[CMDQ_ENT_DWORDS ];u32 cons =readl_relaxed (q->cons_reg);u32 idx =FIELD_GET (CMDQ_CONS_ERR , cons); -struct arm_smmu_cmdq_ent cmd_sync = { - .opcode =CMDQ_OP_CMD_SYNC , - };dev_err (smmu->dev,"CMDQ error (cons 0x%08x): %s\n" , cons, idx <ARRAY_SIZE (cerror_str) ? cerror_str[idx] :"Unknown" );
@@ -416,7 +406,7 @@ void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,dev_err (smmu->dev,"\t0x%016llx\n" , (unsigned long long )cmd[i]);/* Convert the erroneous command into a CMD_SYNC */ -arm_smmu_cmdq_build_cmd (cmd, &cmd_sync); +arm_smmu_cmdq_build_sync_cmd (cmd, smmu, q, cons);queue_write (Q_ENT (q, cons), cmd, q->ent_dwords); }
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +0 -3
@@ -512,9 +512,6 @@ struct arm_smmu_cmdq_ent { } resume;#define CMDQ_OP_CMD_SYNC 0x46 -struct { -u64 msiaddr; - } sync; }; };
Signature · 1 line
2.43.0
PATCH v9 4/6 iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_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 quirk flag to accommodate that.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 +++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7 -1
@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (q->quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;
@@ -690,7 +695,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 && + !(cmdq->q.quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ))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 +3 -0
@@ -543,6 +543,9 @@ struct arm_smmu_queue {u32 __iomem *prod_reg;u32 __iomem *cons_reg; + +#define CMDQ_QUIRK_SYNC_CS_NONE_ONLY BIT(0)/* CMD_SYNC CS field supports CS_NONE only */ +u32 quirks; };struct arm_smmu_queue_poll {
Signature · 1 line
2.43.0
Will Deacon
maintainerRe: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 41 lines · Nicolin Chen
The CMDQV extension in NVIDIA Tegra241 SoC only supports
CS_NONEin the CS field ofCMD_SYNC. Add a quirk flag to accommodate that.Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Nicolin Chen <[email protected]>--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 +++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-)drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (q->quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + !(cmdq->q.quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ))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 +0
-0
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h struct arm_smmu_queue { · line 548
Quoted 6 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3
-0@@ -543,6 +543,9 @@ struct arm_smmu_queue {u32 __iomem *prod_reg;u32 __iomem *cons_reg; + +#define CMDQ_QUIRK_SYNC_CS_NONE_ONLY BIT(0)/* CMD_SYNC CS field supports CS_NONE only */ +u32 quirks;
Please can you use the existing smmu->options field instead of adding another place to track quirks? Or do you need this only for some of the queues for a given SMMU device?
Thanks,
Will
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Hi Will,
Quoted 43 lines · Will Deacon
Quoted 42 lines · Nicolin Chen
The CMDQV extension in NVIDIA Tegra241 SoC only supports
CS_NONEin the CS field ofCMD_SYNC. Add a quirk flag to accommodate that.Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Nicolin Chen <[email protected]>--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 +++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-)drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (q->quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + !(cmdq->q.quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ))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 +0
-0@@ -543,6 +543,9 @@ struct arm_smmu_queue {
Quoted 9 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h struct arm_smmu_queue { · line 548
Quoted 5 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3
-0u32 __iomem *prod_reg;u32 __iomem *cons_reg; + +#define CMDQ_QUIRK_SYNC_CS_NONE_ONLY BIT(0)/* CMD_SYNC CS field supports CS_NONE only */ +u32 quirks;Please can you use the existing
smmu->optionsfield instead of adding another place to track quirks? Or do you need this only for some of the queues for a given SMMU device?
VCMDQs are extension of a regular SMMU (with its own CMDQ). So, SMMU CMDQ still supports SIG_IRQ for the CS field, while VCMDQs could only support SIG_NONE. In another word, this quirk is not per SMMU but per Queue.
I can highlight this in the commit message, if that would make it clear.
Thanks
Nicolin
Will Deacon
maintainerRe: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 56 lines · Nicolin Chen
Hi Will,
Quoted 43 lines · Will Deacon
Quoted 42 lines · Nicolin Chen
The CMDQV extension in NVIDIA Tegra241 SoC only supports
CS_NONEin the CS field ofCMD_SYNC. Add a quirk flag to accommodate that.Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Nicolin Chen <[email protected]>--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 +++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-)drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (q->quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + !(cmdq->q.quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ))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 +0
-0@@ -543,6 +543,9 @@ struct arm_smmu_queue {Quoted 9 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h struct arm_smmu_queue { · line 548
Quoted 5 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3
-0u32 __iomem *prod_reg;u32 __iomem *cons_reg; + +#define CMDQ_QUIRK_SYNC_CS_NONE_ONLY BIT(0)/* CMD_SYNC CS field supports CS_NONE only */ +u32 quirks;Please can you use the existing
smmu->optionsfield instead of adding another place to track quirks? Or do you need this only for some of the queues for a given SMMU device?
Quoted 7 lines
VCMDQs are extension of a regular SMMU (with its own CMDQ). So, SMMU CMDQ still supports
SIG_IRQfor the CS field, while VCMDQs could only supportSIG_NONE. In another word, this quirk is not per SMMU but per Queue.I can highlight this in the commit message, if that would make it clear.
I think we could still use smmu->options and have something like ARM_SMMU_OPT_SECONDARY_CMDQ_CS_NONE_ONLY which could be applied when the queue is != arm_smmu_get_cmdq(smmu).
Will
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 62 lines · Will Deacon
Quoted 61 lines · Nicolin Chen
Hi Will,
Quoted 43 lines · Will Deacon
Quoted 42 lines · Nicolin Chen
The CMDQV extension in NVIDIA Tegra241 SoC only supports
CS_NONEin the CS field ofCMD_SYNC. Add a quirk flag to accommodate that.Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Nicolin Chen <[email protected]>--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 +++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-)drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (q->quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + !(cmdq->q.quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ))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 +0
-0@@ -543,6 +543,9 @@ struct arm_smmu_queue {Quoted 9 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h struct arm_smmu_queue { · line 548
Quoted 5 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3
-0u32 __iomem *prod_reg;u32 __iomem *cons_reg; + +#define CMDQ_QUIRK_SYNC_CS_NONE_ONLY BIT(0)/* CMD_SYNC CS field supports CS_NONE only */ +u32 quirks;Please can you use the existing
smmu->optionsfield instead of adding another place to track quirks? Or do you need this only for some of the queues for a given SMMU device?VCMDQs are extension of a regular SMMU (with its own CMDQ). So, SMMU CMDQ still supports
SIG_IRQfor the CS field, while VCMDQs could only supportSIG_NONE. In another word, this quirk is not per SMMU but per Queue.
Quoted 6 lines
Quoted 2 lines
I can highlight this in the commit message, if that would make it clear.
I think we could still use
smmu->optionsand have something likeARM_SMMU_OPT_SECONDARY_CMDQ_CS_NONE_ONLYwhich could be applied when the queue is !=arm_smmu_get_cmdq(smmu).
A queue can be cmdq, ecmdq, vcmdq. Only VCMDQ has such a quirk. So arm_smmu_get_cmdq(smmu) is unlikely going to work if we add ECMDQ later. Also, ARM_SMMU_OPT_SECONDARY_CMDQ_CS_NONE_ONLY is very ambiguous IMHO. What we need is to check clearly if VCMDQ is being used, so that leaves us an alternative:
--------------------------------------------------------------
enum arm_smmu_cmdq_type {
ARM_SMMU_CMDQ,
ARM_SMMU_ECMDQ,
TEGRA241_VCMDQ,
};@@ -543,6 +543,9 @@ struct arm_smmu_queue {
u32 __iomem *prod_reg;
u32 __iomem *cons_reg;
+
+ enum arm_smmu_queue_type type;
};
struct arm_smmu_queue_poll {
@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,
FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH) | FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB);
+ if (cmdq->type == TEGRA241_VCMDQ) {
+ cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_NONE);
+ return;
+ }
+
if (!(smmu->options & ARM_SMMU_OPT_MSIPOLL)) {
cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
return;@@ -690,7 +695,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 &&
+ cmdq->type != TEGRA241_VCMDQ) {
return __arm_smmu_cmdq_poll_until_msi(smmu, cmdq, llq);
--------------------------------------------------------------
Would you prefer this one? I feel CMDQ_QUIRK_SYNC_CS_NONE_ONLY is more general looking though..
Thanks
Nicolin
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 23 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-2@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (cmdq->type ==TEGRA241_VCMDQ ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + cmdq->type !=TEGRA241_VCMDQ ) {return __arm_smmu_cmdq_poll_until_msi (smmu, cmdq, llq); --------------------------------------------------------------
Quoted 2 lines
Would you prefer this one? I feel
CMDQ_QUIRK_SYNC_CS_NONE_ONLYis more general looking though..
And we would need some additional lines of comments for the two pieces above, explaining why TEGRA241_VCMDQ type needs the first one while bypasses the second one. Again, it feels even worse :(
Thanks
Nicolin
Will Deacon
maintainerRe: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 22 lines · Nicolin Chen
Quoted 21 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (cmdq->type ==TEGRA241_VCMDQ ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + cmdq->type !=TEGRA241_VCMDQ ) {return __arm_smmu_cmdq_poll_until_msi (smmu, cmdq, llq);
Quoted 8 lines
Quoted 4 lines
(quoted diff) +0
-1--------------------------------------------------------------Would you prefer this one? I feel
CMDQ_QUIRK_SYNC_CS_NONE_ONLYis more general looking though..And we would need some additional lines of comments for the two pieces above, explaining why
TEGRA241_VCMDQtype needs the first one while bypasses the second one. Again, it feels even worse :(
I hacked the code around a bit this afternoon. Please can you see if:
https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/log/?h=for-nicolin/grace-vcmdq-wip
does roughly what you need?
Will
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Hi Will,
Quoted 32 lines · Will Deacon
Quoted 22 lines · Nicolin Chen
Quoted 21 lines · Nicolin Chen
(quoted diff) +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu, FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH) | FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB); + if (cmdq->type == TEGRA241_VCMDQ) { + cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_NONE); + return; + } + if (!(smmu->options & ARM_SMMU_OPT_MSIPOLL)) { cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV); return;@@ -690,7 +695,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 && + cmdq->type != TEGRA241_VCMDQ) { return __arm_smmu_cmdq_poll_until_msi(smmu, cmdq, llq);Quoted 8 lines
Quoted 4 lines
(quoted diff) +0
-1--------------------------------------------------------------Would you prefer this one? I feel
CMDQ_QUIRK_SYNC_CS_NONE_ONLYis more general looking though..And we would need some additional lines of comments for the two pieces above, explaining why
TEGRA241_VCMDQtype needs the first one while bypasses the second one. Again, it feels even worse :(
Quoted 5 lines
I hacked the code around a bit this afternoon. Please can you see if:
https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/log/?h=for-nicolin/grace-vcmdq-wip
does roughly what you need?
I appreciate the patch. Yet, we cannot use IORT's model field. This would need to go through IORT documentation, for A. And B, we had a very long discussion with ARM (Robin was there) years ago, and concluded that this CMDQV would not be a model in IORT but a DSDT node as an extension. So, this is firm...
With that, we cannot avoid an unconditional hard-coding tegra function call even if we switch to an impl design:
+static int acpi_smmu_impl_init(u32 model, struct arm_smmu_device *smmu) +{
+ /*
+ * unconditional go through ACPI table to detect if there is a tegra241
+ * implementation that extends SMMU with a CMDQV. The probe() will fill
+ * the smmu->impl pointer upon success. Otherwise, fall back to regular
+ * SMMU CMDQ.
+ */
+ tegra241_impl_acpi_probe(smmu);
+ return 0;
+}
As for arm_smmu_cmdq_needs_busy_polling, it doesn't really look very optimal to me. But if you insist on having an smmu option, we still have to take in the PATCH-3 in this series, enforcing an arm_smmu_cmdq_build_sync_cmd() call in the IRQ handler too. So, it would eventually look like [attachment].
Thanks!
Nicolin
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +21 -7
@@ -352,15 +352,26 @@ arm_smmu_get_cmdq(struct arm_smmu_device *smmu, u8 opcode)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_SECONDARY_CMDQ_CS_NONE_ONLY ; +} +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; + cmd[1 ] =0 ; cmd[0 ] =FIELD_PREP (CMDQ_0_OP ,CMDQ_OP_CMD_SYNC ) |FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); -if (q->quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY ) { +if (arm_smmu_cmdq_needs_busy_polling (smmu, cmdq)) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE );return ; }
@@ -380,7 +391,7 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu, }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" ,
@@ -388,6 +399,7 @@ 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 ];
@@ -426,14 +438,14 @@ void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,dev_err (smmu->dev,"\t0x%016llx\n" , (unsigned long long )cmd[i]);/* Convert the erroneous command into a CMD_SYNC */ -arm_smmu_cmdq_build_sync_cmd (cmd, smmu, q, cons); +arm_smmu_cmdq_build_sync_cmd (cmd, smmu, cmdq, cons);queue_write (Q_ENT (q, cons), cmd, q->ent_dwords); }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); }/*
@@ -711,7 +723,7 @@ static int arm_smmu_cmdq_poll_until_sync(struct arm_smmu_device *smmu, struct arm_smmu_ll_queue *llq) {if (smmu->options &ARM_SMMU_OPT_MSIPOLL && - !(cmdq->q.quirks &CMDQ_QUIRK_SYNC_CS_NONE_ONLY )) + !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);
@@ -797,7 +809,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 );/*
@@ -3985,6 +3997,8 @@ static int arm_smmu_device_acpi_probe(struct platform_device *pdev, smmu->features |=ARM_SMMU_FEAT_COHERENCY ; smmu->tegra241_cmdqv =tegra241_cmdqv_acpi_probe (smmu, node); +if (smmu->tegra241_cmdqv) + smmu->options |=ARM_SMMU_OPT_SECONDARY_CMDQ_CS_NONE_ONLY ;return 0 ; }
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +6 -5
@@ -654,10 +654,11 @@ struct arm_smmu_device {#define ARM_SMMU_FEAT_ATTR_TYPES_OVR (1 << 20)u32 features; -#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0) -#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_SKIP_PREFETCH (1 << 0) +#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_SECONDARY_CMDQ_CS_NONE_ONLY (1 << 4)u32 options;struct arm_smmu_cmdq cmdq;
@@ -805,7 +806,7 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid, unsigned long iova, size_t size);void __arm_smmu_cmdq_skip_err (struct arm_smmu_device *smmu, -struct arm_smmu_queue *q); +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,
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +1 -1
@@ -266,7 +266,7 @@ static void tegra241_vintf0_handle_error(struct tegra241_vintf *vintf)u32 gerror =readl_relaxed (REG_VCMDQ_PAGE0 (vcmdq,GERROR ));__arm_smmu_cmdq_skip_err (vintf->cmdqv->smmu, - &vcmdq->cmdq.q); + &vcmdq->cmdq);writel (gerror,REG_VCMDQ_PAGE0 (vcmdq,GERRORN )); map &= ~BIT_ULL (lidx); }
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 62 lines · Nicolin Chen
Hi Will,
Quoted 32 lines · Will Deacon
Quoted 22 lines · Nicolin Chen
Quoted 21 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (cmdq->type ==TEGRA241_VCMDQ ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + cmdq->type !=TEGRA241_VCMDQ ) {return __arm_smmu_cmdq_poll_until_msi (smmu, cmdq, llq);Quoted 8 lines
Quoted 4 lines
(quoted diff) +0
-1--------------------------------------------------------------Would you prefer this one? I feel
CMDQ_QUIRK_SYNC_CS_NONE_ONLYis more general looking though..And we would need some additional lines of comments for the two pieces above, explaining why
TEGRA241_VCMDQtype needs the first one while bypasses the second one. Again, it feels even worse :(Quoted 5 lines
I hacked the code around a bit this afternoon. Please can you see if:
https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/log/?h=for-nicolin/grace-vcmdq-wip
does roughly what you need?
I appreciate the patch. Yet, we cannot use IORT's model field. This would need to go through IORT documentation, for A. And B, we had a very long discussion with ARM (Robin was there) years ago, and concluded that this CMDQV would not be a model in IORT but a DSDT node as an extension. So, this is firm...
With that, we cannot avoid an unconditional hard-coding tegra function call even if we switch to an impl design:
(quoted diff) +11
-0+static int acpi_smmu_impl_init(u32 model, struct arm_smmu_device *smmu) +{ + /* + * unconditional go through ACPI table to detect if there is a tegra241 + * implementation that extends SMMU with a CMDQV. The probe() will fill + * the smmu->impl pointer upon success. Otherwise, fall back to regular + * SMMU CMDQ. + */ + tegra241_impl_acpi_probe(smmu); + return 0; +}
Quoted 5 lines
As for
arm_smmu_cmdq_needs_busy_polling, it doesn't really look very optimal to me. But if you insist on having an smmu option, we still have to take in the PATCH-3 in this series, enforcing anarm_smmu_cmdq_build_sync_cmd()call in the IRQ handler too. So, it would eventually look like [attachment].
Please ignore the attachment. Since we are adding arm_smmu_impl, I figure that we could add an arm_smmu_cmdq_impl too. There's an another small feature that I didn't implement in this v9, while being able to benefit from a cmdq impl now.
The impl can also hold a boolean busy_polling, so we won't need a global smmu option.
I will send a new version asap, though I am not sure if we can still make it to this cycle that we hoped for :-/
Thanks
Nicolin
Will Deacon
maintainerRe: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 72 lines · Nicolin Chen
Quoted 60 lines · Nicolin Chen
Quoted 32 lines · Will Deacon
Quoted 22 lines · Nicolin Chen
Quoted 21 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (cmdq->type ==TEGRA241_VCMDQ ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + cmdq->type !=TEGRA241_VCMDQ ) {return __arm_smmu_cmdq_poll_until_msi (smmu, cmdq, llq);Quoted 8 lines
Quoted 4 lines
(quoted diff) +0
-1--------------------------------------------------------------Would you prefer this one? I feel
CMDQ_QUIRK_SYNC_CS_NONE_ONLYis more general looking though..And we would need some additional lines of comments for the two pieces above, explaining why
TEGRA241_VCMDQtype needs the first one while bypasses the second one. Again, it feels even worse :(Quoted 5 lines
I hacked the code around a bit this afternoon. Please can you see if:
https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/log/?h=for-nicolin/grace-vcmdq-wip
does roughly what you need?
I appreciate the patch. Yet, we cannot use IORT's model field. This would need to go through IORT documentation, for A. And B, we had a very long discussion with ARM (Robin was there) years ago, and concluded that this CMDQV would not be a model in IORT but a DSDT node as an extension. So, this is firm...
With that, we cannot avoid an unconditional hard-coding tegra function call even if we switch to an impl design:
(quoted diff) +11
-0+static int acpi_smmu_impl_init(u32 model, struct arm_smmu_device *smmu) +{ + /* + * unconditional go through ACPI table to detect if there is a tegra241 + * implementation that extends SMMU with a CMDQV. The probe() will fill + * the smmu->impl pointer upon success. Otherwise, fall back to regular + * SMMU CMDQ. + */ + tegra241_impl_acpi_probe(smmu); + return 0; +}Quoted 5 lines
As for
arm_smmu_cmdq_needs_busy_polling, it doesn't really look very optimal to me. But if you insist on having an smmu option, we still have to take in the PATCH-3 in this series, enforcing anarm_smmu_cmdq_build_sync_cmd()call in the IRQ handler too. So, it would eventually look like [attachment].Please ignore the attachment. Since we are adding
arm_smmu_impl, I figure that we could add anarm_smmu_cmdq_impltoo. There's an another small feature that I didn't implement in this v9, while being able to benefit from a cmdq impl now.
Quoted 2 lines
The impl can also hold a boolean
busy_polling, so we won't need a global smmu option.
So /that/ might be overkill. Architectural queues can use polling, so I don't mind having that option in the driver and it should keep the number of impl hooks to a minimum.
Quoted 2 lines
I will send a new version asap, though I am not sure if we can still make it to this cycle that we hoped for :-/
I'm in fixes-only mode at this point, especially since we've not had a linux-next for a while.
Will
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 11 lines · Will Deacon
Quoted 11 lines
Quoted 5 lines
As for
arm_smmu_cmdq_needs_busy_polling, it doesn't really look very optimal to me. But if you insist on having an smmu option, we still have to take in the PATCH-3 in this series, enforcing anarm_smmu_cmdq_build_sync_cmd()call in the IRQ handler too. So, it would eventually look like [attachment].Please ignore the attachment. Since we are adding
arm_smmu_impl, I figure that we could add anarm_smmu_cmdq_impltoo. There's an another small feature that I didn't implement in this v9, while being able to benefit from a cmdq impl now.
Quoted 6 lines
Quoted 2 lines
The impl can also hold a boolean
busy_polling, so we won't need a global smmu option.So /that/ might be overkill. Architectural queues can use polling, so I don't mind having that option in the driver and it should keep the number of impl hooks to a minimum.
OK. Let's make an option as you suggested.
Quoted 5 lines
Quoted 2 lines
I will send a new version asap, though I am not sure if we can still make it to this cycle that we hoped for :-/
I'm in fixes-only mode at this point, especially since we've not had a linux-next for a while.
Sad that we missed again. Thanks for letting me know that..
Nicolin
Will Deacon
maintainerRe: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
In reply to Nicolin ChenQuoted 37 lines · Nicolin Chen
Quoted 36 lines · Will Deacon
Quoted 22 lines · Nicolin Chen
Quoted 21 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +7
-1@@ -345,6 +345,11 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,FIELD_PREP (CMDQ_SYNC_0_MSH ,ARM_SMMU_SH_ISH ) |FIELD_PREP (CMDQ_SYNC_0_MSIATTR ,ARM_SMMU_MEMATTR_OIWB ); +if (cmdq->type ==TEGRA241_VCMDQ ) { + cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_NONE ); +return ; + } +if (!(smmu->options &ARM_SMMU_OPT_MSIPOLL )) { cmd[0 ] |=FIELD_PREP (CMDQ_SYNC_0_CS ,CMDQ_SYNC_0_CS_SEV );return ;@@ -690,7 +695,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 && + cmdq->type !=TEGRA241_VCMDQ ) {return __arm_smmu_cmdq_poll_until_msi (smmu, cmdq, llq);Quoted 8 lines
Quoted 4 lines
(quoted diff) +0
-1--------------------------------------------------------------Would you prefer this one? I feel
CMDQ_QUIRK_SYNC_CS_NONE_ONLYis more general looking though..And we would need some additional lines of comments for the two pieces above, explaining why
TEGRA241_VCMDQtype needs the first one while bypasses the second one. Again, it feels even worse :(I hacked the code around a bit this afternoon. Please can you see if:
https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/log/?h=for-nicolin/grace-vcmdq-wip
Quoted 7 lines
Quoted 1 line
does roughly what you need?
I appreciate the patch. Yet, we cannot use IORT's model field. This would need to go through IORT documentation, for A. And B, we had a very long discussion with ARM (Robin was there) years ago, and concluded that this CMDQV would not be a model in IORT but a DSDT node as an extension. So, this is firm...
Seems like a bad outcome given that you've clearly modified the IP, but whatever. We can parse the DSDT when we detect whatever the model actually is; I don't think that's a huge issue.
Review
Quoted 12 lines
With that, we cannot avoid an unconditional hard-coding tegra function call even if we switch to an impl design:
(quoted diff) +9
-0+static int acpi_smmu_impl_init(u32 model, struct arm_smmu_device *smmu) +{ + /* + * unconditional go through ACPI table to detect if there is a tegra241 + * implementation that extends SMMU with a CMDQV. The probe() will fill + * the smmu->impl pointer upon success. Otherwise, fall back to regular + * SMMU CMDQ. + */ + tegra241_impl_acpi_probe(smmu);
In-line the minimal DSDT parsing to figure out if we're on a Tegra part. If it's that bad, put it in a static inline in arm-smmu-v3.h.
Quoted 5 lines
(quoted diff) +2
-0+ return 0; +}As for
arm_smmu_cmdq_needs_busy_polling, it doesn't really look very optimal to me.
"optimal" in what sense? In that you don't like how it smells, or that it's measurably bad?
Quoted 3 lines
But if you insist on having an smmu option, we still have to take in the PATCH-3 in this series, enforcing an
arm_smmu_cmdq_build_sync_cmd()call in the IRQ handler too. So, it would eventually look like [attachment].
With my hacks, I think you can just call arm_smmu_cmdq_build_sync_cmd() from the irqhandler and it will work.
Will
Will Deacon
maintainerRe: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 7 lines · Will Deacon
Quoted 3 lines · Nicolin Chen
But if you insist on having an smmu option, we still have to take in the PATCH-3 in this series, enforcing an
arm_smmu_cmdq_build_sync_cmd()call in the IRQ handler too. So, it would eventually look like [attachment].With my hacks, I think you can just call
arm_smmu_cmdq_build_sync_cmd()from the irqhandler and it will work.
Hmm, actually, that will mean we end up using MSIs for the error case on hardware which supports it, which is a strange change in behaviour.
What does your hardware do if it sees SIG_SEV in a CMD_SYNC? Is it just a case of failing to generate the event on completion, or does it treat it as an invalid opcode?
Will
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Quoted 9 lines · Will Deacon
External email: Use caution opening links or attachments
Quoted 5 lines · Will Deacon
Quoted 3 lines · Nicolin Chen
But if you insist on having an smmu option, we still have to take in the PATCH-3 in this series, enforcing an
arm_smmu_cmdq_build_sync_cmd()call in the IRQ handler too. So, it would eventually look like [attachment].
Quoted 5 lines
Quoted 2 lines
With my hacks, I think you can just call
arm_smmu_cmdq_build_sync_cmd()from the irqhandler and it will work.Hmm, actually, that will mean we end up using MSIs for the error case on hardware which supports it, which is a strange change in behaviour.
Yes. I highlighted the smae in the commit log of PATCH-3:
iommu/arm-smmu-v3: Enforce arm_smmu_cmdq_build_sync_cmd
Do you foresee some potential risk of doing that?
Quoted 3 lines
What does your hardware do if it sees
SIG_SEVin aCMD_SYNC? Is it just a case of failing to generate the event on completion, or does it treat it as an invalid opcode?
That would be an invalid opcode.
Thanks
Nicolin
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
In reply to Will DeaconQuoted 15 lines · Will Deacon
Review
Quoted 12 lines
With that, we cannot avoid an unconditional hard-coding tegra function call even if we switch to an impl design:
(quoted diff) +9
-0+static int acpi_smmu_impl_init(u32 model, struct arm_smmu_device *smmu) +{ + /* + * unconditional go through ACPI table to detect if there is a tegra241 + * implementation that extends SMMU with a CMDQV. The probe() will fill + * the smmu->impl pointer upon success. Otherwise, fall back to regular + * SMMU CMDQ. + */ + tegra241_impl_acpi_probe(smmu);In-line the minimal DSDT parsing to figure out if we're on a Tegra part. If it's that bad, put it in a static inline in
arm-smmu-v3.h.
OK. How about the following?
/* arm-smmu-v3.h */
static inline void arm_smmu_impl_acpi_dsdt_probe(struct arm_smmu_device *smmu,
struct acpi_iort_node *node)
{
tegra241_cmdqv_acpi_dsdt_probe(smmu, node);
}/* arm-smmu-v3.c */
static int arm_smmu_impl_acpi_probe(struct arm_smmu_device *smmu,
struct acpi_iort_node *node)
{
/*
* DSDT might holds some SMMU extension, so we have no option but to go
* through ACPI tables unconditionally. This probe function should fill
* the smmu->impl pointer upon success. Otherwise, just carry on with a
* standard SMMU.
*/
arm_smmu_impl_acpi_dsdt_probe(smmu, node);
return 0;
}Quoted 8 lines
Quoted 5 lines
(quoted diff) +2
-0+ return 0; +}As for
arm_smmu_cmdq_needs_busy_polling, it doesn't really look very optimal to me."optimal" in what sense? In that you don't like how it smells, or that it's measurably bad?
It would potentially not work if someday an implementation has two secondary queues? I got your point of making it an option just like the existing ARM_SMMU_OPT_MSIPOLL though..
Thanks
Nicolin
Re: [PATCH v9 4/6] iommu/arm-smmu-v3: Add CS_NONE quirk for CONFIG_TEGRA241_CMDQV
Hi Will,
Quoted 29 lines · Nicolin Chen
Quoted 15 lines · Will Deacon
Review
Quoted 12 lines
With that, we cannot avoid an unconditional hard-coding tegra function call even if we switch to an impl design:
(quoted diff) +9
-0+static int acpi_smmu_impl_init(u32 model, struct arm_smmu_device *smmu) +{ + /* + * unconditional go through ACPI table to detect if there is a tegra241 + * implementation that extends SMMU with a CMDQV. The probe() will fill + * the smmu->impl pointer upon success. Otherwise, fall back to regular + * SMMU CMDQ. + */ + tegra241_impl_acpi_probe(smmu);In-line the minimal DSDT parsing to figure out if we're on a Tegra part. If it's that bad, put it in a static inline in
arm-smmu-v3.h.OK. How about the following?
/*
arm-smmu-v3.h*/
static inline void arm_smmu_impl_acpi_dsdt_probe(structarm_smmu_device*smmu,
structacpi_iort_node*node){ tegra241_cmdqv_acpi_dsdt_probe(smmu, node); }/*
arm-smmu-v3.c*/
static int arm_smmu_impl_acpi_probe(structarm_smmu_device*smmu,
structacpi_iort_node*node)
Quoted 11 lines
{
/*
* DSDT might holds some SMMU extension, so we have no option but to go
* through ACPI tables unconditionally. This probe function should fill
* the smmu->impl pointer upon success. Otherwise, just carry on with a
* standard SMMU.
*/
arm_smmu_impl_acpi_dsdt_probe(smmu, node);
return 0;
}I have reworked my series and it looks like:
-------------------------------------------------------------
@ -627,9 +630,35 @@ struct arm_smmu_strtab_cfg {
u32 strtab_base_cfg;};
+struct arm_smmu_impl {
+ 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,
+ u8 opcode);
+};
+
+#ifdef CONFIG_TEGRA241_CMDQV
+struct arm_smmu_device * +tegra241_cmdqv_acpi_dsdt_probe(struct arm_smmu_device *smmu,
+ struct acpi_iort_node *node);
+#endif
+
+static inline struct arm_smmu_device * +arm_smmu_impl_acpi_dsdt_probe(struct arm_smmu_device *smmu,
+ struct acpi_iort_node *node)
+{
+#ifdef CONFIG_TEGRA241_CMDQV
+ smmu = tegra241_cmdqv_acpi_dsdt_probe(smmu, node);
+#endif
+ return smmu;
+}
+
/* An SMMUv3 instance */
struct arm_smmu_device {
struct device *dev;
+ /* An SMMUv3 implementation */
+ const struct arm_smmu_impl *impl;
+
void __iomem *base;
void __iomem *page1;-------------------------------------------------------------
One thing that I want to confirm is about the smmu pointer. I implemented in the way that SMMUv2 driver does, i.e. the passed-in SMMU pointer gets devm_realloc() to &cmdev->smmu. Is it something you would prefer?
Thanks
Nicolin
PATCH v9 5/6 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).
However, it is very important for this in-kernel support to get merged and installed to VMs running on Grace-powered servers as soon as possible. So, later those servers would only need to upgrade their host kernels for the user-space support.
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 | 52 +- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 50 ++ .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 842 ++++++++++++++++++ 6 files changed, 945 insertions(+), 12 deletions(-) create mode 100644 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
MAINTAINERS +1 -0
@@ -22078,6 +22078,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
@@ -423,6 +423,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,6 +2,7 @@ obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o arm_smmu_v3-objs-y += arm-smmu-v3.o arm_smmu_v3-objs-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o +arm_smmu_v3-objs-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o arm_smmu_v3-objs := $(arm_smmu_v3-objs-y) obj-$(CONFIG_ARM_SMMU_V3_KUNIT_TEST) += arm-smmu-v3-test.o
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +40 -12
123 lines not on this page · raw message
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +50 -0
66 lines not on this page · raw message
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c new file +842 -0
842 lines not on this page · raw message
Signature · 1 line
2.43.0
Will Deacon
maintainerRe: [PATCH v9 5/6] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
Quoted 26 lines · Nicolin Chen
From: 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_NONEin the CS field ofCMD_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).
Quoted 4 lines
However, it is very important for this in-kernel support to get merged and installed to VMs running on Grace-powered servers as soon as possible. So, later those servers would only need to upgrade their host kernels for the user-space support.
^^^ This is a weird paragraph to put in the commit message.
Quoted 68 lines
As the initial version, the CMDQV driver only supports ACPI configurations.
Signed-off-by Nate Watterson <[email protected]>Reviewed-by Jason Gunthorpe <[email protected]>Co-developed-by Nicolin Chen <[email protected]>Signed-off-by Nicolin Chen <[email protected]>--- MAINTAINERS | 1 + drivers/iommu/Kconfig | 11 + drivers/iommu/arm/arm-smmu-v3/Makefile | 1 + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 52 +- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 50 ++ .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 842 ++++++++++++++++++ 6 files changed, 945 insertions(+), 12 deletions(-) create mode 100644 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.cMAINTAINERS +1
-0@@ -22078,6 +22078,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@@ -423,6 +423,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_IOMMUdrivers/iommu/arm/arm-smmu-v3/Makefile +1
-0@@ -2,6 +2,7 @@ obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o arm_smmu_v3-objs-y += arm-smmu-v3.o arm_smmu_v3-objs-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o +arm_smmu_v3-objs-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o arm_smmu_v3-objs := $(arm_smmu_v3-objs-y) obj-$(CONFIG_ARM_SMMU_V3_KUNIT_TEST) += arm-smmu-v3-test.odrivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +0
-0
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) · line 340
Quoted 7 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +3
-0@@ -334,6 +334,9 @@ 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) { +if (arm_smmu_has_tegra241_cmdqv (smmu)) +return tegra241_cmdqv_get_cmdq (smmu); +return &smmu->cmdq;
Hardcoding all these tegra-specific checks in the core driver is pretty horrible :/
Instead, please can we do something similar to the SMMUv2 driver? That is, tweak the probe routine to call something akin to the arm_smmu_impl_init() function, which looks at the 'model' field pulled out of the IORT and can then dispatch directly to a tegra-specific init function (see, e.g. nvidia_smmu_impl_init() for SMMUv2).
From there, you can both install function pointers into the 'arm_smmu_device' structure which can be used instead of having the the 'if (tegra)' checks in the main driver and you can also re-allocate the structu to live inside a private structure instead of having the backpointer.
Maybe those cmdq function pointers would be happy for other extensions too (e.g. the ECMDQ stuff at [1]).
Will
Re: [PATCH v9 5/6] iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV
Hi Will,
Quoted 27 lines · Will Deacon
Quoted 26 lines · Nicolin Chen
From: 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_NONEin the CS field ofCMD_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).
Quoted 6 lines
Quoted 4 lines
However, it is very important for this in-kernel support to get merged and installed to VMs running on Grace-powered servers as soon as possible. So, later those servers would only need to upgrade their host kernels for the user-space support.
^^^ This is a weird paragraph to put in the commit message.
Ah, I could drop that if you prefer. We already highlight it in the cover-letter anyway :)
Quoted 78 lines
Quoted 67 lines
As the initial version, the CMDQV driver only supports ACPI configurations.
Signed-off-by Nate Watterson <[email protected]>Reviewed-by Jason Gunthorpe <[email protected]>Co-developed-by Nicolin Chen <[email protected]>Signed-off-by Nicolin Chen <[email protected]>--- MAINTAINERS | 1 + drivers/iommu/Kconfig | 11 + drivers/iommu/arm/arm-smmu-v3/Makefile | 1 + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 52 +- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 50 ++ .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 842 ++++++++++++++++++ 6 files changed, 945 insertions(+), 12 deletions(-) create mode 100644 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.cMAINTAINERS +1
-0@@ -22078,6 +22078,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@@ -423,6 +423,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_IOMMUdrivers/iommu/arm/arm-smmu-v3/Makefile +1
-0@@ -2,6 +2,7 @@ obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o arm_smmu_v3-objs-y += arm-smmu-v3.o arm_smmu_v3-objs-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o +arm_smmu_v3-objs-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o arm_smmu_v3-objs := $(arm_smmu_v3-objs-y) obj-$(CONFIG_ARM_SMMU_V3_KUNIT_TEST) += arm-smmu-v3-test.odrivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +0
-0drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) · line 340
Quoted 7 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +3
-0@@ -334,6 +334,9 @@ 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) { +if (arm_smmu_has_tegra241_cmdqv (smmu)) +return tegra241_cmdqv_get_cmdq (smmu); +return &smmu->cmdq;Hardcoding all these tegra-specific checks in the core driver is pretty horrible :/
Quoted 5 lines
Instead, please can we do something similar to the SMMUv2 driver? That is, tweak the probe routine to call something akin to the
arm_smmu_impl_init()function, which looks at the 'model' field pulled out of the IORT and can then dispatch directly to a tegra-specific init function (see, e.g.nvidia_smmu_impl_init()for SMMUv2).
Unfortunately, this isn't like the SMMUv2: the whole CMDQV thing is not really a 'model', as ARM suggested us from the beginning not to use the 'model' field but to treat it as an extension via DSDT v.s. IORT. So, there is unlikely a way to avoid some level of hardcoding to check "cmdqv" in the SMMUv3 driver, since CMDQV HW info sits outside the IORT, while still requiring everything in the SMMUv3.
FWIW, we had the following piece in our earlier version (nearly three years ago), which looked equally "horrible" IMHO:
struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu) {
+ /*
+ * Nvidia implementation supports ACPI only, so calling its init()
+ * unconditionally to walk through ACPI tables to probe the device.
+ * It will keep the smmu pointer intact, if it fails.
+ */
+ smmu = nvidia_smmu_v3_impl_init(smmu);
And the current extension design is a preferable way, suggested by Jason at that time during our internal reviews against this impl design above. I am leaving some of his remarks, just FYI:
-------------------------------------------------------------------
Do not create a huge complicated artifice that could have been done with a few simple ifs. An ill defined abstraction is not more maintainable just because it has function pointers.
-------------------------------------------------------------------
Quoted 6 lines
From there, you can both install function pointers into the '
arm_smmu_device' structure which can be used instead of having the the 'if (tegra)' checks in the main driver and you can also re-allocate the structu to live inside a private structure instead of having the backpointer.
Quoted 6 lines
Maybe those cmdq function pointers would be happy for other extensions too (e.g. the ECMDQ stuff at [1]).
Will
We have studied the ECMDQ patches too. It simply needs something similar in the arm_smmu_get_cmdq(), as we did in our design.
Worth mentioning that the whole preempt_disable thing is unlikely required any more after the patch in this series:
[PATCH v9 2/6] iommu/arm-smmu-v3: Issue a batch of commands to the same cmdq
Thanks
Nicolin
PATCH v9 6/6 iommu/tegra241-cmdqv: Limit CMDs for 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, add a new helper to scan the input cmd to make sure it is supported when selecting a queue, though this assumes that SMMUv3 driver will only add the same type of commands into an arm_smmu_cmdq_batch as it does today.
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 | 31 +++++++++++----- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 5 +-- .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 36 ++++++++++++++++++- 3 files changed, 60 insertions(+), 12 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +22 -9
@@ -332,10 +332,22 @@ 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,u8 opcode) { +/* +* TEGRA241 CMDQV has two modes to execute commands: host and guest. +* The host mode supports all the opcodes, while the guest mode only +* supports a few invalidation ones (check tegra241_vintf_support_cmd) +* and also a CMD_SYNC added by arm_smmu_cmdq_issue_cmdlist(..., true). +* +* Here pass in the representing opcode for either a single command or +* an arm_smmu_cmdq_batch, assuming that this SMMU driver will only add +* same type of commands into a batch as it does today or it will only +* mix supported invalidation commands in a batch. +*/ if (arm_smmu_has_tegra241_cmdqv (smmu)) -return tegra241_cmdqv_get_cmdq (smmu); +return tegra241_cmdqv_get_cmdq (smmu, opcode);return &smmu->cmdq; }
@@ -871,7 +883,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->opcode), cmd,1 , sync); } static int arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
@@ -887,10 +899,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, +u8 opcode) { cmds->num =0 ; - cmds->cmdq =arm_smmu_get_cmdq (smmu); + cmds->cmdq =arm_smmu_get_cmdq (smmu, opcode); } static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,
@@ -1169,7 +1182,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.opcode);for (i =0 ; i < master->num_streams; i++) { cmd.cfgi.sid = master->streams[i].id;arm_smmu_cmdq_batch_add (smmu, &cmds, &cmd);
@@ -2014,7 +2027,7 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master)arm_smmu_atc_inv_to_cmd (IOMMU_NO_PASID ,0 ,0 , &cmd); -arm_smmu_cmdq_batch_init (master->smmu, &cmds); +arm_smmu_cmdq_batch_init (master->smmu, &cmds, cmd.opcode);for (i =0 ; i < master->num_streams; i++) { cmd.atc.sid = master->streams[i].id;arm_smmu_cmdq_batch_add (master->smmu, &cmds, &cmd);
@@ -2054,7 +2067,7 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid,arm_smmu_atc_inv_to_cmd (ssid, iova, size, &cmd); -arm_smmu_cmdq_batch_init (smmu_domain->smmu, &cmds); +arm_smmu_cmdq_batch_init (smmu_domain->smmu, &cmds,CMDQ_OP_ATC_INV );spin_lock_irqsave (&smmu_domain->devices_lock, flags);list_for_each_entry (master, &smmu_domain->devices, domain_head) {
@@ -2131,7 +2144,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->opcode);while (iova < end) {if (smmu->features &ARM_SMMU_FEAT_RANGE_INV ) {
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3 -2
@@ -879,7 +879,8 @@ struct tegra241_cmdqv *tegra241_cmdqv_acpi_probe(struct arm_smmu_device *smmu, struct acpi_iort_node *node);void tegra241_cmdqv_device_remove (struct arm_smmu_device *smmu);int tegra241_cmdqv_device_reset (struct arm_smmu_device *smmu); -struct arm_smmu_cmdq *tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu); +struct arm_smmu_cmdq *tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu, +u8 opcode);#else /* CONFIG_TEGRA241_CMDQV */ static inline bool arm_smmu_has_tegra241_cmdqv (struct arm_smmu_device *smmu) {
@@ -903,7 +904,7 @@ static inline int tegra241_cmdqv_device_reset(struct arm_smmu_device *smmu) }static inline struct arm_smmu_cmdq * -tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu) +tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu,u8 opcode) {return NULL ; }
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +35 -1
@@ -144,6 +144,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
@@ -152,6 +153,7 @@ struct tegra241_vintf {u16 idx;bool enabled; +bool hyp_own;struct tegra241_cmdqv *cmdqv;struct tegra241_vcmdq **lvcmdqs;
@@ -290,7 +292,25 @@ static irqreturn_t tegra241_cmdqv_isr(int irq, void *devid)/* Command Queue Selecting Function */ -struct arm_smmu_cmdq *tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu) +static bool tegra241_vintf_support_cmd (struct tegra241_vintf *vintf,u8 opcode) +{ +/* Hypervisor-owned VINTF can execute any command in its VCMDQs */ +if (READ_ONCE (vintf->hyp_own)) +return true; + +/* Guest-owned VINTF must check against the list of supported CMDs */ +switch (opcode) { +case CMDQ_OP_TLBI_NH_ASID : +case CMDQ_OP_TLBI_NH_VA : +case CMDQ_OP_ATC_INV : +return true; +default : +return false; + } +} + +struct arm_smmu_cmdq *tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu, +u8 opcode) {struct tegra241_cmdqv *cmdqv = smmu->tegra241_cmdqv;struct tegra241_vintf *vintf = cmdqv->vintfs[0 ];
@@ -304,6 +324,10 @@ struct arm_smmu_cmdq *tegra241_cmdqv_get_cmdq(struct arm_smmu_device *smmu)if (!READ_ONCE (vintf->enabled))return &smmu->cmdq; +/* Unsupported CMD go for smmu->cmdq pathway */ +if (!tegra241_vintf_support_cmd (vintf, opcode)) +return &smmu->cmdq; +/* * Select a LVCMDQ to use. Here we use a temporal solution to * balance out traffic on cmdq issuing: each cmdq has its own
@@ -393,12 +417,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]) {
Signature · 1 line
2.43.0
Hi!
Quoted 7 lines
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.
Text is block-aligned without duplicated spaces. How did you do that...?
Anyway, it looks great.
Best regards,
Pavel
Signature · 1 line
People of Russia, stop Putin before his war on Ukraine escalates.
Quoted 10 lines · Pavel Machek
Hi!
Quoted 7 lines
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.
Quoted 2 lines
Text is block-aligned without duplicated spaces. How did you do that...?
By OCD? Nothing fancy :)
Thanks
Nicolin