Commit f5c262b5 authored by Fangyu Yu's avatar Fangyu Yu Committed by Joerg Roedel
Browse files

iommu/riscv: Add IOTINVAL after updating DDT/PDT entries



Add riscv_iommu_iodir_iotinval() to perform required TLB and context cache
invalidations after updating DDT or PDT entries, as mandated by the RISC-V
IOMMU specification (Section 6.3.1 and 6.3.2).

Fixes: 488ffbf1 ("iommu/riscv: Paging domain support")
Signed-off-by: default avatarFangyu Yu <fangyu.yu@linux.alibaba.com>
Reviewed-by: default avatarAndrew Jones <andrew.jones@oss.qualcomm.com>
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
parent f338e773
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -996,7 +996,67 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain,
}

#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)
 * after modifying DDT or PDT entries
 */
static void riscv_iommu_iodir_iotinval(struct riscv_iommu_device *iommu,
				       bool inval_pdt, unsigned long iohgatp,
				       struct riscv_iommu_dc *dc,
				       struct riscv_iommu_pc *pc)
{
	struct riscv_iommu_command cmd;

	riscv_iommu_cmd_inval_vma(&cmd);

	if (FIELD_GET(RISCV_IOMMU_DC_IOHGATP_MODE, iohgatp) ==
	    RISCV_IOMMU_DC_IOHGATP_MODE_BARE) {
		if (inval_pdt) {
			/*
			 * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and
			 * PSCID=PC.PSCID
			 */
			riscv_iommu_cmd_inval_set_pscid(&cmd,
				FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta));
		} else {
			if (!FIELD_GET(RISCV_IOMMU_DC_TC_PDTV, dc->tc) &&
			    FIELD_GET(RISCV_IOMMU_DC_FSC_MODE, dc->fsc) !=
			    RISCV_IOMMU_DC_FSC_MODE_BARE) {
				/*
				 * DC.tc.PDTV == 0 && DC.fsc.MODE != Bare
				 * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and
				 * PSCID=DC.ta.PSCID
				 */
				riscv_iommu_cmd_inval_set_pscid(&cmd,
					FIELD_GET(RISCV_IOMMU_DC_TA_PSCID, dc->ta));
			}
			/* else: IOTINVAL.VMA with GV=AV=PSCV=0 */
		}
	} else {
		riscv_iommu_cmd_inval_set_gscid(&cmd,
			FIELD_GET(RISCV_IOMMU_DC_IOHGATP_GSCID, iohgatp));

		if (inval_pdt) {
			/*
			 * IOTINVAL.VMA with GV=1, AV=0, and PSCV=1, and
			 * GSCID=DC.iohgatp.GSCID, PSCID=PC.PSCID
			 */
			riscv_iommu_cmd_inval_set_pscid(&cmd,
				FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta));
		}
		/*
		 * else: IOTINVAL.VMA with GV=1,AV=PSCV=0,and
		 * GSCID=DC.iohgatp.GSCID
		 *
		 * IOTINVAL.GVMA with GV=1,AV=0,and
		 * GSCID=DC.iohgatp.GSCID
		 * TODO: For now, the Second-Stage feature have not yet been merged,
		 * also issue IOTINVAL.GVMA once second-stage support is merged.
		 */
	}
	riscv_iommu_cmd_send(iommu, &cmd);
}
/*
 * Update IODIR for the device.
 *
@@ -1031,6 +1091,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu,
		riscv_iommu_cmd_iodir_inval_ddt(&cmd);
		riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]);
		riscv_iommu_cmd_send(iommu, &cmd);
		/*
		 * For now, the SVA and PASID features have not yet been merged, the
		 * default configuration is inval_pdt=false and pc=NULL.
		 */
		riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL);
		sync_required = true;
	}

@@ -1056,6 +1121,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu,
		riscv_iommu_cmd_iodir_inval_ddt(&cmd);
		riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]);
		riscv_iommu_cmd_send(iommu, &cmd);
		/*
		 * For now, the SVA and PASID features have not yet been merged, the
		 * default configuration is inval_pdt=false and pc=NULL.
		 */
		riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL);
	}

	riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);