Hi Eric,

> -----Original Message-----
> From: Eric Auger <eric.au...@redhat.com>
> Sent: 05 September 2025 13:46
> To: qemu-...@nongnu.org; qemu-devel@nongnu.org; Shameer Kolothum
> <skolothum...@nvidia.com>
> Cc: peter.mayd...@linaro.org; Jason Gunthorpe <j...@nvidia.com>; Nicolin
> Chen <nicol...@nvidia.com>; ddut...@redhat.com; berra...@redhat.com;
> Nathan Chen <nath...@nvidia.com>; Matt Ochs <mo...@nvidia.com>;
> smost...@google.com; linux...@huawei.com; wangzh...@hisilicon.com;
> jiangkun...@huawei.com; jonathan.came...@huawei.com;
> zhangfei....@linaro.org; zhenzhong.d...@intel.com;
> shameerkolot...@gmail.com
> Subject: Re: [RFC PATCH v3 13/15] hw/arm/smmuv3: Forward invalidation
> commands to hw
> 
> External email: Use caution opening links or attachments
> 
> 
> Hi Shameer,
> 
> On 7/14/25 5:59 PM, Shameer Kolothum wrote:
> > From: Nicolin Chen <nicol...@nvidia.com>
> >
> > Use the provided smmuv3-accel helper functions to issue the
> > invalidation commands to host SMMUv3.
> >
> > Signed-off-by: Nicolin Chen <nicol...@nvidia.com>
> > Signed-off-by: Shameer Kolothum
> <shameerali.kolothum.th...@huawei.com>
> > ---
> >  hw/arm/smmuv3-internal.h | 11 +++++++++++
> >  hw/arm/smmuv3.c          | 28 ++++++++++++++++++++++++++++
> >  2 files changed, 39 insertions(+)
> >
> > diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> > index 8cb6a9238a..f3aeaf6375 100644
> > --- a/hw/arm/smmuv3-internal.h
> > +++ b/hw/arm/smmuv3-internal.h
> > @@ -233,6 +233,17 @@ static inline bool
> smmuv3_gerror_irq_enabled(SMMUv3State *s)
> >  #define Q_CONS_WRAP(q) (((q)->cons & WRAP_MASK(q)) >> (q)-
> >log2size)
> >  #define Q_PROD_WRAP(q) (((q)->prod & WRAP_MASK(q)) >> (q)-
> >log2size)
> >
> > +static inline int smmuv3_q_ncmds(SMMUQueue *q)
> > +{
> > +    uint32_t prod = Q_PROD(q);
> > +    uint32_t cons = Q_CONS(q);
> > +
> > +    if (Q_PROD_WRAP(q) == Q_CONS_WRAP(q))
> > +        return prod - cons;
> > +    else
> > +        return WRAP_MASK(q) - cons + prod;
> > +}
> > +
> >  static inline bool smmuv3_q_full(SMMUQueue *q)
> >  {
> >      return ((q->cons ^ q->prod) & WRAP_INDEX_MASK(q)) ==
> WRAP_MASK(q);
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index c94bfe6564..97ecca0764 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -1285,10 +1285,17 @@ static int
> smmuv3_cmdq_consume(SMMUv3State *s)
> >      SMMUCmdError cmd_error = SMMU_CERROR_NONE;
> >      SMMUQueue *q = &s->cmdq;
> >      SMMUCommandType type = 0;
> > +    SMMUCommandBatch batch = {};
> > +    uint32_t ncmds;
> >
> >      if (!smmuv3_cmdq_enabled(s)) {
> >          return 0;
> >      }
> > +
> > +    ncmds = smmuv3_q_ncmds(q);
> > +    batch.cmds = g_new0(Cmd, ncmds);
> > +    batch.cons = g_new0(uint32_t, ncmds);
> so you are provisionning space for n commands found in the queue,
> independently on knowing whether they will be batched, ie. only
> invalidation commands are. Then commands are added in the batch one by
> one and you increment batch->ncmds in smmuv3_accel_batch_cmd. I agree
> with Jonathan. This looks weird. AT least I would introduce a kelper
> that inits a Back of ncmds and I would make all the batch fields
> private. You you end up with the init +
> smmuv3_accel_add_cmd_to_batch(batch, cmd). Then independently on the
> ncmds you can issue a smmuv3_accel_issue_cmd_batch that would return if
> there is nothing in the batch. You also need a batch deallocation
> helper. 

Agree, at present we pre-allocate irrespective of whether there will any
Invalidation cmds or not. I will take another look and incorporate your above
suggestion to improve this. 

I remember I expressed in the past my concern about having
> commands executed out of order. I don't remember out conclusion on that
> but this shall be clearly studied and conclusion shall be put in the
> commit message.

Yes, you did, and I missed it. Sorry about that.

I think it is safe to honour the execution order of Guest here. From a quick 
glance, I
couldn’t find anything related to a safe out of order execution guidance from
SMMUv3 specification. Also, we can't be sure how Guest will be 
modified/optimised
in the future to completely rule out problems if we do out-of-order executions. 

Hence, my plan for next is to start batching if we see Invalidation cmds and 
submit
the batch If any non-invalidation commands are encountered in between.

@Nicolin, do you foresee any issues with above approach? From the current
Host SMMUV3 driver, batching of commands is mainly used for invalidations
(except for certain arm_smmu_cmdq_issue_cmd_with_sync() cases). So 
I guess we are good from a performance optimisation point of view if we can
cover invalidations as above.

> > +
> >      /*
> >       * some commands depend on register values, typically CR0. In case 
> > those
> >       * register values change while handling the command, spec says it
> > @@ -1383,6 +1390,7 @@ static int
> smmuv3_cmdq_consume(SMMUv3State *s)
> >
> >              trace_smmuv3_cmdq_cfgi_cd(sid);
> >              smmuv3_flush_config(sdev);
> > +            smmuv3_accel_batch_cmd(sdev->smmu, sdev, &batch, &cmd, &q-
> >cons);
> >              break;
> >          }
> >          case SMMU_CMD_TLBI_NH_ASID:
> > @@ -1406,6 +1414,7 @@ static int
> smmuv3_cmdq_consume(SMMUv3State *s)
> >              trace_smmuv3_cmdq_tlbi_nh_asid(asid);
> >              smmu_inv_notifiers_all(&s->smmu_state);
> >              smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
> > +            smmuv3_accel_batch_cmd(bs, NULL, &batch, &cmd, &q->cons);
> >              break;
> >          }
> >          case SMMU_CMD_TLBI_NH_ALL:
> > @@ -1433,6 +1442,7 @@ static int
> smmuv3_cmdq_consume(SMMUv3State *s)
> >              trace_smmuv3_cmdq_tlbi_nsnh();
> >              smmu_inv_notifiers_all(&s->smmu_state);
> >              smmu_iotlb_inv_all(bs);
> > +            smmuv3_accel_batch_cmd(bs, NULL, &batch, &cmd, &q->cons);
> >              break;
> >          case SMMU_CMD_TLBI_NH_VAA:
> >          case SMMU_CMD_TLBI_NH_VA:
> > @@ -1441,6 +1451,7 @@ static int
> smmuv3_cmdq_consume(SMMUv3State *s)
> >                  break;
> >              }
> >              smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1);
> > +            smmuv3_accel_batch_cmd(bs, NULL, &batch, &cmd, &q->cons);
> >              break;
> >          case SMMU_CMD_TLBI_S12_VMALL:
> >          {
> > @@ -1499,12 +1510,29 @@ static int
> smmuv3_cmdq_consume(SMMUv3State *s)
> >          queue_cons_incr(q);
> >      }
> >
> > +    qemu_mutex_lock(&s->mutex);
> > +    if (!cmd_error && batch.ncmds) {
> > +        if (!smmuv3_accel_issue_cmd_batch(bs, &batch)) {
> > +            if (batch.ncmds) {
> > +                q->cons = batch.cons[batch.ncmds - 1];
> > +            } else {
> > +                q->cons = batch.cons[0]; /* FIXME: Check */
> > +            }
> > +            qemu_log_mask(LOG_GUEST_ERROR, "Illegal command type: %d\n",
> > +                          CMD_TYPE(&batch.cmds[batch.ncmds]));
> Can't you have other error types returned?

Kernel can return EOPNOTSUPP/EINVAL/ENOMEM/EFAULT/ ETIMEDOUT errors.
Of these, only ETIMEDOUT is related to the actual host Queue when an attempted
SYNC results in timeout.

So, between CERROR_ILL/ _ABT/ _ATC_INV_SYNC I think it is best to set CERROR_ILL
here.

Thanks,
Shameer

> 
> Thanks
> 
> Eric
> > +            cmd_error = SMMU_CERROR_ILL;
> > +        }
> > +    }
> > +    qemu_mutex_unlock(&s->mutex);
> > +
> >      if (cmd_error) {
> >          trace_smmuv3_cmdq_consume_error(smmu_cmd_string(type),
> cmd_error);
> >          smmu_write_cmdq_err(s, cmd_error);
> >          smmuv3_trigger_irq(s, SMMU_IRQ_GERROR,
> R_GERROR_CMDQ_ERR_MASK);
> >      }
> >
> > +    g_free(batch.cmds);
> > +    g_free(batch.cons);
> >      trace_smmuv3_cmdq_consume_out(Q_PROD(q), Q_CONS(q),
> >                                    Q_PROD_WRAP(q), Q_CONS_WRAP(q));
> >

Reply via email to