[RFC PATCH v2 1/9] iommu/riscv: Use DC.tc.V as the device context valid bit
From: Gong Shuai
Date: Thu Oct 29 2026 - 02:13:42 EST
Previously, riscv_iommu_iodir_update() accepted only a partial device
context and used bit 0 of the translation attributes as the valid
flag. It also kept only GADE in DC.tc and dropped the other fields
needed to pass guest translation settings for nested domains.
Now that the function accepts a complete device context, take the
valid bit from DC.tc.V and copy all defined TC fields so the guest
configuration reaches the hardware.
Use the DC field macros for the remaining device context updates as
well.
Signed-off-by: Gong Shuai <gong.shuai@xxxxxxxxxxxxxxxx>
---
drivers/iommu/riscv/iommu-bits.h | 6 ++++++
drivers/iommu/riscv/iommu.c | 28 ++++++++++++----------------
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 65d1f2250011..80c32f00ee5e 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -348,6 +348,12 @@ struct riscv_iommu_dc {
#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
+/*
+ * All bits of dc.tc as defined by the spec. Bits 12-23 and 32-63
+ * are reserved for future standard use, bits 24-31 are for custom use.
+ */
+#define RISCV_IOMMU_DC_TC_DEFINED GENMASK_ULL(11, 0)
+
/* Second-stage (aka G-stage) context fields */
#define RISCV_IOMMU_DC_IOHGATP_PPN RISCV_IOMMU_ATP_PPN_FIELD
#define RISCV_IOMMU_DC_IOHGATP_GSCID GENMASK_ULL(59, 44)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index ca24d1b836d9..554361dd3159 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1132,7 +1132,6 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain,
rcu_read_unlock();
}
-#define RISCV_IOMMU_FSC_BARE 0
/*
* This function sends IOTINVAL commands as required by the RISC-V
* IOMMU specification (Section 6.3.1 and 6.3.2 in 1.0 spec version)
@@ -1243,18 +1242,14 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu,
riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
/*
- * For device context with DC_TC_PDTV = 0, translation attributes valid bit
- * is stored as DC_TC_V bit (both sharing the same location at BIT(0)).
+ * Only defined bits are writable by the driver.
*/
for (i = 0; i < fwspec->num_ids; i++) {
dc = riscv_iommu_get_dc(iommu, fwspec->ids[i]);
- tc = READ_ONCE(dc->tc);
- tc &= ~RISCV_IOMMU_DC_TC_GADE;
- tc |= new_dc->tc & RISCV_IOMMU_DC_TC_GADE;
- tc |= new_dc->ta & RISCV_IOMMU_DC_TC_V;
+ tc = new_dc->tc & RISCV_IOMMU_DC_TC_DEFINED;
WRITE_ONCE(dc->fsc, new_dc->fsc);
- WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_PC_TA_PSCID);
+ WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_DC_TA_PSCID);
WRITE_ONCE(dc->iohgatp, new_dc->iohgatp);
/* Update device context, write TC.V as the last step. */
dma_wmb();
@@ -1373,11 +1368,11 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
if (!riscv_iommu_fsc_supported(iommu, pt_info.fsc_iosatp_mode))
return -ENODEV;
- dc.fsc = FIELD_PREP(RISCV_IOMMU_PC_FSC_MODE, pt_info.fsc_iosatp_mode) |
- FIELD_PREP(RISCV_IOMMU_PC_FSC_PPN, pt_info.ppn);
+ dc.fsc = FIELD_PREP(RISCV_IOMMU_DC_FSC_MODE, pt_info.fsc_iosatp_mode) |
+ FIELD_PREP(RISCV_IOMMU_DC_FSC_PPN, pt_info.ppn);
}
- dc.ta = FIELD_PREP(RISCV_IOMMU_PC_TA_PSCID, domain->pscid) |
- RISCV_IOMMU_PC_TA_V;
+ dc.ta = FIELD_PREP(RISCV_IOMMU_DC_TA_PSCID, domain->pscid);
+ dc.tc |= RISCV_IOMMU_DC_TC_V;
if (riscv_iommu_bond_link(domain, dev))
return -ENOMEM;
@@ -1520,9 +1515,10 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
struct riscv_iommu_dc dc = {0};
- dc.fsc = RISCV_IOMMU_FSC_BARE;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = 0;
- /* Make device context invalid, translation requests will fault w/ #258 */
+ /* Make device context invalid (DC.tc.V = 0), translation requests will fault w/ #258 */
riscv_iommu_iodir_update(iommu, dev, &dc);
riscv_iommu_bond_unlink(info->domain, dev);
info->domain = NULL;
@@ -1545,8 +1541,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
struct riscv_iommu_dc dc = {0};
- dc.fsc = RISCV_IOMMU_FSC_BARE;
- dc.ta = RISCV_IOMMU_PC_TA_V;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = RISCV_IOMMU_DC_TC_V;
riscv_iommu_iodir_update(iommu, dev, &dc);
riscv_iommu_bond_unlink(info->domain, dev);
--
2.53.0