[PATCH RFC v4 09/18] riscv_cbqri: Add bandwidth controller probe and allocation device ops
Drew Fustini
fustini at kernel.org
Fri May 15 23:15:30 PDT 2026
On Tue, May 12, 2026 at 02:29:38AM +0000, sashiko-bot at kernel.org wrote:
[..]
> > +static int cbqri_bc_alloc_op(struct cbqri_controller *ctrl, int operation, int rcid)
> > +{
> > + int reg_offset = CBQRI_BC_ALLOC_CTL_OFF;
> > + int status;
> > + u64 reg;
> > +
> > + lockdep_assert_held(&ctrl->lock);
> > +
> > + if (ctrl->faulted)
> > + return -EIO;
> > +
> > + if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) {
>
> If a timeout in cbqri_wait_busy_flag() sets ctrl->faulted = true, will
> runtime operations like cbqri_bc_alloc_op() ever execute again? Because
> it returns early here when ctrl->faulted is true, the polling function
> is never called again to clear the flag, which seems to permanently
> disable the controller after a single timeout.
I'll drop the ctrl->faulted early return from cbqri_bc_alloc_op(),
cbqri_cc_alloc_op() and cbqri_mon_op() to avoid locking the controller
out for the lifetime of the driver.
> > +static int cbqri_apply_bc_field(struct cbqri_controller *ctrl, u32 closid,
> > + void (*set)(struct cbqri_controller *, u64),
> > + u64 (*get)(struct cbqri_controller *),
> > + u64 val, bool *committed)
> > +{
> > + int ret;
> > + u64 reg;
> > +
> > + lockdep_assert_held(&ctrl->lock);
> > +
> > + /* Load current RCID state so the unmodified field is preserved */
> > + ret = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, closid);
> > + if (ret < 0)
> > + return ret;
>
> Does this initial read need the same sentinel protection as the
> verification read? If this READ_LIMIT silently fails, the staging
> register might retain data from a previous operation (like a different
> RCID). Since set() only modifies the target field, CONFIG_LIMIT could
> commit the stale data in the unmodified field, causing cross-RCID state
> corruption.
I'll stop relying on the register to preserve the unmodified field. I
will add an mweight_cache alongside rbwb_cache.
> > + reg = get(ctrl);
> > + if (reg != val) {
> > + pr_err_ratelimited("BC field verify mismatch (reg=0x%llx != val=%llu)\n",
> > + reg, val);
> > + return -EIO;
> > + }
> > +
> > + return 0;
> > +}
>
> If the verification fails here and returns -EIO, *committed remains
> true. When called from cbqri_apply_rbwb(), this causes the rejected
> value to be cached in ctrl->rbwb_cache[closid]. If the requested value
> was smaller than the previous one, could this cause the software cache
> to underestimate the reserved capacity and allow future allocations to
> exceed the MRBWB hardware limit?
I'll change the order so that committed is only set to true after the
verify readback succeeds.
> > +int cbqri_apply_mweight_config(struct cbqri_controller *ctrl, u32 closid,
> > + u64 mweight)
> > +{
> > + int ret;
> > +
> > + mutex_lock(&ctrl->lock);
> > + ret = cbqri_apply_bc_field(ctrl, closid,
> > + cbqri_set_mweight, cbqri_get_mweight,
> > + mweight, NULL);
> > + mutex_unlock(&ctrl->lock);
> > + return ret;
> > +}
>
> What happens if an arbitrarily large mweight is passed in? FIELD_MODIFY
> silently truncates values larger than the 8-bit MWEIGHT_MASK. The
> verification step in cbqri_apply_bc_field() will then compare the
> truncated hardware value against the original untruncated val and
> always fail, returning -EIO and logging a hardware failure instead of
> returning -EINVAL. Should this have bounds checking similar to
> cbqri_apply_rbwb()?
I will bound mweight against FIELD_MAX(MWEIGHT_MASK) at the beginning.
>
> > @@ -437,6 +664,83 @@ static int cbqri_probe_cc(struct cbqri_controller *ctrl)
> > return 0;
> > }
> >
> > +static int cbqri_probe_bc(struct cbqri_controller *ctrl)
> > +{
> > + bool has_mon_at_code = false;
> > + int err, status;
> > + u64 reg;
>
> [ ... ]
>
> > + /* Probe monitoring features */
> > + err = cbqri_probe_feature(ctrl, CBQRI_BC_MON_CTL_OFF,
> > + CBQRI_BC_MON_CTL_OP_READ_COUNTER, &status,
> > + &has_mon_at_code);
>
> When probing features, cbqri_probe_feature() modifies the OP mask and
> clears RCID_MASK, but it doesn't appear to clear EVT_ID_MASK:
>
> drivers/resctrl/cbqri_devices.c:cbqri_probe_feature() {
> ...
> FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_OP_MASK, ®, operation);
> reg &= ~CBQRI_CONTROL_REGISTERS_RCID_MASK;
> iowrite64(reg, ctrl->base + reg_offset);
> ...
> }
>
> If the hardware or firmware left an unsupported Event ID in those bits,
> could the hardware reject the READ_COUNTER operation, causing the probe
> to see STATUS != SUCCESS and incorrectly assume monitoring is not
> supported?
I will clear OP, AT, RCID and EVT_ID on every write in the probe.
-Drew
More information about the linux-riscv
mailing list