[PATCH RFC v6 10/18] riscv_cbqri: Add bandwidth controller monitoring device ops
Drew Fustini <[email protected]> Mon, 01 Jun 2026 13:36:04 -0700
| Newsgroups | dev.linux.lists.acpica-devel,dev.linux.lists.linux-rt-devel,org.infradead.lists.linux-riscv,org.kernel.vger.linux-acpi,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Add the BC monitoring primitives. cbqri_init_bc_mon_counters() pre-arms each MCID with the TOTAL_READ_WRITE event and allocates the per-MCID software accumulator (struct cbqri_bc_mon_state) so subsequent reads can extend the 62-bit hardware counter to the 64-bit byte total resctrl expects. cbqri_bc_mon_overflow() recovers a single-wrap delta. The OVF bit signals multi-wrap and is the caller's concern. cbqri_find_only_mon_bc() returns NULL when zero or more than one mon-capable BC is present. A BC's counter can only accurately back L3 mbm_total_bytes when every memory request flows through that BC. Assisted-by: Claude:claude-opus-4-7 Co-developed-by: Adrien Ricciardi <[email protected]> Signed-off-by: Adrien Ricciardi <[email protected]> Signed-off-by: Drew Fustini <[email protected]> --- drivers/resctrl/cbqri_devices.c | 75 ++++++++++++++++++++++++++++++++++++++++ drivers/resctrl/cbqri_internal.h | 37 ++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/drivers/resctrl/cbqri_devices.c b/drivers/resctrl/cbqri_devices.c index 6093706b1ec4..b1a6ce35042a 100644 --- a/drivers/resctrl/cbqri_devices.c +++ b/drivers/resctrl/cbqri_devices.c @@ -905,6 +905,80 @@ int cbqri_init_mon_counters(struct cbqri_controller *ctrl) return 0; } +/* + * 62-bit BC counter delta. Inputs must be pre-masked to + * CBQRI_BC_MON_CTR_VAL_CTR_MASK. The shift promotes the modular + * subtraction into 64-bit so a single wrap (cur < prev) yields the + * correct delta. Multi-wrap is handled by the caller via the + * hardware OVF bit (CBQRI 4.3). This function only needs to recover + * from at most one wrap. + */ +u64 cbqri_bc_mon_overflow(u64 prev_ctr, u64 cur_ctr) +{ + const unsigned int shift = 64 - 62; + u64 chunks = (cur_ctr << shift) - (prev_ctr << shift); + + return chunks >> shift; +} + +/* + * Allocate the per-MCID software accumulator and pre-arm every MCID + * with TOTAL_READ_WRITE so subsequent reads just snapshot the live + * counter. + * + * Caller responsibility: serialize concurrent invocations on the same + * single mon-capable BC (cbqri_resctrl uses cbqri_domain_list_lock for + * this). + */ +int cbqri_init_bc_mon_counters(struct cbqri_controller *bc) +{ + int i, err; + + if (bc->mbm_total_states) + return 0; + + bc->mbm_total_states = kcalloc(bc->mcid_count, + sizeof(*bc->mbm_total_states), + GFP_KERNEL); + if (!bc->mbm_total_states) + return -ENOMEM; + + for (i = 0; i < bc->mcid_count; i++) { + mutex_lock(&bc->lock); + err = cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF, + CBQRI_BC_MON_CTL_OP_CONFIG_EVENT, + i, CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL); + mutex_unlock(&bc->lock); + if (err) { + kfree(bc->mbm_total_states); + bc->mbm_total_states = NULL; + return err; + } + } + return 0; +} + +/* + * Return the single mon-capable BC, NULL if zero or more than one. BC + * counters can only accurately surface as L3 mbm_total_bytes if every memory + * request flows through the same BC. + */ +struct cbqri_controller *cbqri_find_only_mon_bc(void) +{ + struct cbqri_controller *ctrl, *only_bc = NULL; + + list_for_each_entry(ctrl, &cbqri_controllers, list) { + if (ctrl->type != CBQRI_CONTROLLER_TYPE_BANDWIDTH) + continue; + if (!ctrl->mon_capable) + continue; + if (only_bc) + return NULL; + only_bc = ctrl; + } + return only_bc; +} + void cbqri_controller_destroy(struct cbqri_controller *ctrl) { /* @@ -916,6 +990,7 @@ void cbqri_controller_destroy(struct cbqri_controller *ctrl) iounmap(ctrl->base); release_mem_region(ctrl->addr, ctrl->size); } + kfree(ctrl->mbm_total_states); kfree(ctrl->mweight_cache); kfree(ctrl->rbwb_cache); kfree(ctrl); diff --git a/drivers/resctrl/cbqri_internal.h b/drivers/resctrl/cbqri_internal.h index 4f806689d503..68a40f846f40 100644 --- a/drivers/resctrl/cbqri_internal.h +++ b/drivers/resctrl/cbqri_internal.h @@ -69,8 +69,17 @@ #define CBQRI_CC_MON_CTL_OP_CONFIG_EVENT 1 #define CBQRI_CC_MON_CTL_OP_READ_COUNTER 2 +#define CBQRI_BC_MON_CTL_OP_CONFIG_EVENT 1 #define CBQRI_BC_MON_CTL_OP_READ_COUNTER 2 +/* Bandwidth usage monitoring event IDs (CBQRI spec Table 10) */ +#define CBQRI_BC_EVT_ID_TOTAL_READ_WRITE 1 + +/* bc_mon_ctr_val layout (CBQRI spec section 4.3, Figure 7) */ +#define CBQRI_BC_MON_CTR_VAL_CTR_MASK GENMASK_ULL(61, 0) +#define CBQRI_BC_MON_CTR_VAL_INVALID BIT_ULL(62) +#define CBQRI_BC_MON_CTR_VAL_OVF BIT_ULL(63) + /* mon_ctl field masks (CC and BC share an identical OP/MCID/EVT_ID/STATUS layout) */ #define CBQRI_MON_CTL_OP_MASK GENMASK_ULL(4, 0) #define CBQRI_MON_CTL_MCID_MASK GENMASK_ULL(19, 8) @@ -96,6 +105,19 @@ struct riscv_cbqri_bandwidth_caps { bool supports_alloc_at_code; }; +/** + * struct cbqri_bc_mon_state - per-MCID software accumulator for BC bandwidth + * @prev_ctr: previous 62-bit hardware snapshot (already masked to CTR field) + * @chunks: accumulated 64-bit byte total across hardware wraparounds + * + * Updated in resctrl_arch_rmid_read() under cbqri_controller::lock and + * zeroed by resctrl_arch_reset_rmid(). + */ +struct cbqri_bc_mon_state { + u64 prev_ctr; + u64 chunks; +}; + /** * enum cbqri_at - capacity controller access type for CDP * @CBQRI_AT_DATA: data access (CBQRI Table 1, AT=0) @@ -165,6 +187,15 @@ struct cbqri_controller { u16 *rbwb_cache; u8 *mweight_cache; + /* + * Per-MCID 64-bit software accumulator for the BC's mbm_total_bytes + * event. Allocated by cbqri_init_bc_mon_counters() when this BC is + * paired with an L3 monitoring domain, sized by ->mcid_count. NULL + * on capacity controllers and on BCs that are not mon-paired. + * Protected by ->lock along with the surrounding MMIO sequence. + */ + struct cbqri_bc_mon_state *mbm_total_states; + struct list_head list; struct cache_controller { @@ -207,4 +238,10 @@ int cbqri_read_rbwb(struct cbqri_controller *ctrl, u32 closid, u64 *rbwb_out); int cbqri_read_mweight(struct cbqri_controller *ctrl, u32 closid, u64 *mweight_out); +u64 cbqri_bc_mon_overflow(u64 prev_ctr, u64 cur_ctr); + +int cbqri_init_bc_mon_counters(struct cbqri_controller *bc); + +struct cbqri_controller *cbqri_find_only_mon_bc(void); + #endif /* _DRIVERS_RESCTRL_CBQRI_INTERNAL_H */ -- 2.43.0