[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v5 09/13] hw/riscv/riscv-iommu: add ATS support
From: |
Alistair Francis |
Subject: |
Re: [PATCH v5 09/13] hw/riscv/riscv-iommu: add ATS support |
Date: |
Fri, 19 Jul 2024 13:43:27 +1000 |
On Tue, Jul 9, 2024 at 3:37 AM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> Add PCIe Address Translation Services (ATS) capabilities to the IOMMU.
> This will add support for ATS translation requests in Fault/Event
> queues, Page-request queue and IOATC invalidations.
>
> Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reviewed-by: Frank Chang <frank.chang@sifive.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/riscv-iommu-bits.h | 43 +++++++++++-
> hw/riscv/riscv-iommu.c | 129 +++++++++++++++++++++++++++++++++++-
> hw/riscv/riscv-iommu.h | 1 +
> hw/riscv/trace-events | 3 +
> 4 files changed, 173 insertions(+), 3 deletions(-)
>
> diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h
> index 1dd2e2c7d6..b1546d3669 100644
> --- a/hw/riscv/riscv-iommu-bits.h
> +++ b/hw/riscv/riscv-iommu-bits.h
> @@ -79,6 +79,7 @@ struct riscv_iommu_pq_record {
> #define RISCV_IOMMU_CAP_SV57X4 BIT_ULL(19)
> #define RISCV_IOMMU_CAP_MSI_FLAT BIT_ULL(22)
> #define RISCV_IOMMU_CAP_MSI_MRIF BIT_ULL(23)
> +#define RISCV_IOMMU_CAP_ATS BIT_ULL(25)
> #define RISCV_IOMMU_CAP_T2GPA BIT_ULL(26)
> #define RISCV_IOMMU_CAP_IGS GENMASK_ULL(29, 28)
> #define RISCV_IOMMU_CAP_PAS GENMASK_ULL(37, 32)
> @@ -208,6 +209,7 @@ struct riscv_iommu_dc {
>
> /* Translation control fields */
> #define RISCV_IOMMU_DC_TC_V BIT_ULL(0)
> +#define RISCV_IOMMU_DC_TC_EN_ATS BIT_ULL(1)
> #define RISCV_IOMMU_DC_TC_EN_PRI BIT_ULL(2)
> #define RISCV_IOMMU_DC_TC_T2GPA BIT_ULL(3)
> #define RISCV_IOMMU_DC_TC_DTF BIT_ULL(4)
> @@ -269,6 +271,20 @@ struct riscv_iommu_command {
> #define RISCV_IOMMU_CMD_IODIR_DV BIT_ULL(33)
> #define RISCV_IOMMU_CMD_IODIR_DID GENMASK_ULL(63, 40)
>
> +/* 3.1.4 I/O MMU PCIe ATS */
> +#define RISCV_IOMMU_CMD_ATS_OPCODE 4
> +#define RISCV_IOMMU_CMD_ATS_FUNC_INVAL 0
> +#define RISCV_IOMMU_CMD_ATS_FUNC_PRGR 1
> +#define RISCV_IOMMU_CMD_ATS_PID GENMASK_ULL(31, 12)
> +#define RISCV_IOMMU_CMD_ATS_PV BIT_ULL(32)
> +#define RISCV_IOMMU_CMD_ATS_DSV BIT_ULL(33)
> +#define RISCV_IOMMU_CMD_ATS_RID GENMASK_ULL(55, 40)
> +#define RISCV_IOMMU_CMD_ATS_DSEG GENMASK_ULL(63, 56)
> +/* dword1 is the ATS payload, two different payload types for INVAL and PRGR
> */
> +
> +/* ATS.PRGR payload */
> +#define RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE GENMASK_ULL(47, 44)
> +
> enum riscv_iommu_dc_fsc_atp_modes {
> RISCV_IOMMU_DC_FSC_MODE_BARE = 0,
> RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV32 = 8,
> @@ -335,7 +351,32 @@ enum riscv_iommu_fq_ttypes {
> RISCV_IOMMU_FQ_TTYPE_TADDR_INST_FETCH = 5,
> RISCV_IOMMU_FQ_TTYPE_TADDR_RD = 6,
> RISCV_IOMMU_FQ_TTYPE_TADDR_WR = 7,
> - RISCV_IOMMU_FW_TTYPE_PCIE_MSG_REQ = 8,
> + RISCV_IOMMU_FQ_TTYPE_PCIE_ATS_REQ = 8,
> + RISCV_IOMMU_FW_TTYPE_PCIE_MSG_REQ = 9,
> +};
> +
> +/* Header fields */
> +#define RISCV_IOMMU_PREQ_HDR_PID GENMASK_ULL(31, 12)
> +#define RISCV_IOMMU_PREQ_HDR_PV BIT_ULL(32)
> +#define RISCV_IOMMU_PREQ_HDR_PRIV BIT_ULL(33)
> +#define RISCV_IOMMU_PREQ_HDR_EXEC BIT_ULL(34)
> +#define RISCV_IOMMU_PREQ_HDR_DID GENMASK_ULL(63, 40)
> +
> +/* Payload fields */
> +#define RISCV_IOMMU_PREQ_PAYLOAD_R BIT_ULL(0)
> +#define RISCV_IOMMU_PREQ_PAYLOAD_W BIT_ULL(1)
> +#define RISCV_IOMMU_PREQ_PAYLOAD_L BIT_ULL(2)
> +#define RISCV_IOMMU_PREQ_PAYLOAD_M GENMASK_ULL(2, 0)
> +#define RISCV_IOMMU_PREQ_PRG_INDEX GENMASK_ULL(11, 3)
> +#define RISCV_IOMMU_PREQ_UADDR GENMASK_ULL(63, 12)
> +
> +
> +/*
> + * struct riscv_iommu_msi_pte - MSI Page Table Entry
> + */
> +struct riscv_iommu_msi_pte {
> + uint64_t pte;
> + uint64_t mrif_info;
> };
>
> /* Fields on pte */
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index 76728baa77..78058a49ae 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -639,6 +639,20 @@ static bool
> riscv_iommu_validate_device_ctx(RISCVIOMMUState *s,
> RISCVIOMMUContext *ctx)
> {
> uint32_t fsc_mode, msi_mode;
> + uint64_t gatp;
> +
> + if (!(s->cap & RISCV_IOMMU_CAP_ATS) &&
> + (ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS ||
> + ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI ||
> + ctx->tc & RISCV_IOMMU_DC_TC_PRPR)) {
> + return false;
> + }
> +
> + if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS) &&
> + (ctx->tc & RISCV_IOMMU_DC_TC_T2GPA ||
> + ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI)) {
> + return false;
> + }
>
> if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI) &&
> ctx->tc & RISCV_IOMMU_DC_TC_PRPR) {
> @@ -659,6 +673,12 @@ static bool
> riscv_iommu_validate_device_ctx(RISCVIOMMUState *s,
> }
> }
>
> + gatp = get_field(ctx->gatp, RISCV_IOMMU_ATP_MODE_FIELD);
> + if (ctx->tc & RISCV_IOMMU_DC_TC_T2GPA &&
> + gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE) {
> + return false;
> + }
> +
> fsc_mode = get_field(ctx->satp, RISCV_IOMMU_DC_FSC_MODE);
>
> if (ctx->tc & RISCV_IOMMU_DC_TC_PDTV) {
> @@ -809,7 +829,12 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s,
> RISCVIOMMUContext *ctx)
> RISCV_IOMMU_DC_IOHGATP_MODE_BARE);
> ctx->satp = set_field(0, RISCV_IOMMU_ATP_MODE_FIELD,
> RISCV_IOMMU_DC_FSC_MODE_BARE);
> +
> ctx->tc = RISCV_IOMMU_DC_TC_V;
> + if (s->enable_ats) {
> + ctx->tc |= RISCV_IOMMU_DC_TC_EN_ATS;
> + }
> +
> ctx->ta = 0;
> ctx->msiptp = 0;
> return 0;
> @@ -1271,6 +1296,16 @@ static int riscv_iommu_translate(RISCVIOMMUState *s,
> RISCVIOMMUContext *ctx,
> enable_pri = (iotlb->perm == IOMMU_NONE) && (ctx->tc & BIT_ULL(32));
> enable_pid = (ctx->tc & RISCV_IOMMU_DC_TC_PDTV);
>
> + /* Check for ATS request. */
> + if (iotlb->perm == IOMMU_NONE) {
> + /* Check if ATS is disabled. */
> + if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS)) {
> + enable_pri = false;
> + fault = RISCV_IOMMU_FQ_CAUSE_TTYPE_BLOCKED;
> + goto done;
> + }
> + }
> +
> qemu_mutex_lock(&s->iot_lock);
> iot = riscv_iommu_iot_lookup(ctx, iot_cache, iotlb->iova);
> qemu_mutex_unlock(&s->iot_lock);
> @@ -1318,11 +1353,11 @@ done:
> }
>
> if (fault) {
> - unsigned ttype;
> + unsigned ttype = RISCV_IOMMU_FQ_TTYPE_PCIE_ATS_REQ;
>
> if (iotlb->perm & IOMMU_RW) {
> ttype = RISCV_IOMMU_FQ_TTYPE_UADDR_WR;
> - } else {
> + } else if (iotlb->perm & IOMMU_RO) {
> ttype = RISCV_IOMMU_FQ_TTYPE_UADDR_RD;
> }
>
> @@ -1350,6 +1385,73 @@ static MemTxResult riscv_iommu_iofence(RISCVIOMMUState
> *s, bool notify,
> MEMTXATTRS_UNSPECIFIED);
> }
>
> +static void riscv_iommu_ats(RISCVIOMMUState *s,
> + struct riscv_iommu_command *cmd, IOMMUNotifierFlag flag,
> + IOMMUAccessFlags perm,
> + void (*trace_fn)(const char *id))
> +{
> + RISCVIOMMUSpace *as = NULL;
> + IOMMUNotifier *n;
> + IOMMUTLBEvent event;
> + uint32_t pid;
> + uint32_t devid;
> + const bool pv = cmd->dword0 & RISCV_IOMMU_CMD_ATS_PV;
> +
> + if (cmd->dword0 & RISCV_IOMMU_CMD_ATS_DSV) {
> + /* Use device segment and requester id */
> + devid = get_field(cmd->dword0,
> + RISCV_IOMMU_CMD_ATS_DSEG | RISCV_IOMMU_CMD_ATS_RID);
> + } else {
> + devid = get_field(cmd->dword0, RISCV_IOMMU_CMD_ATS_RID);
> + }
> +
> + pid = get_field(cmd->dword0, RISCV_IOMMU_CMD_ATS_PID);
> +
> + qemu_mutex_lock(&s->core_lock);
> + QLIST_FOREACH(as, &s->spaces, list) {
> + if (as->devid == devid) {
> + break;
> + }
> + }
> + qemu_mutex_unlock(&s->core_lock);
> +
> + if (!as || !as->notifier) {
> + return;
> + }
> +
> + event.type = flag;
> + event.entry.perm = perm;
> + event.entry.target_as = s->target_as;
> +
> + IOMMU_NOTIFIER_FOREACH(n, &as->iova_mr) {
> + if (!pv || n->iommu_idx == pid) {
> + event.entry.iova = n->start;
> + event.entry.addr_mask = n->end - n->start;
> + trace_fn(as->iova_mr.parent_obj.name);
> + memory_region_notify_iommu_one(n, &event);
> + }
> + }
> +}
> +
> +static void riscv_iommu_ats_inval(RISCVIOMMUState *s,
> + struct riscv_iommu_command *cmd)
> +{
> + return riscv_iommu_ats(s, cmd, IOMMU_NOTIFIER_DEVIOTLB_UNMAP, IOMMU_NONE,
> + trace_riscv_iommu_ats_inval);
> +}
> +
> +static void riscv_iommu_ats_prgr(RISCVIOMMUState *s,
> + struct riscv_iommu_command *cmd)
> +{
> + unsigned resp_code = get_field(cmd->dword1,
> + RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE);
> +
> + /* Using the access flag to carry response code information */
> + IOMMUAccessFlags perm = resp_code ? IOMMU_NONE : IOMMU_RW;
> + return riscv_iommu_ats(s, cmd, IOMMU_NOTIFIER_MAP, perm,
> + trace_riscv_iommu_ats_prgr);
> +}
> +
> static void riscv_iommu_process_ddtp(RISCVIOMMUState *s)
> {
> uint64_t old_ddtp = s->ddtp;
> @@ -1505,6 +1607,25 @@ static void
> riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
> get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_PID));
> break;
>
> + /* ATS commands */
> + case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_ATS_FUNC_INVAL,
> + RISCV_IOMMU_CMD_ATS_OPCODE):
> + if (!s->enable_ats) {
> + goto cmd_ill;
> + }
> +
> + riscv_iommu_ats_inval(s, &cmd);
> + break;
> +
> + case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_ATS_FUNC_PRGR,
> + RISCV_IOMMU_CMD_ATS_OPCODE):
> + if (!s->enable_ats) {
> + goto cmd_ill;
> + }
> +
> + riscv_iommu_ats_prgr(s, &cmd);
> + break;
> +
> default:
> cmd_ill:
> /* Invalid instruction, do not advance instruction index. */
> @@ -1900,6 +2021,9 @@ static void riscv_iommu_realize(DeviceState *dev, Error
> **errp)
> if (s->enable_msi) {
> s->cap |= RISCV_IOMMU_CAP_MSI_FLAT | RISCV_IOMMU_CAP_MSI_MRIF;
> }
> + if (s->enable_ats) {
> + s->cap |= RISCV_IOMMU_CAP_ATS;
> + }
> if (s->enable_s_stage) {
> s->cap |= RISCV_IOMMU_CAP_SV32 | RISCV_IOMMU_CAP_SV39 |
> RISCV_IOMMU_CAP_SV48 | RISCV_IOMMU_CAP_SV57;
> @@ -2012,6 +2136,7 @@ static Property riscv_iommu_properties[] = {
> DEFINE_PROP_UINT32("ioatc-limit", RISCVIOMMUState, iot_limit,
> LIMIT_CACHE_IOT),
> DEFINE_PROP_BOOL("intremap", RISCVIOMMUState, enable_msi, TRUE),
> + DEFINE_PROP_BOOL("ats", RISCVIOMMUState, enable_ats, TRUE),
> DEFINE_PROP_BOOL("off", RISCVIOMMUState, enable_off, TRUE),
> DEFINE_PROP_BOOL("s-stage", RISCVIOMMUState, enable_s_stage, TRUE),
> DEFINE_PROP_BOOL("g-stage", RISCVIOMMUState, enable_g_stage, TRUE),
> diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
> index 0594e654f9..3a1bd5b5dc 100644
> --- a/hw/riscv/riscv-iommu.h
> +++ b/hw/riscv/riscv-iommu.h
> @@ -38,6 +38,7 @@ struct RISCVIOMMUState {
>
> bool enable_off; /* Enable out-of-reset OFF mode (DMA disabled) */
> bool enable_msi; /* Enable MSI remapping */
> + bool enable_ats; /* Enable ATS support */
> bool enable_s_stage; /* Enable S/VS-Stage translation */
> bool enable_g_stage; /* Enable G-Stage translation */
>
> diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events
> index 42a97caffa..4b486b6420 100644
> --- a/hw/riscv/trace-events
> +++ b/hw/riscv/trace-events
> @@ -9,3 +9,6 @@ riscv_iommu_msi(const char *id, unsigned b, unsigned d,
> unsigned f, uint64_t iov
> riscv_iommu_cmd(const char *id, uint64_t l, uint64_t u) "%s: command
> 0x%"PRIx64" 0x%"PRIx64
> riscv_iommu_notifier_add(const char *id) "%s: dev-iotlb notifier added"
> riscv_iommu_notifier_del(const char *id) "%s: dev-iotlb notifier removed"
> +riscv_iommu_ats(const char *id, unsigned b, unsigned d, unsigned f, uint64_t
> iova) "%s: translate request %04x:%02x.%u iova: 0x%"PRIx64
> +riscv_iommu_ats_inval(const char *id) "%s: dev-iotlb invalidate"
> +riscv_iommu_ats_prgr(const char *id) "%s: dev-iotlb page request group
> response"
> --
> 2.45.2
>
>
- Re: [PATCH v5 05/13] hw/riscv: add riscv-iommu-pci reference device, (continued)
- [PATCH v5 03/13] hw/riscv: add RISC-V IOMMU base emulation, Daniel Henrique Barboza, 2024/07/08
- [PATCH v5 06/13] hw/riscv/virt.c: support for RISC-V IOMMU PCIDevice hotplug, Daniel Henrique Barboza, 2024/07/08
- [PATCH v5 08/13] hw/riscv/riscv-iommu: add Address Translation Cache (IOATC), Daniel Henrique Barboza, 2024/07/08
- [PATCH v5 09/13] hw/riscv/riscv-iommu: add ATS support, Daniel Henrique Barboza, 2024/07/08
- Re: [PATCH v5 09/13] hw/riscv/riscv-iommu: add ATS support,
Alistair Francis <=
- [PATCH v5 07/13] test/qtest: add riscv-iommu-pci tests, Daniel Henrique Barboza, 2024/07/08
- [PATCH v5 11/13] hw/riscv/riscv-iommu: Add another irq for mrif notifications, Daniel Henrique Barboza, 2024/07/08
[PATCH v5 10/13] hw/riscv/riscv-iommu: add DBG support, Daniel Henrique Barboza, 2024/07/08
[PATCH v5 12/13] qtest/riscv-iommu-test: add init queues test, Daniel Henrique Barboza, 2024/07/08
[PATCH v5 13/13] docs/specs: add riscv-iommu, Daniel Henrique Barboza, 2024/07/08