2026-02-01T15:58:10-08:00, Drew Fustini <[email protected]>:
> From: Nicolas Pitre <[email protected]>
>
> Implement a bandwidth controller according to the Capacity and Bandwidth
> QoS Register Interface (CBQRI) which supports these capabilities:
>
> - Number of access types: 2 (code and data)
> - Usage monitoring operations: CONFIG_EVENT, READ_COUNTER
> - Event IDs supported: None, Total read/write byte count, Total
> read byte count, Total write byte count
> - Bandwidth allocation operations: CONFIG_LIMIT, READ_LIMIT
>
> Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> Signed-off-by: Nicolas Pitre <[email protected]>
> [fustini: add fields introduced in the ratified spec: rpfx and p]
> Signed-off-by: Drew Fustini <[email protected]>
> ---
> diff --git a/hw/riscv/cbqri_bandwidth.c b/hw/riscv/cbqri_bandwidth.c
> [...]
> +static uint32_t bandwidth_config(RiscvCbqriBandwidthState *bc,
> + uint32_t rcid, uint32_t at,
> + bool *busy)
> +{
> + BandwidthAllocation *bw_alloc = get_bw_alloc(bc, rcid, at);
> +
> + /*
> + * Bandwidth is allocated in multiples of bandwidth blocks, and the
> + * value in Rbwb must be at least 1 and must not exceed MRBWB value.
> + */
> + if (bc->bw_allocations[0].Rbwb < 1) {
> + return BC_ALLOC_STATUS_INVAL_OP;
> + } else if (bc->bw_allocations[0].Rbwb > bc->mrbwb) {
> + return BC_ALLOC_STATUS_INVAL_OP;
> + }
"the sum of Rbwb allocated across all RCIDs must not exceed MRBWB".
> [...]
> +static void riscv_cbqri_bc_write_mon_ctl(RiscvCbqriBandwidthState *bc,
> + uint64_t value)
> +{
> [...]
> + if (mcid >= bc->nb_mcids) {
> + status = BC_MON_CTL_STATUS_INVAL_MCID;
> + } else if (op == BC_MON_OP_CONFIG_EVENT &&
> + bc->supports_mon_op_config_event) {
> + if (evt_id == BC_EVT_ID_None &&
> + bc->supports_mon_evt_id_none) {
> + bc->mon_counters[mcid].active = false;
> + status = BC_MON_CTL_STATUS_SUCCESS;
> + } else if ((evt_id == BC_EVT_ID_RDWR_count &&
> + bc->supports_mon_evt_id_rdwr_count) ||
> + (evt_id == BC_EVT_ID_RDONLY_count &&
> + bc->supports_mon_evt_id_rdonly_count) ||
> + (evt_id == BC_EVT_ID_WRONLY_count &&
> + bc->supports_mon_evt_id_wronly_count)) {
> + if (atv && !is_valid_at(bc, at)) {
> + status = BC_MON_CTL_STATUS_INVAL_AT;
> + } else {
> + bc->mon_counters[mcid].ctr_val =
> + FIELD_DP64(0, BC_MON_CTR_VAL, INVALID, 1);
This caught my attention even in the capacity controller.
Maybe a it's worth a short comment that we set INVALID, because we don't
actually do any bookkeeping?
> [...]
> +DeviceState *riscv_cbqri_bc_create(hwaddr addr,
> + const RiscvCbqriBandwidthCaps *caps,
> + const char *target_name)
> +{
> + DeviceState *dev = qdev_new(TYPE_RISCV_CBQRI_BC);
> +
> + qdev_prop_set_uint64(dev, "mmio_base", addr);
> + qdev_prop_set_string(dev, "target", target_name);
> + qdev_prop_set_uint16(dev, "max_mcids", caps->nb_mcids);
> + qdev_prop_set_uint16(dev, "max_rcids", caps->nb_rcids);
> + qdev_prop_set_uint16(dev, "nbwblks", caps->nbwblks);
Missing mrbwb.
Thanks.