Hi Daniel, There is no response from Tomasz. Should this patch be merged?
Jason Chien <jason.ch...@sifive.com> 於 2024年12月18日 週三 下午5:52寫道: > Ping. > > Jason Chien <jason.ch...@sifive.com> 於 2024年11月25日 週一 下午8:49寫道: > >> Hi Tomasz, any thoughs? >> >> Daniel Henrique Barboza <dbarb...@ventanamicro.com> 於 2024年11月12日 週二 >> 下午8:26寫道: >> >>> >>> CCing Tomasz >>> >>> On 11/8/24 8:01 AM, Jason Chien wrote: >>> > This commit introduces a translation tag to avoid invalidating an entry >>> > that should not be invalidated when IOMMU executes invalidation >>> commands. >>> > E.g. IOTINVAL.VMA with GV=0, AV=0, PSCV=1 invalidates both a mapping >>> > of single stage translation and a mapping of nested translation with >>> > the same PSCID, but only the former one should be invalidated. >>> > >>> > Signed-off-by: Jason Chien <jason.ch...@sifive.com> >>> > --- >>> >>> >>> LGTM but I would like to hear from Tomasz if adding this new abstraction >>> is >>> the best way to what seems to be a bug in riscv_iommu_process_cq_tail(). >>> >>> >>> Daniel >>> >>> >>> > hw/riscv/riscv-iommu.c | 205 >>> ++++++++++++++++++++++++++++++----------- >>> > 1 file changed, 153 insertions(+), 52 deletions(-) >>> > >>> > diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c >>> > index ff9deefe37..ac6bbf91d6 100644 >>> > --- a/hw/riscv/riscv-iommu.c >>> > +++ b/hw/riscv/riscv-iommu.c >>> > @@ -64,8 +64,16 @@ struct RISCVIOMMUContext { >>> > uint64_t msiptp; /* MSI redirection page table >>> pointer */ >>> > }; >>> > >>> > +typedef enum RISCVIOMMUTransTag { >>> > + RISCV_IOMMU_TRANS_TAG_BY, /* Bypass */ >>> > + RISCV_IOMMU_TRANS_TAG_SS, /* Single Stage */ >>> > + RISCV_IOMMU_TRANS_TAG_VG, /* G-stage only */ >>> > + RISCV_IOMMU_TRANS_TAG_VN, /* Nested translation */ >>> > +} RISCVIOMMUTransTag; >>> > + >>> > /* Address translation cache entry */ >>> > struct RISCVIOMMUEntry { >>> > + RISCVIOMMUTransTag tag; /* Translation Tag */ >>> > uint64_t iova:44; /* IOVA Page Number */ >>> > uint64_t pscid:20; /* Process Soft-Context identifier */ >>> > uint64_t phys:44; /* Physical Page Number */ >>> > @@ -1228,7 +1236,7 @@ static gboolean >>> riscv_iommu_iot_equal(gconstpointer v1, gconstpointer v2) >>> > RISCVIOMMUEntry *t1 = (RISCVIOMMUEntry *) v1; >>> > RISCVIOMMUEntry *t2 = (RISCVIOMMUEntry *) v2; >>> > return t1->gscid == t2->gscid && t1->pscid == t2->pscid && >>> > - t1->iova == t2->iova; >>> > + t1->iova == t2->iova && t1->tag == t2->tag; >>> > } >>> > >>> > static guint riscv_iommu_iot_hash(gconstpointer v) >>> > @@ -1237,67 +1245,115 @@ static guint >>> riscv_iommu_iot_hash(gconstpointer v) >>> > return (guint)t->iova; >>> > } >>> > >>> > -/* GV: 1 PSCV: 1 AV: 1 */ >>> > +/* GV: 0 AV: 0 PSCV: 0 GVMA: 0 */ >>> > +/* GV: 0 AV: 0 GVMA: 1 */ >>> > +static >>> > +void riscv_iommu_iot_inval_all(gpointer key, gpointer value, gpointer >>> data) >>> > +{ >>> > + RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > + RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > + if (iot->tag == arg->tag) { >>> > + iot->perm = IOMMU_NONE; >>> > + } >>> > +} >>> > + >>> > +/* GV: 0 AV: 0 PSCV: 1 GVMA: 0 */ >>> > +static >>> > +void riscv_iommu_iot_inval_pscid(gpointer key, gpointer value, >>> gpointer data) >>> > +{ >>> > + RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > + RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > + if (iot->tag == arg->tag && >>> > + iot->pscid == arg->pscid) { >>> > + iot->perm = IOMMU_NONE; >>> > + } >>> > +} >>> > + >>> > +/* GV: 0 AV: 1 PSCV: 0 GVMA: 0 */ >>> > +static >>> > +void riscv_iommu_iot_inval_iova(gpointer key, gpointer value, >>> gpointer data) >>> > +{ >>> > + RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > + RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > + if (iot->tag == arg->tag && >>> > + iot->iova == arg->iova) { >>> > + iot->perm = IOMMU_NONE; >>> > + } >>> > +} >>> > + >>> > +/* GV: 0 AV: 1 PSCV: 1 GVMA: 0 */ >>> > static void riscv_iommu_iot_inval_pscid_iova(gpointer key, gpointer >>> value, >>> > gpointer data) >>> > { >>> > RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > - if (iot->gscid == arg->gscid && >>> > + if (iot->tag == arg->tag && >>> > iot->pscid == arg->pscid && >>> > iot->iova == arg->iova) { >>> > iot->perm = IOMMU_NONE; >>> > } >>> > } >>> > >>> > -/* GV: 1 PSCV: 1 AV: 0 */ >>> > -static void riscv_iommu_iot_inval_pscid(gpointer key, gpointer value, >>> > - gpointer data) >>> > +/* GV: 1 AV: 0 PSCV: 0 GVMA: 0 */ >>> > +/* GV: 1 AV: 0 GVMA: 1 */ >>> > +static >>> > +void riscv_iommu_iot_inval_gscid(gpointer key, gpointer value, >>> gpointer data) >>> > { >>> > RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > - if (iot->gscid == arg->gscid && >>> > - iot->pscid == arg->pscid) { >>> > + if (iot->tag == arg->tag && >>> > + iot->gscid == arg->gscid) { >>> > iot->perm = IOMMU_NONE; >>> > } >>> > } >>> > >>> > -/* GV: 1 GVMA: 1 */ >>> > -static void riscv_iommu_iot_inval_gscid_gpa(gpointer key, gpointer >>> value, >>> > - gpointer data) >>> > +/* GV: 1 AV: 0 PSCV: 1 GVMA: 0 */ >>> > +static void riscv_iommu_iot_inval_gscid_pscid(gpointer key, gpointer >>> value, >>> > + gpointer data) >>> > { >>> > RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > - if (iot->gscid == arg->gscid) { >>> > - /* simplified cache, no GPA matching */ >>> > + if (iot->tag == arg->tag && >>> > + iot->gscid == arg->gscid && >>> > + iot->pscid == arg->pscid) { >>> > iot->perm = IOMMU_NONE; >>> > } >>> > } >>> > >>> > -/* GV: 1 GVMA: 0 */ >>> > -static void riscv_iommu_iot_inval_gscid(gpointer key, gpointer value, >>> > - gpointer data) >>> > +/* GV: 1 AV: 1 PSCV: 0 GVMA: 0 */ >>> > +/* GV: 1 AV: 1 GVMA: 1 */ >>> > +static void riscv_iommu_iot_inval_gscid_iova(gpointer key, gpointer >>> value, >>> > + gpointer data) >>> > { >>> > RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > - if (iot->gscid == arg->gscid) { >>> > + if (iot->tag == arg->tag && >>> > + iot->gscid == arg->gscid && >>> > + iot->iova == arg->iova) { >>> > iot->perm = IOMMU_NONE; >>> > } >>> > } >>> > >>> > -/* GV: 0 */ >>> > -static void riscv_iommu_iot_inval_all(gpointer key, gpointer value, >>> > - gpointer data) >>> > +/* GV: 1 AV: 1 PSCV: 1 GVMA: 0 */ >>> > +static void riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key, >>> gpointer value, >>> > + gpointer data) >>> > { >>> > RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; >>> > - iot->perm = IOMMU_NONE; >>> > + RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; >>> > + if (iot->tag == arg->tag && >>> > + iot->gscid == arg->gscid && >>> > + iot->pscid == arg->pscid && >>> > + iot->iova == arg->iova) { >>> > + iot->perm = IOMMU_NONE; >>> > + } >>> > } >>> > >>> > /* caller should keep ref-count for iot_cache object */ >>> > static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext >>> *ctx, >>> > - GHashTable *iot_cache, hwaddr iova) >>> > + GHashTable *iot_cache, hwaddr iova, RISCVIOMMUTransTag transtag) >>> > { >>> > RISCVIOMMUEntry key = { >>> > + .tag = transtag, >>> > .gscid = get_field(ctx->gatp, RISCV_IOMMU_DC_IOHGATP_GSCID), >>> > .pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID), >>> > .iova = PPN_DOWN(iova), >>> > @@ -1323,10 +1379,11 @@ static void >>> riscv_iommu_iot_update(RISCVIOMMUState *s, >>> > } >>> > >>> > static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func, >>> > - uint32_t gscid, uint32_t pscid, hwaddr iova) >>> > + uint32_t gscid, uint32_t pscid, hwaddr iova, RISCVIOMMUTransTag >>> transtag) >>> > { >>> > GHashTable *iot_cache; >>> > RISCVIOMMUEntry key = { >>> > + .tag = transtag, >>> > .gscid = gscid, >>> > .pscid = pscid, >>> > .iova = PPN_DOWN(iova), >>> > @@ -1337,9 +1394,24 @@ static void >>> riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func, >>> > g_hash_table_unref(iot_cache); >>> > } >>> > >>> > +static RISCVIOMMUTransTag riscv_iommu_get_transtag(RISCVIOMMUContext >>> *ctx) >>> > +{ >>> > + uint64_t satp = get_field(ctx->satp, RISCV_IOMMU_ATP_MODE_FIELD); >>> > + uint64_t gatp = get_field(ctx->gatp, RISCV_IOMMU_ATP_MODE_FIELD); >>> > + >>> > + if (satp == RISCV_IOMMU_DC_FSC_MODE_BARE) { >>> > + return (gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE) ? >>> > + RISCV_IOMMU_TRANS_TAG_BY : RISCV_IOMMU_TRANS_TAG_VG; >>> > + } else { >>> > + return (gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE) ? >>> > + RISCV_IOMMU_TRANS_TAG_SS : RISCV_IOMMU_TRANS_TAG_VN; >>> > + } >>> > +} >>> > + >>> > static int riscv_iommu_translate(RISCVIOMMUState *s, >>> RISCVIOMMUContext *ctx, >>> > IOMMUTLBEntry *iotlb, bool enable_cache) >>> > { >>> > + RISCVIOMMUTransTag transtag = riscv_iommu_get_transtag(ctx); >>> > RISCVIOMMUEntry *iot; >>> > IOMMUAccessFlags perm; >>> > bool enable_pid; >>> > @@ -1365,7 +1437,7 @@ static int riscv_iommu_translate(RISCVIOMMUState >>> *s, RISCVIOMMUContext *ctx, >>> > } >>> > } >>> > >>> > - iot = riscv_iommu_iot_lookup(ctx, iot_cache, iotlb->iova); >>> > + iot = riscv_iommu_iot_lookup(ctx, iot_cache, iotlb->iova, >>> transtag); >>> > perm = iot ? iot->perm : IOMMU_NONE; >>> > if (perm != IOMMU_NONE) { >>> > iotlb->translated_addr = PPN_PHYS(iot->phys); >>> > @@ -1396,6 +1468,7 @@ static int riscv_iommu_translate(RISCVIOMMUState >>> *s, RISCVIOMMUContext *ctx, >>> > iot->gscid = get_field(ctx->gatp, >>> RISCV_IOMMU_DC_IOHGATP_GSCID); >>> > iot->pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID); >>> > iot->perm = iotlb->perm; >>> > + iot->tag = transtag; >>> > riscv_iommu_iot_update(s, iot_cache, iot); >>> > } >>> > >>> > @@ -1603,44 +1676,72 @@ static void >>> riscv_iommu_process_cq_tail(RISCVIOMMUState *s) >>> > >>> > case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IOTINVAL_FUNC_GVMA, >>> > RISCV_IOMMU_CMD_IOTINVAL_OPCODE): >>> > - if (cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV) { >>> > + { >>> > + bool gv = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV); >>> > + bool av = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV); >>> > + bool pscv = !!(cmd.dword0 & >>> RISCV_IOMMU_CMD_IOTINVAL_PSCV); >>> > + uint32_t gscid = get_field(cmd.dword0, >>> > + >>> RISCV_IOMMU_CMD_IOTINVAL_GSCID); >>> > + uint32_t pscid = get_field(cmd.dword0, >>> > + >>> RISCV_IOMMU_CMD_IOTINVAL_PSCID); >>> > + hwaddr iova = (cmd.dword1 << 2) & TARGET_PAGE_MASK; >>> > + >>> > + if (pscv) { >>> > /* illegal command arguments IOTINVAL.GVMA & PSCV == >>> 1 */ >>> > goto cmd_ill; >>> > - } else if (!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV)) { >>> > - /* invalidate all cache mappings */ >>> > - func = riscv_iommu_iot_inval_all; >>> > - } else if (!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV)) { >>> > - /* invalidate cache matching GSCID */ >>> > - func = riscv_iommu_iot_inval_gscid; >>> > - } else { >>> > - /* invalidate cache matching GSCID and ADDR (GPA) */ >>> > - func = riscv_iommu_iot_inval_gscid_gpa; >>> > } >>> > - riscv_iommu_iot_inval(s, func, >>> > - get_field(cmd.dword0, >>> RISCV_IOMMU_CMD_IOTINVAL_GSCID), 0, >>> > - cmd.dword1 << 2 & TARGET_PAGE_MASK); >>> > + >>> > + func = riscv_iommu_iot_inval_all; >>> > + >>> > + if (gv) { >>> > + func = (av) ? riscv_iommu_iot_inval_gscid_iova : >>> > + riscv_iommu_iot_inval_gscid; >>> > + } >>> > + >>> > + riscv_iommu_iot_inval( >>> > + s, func, gscid, pscid, iova, >>> RISCV_IOMMU_TRANS_TAG_VG); >>> > + >>> > + riscv_iommu_iot_inval( >>> > + s, func, gscid, pscid, iova, >>> RISCV_IOMMU_TRANS_TAG_VN); >>> > break; >>> > + } >>> > >>> > case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA, >>> > RISCV_IOMMU_CMD_IOTINVAL_OPCODE): >>> > - if (!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV)) { >>> > - /* invalidate all cache mappings, simplified model */ >>> > - func = riscv_iommu_iot_inval_all; >>> > - } else if (!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV)) >>> { >>> > - /* invalidate cache matching GSCID, simplified model >>> */ >>> > - func = riscv_iommu_iot_inval_gscid; >>> > - } else if (!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV)) { >>> > - /* invalidate cache matching GSCID and PSCID */ >>> > - func = riscv_iommu_iot_inval_pscid; >>> > + { >>> > + bool gv = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV); >>> > + bool av = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV); >>> > + bool pscv = !!(cmd.dword0 & >>> RISCV_IOMMU_CMD_IOTINVAL_PSCV); >>> > + uint32_t gscid = get_field(cmd.dword0, >>> > + >>> RISCV_IOMMU_CMD_IOTINVAL_GSCID); >>> > + uint32_t pscid = get_field(cmd.dword0, >>> > + >>> RISCV_IOMMU_CMD_IOTINVAL_PSCID); >>> > + hwaddr iova = (cmd.dword1 << 2) & TARGET_PAGE_MASK; >>> > + RISCVIOMMUTransTag transtag; >>> > + >>> > + if (gv) { >>> > + transtag = RISCV_IOMMU_TRANS_TAG_VN; >>> > + if (pscv) { >>> > + func = (av) ? >>> riscv_iommu_iot_inval_gscid_pscid_iova : >>> > + riscv_iommu_iot_inval_gscid_pscid; >>> > + } else { >>> > + func = (av) ? riscv_iommu_iot_inval_gscid_iova : >>> > + riscv_iommu_iot_inval_gscid; >>> > + } >>> > } else { >>> > - /* invalidate cache matching GSCID and PSCID and ADDR >>> (IOVA) */ >>> > - func = riscv_iommu_iot_inval_pscid_iova; >>> > + transtag = RISCV_IOMMU_TRANS_TAG_SS; >>> > + if (pscv) { >>> > + func = (av) ? riscv_iommu_iot_inval_pscid_iova : >>> > + riscv_iommu_iot_inval_pscid; >>> > + } else { >>> > + func = (av) ? riscv_iommu_iot_inval_iova : >>> > + riscv_iommu_iot_inval_all; >>> > + } >>> > } >>> > - riscv_iommu_iot_inval(s, func, >>> > - get_field(cmd.dword0, RISCV_IOMMU_CMD_IOTINVAL_GSCID), >>> > - get_field(cmd.dword0, RISCV_IOMMU_CMD_IOTINVAL_PSCID), >>> > - cmd.dword1 << 2 & TARGET_PAGE_MASK); >>> > + >>> > + riscv_iommu_iot_inval(s, func, gscid, pscid, iova, >>> transtag); >>> > break; >>> > + } >>> > >>> > case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT, >>> > RISCV_IOMMU_CMD_IODIR_OPCODE): >>> >>>