[PATCH RFC v3 04/11] RISC-V: QoS: add CBQRI hardware interface
Drew Fustini <[email protected]>
| Newsgroups | dev.linux.lists.acpica-devel,org.infradead.lists.linux-riscv,org.kernel.vger.linux-acpi,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Add the CBQRI controller hardware interface layer. Define data structures representing CBQRI controller properties (cbqri_controller) and hardware capabilities for capacity and bandwidth controllers (riscv_cbqri_capacity_caps, riscv_cbqri_bandwidth_caps) in include/linux/riscv_qos.h. Define MMIO register offsets, field masks, and internal wrapper structs (cbqri_resctrl_res, cbqri_resctrl_dom, cbqri_config) in internal.h. Implement MMIO helpers for capacity block mask and bandwidth reservation, alloc control operations for capacity and bandwidth controllers, and probe functions to discover controller capabilities. A per-controller spinlock serializes multi-step MMIO sequences. Co-developed-by: Adrien Ricciardi <[email protected]> Signed-off-by: Adrien Ricciardi <[email protected]> Signed-off-by: Drew Fustini <[email protected]> --- MAINTAINERS | 1 + arch/riscv/kernel/qos/internal.h | 81 +++++++ arch/riscv/kernel/qos/qos_resctrl.c | 432 ++++++++++++++++++++++++++++++++++++ include/linux/riscv_qos.h | 76 +++++++ 4 files changed, 590 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b17f885411ba..6a66d7047c51 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22785,6 +22785,7 @@ L: [email protected] S: Supported F: arch/riscv/include/asm/qos.h F: arch/riscv/kernel/qos/ +F: include/linux/riscv_qos.h RISC-V RPMI AND MPXY DRIVERS M: Rahul Pathak <[email protected]> diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h new file mode 100644 index 000000000000..edbcbd9471b1 --- /dev/null +++ b/arch/riscv/kernel/qos/internal.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_RISCV_QOS_INTERNAL_H +#define _ASM_RISCV_QOS_INTERNAL_H + +#include <linux/bitfield.h> +#include <linux/resctrl.h> +#include <linux/riscv_qos.h> + +#define RISCV_RESCTRL_EMPTY_CLOSID ((u32)~0) + +#define CBQRI_CC_CAPABILITIES_OFF 0 +#define CBQRI_CC_MON_CTL_OFF 8 +#define CBQRI_CC_MON_CTL_VAL_OFF 16 +#define CBQRI_CC_ALLOC_CTL_OFF 24 +#define CBQRI_CC_BLOCK_MASK_OFF 32 + +#define CBQRI_BC_CAPABILITIES_OFF 0 +#define CBQRI_BC_MON_CTL_OFF 8 +#define CBQRI_BC_MON_CTR_VAL_OFF 16 +#define CBQRI_BC_ALLOC_CTL_OFF 24 +#define CBQRI_BC_BW_ALLOC_OFF 32 + +#define CBQRI_CC_CAPABILITIES_VER_MINOR_MASK GENMASK(3, 0) +#define CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK GENMASK(7, 4) + +#define CBQRI_CC_CAPABILITIES_NCBLKS_MASK GENMASK(23, 8) +#define CBQRI_CC_CAPABILITIES_FRCID_MASK GENMASK(24, 24) + +#define CBQRI_BC_CAPABILITIES_VER_MINOR_MASK GENMASK(3, 0) +#define CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK GENMASK(7, 4) + +#define CBQRI_BC_CAPABILITIES_NBWBLKS_MASK GENMASK(23, 8) +#define CBQRI_BC_CAPABILITIES_MRBWB_MASK GENMASK_ULL(47, 32) + +#define CBQRI_CONTROL_REGISTERS_OP_MASK GENMASK(4, 0) +#define CBQRI_CONTROL_REGISTERS_AT_MASK GENMASK(7, 5) +#define CBQRI_CONTROL_REGISTERS_AT_DATA 0 +#define CBQRI_CONTROL_REGISTERS_AT_CODE 1 +#define CBQRI_CONTROL_REGISTERS_RCID_MASK GENMASK(19, 8) +#define CBQRI_CONTROL_REGISTERS_STATUS_MASK GENMASK_ULL(38, 32) +#define CBQRI_CONTROL_REGISTERS_BUSY_MASK GENMASK_ULL(39, 39) +#define CBQRI_CONTROL_REGISTERS_RBWB_MASK GENMASK(15, 0) + +#define CBQRI_CC_MON_CTL_OP_CONFIG_EVENT 1 +#define CBQRI_CC_MON_CTL_OP_READ_COUNTER 2 +#define CBQRI_CC_MON_CTL_STATUS_SUCCESS 1 + +#define CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT 1 +#define CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT 2 +#define CBQRI_CC_ALLOC_CTL_OP_FLUSH_RCID 3 +#define CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS 1 + +#define CBQRI_BC_MON_CTL_OP_CONFIG_EVENT 1 +#define CBQRI_BC_MON_CTL_OP_READ_COUNTER 2 +#define CBQRI_BC_MON_CTL_STATUS_SUCCESS 1 + +#define CBQRI_BC_ALLOC_CTL_OP_CONFIG_LIMIT 1 +#define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2 +#define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1 + +int qos_resctrl_setup(void); +int qos_resctrl_online_cpu(unsigned int cpu); +int qos_resctrl_offline_cpu(unsigned int cpu); + +struct cbqri_resctrl_res { + struct rdt_resource resctrl_res; + u32 max_rcid; + u32 max_mcid; +}; + +struct cbqri_resctrl_dom { + struct rdt_ctrl_domain resctrl_ctrl_dom; + struct cbqri_controller *hw_ctrl; +}; + +struct cbqri_config { + u64 cbm; /* capacity block mask */ + u64 rbwb; /* reserved bandwidth blocks */ +}; + +#endif /* _ASM_RISCV_QOS_INTERNAL_H */ diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c new file mode 100644 index 000000000000..6d294f2f2504 --- /dev/null +++ b/arch/riscv/kernel/qos/qos_resctrl.c @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) "qos: resctrl: " fmt + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> +#include <linux/resctrl.h> +#include <linux/riscv_qos.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <asm/csr.h> +#include <asm/qos.h> +#include "internal.h" + +static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES]; + +static bool exposed_alloc_capable; +/* CDP (code data prioritization) on x86 is AT (access type) on RISC-V */ +static bool exposed_cdp_l2_capable; +static bool exposed_cdp_l3_capable; +static bool is_cdp_l2_enabled; +static bool is_cdp_l3_enabled; + +/* used by resctrl_arch_system_num_rmid_idx() */ +static u32 max_rmid; + +LIST_HEAD(cbqri_controllers); + +static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset, + u64 *regp); + +/* Set capacity block mask (cc_block_mask) */ +static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm) +{ + iowrite64(cbm, ctrl->base + CBQRI_CC_BLOCK_MASK_OFF); +} + +/* Set the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */ +static void cbqri_set_rbwb(struct cbqri_controller *ctrl, u64 rbwb) +{ + u64 reg; + + reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF); + reg &= ~CBQRI_CONTROL_REGISTERS_RBWB_MASK; + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_RBWB_MASK, rbwb); + iowrite64(reg, ctrl->base + CBQRI_BC_BW_ALLOC_OFF); +} + +/* Get the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */ +static u64 cbqri_get_rbwb(struct cbqri_controller *ctrl) +{ + u64 reg; + + reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF); + return FIELD_GET(CBQRI_CONTROL_REGISTERS_RBWB_MASK, reg); +} + +static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset, + u64 *regp) +{ + u64 reg; + int ret; + + ret = readq_poll_timeout_atomic(ctrl->base + reg_offset, reg, + !FIELD_GET(CBQRI_CONTROL_REGISTERS_BUSY_MASK, reg), + 0, 1000); + if (!ret && regp) + *regp = reg; + + return ret; +} + +/* Perform capacity allocation control operation on capacity controller */ +static int cbqri_cc_alloc_op(struct cbqri_controller *ctrl, int operation, int rcid, + enum resctrl_conf_type type) +{ + int reg_offset = CBQRI_CC_ALLOC_CTL_OFF; + int status; + u64 reg; + + reg = ioread64(ctrl->base + reg_offset); + reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK; + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation); + reg &= ~CBQRI_CONTROL_REGISTERS_RCID_MASK; + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_RCID_MASK, rcid); + + /* CBQRI capacity AT is only supported on L2 and L3 caches for now */ + if (ctrl->type == CBQRI_CONTROLLER_TYPE_CAPACITY && + ((ctrl->cache.cache_level == 2 && is_cdp_l2_enabled) || + (ctrl->cache.cache_level == 3 && is_cdp_l3_enabled))) { + reg &= ~CBQRI_CONTROL_REGISTERS_AT_MASK; + switch (type) { + case CDP_CODE: + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK, + CBQRI_CONTROL_REGISTERS_AT_CODE); + break; + case CDP_DATA: + default: + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK, + CBQRI_CONTROL_REGISTERS_AT_DATA); + break; + } + } + + iowrite64(reg, ctrl->base + reg_offset); + + if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) { + pr_err("%s(): BUSY timeout when executing the operation\n", __func__); + return -EIO; + } + + status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg); + if (status != CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) { + pr_err("%s(): operation %d failed: status=%d\n", __func__, operation, status); + return -EIO; + } + + return 0; +} + +/* + * Write a capacity block mask and verify the hardware accepted it by + * reading back the value after a CONFIG_LIMIT + READ_LIMIT sequence. + */ +static int cbqri_apply_cache_config(struct cbqri_resctrl_dom *hw_dom, u32 closid, + enum resctrl_conf_type type, struct cbqri_config *cfg) +{ + struct cbqri_controller *ctrl = hw_dom->hw_ctrl; + int err = 0; + u64 reg; + + spin_lock(&ctrl->lock); + + /* Set capacity block mask (cc_block_mask) */ + cbqri_set_cbm(ctrl, cfg->cbm); + + /* Capacity config limit operation */ + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, closid, type); + if (err < 0) { + pr_err("%s(): operation failed: err = %d\n", __func__, err); + goto out; + } + + /* Clear cc_block_mask before read limit to verify op works */ + cbqri_set_cbm(ctrl, 0); + + /* Perform a capacity read limit operation to verify blockmask */ + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, type); + if (err < 0) { + pr_err("%s(): operation failed: err = %d\n", __func__, err); + goto out; + } + + /* Read capacity blockmask to verify it matches the requested config */ + reg = ioread64(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF); + if (reg != cfg->cbm) { + pr_err("%s(): failed to verify allocation (reg:%llx != cbm:%llx)\n", + __func__, reg, cfg->cbm); + err = -EIO; + } + +out: + spin_unlock(&ctrl->lock); + return err; +} + +/* Perform bandwidth allocation control operation on bandwidth controller */ +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; + + reg = ioread64(ctrl->base + reg_offset); + reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK; + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation); + reg &= ~CBQRI_CONTROL_REGISTERS_RCID_MASK; + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_RCID_MASK, rcid); + iowrite64(reg, ctrl->base + reg_offset); + + if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) { + pr_err("%s(): BUSY timeout when executing the operation\n", __func__); + return -EIO; + } + + status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg); + if (status != CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) { + pr_err("%s(): operation %d failed with status = %d\n", + __func__, operation, status); + return -EIO; + } + + return 0; +} + +/* + * Write a bandwidth reservation and verify the hardware accepted it by + * reading back the value after a CONFIG_LIMIT + READ_LIMIT sequence. + */ +static int cbqri_apply_bw_config(struct cbqri_resctrl_dom *hw_dom, u32 closid, + enum resctrl_conf_type type, struct cbqri_config *cfg) +{ + struct cbqri_controller *ctrl = hw_dom->hw_ctrl; + int ret = 0; + u64 reg; + + spin_lock(&ctrl->lock); + + /* Set reserved bandwidth blocks */ + cbqri_set_rbwb(ctrl, cfg->rbwb); + + /* Bandwidth config limit operation */ + ret = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_CONFIG_LIMIT, closid); + if (ret < 0) { + pr_err("%s(): operation failed: ret = %d\n", __func__, ret); + goto out; + } + + /* Clear rbwb before read limit to verify op works */ + cbqri_set_rbwb(ctrl, 0); + + /* Bandwidth allocation read limit operation to verify */ + ret = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, closid); + if (ret < 0) + goto out; + + /* Read bandwidth allocation to verify it matches the requested config */ + reg = cbqri_get_rbwb(ctrl); + if (reg != cfg->rbwb) { + pr_err("%s(): failed to verify allocation (reg:%llx != rbwb:%llu)\n", + __func__, reg, cfg->rbwb); + ret = -EIO; + } + +out: + spin_unlock(&ctrl->lock); + return ret; +} + +static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset, + int operation, int *status, bool *access_type_supported) +{ + u64 reg, saved_reg; + int at; + + /* Keep the initial register value to preserve the WPRI fields */ + reg = ioread64(ctrl->base + reg_offset); + saved_reg = reg; + + /* Execute the requested operation to find if the register is implemented */ + reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK; + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation); + iowrite64(reg, ctrl->base + reg_offset); + if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) { + pr_err("%s(): BUSY timeout when executing the operation\n", __func__); + return -EIO; + } + + /* Get the operation status */ + *status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg); + + /* + * Check for the AT support if the register is implemented + * (if not, the status value will remain 0) + */ + if (*status != 0) { + /* Set the AT field to a valid value */ + reg = saved_reg; + reg &= ~CBQRI_CONTROL_REGISTERS_AT_MASK; + reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK, + CBQRI_CONTROL_REGISTERS_AT_CODE); + iowrite64(reg, ctrl->base + reg_offset); + if (cbqri_wait_busy_flag(ctrl, reg_offset, ®) < 0) { + pr_err("%s(): BUSY timeout when setting AT field\n", __func__); + return -EIO; + } + + /* + * If the AT field value has been reset to zero, + * then the AT support is not present + */ + at = FIELD_GET(CBQRI_CONTROL_REGISTERS_AT_MASK, reg); + if (at == CBQRI_CONTROL_REGISTERS_AT_CODE) + *access_type_supported = true; + else + *access_type_supported = false; + } + + /* Restore the original register value */ + iowrite64(saved_reg, ctrl->base + reg_offset); + if (cbqri_wait_busy_flag(ctrl, reg_offset, NULL) < 0) { + pr_err("%s(): BUSY timeout when restoring the original register value\n", __func__); + return -EIO; + } + + return 0; +} + +static int cbqri_probe_cc(struct cbqri_controller *ctrl) +{ + int err, status; + u64 reg; + + reg = ioread64(ctrl->base + CBQRI_CC_CAPABILITIES_OFF); + if (reg == 0) + return -ENODEV; + + ctrl->ver_minor = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MINOR_MASK, reg); + ctrl->ver_major = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK, reg); + ctrl->cc.supports_alloc_op_flush_rcid = + FIELD_GET(CBQRI_CC_CAPABILITIES_FRCID_MASK, reg); + ctrl->cc.ncblks = FIELD_GET(CBQRI_CC_CAPABILITIES_NCBLKS_MASK, reg); + + pr_debug("version=%d.%d ncblks=%d cache_level=%d\n", + ctrl->ver_major, ctrl->ver_minor, + ctrl->cc.ncblks, ctrl->cache.cache_level); + + /* Probe allocation features (monitoring not yet implemented) */ + err = cbqri_probe_feature(ctrl, CBQRI_CC_ALLOC_CTL_OFF, + CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, + &status, &ctrl->cc.supports_alloc_at_code); + if (err) + return err; + + if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) { + ctrl->alloc_capable = true; + exposed_alloc_capable = true; + } + + return 0; +} + +static int cbqri_probe_bc(struct cbqri_controller *ctrl) +{ + int err, status; + u64 reg; + + reg = ioread64(ctrl->base + CBQRI_BC_CAPABILITIES_OFF); + if (reg == 0) + return -ENODEV; + + ctrl->ver_minor = FIELD_GET(CBQRI_BC_CAPABILITIES_VER_MINOR_MASK, reg); + ctrl->ver_major = FIELD_GET(CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK, reg); + ctrl->bc.nbwblks = FIELD_GET(CBQRI_BC_CAPABILITIES_NBWBLKS_MASK, reg); + ctrl->bc.mrbwb = FIELD_GET(CBQRI_BC_CAPABILITIES_MRBWB_MASK, reg); + + if (!ctrl->bc.nbwblks) { + pr_err("bandwidth controller has nbwblks=0\n"); + return -EINVAL; + } + + pr_debug("version=%d.%d nbwblks=%d mrbwb=%d\n", + ctrl->ver_major, ctrl->ver_minor, + ctrl->bc.nbwblks, ctrl->bc.mrbwb); + + /* Probe allocation features (monitoring not yet implemented) */ + err = cbqri_probe_feature(ctrl, CBQRI_BC_ALLOC_CTL_OFF, + CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, + &status, &ctrl->bc.supports_alloc_at_code); + if (err) + return err; + + if (status == CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) { + ctrl->alloc_capable = true; + exposed_alloc_capable = true; + } + + return 0; +} + +static int cbqri_probe_controller(struct cbqri_controller *ctrl) +{ + int err; + + pr_debug("controller info: type=%d addr=%pa size=%pa max-rcid=%u max-mcid=%u\n", + ctrl->type, &ctrl->addr, &ctrl->size, + ctrl->rcid_count, ctrl->mcid_count); + + if (!ctrl->addr) { + pr_warn("%s(): controller has invalid addr=0x0, skipping\n", __func__); + return -EINVAL; + } + + if (!request_mem_region(ctrl->addr, ctrl->size, "cbqri_controller")) { + pr_err("%s(): request_mem_region failed for %pa\n", + __func__, &ctrl->addr); + return -EBUSY; + } + + ctrl->base = ioremap(ctrl->addr, ctrl->size); + if (!ctrl->base) { + pr_err("%s(): ioremap failed for %pa\n", __func__, &ctrl->addr); + err = -ENOMEM; + goto err_release; + } + + spin_lock_init(&ctrl->lock); + + switch (ctrl->type) { + case CBQRI_CONTROLLER_TYPE_CAPACITY: + err = cbqri_probe_cc(ctrl); + break; + case CBQRI_CONTROLLER_TYPE_BANDWIDTH: + err = cbqri_probe_bc(ctrl); + break; + default: + pr_err("unknown controller type %d\n", ctrl->type); + err = -ENODEV; + break; + } + + if (err) + goto err_iounmap; + + /* + * max_rmid is used by resctrl_arch_system_num_rmid_idx() + * Find the smallest mcid_count amongst all controllers. + */ + max_rmid = min(max_rmid, ctrl->mcid_count); + + return 0; + +err_iounmap: + iounmap(ctrl->base); + ctrl->base = NULL; +err_release: + release_mem_region(ctrl->addr, ctrl->size); + return err; +} diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h new file mode 100644 index 000000000000..0f3daae2e84f --- /dev/null +++ b/include/linux/riscv_qos.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __LINUX_RISCV_QOS_H +#define __LINUX_RISCV_QOS_H + +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <asm/qos.h> + +enum cbqri_controller_type { + CBQRI_CONTROLLER_TYPE_CAPACITY, + CBQRI_CONTROLLER_TYPE_BANDWIDTH, + CBQRI_CONTROLLER_TYPE_UNKNOWN +}; + +/* Capacity Controller hardware capabilities */ +struct riscv_cbqri_capacity_caps { + u16 ncblks; /* number of capacity blocks */ + + bool supports_alloc_at_code; + bool supports_alloc_op_flush_rcid; +}; + +/* Bandwidth Controller hardware capabilities */ +struct riscv_cbqri_bandwidth_caps { + u16 nbwblks; /* number of bandwidth blocks */ + u16 mrbwb; /* max reserved bw blocks */ + + bool supports_alloc_at_code; +}; + +struct cbqri_controller { + void __iomem *base; + /* + * Protects multi-step MMIO register sequences on this controller. + * CBQRI operations (e.g. CONFIG_LIMIT, READ_LIMIT) require writing + * an operation register, waiting for the busy flag to clear, then + * reading back the result. These sequences must be atomic per + * controller to prevent interleaving. + */ + spinlock_t lock; + + int ver_major; + int ver_minor; + + struct riscv_cbqri_bandwidth_caps bc; + struct riscv_cbqri_capacity_caps cc; + + bool alloc_capable; + + phys_addr_t addr; + phys_addr_t size; + enum cbqri_controller_type type; + u32 rcid_count; + u32 mcid_count; + struct list_head list; + + struct cache_controller { + u32 cache_level; + u32 cache_size; /* in bytes */ + struct cpumask cpu_mask; + /* Unique Cache ID from the PPTT table's Cache Type Structure */ + u32 cache_id; + } cache; + + struct mem_controller { + /* Proximity Domain from SRAT table Memory Affinity Controller */ + u32 prox_dom; + struct cpumask cpu_mask; + } mem; +}; + +extern struct list_head cbqri_controllers; + +#endif /* __LINUX_RISCV_QOS_H */ -- 2.43.0