* [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface
@ 2026-01-28 20:27 Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 01/17] dt-bindings: riscv: Add Ssqosid extension description Drew Fustini
` (16 more replies)
0 siblings, 17 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree, Conor Dooley
This RFC series implements the RISC-V Quality-of-Service Identifiers
(Ssqosid) extension [1] which adds the srmcfg register. It also
implements the RISC-V Capacity and Bandwidth Controller QoS Register
Interface (CBQRI) specification [2] and integrates resctrl [3] support.
The patches are also available as a branch [4].
There is a Qemu patch series [5] that implements Ssqosid and CBQRI, and
a corresponding Qemu branch with those patches too [6]. ACPI RQSC
support [7] is imeplemented as a set of additional patches [8].
[1] https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
[2] https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
[3] https://docs.kernel.org/filesystems/resctrl.html
[4] https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git/log/?h=b4/ssqosid-cbqri
[5] https://lore.kernel.org/qemu-devel/20260105-riscv-ssqosid-cbqri-v4-0-9ad7671dde78@kernel.org/
[6] https://github.com/tt-fustini/qemu/tree/b4/riscv-ssqosid-cbqri
[7] https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
[8] https://github.com/tt-fustini/qemu/tree/b4/riscv-rqsc
RISC-V QoS
----------
QoS (Quality of Service) in this context is concerned with shared
resources on an SoC such as cache capacity and memory bandwidth.
The Sssqosid extension defines the srmcfg CSR which configures a hart
with two identifiers:
- Resource Control ID (RCID)
- Monitoring Counter ID (MCID)
These identifiers accompany each request issued by the hart to shared
resource controllers. This allows the capacity and bandwidth resources
used by a software workload (e.g. a process or a set of processes) to be
controlled and monitored.
CBQRI defines operations to configure resource usage limits, in the form
of capacity or bandwidth, for an RCID. CBQRI also defines operations to
configure counters to track resource utilization per MCID. Furthermore,
the Access Type (AT) field allows resource usage to be differentiated
between data and code.
x86 comparison
--------------
The existing QoS identifiers on x86 map well:
CLOSID (Class of Service ID) on x86 is RCID on RISC-V
RMID (Resource Monitoring ID) on x86 is MCID on RISC-V
In addition, CDP (code data prioritization) on x86 is similar to the
AT (access type) field in CBQRI which defines code and data types.
One aspect of CBQRI that simplifies the RISC-V resctrl interface is that
any cpu (technically a hart, or hardware thread, in RISC-V terminology)
can access the memory-mapped registers of any CBQRI controller in the
system. This means it does not matter which cpu runs the resctrl code.
Example SoC
-----------
This series was developed and tested using the Qemu virt platform [8]
configured as a hypothetical SoC with a cache controller that implements
CBQRI capacity operations and a memory controller that implements CBQRI
bandwidth operations.
- L2 cache controllers
- Resource type: Capacity
- Number of capacity blocks (NCBLKS): 12
- In the context of a set-associative cache, the number of
capacity blocks can be thought of as the number of ways
- Number of access types: 2 (code and data)
- Usage monitoring not supported
- Capacity allocation operations: CONFIG_LIMIT, READ_LIMIT
- Last-level cache (LLC) controller
- Resource type: Capacity
- Number of capacity blocks (NCBLKS): 16
- Number of access types: 2 (code and data)
- Usage monitoring operations: CONFIG_EVENT, READ_COUNTER
- Event IDs supported: None, Occupancy
- Capacity allocation ops: CONFIG_LIMIT, READ_LIMIT, FLUSH_RCID
- Memory controllers
- Resource type: Bandwidth
- Number of bandwidth blocks (NBWBLKS): 1024
- Bandwidth blocks do not have a unit but instead represent a
portion of the total bandwidth resource. For NWBLKS of 1024,
each block represents about 0.1% of the bandwidth resource.
- Maximum reserved bandwidth blocks (MRBWB): 819 (80% of NBWBLKS)
- Number of access types: 1 (no code/data differentiation)
- 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
The memory map for this example SoC:
Base addr Size
0x4820000 4KB Cluster 0 L2 cache controller
0x4821000 4KB Cluster 1 L2 cache controller
0x4828000 4KB Memory controller 0
0x4829000 4KB Memory controller 1
0X482a000 4KB Memory controller 2
0X482b000 4KB Shared LLC cache controller
This configuration is only meant to provide a "concrete" example, and it
represents just one of many possible ways that hardware can implement
the CBQRI spec.
The example SoC configuration is created with the following:
qemu-system-riscv64 \
-M virt,pflash0=pflash0,pflash1=pflash1,aia=aplic-imsic \
-smp cpus=8,sockets=1,clusters=2,cores=4,threads=1 \
-m 1G \
-nographic \
-kernel ${LINUX}/arch/riscv/boot/Image \
-append "root=/dev/vda rootwait" \
-blockdev node-name=pflash0,driver=file,read-only=on,filename=${EDK}/RISCV_VIRT_CODE.fd \
-blockdev node-name=pflash1,driver=file,filename=${EDK}/RISCV_VIRT_VARS.fd \
-drive if=none,file=${ROOTFS}/rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-device qemu-xhci \
-device usb-kbd \
-device virtio-net-pci,netdev=net0 \
-netdev user,id=net0 \
-device riscv.cbqri.capacity,max_mcids=256,max_rcids=64,ncblks=12,alloc_op_flush_rcid=false,mon_op_config_event=false,mon_op_read_counter=false,mon_evt_id_none=false,mon_evt_id_occupancy=false,mmio_base=0x04820000 \
-device riscv.cbqri.capacity,max_mcids=256,max_rcids=64,ncblks=12,alloc_op_flush_rcid=false,mon_op_config_event=false,mon_op_read_counter=false,mon_evt_id_none=false,mon_evt_id_occupancy=false,mmio_base=0x04821000 \
-device riscv.cbqri.capacity,max_mcids=256,max_rcids=64,ncblks=16,mmio_base=0x0482B000 \
-device riscv.cbqri.bandwidth,max_mcids=256,max_rcids=64,nbwblks=1024,mrbwb=819,mmio_base=0x04828000 \
-device riscv.cbqri.bandwidth,max_mcids=256,max_rcids=64,nbwblks=1024,mrbwb=819,mmio_base=0x04829000 \
-device riscv.cbqri.bandwidth,max_mcids=256,max_rcids=64,nbwblks=1024,mrbwb=819,mmio_base=0x0482a000
Versions
--------
Changes in v2:
- Add support for ACPI RQSC table which provides the details needed to
discover the CBQRI controllers and support resctrl
- Drop the "not for upstream" platform drivers and qemu dts patches.
Those can be found in v1 and were only for the RFC series. The
branch for the v1 series is preserved as ssqosid-cbqri-rfc-v1
- Change cbqri_wait_busy_flag() from 100 ms to 1 ms to avoid
unnecessary latency.
- Change resctrl_arch_get_config() to return resctrl_get_default_ctrl()
instead of a negative errno value which is not valid for u32.
- Change cbqri_probe_controller() to return -EBUSY when
request_mem_region() fails
- Change resctrl_arch_get_config() to now longer increment when rbwb
modulo ctrl->bc.nbwblks is true
- Fix indentation in cbqri_set_cbm(), cbqri_set_rbwb() and
cbqri_get_rbwb().
- Link to v1: https://lore.kernel.org/r/20260119-ssqosid-cbqri-v1-0-aa2a75153832@kernel.org
Older related series for reference:
[RFC PATCH 00/21] RISC-V: QoS: add CBQRI resctrl interface
https://lore.kernel.org/all/20230419111111.477118-1-dfustini@baylibre.com/
The original RFC from the CBQRI proof-of-concept in 2023 that worked
in conjunction with the Qemu patch series for the proof-of-concept.
[PATCH v4 0/3] RISC-V: Detect Ssqosid extension and handle srmcfg CSR
https://lore.kernel.org/all/20251007-ssqosid-v4-0-e8b57e59d812@kernel.org/
More recently I thought it would be simpler to upstream just the
Ssqosid patches first. However, I got feedback that it was hard to
review without the CBQRI patches in the same series.
Open issues:
------------
- Checkpatch false positive: there is a checkpatch warning about
"Argument '__next' is not used in function-like macro"
- __switch_to_srmcfg(__next) is needed to avoid the error reported
by LKP for riscv-allnoconfig:
https://lore.kernel.org/oe-kbuild-all/202509162355.wByessnb-lkp@intel.com/
- __switch_to_srmcfg() will trigger a build error in clang when
CONFIG_RISCV_ISA_SSQOSID is turned off.
- The number of CBQRI controllers is hard coded
- This was done as a simple approach in the proof-of-concept as there
were 6 controllers
- I need to refactor this so that it is dynamically allocated based
on the number of controllers present in the system
- Refactor or eliminate find_acpi_cache_from_id()
- find_acpi_cache_from_id is based on find_acpi_cache_level_from_id
in commit c4170570cc7f ("ACPI / PPTT: Find PPTT cache level by ID")
from the morse/mpam/snapshot/v6.14-rc1 branch.
- The version that of find_acpi_cache_level_from_id() that landed
upstream has changed so find_acpi_cache_from_id() needs to be
updated if it is going to remain in this patch series.
- However, there may be a simpler way for acpi_parse_rqsc() to get a
pointer to acpi_pptt_cache.
- No L2 and L3 cache occupancy monitoring
- This is not currently implemented and I have to decided to leave
it as an enhancement for a future series after the Ssqosid and
CBQRI core are merged.
- No MBM (bandwidth monitoring)
- MBA schema works ok for the CBQRI-enabled memory controllers, but
resctrl does not currently have solution for representing MBM for
bandwidth resources that are not associated with a L3 cache.
- For the old CBQRI proof-of-concept RFC, two separate domains were
created for each memory controller: one for MB (allocation) and one
for MBM (monitoring).
- The monitoring domains had to pretend that these memory controllers
were L3 caches which is not the case. I have removed this as it was
too complicated and not the right solution.
- There is active discussion about allowing different scopes for
resources which I think would solve this problem:
https://lore.kernel.org/all/aXUK7XFsHl+gnwA%2F@x1/
---
Drew Fustini (17):
dt-bindings: riscv: Add Ssqosid extension description
RISC-V: Detect the Ssqosid extension
RISC-V: Add support for srmcfg CSR from Ssqosid ext
RISC-V: QoS: define properties of CBQRI controllers
RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
RISC-V: QoS: define CBQRI resctrl resources and domains
RISC-V: QoS: define prototypes for resctrl interface
RISC-V: QoS: add resctrl interface for CBQRI controllers
RISC-V: QoS: expose implementation to resctrl
RISC-V: QoS: add late_initcall to setup resctrl interface
RISC-V: QoS: add to build when CONFIG_RISCV_ISA_SSQOSID set
RISC-V: QoS: make CONFIG_RISCV_ISA_SSQOSID select resctrl
acpi: pptt: Add helper to find a cache from id
include: acpi: actbl2: Add structs for RQSC table
RISC-V: QoS: add Cache ID and Prox Dom to CBQRI controllers
acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table
acpi: riscv: Add support for RISC-V Quality of Service Controller (RQSC)
.../devicetree/bindings/riscv/extensions.yaml | 6 +
MAINTAINERS | 10 +
arch/riscv/Kconfig | 20 +
arch/riscv/include/asm/acpi.h | 10 +
arch/riscv/include/asm/csr.h | 8 +
arch/riscv/include/asm/hwcap.h | 1 +
arch/riscv/include/asm/processor.h | 3 +
arch/riscv/include/asm/qos.h | 41 +
arch/riscv/include/asm/resctrl.h | 2 +
arch/riscv/include/asm/switch_to.h | 3 +
arch/riscv/kernel/Makefile | 2 +
arch/riscv/kernel/cpufeature.c | 1 +
arch/riscv/kernel/qos/Makefile | 2 +
arch/riscv/kernel/qos/internal.h | 155 +++
arch/riscv/kernel/qos/qos.c | 32 +
arch/riscv/kernel/qos/qos_resctrl.c | 1192 ++++++++++++++++++++
drivers/acpi/pptt.c | 63 ++
drivers/acpi/riscv/Makefile | 2 +-
drivers/acpi/riscv/init.c | 19 +
drivers/acpi/riscv/rqsc.c | 112 ++
include/acpi/actbl2.h | 92 ++
include/linux/acpi.h | 8 +
include/linux/riscv_qos.h | 85 ++
23 files changed, 1868 insertions(+), 1 deletion(-)
---
base-commit: 9ace4753a5202b02191d54e9fdf7f9e3d02b85eb
change-id: 20260112-ssqosid-cbqri-407cfcda9ff4
Best regards,
--
Drew Fustini <fustini@kernel.org>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH RFC v2 01/17] dt-bindings: riscv: Add Ssqosid extension description
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 02/17] RISC-V: Detect the Ssqosid extension Drew Fustini
` (15 subsequent siblings)
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree, Conor Dooley
Document the ratified Supervisor-mode Quality of Service ID (Ssqosid)
extension v1.0.
Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
Documentation/devicetree/bindings/riscv/extensions.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 5bab356addc8..27a7b4e63eb1 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -165,6 +165,12 @@ properties:
ratified at commit d70011dde6c2 ("Update to ratified state")
of riscv-j-extension.
+ - const: ssqosid
+ description: |
+ The Ssqosid extension for Quality of Service ID is ratified
+ as v1.0 in commit 5059e0ca641c ("Merge pull request #7 from
+ ved-rivos/Ratified") of riscv-ssqosid.
+
- const: sstc
description: |
The standard Sstc supervisor-level extension for time compare as
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 02/17] RISC-V: Detect the Ssqosid extension
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 01/17] dt-bindings: riscv: Add Ssqosid extension description Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext Drew Fustini
` (14 subsequent siblings)
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Ssqosid is the RISC-V Quality-of-Service (QoS) Identifiers specification
which defines the Supervisor Resource Management Configuration (srmcfg)
register.
Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
[fustini: rebase on current upstream]
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/include/asm/hwcap.h | 1 +
arch/riscv/kernel/cpufeature.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 4369a2338541..28dff8233b34 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -110,6 +110,7 @@
#define RISCV_ISA_EXT_ZALASR 101
#define RISCV_ISA_EXT_ZILSD 102
#define RISCV_ISA_EXT_ZCLSD 103
+#define RISCV_ISA_EXT_SSQOSID 104
#define RISCV_ISA_EXT_XLINUXENVCFG 127
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index c05b11596c19..bf704b48679c 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -558,6 +558,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
+ __RISCV_ISA_EXT_DATA(ssqosid, RISCV_ISA_EXT_SSQOSID),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
__RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 01/17] dt-bindings: riscv: Add Ssqosid extension description Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 02/17] RISC-V: Detect the Ssqosid extension Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-02-02 3:17 ` [External] " yunhui cui
2026-02-02 4:27 ` yunhui cui
2026-01-28 20:27 ` [PATCH RFC v2 04/17] RISC-V: QoS: define properties of CBQRI controllers Drew Fustini
` (13 subsequent siblings)
16 siblings, 2 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Add support for the srmcfg CSR defined in the Ssqosid ISA extension
(Supervisor-mode Quality of Service ID). The CSR contains two fields:
- Resource Control ID (RCID) used determine resource allocation
- Monitoring Counter ID (MCID) used to track resource usage
Requests from a hart to shared resources like cache will be tagged with
these IDs. This allows the usage of shared resources to be associated
with the task currently running on the hart.
A srmcfg field is added to thread_struct and has the same format as the
srmcfg CSR. This allows the scheduler to set the hart's srmcfg CSR to
contain the RCID and MCID for the task that is being scheduled in. The
srmcfg CSR is only written to if the thread_struct.srmcfg is different
than the current value of the CSR.
A per-cpu variable cpu_srmcfg is used to mirror that state of the CSR.
This is because access to L1D hot memory should be several times faster
than a CSR read. Also, in the case of virtualization, accesses to this
CSR are trapped in the hypervisor.
Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
[fustini: rename csr, refactor switch_to, rebase on upstream]
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 7 +++++++
arch/riscv/Kconfig | 17 ++++++++++++++++
arch/riscv/include/asm/csr.h | 8 ++++++++
arch/riscv/include/asm/processor.h | 3 +++
arch/riscv/include/asm/qos.h | 41 ++++++++++++++++++++++++++++++++++++++
arch/riscv/include/asm/switch_to.h | 3 +++
arch/riscv/kernel/Makefile | 2 ++
arch/riscv/kernel/qos/Makefile | 2 ++
arch/riscv/kernel/qos/qos.c | 5 +++++
9 files changed, 88 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 765ad2daa218..e98d553bd0ca 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22505,6 +22505,13 @@ F: drivers/perf/riscv_pmu.c
F: drivers/perf/riscv_pmu_legacy.c
F: drivers/perf/riscv_pmu_sbi.c
+RISC-V QOS RESCTRL SUPPORT
+M: Drew Fustini <fustini@kernel.org>
+L: linux-riscv@lists.infradead.org
+S: Supported
+F: arch/riscv/include/asm/qos.h
+F: arch/riscv/kernel/qos/
+
RISC-V RPMI AND MPXY DRIVERS
M: Rahul Pathak <rahul@summations.net>
M: Anup Patel <anup@brainfault.org>
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 6b39f37f769a..35a6238b02c5 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -595,6 +595,23 @@ config RISCV_ISA_SVNAPOT
If you don't know what to do here, say Y.
+config RISCV_ISA_SSQOSID
+ bool "Ssqosid extension support for supervisor mode Quality of Service ID"
+ default y
+ help
+ Adds support for the Ssqosid ISA extension (Supervisor-mode
+ Quality of Service ID).
+
+ Ssqosid defines the srmcfg CSR which allows the system to tag the
+ running process with an RCID (Resource Control ID) and MCID
+ (Monitoring Counter ID). The RCID is used to determine resource
+ allocation. The MCID is used to track resource usage in event
+ counters.
+
+ For example, a cache controller may use the RCID to apply a
+ cache partitioning scheme and use the MCID to track how much
+ cache a process, or a group of processes, is using.
+
config RISCV_ISA_SVPBMT
bool "Svpbmt extension support for supervisor mode page-based memory types"
depends on 64BIT && MMU
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 4a37a98398ad..2590b89b8f72 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -75,6 +75,13 @@
#define SATP_ASID_MASK _AC(0xFFFF, UL)
#endif
+/* SRMCFG fields */
+#define SRMCFG_RCID_MASK _AC(0x00000FFF, UL)
+#define SRMCFG_MCID_MASK SRMCFG_RCID_MASK
+#define SRMCFG_MCID_SHIFT 16
+#define SRMCFG_MASK ((SRMCFG_MCID_MASK << SRMCFG_MCID_SHIFT) | \
+ SRMCFG_RCID_MASK)
+
/* Exception cause high bit - is an interrupt if set */
#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
@@ -317,6 +324,7 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
+#define CSR_SRMCFG 0x181
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index da5426122d28..183c55e32b96 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -122,6 +122,9 @@ struct thread_struct {
/* A forced icache flush is not needed if migrating to the previous cpu. */
unsigned int prev_cpu;
#endif
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+ u32 srmcfg;
+#endif
};
/* Whitelist the fstate from the task_struct for hardened usercopy */
diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h
new file mode 100644
index 000000000000..84830d7c6dc4
--- /dev/null
+++ b/arch/riscv/include/asm/qos.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_RISCV_QOS_H
+#define _ASM_RISCV_QOS_H
+
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+
+#include <linux/sched.h>
+#include <linux/jump_label.h>
+
+#include <asm/barrier.h>
+#include <asm/csr.h>
+#include <asm/hwcap.h>
+
+/* cached value of srmcfg csr for each cpu */
+DECLARE_PER_CPU(u32, cpu_srmcfg);
+
+static inline void __switch_to_srmcfg(struct task_struct *next)
+{
+ u32 *cpu_srmcfg_ptr = this_cpu_ptr(&cpu_srmcfg);
+ u32 thread_srmcfg;
+
+ thread_srmcfg = READ_ONCE(next->thread.srmcfg);
+
+ if (thread_srmcfg != *cpu_srmcfg_ptr) {
+ *cpu_srmcfg_ptr = thread_srmcfg;
+ csr_write(CSR_SRMCFG, thread_srmcfg);
+ }
+}
+
+static __always_inline bool has_srmcfg(void)
+{
+ return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID);
+}
+
+#else /* ! CONFIG_RISCV_ISA_SSQOSID */
+
+static __always_inline bool has_srmcfg(void) { return false; }
+#define __switch_to_srmcfg(__next) do { } while (0)
+
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
+#endif /* _ASM_RISCV_QOS_H */
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 0e71eb82f920..a684a3795d3d 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -14,6 +14,7 @@
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/csr.h>
+#include <asm/qos.h>
#ifdef CONFIG_FPU
extern void __fstate_save(struct task_struct *save_to);
@@ -119,6 +120,8 @@ do { \
__switch_to_fpu(__prev, __next); \
if (has_vector() || has_xtheadvector()) \
__switch_to_vector(__prev, __next); \
+ if (has_srmcfg()) \
+ __switch_to_srmcfg(__next); \
if (switch_to_should_flush_icache(__next)) \
local_flush_icache_all(); \
__switch_to_envcfg(__next); \
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index f60fce69b725..a3c36d18145c 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -125,3 +125,5 @@ obj-$(CONFIG_ACPI) += acpi.o
obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o
obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
+
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos/
diff --git a/arch/riscv/kernel/qos/Makefile b/arch/riscv/kernel/qos/Makefile
new file mode 100644
index 000000000000..9f996263a86d
--- /dev/null
+++ b/arch/riscv/kernel/qos/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
diff --git a/arch/riscv/kernel/qos/qos.c b/arch/riscv/kernel/qos/qos.c
new file mode 100644
index 000000000000..7b06f7ae9056
--- /dev/null
+++ b/arch/riscv/kernel/qos/qos.c
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <asm/qos.h>
+
+/* cached value of sqoscfg csr for each cpu */
+DEFINE_PER_CPU(u32, cpu_srmcfg);
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 04/17] RISC-V: QoS: define properties of CBQRI controllers
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (2 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities Drew Fustini
` (12 subsequent siblings)
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Define data structure to represent the CBQRI properties that a driver
for an CBQRI-capable controller would discover during probe.
Each instance of a CBQRI-capable controller is added to a list that the
RISC-V CBQRI resctrl implementation will consume.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 1 +
include/linux/riscv_qos.h | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index e98d553bd0ca..31e536304972 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22511,6 +22511,7 @@ L: linux-riscv@lists.infradead.org
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 <rahul@summations.net>
diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
new file mode 100644
index 000000000000..51c3a96bbcd0
--- /dev/null
+++ b/include/linux/riscv_qos.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __LINUX_RISCV_QOS_H
+#define __LINUX_RISCV_QOS_H
+
+#include <linux/iommu.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
+};
+
+struct cbqri_controller_info {
+ unsigned long addr;
+ unsigned long 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;
+ } cache;
+};
+
+extern struct list_head cbqri_controllers;
+
+#endif /* __LINUX_RISCV_QOS_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (3 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 04/17] RISC-V: QoS: define properties of CBQRI controllers Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-02-13 23:13 ` Reinette Chatre
2026-01-28 20:27 ` [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains Drew Fustini
` (11 subsequent siblings)
16 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Define data structures to store the capacity and bandwidth capabilities
that are discovered for a CBQRI-capable controller.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/kernel/qos/internal.h | 128 +++++++++++++++++++++++++++++++++++++++
1 file changed, 128 insertions(+)
diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
new file mode 100644
index 000000000000..ff2c7eff50be
--- /dev/null
+++ b/arch/riscv/kernel/qos/internal.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_RISCV_QOS_INTERNAL_H
+#define _ASM_RISCV_QOS_INTERNAL_H
+
+#include <linux/resctrl.h>
+
+#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_FRCID_MASK 0x1
+#define CBQRI_CC_CAPABILITIES_FRCID_SHIFT 24
+
+#define CBQRI_CC_CAPABILITIES_NCBLKS_SHIFT 8
+#define CBQRI_CC_CAPABILITIES_NCBLKS_MASK 0xFFFF
+
+#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_SHIFT 8
+#define CBQRI_BC_CAPABILITIES_NBWBLKS_MASK 0xFFFF
+#define CBQRI_BC_CAPABILITIES_MRBWB_SHIFT 32
+#define CBQRI_BC_CAPABILITIES_MRBWB_MASK 0xFFFF
+
+#define CBQRI_CONTROL_REGISTERS_BUSY_SHIFT 39
+#define CBQRI_CONTROL_REGISTERS_BUSY_MASK 0x01
+#define CBQRI_CONTROL_REGISTERS_STATUS_SHIFT 32
+#define CBQRI_CONTROL_REGISTERS_STATUS_MASK 0x7F
+#define CBQRI_CONTROL_REGISTERS_OP_SHIFT 0
+#define CBQRI_CONTROL_REGISTERS_OP_MASK 0x1F
+#define CBQRI_CONTROL_REGISTERS_AT_SHIFT 5
+#define CBQRI_CONTROL_REGISTERS_AT_MASK 0x07
+#define CBQRI_CONTROL_REGISTERS_AT_DATA 0
+#define CBQRI_CONTROL_REGISTERS_AT_CODE 1
+#define CBQRI_CONTROL_REGISTERS_RCID_SHIFT 8
+#define CBQRI_CONTROL_REGISTERS_RCID_MASK 0xFFF
+#define CBQRI_CONTROL_REGISTERS_RBWB_SHIFT 0
+#define CBQRI_CONTROL_REGISTERS_RBWB_MASK 0xFFFF
+
+#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
+
+/* Capacity Controller hardware capabilities */
+struct riscv_cbqri_capacity_caps {
+ u16 ncblks; /* number of capacity blocks */
+ u16 cache_level;
+ u32 blk_size;
+
+ bool supports_alloc_at_data;
+ bool supports_alloc_at_code;
+
+ bool supports_alloc_op_config_limit;
+ bool supports_alloc_op_read_limit;
+ bool supports_alloc_op_flush_rcid;
+
+ bool supports_mon_at_data;
+ bool supports_mon_at_code;
+
+ bool supports_mon_op_config_event;
+ bool supports_mon_op_read_counter;
+
+ bool supports_mon_evt_id_none;
+ bool supports_mon_evt_id_occupancy;
+};
+
+/* 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_data;
+ bool supports_alloc_at_code;
+
+ bool supports_alloc_op_config_limit;
+ bool supports_alloc_op_read_limit;
+
+ bool supports_mon_at_data;
+ bool supports_mon_at_code;
+
+ bool supports_mon_op_config_event;
+ bool supports_mon_op_read_counter;
+
+ bool supports_mon_evt_id_none;
+ bool supports_mon_evt_id_rdwr_count;
+ bool supports_mon_evt_id_rdonly_count;
+ bool supports_mon_evt_id_wronly_count;
+};
+
+struct cbqri_controller {
+ struct cbqri_controller_info *ctrl_info;
+ void __iomem *base;
+
+ int ver_major;
+ int ver_minor;
+
+ struct riscv_cbqri_bandwidth_caps bc;
+ struct riscv_cbqri_capacity_caps cc;
+
+ bool alloc_capable;
+ bool mon_capable;
+};
+
+#endif /* _ASM_RISCV_QOS_INTERNAL_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (4 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-02-13 23:15 ` Reinette Chatre
2026-03-25 2:31 ` [External] " yunhui cui
2026-01-28 20:27 ` [PATCH RFC v2 07/17] RISC-V: QoS: define prototypes for resctrl interface Drew Fustini
` (10 subsequent siblings)
16 siblings, 2 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Define data structures to encapsulate the resctrl resource
and domain structures.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
[fustini: rebased current upstream]
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/kernel/qos/internal.h | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
index ff2c7eff50be..c0402dd06cfa 100644
--- a/arch/riscv/kernel/qos/internal.h
+++ b/arch/riscv/kernel/qos/internal.h
@@ -65,6 +65,11 @@
#define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2
#define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1
+int qos_resctrl_setup(void);
+void qos_resctrl_exit(void);
+int qos_resctrl_online_cpu(unsigned int cpu);
+int qos_resctrl_offline_cpu(unsigned int cpu);
+
/* Capacity Controller hardware capabilities */
struct riscv_cbqri_capacity_caps {
u16 ncblks; /* number of capacity blocks */
@@ -125,4 +130,26 @@ struct cbqri_controller {
bool mon_capable;
};
+struct cbqri_resctrl_res {
+ struct rdt_resource resctrl_res;
+ struct cbqri_controller controller;
+ u32 max_rcid;
+ u32 max_mcid;
+};
+
+struct cbqri_resctrl_dom {
+ struct rdt_domain_hdr resctrl_dom_hdr;
+ struct rdt_ctrl_domain resctrl_ctrl_dom;
+ struct rdt_mon_domain resctrl_mon_dom;
+ u64 cbm;
+ u64 rbwb;
+ u64 *ctrl_val;
+ struct cbqri_controller *hw_ctrl;
+};
+
+struct cbqri_config {
+ u64 cbm; /* capacity block mask */
+ u64 rbwb; /* reserved bandwidth blocks */
+};
+
#endif /* _ASM_RISCV_QOS_INTERNAL_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 07/17] RISC-V: QoS: define prototypes for resctrl interface
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (5 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-02-13 23:21 ` Reinette Chatre
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
` (9 subsequent siblings)
16 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Define the prototypes for the resctrl interface functions that are
implemented on RISC-V.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
[fustini: rebased on current upstream]
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
include/linux/riscv_qos.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
index 51c3a96bbcd0..0c551ed85fe1 100644
--- a/include/linux/riscv_qos.h
+++ b/include/linux/riscv_qos.h
@@ -3,6 +3,7 @@
#ifndef __LINUX_RISCV_QOS_H
#define __LINUX_RISCV_QOS_H
+#include <linux/resctrl_types.h>
#include <linux/iommu.h>
#include <linux/types.h>
@@ -31,4 +32,47 @@ struct cbqri_controller_info {
extern struct list_head cbqri_controllers;
+bool resctrl_arch_alloc_capable(void);
+bool resctrl_arch_mon_capable(void);
+bool resctrl_arch_is_llc_occupancy_enabled(void);
+bool resctrl_arch_is_mbm_local_enabled(void);
+bool resctrl_arch_is_mbm_total_enabled(void);
+
+struct rdt_resource;
+/*
+ * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
+ * CLOSID on x86 is RCID on RISC-V
+ * RMID on x86 is MCID on RISC-V
+ * CDP on x86 is AT (access type) on RISC-V
+ */
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 pmg);
+void resctrl_arch_sched_in(struct task_struct *tsk);
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+void resctrl_arch_reset_resources(void);
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid,
+ void *arch_mon_ctx);
+struct rdt_domain_hdr *resctrl_arch_find_domain(struct list_head *domain_list, int id);
+
+static inline bool resctrl_arch_event_is_free_running(enum resctrl_event_id evt)
+{
+ /* must be true for resctrl L3 monitoring files to be created */
+ return true;
+}
+
+static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
+{
+ return val;
+}
+
+/* Not needed for RISC-V */
+static inline void resctrl_arch_enable_mon(void) { }
+static inline void resctrl_arch_disable_mon(void) { }
+static inline void resctrl_arch_enable_alloc(void) { }
+static inline void resctrl_arch_disable_alloc(void) { }
+
#endif /* __LINUX_RISCV_QOS_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (6 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 07/17] RISC-V: QoS: define prototypes for resctrl interface Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-02-02 4:12 ` [External] " yunhui cui
` (5 more replies)
2026-01-28 20:27 ` [PATCH RFC v2 09/17] RISC-V: QoS: expose implementation to resctrl Drew Fustini
` (8 subsequent siblings)
16 siblings, 6 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Add interface for CBQRI controller drivers to make use of the resctrl
filesystem.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/kernel/qos/qos_resctrl.c | 1192 +++++++++++++++++++++++++++++++++++
1 file changed, 1192 insertions(+)
diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
new file mode 100644
index 000000000000..d500098599d2
--- /dev/null
+++ b/arch/riscv/kernel/qos/qos_resctrl.c
@@ -0,0 +1,1192 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "qos: resctrl: " fmt
+
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/riscv_qos.h>
+#include <linux/resctrl.h>
+#include <linux/types.h>
+#include <asm/csr.h>
+#include <asm/qos.h>
+#include "internal.h"
+
+#define MAX_CONTROLLERS 6
+static struct cbqri_controller controllers[MAX_CONTROLLERS];
+static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
+
+static bool exposed_alloc_capable;
+static bool exposed_mon_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);
+
+bool resctrl_arch_alloc_capable(void)
+{
+ return exposed_alloc_capable;
+}
+
+bool resctrl_arch_mon_capable(void)
+{
+ return exposed_mon_capable;
+}
+
+bool resctrl_arch_is_llc_occupancy_enabled(void)
+{
+ return true;
+}
+
+bool resctrl_arch_is_mbm_local_enabled(void)
+{
+ return false;
+}
+
+bool resctrl_arch_is_mbm_total_enabled(void)
+{
+ return false;
+}
+
+bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
+{
+ switch (rid) {
+ case RDT_RESOURCE_L2:
+ return is_cdp_l2_enabled;
+
+ case RDT_RESOURCE_L3:
+ return is_cdp_l3_enabled;
+
+ default:
+ return false;
+ }
+}
+
+int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
+{
+ switch (rid) {
+ case RDT_RESOURCE_L2:
+ if (!exposed_cdp_l2_capable)
+ return -ENODEV;
+ is_cdp_l2_enabled = enable;
+ break;
+
+ case RDT_RESOURCE_L3:
+ if (!exposed_cdp_l3_capable)
+ return -ENODEV;
+ is_cdp_l3_enabled = enable;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
+{
+ if (l >= RDT_NUM_RESOURCES)
+ return NULL;
+
+ return &cbqri_resctrl_resources[l].resctrl_res;
+}
+
+struct rdt_domain_hdr *resctrl_arch_find_domain(struct list_head *domain_list, int id)
+{
+ struct rdt_domain_hdr *hdr;
+
+ lockdep_assert_cpus_held();
+
+ list_for_each_entry(hdr, domain_list, list) {
+ if (hdr->id == id)
+ return hdr;
+ }
+
+ return NULL;
+}
+
+bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
+{
+ return false;
+}
+
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
+ enum resctrl_event_id evtid)
+{
+ /* RISC-V can always read an rmid, nothing needs allocating */
+ return NULL;
+}
+
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
+ enum resctrl_event_id evtid, void *arch_mon_ctx)
+{
+ /* not implemented for the RISC-V resctrl interface */
+}
+
+void resctrl_arch_reset_resources(void)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+}
+
+void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
+ enum resctrl_event_id evtid, u32 rmid, u32 closid,
+ u32 cntr_id, bool assign)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+}
+
+int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d,
+ u32 unused, u32 rmid, int cntr_id,
+ enum resctrl_event_id eventid, u64 *val)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+ return 0;
+}
+
+bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+ return false;
+}
+
+int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+ return 0;
+}
+
+void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
+ u32 unused, u32 rmid, int cntr_id,
+ enum resctrl_event_id eventid)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+}
+
+bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+ return false;
+}
+
+int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+ return 0;
+}
+
+/*
+ * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
+ * CLOSID on x86 is RCID on RISC-V
+ * RMID on x86 is MCID on RISC-V
+ */
+u32 resctrl_arch_get_num_closid(struct rdt_resource *res)
+{
+ struct cbqri_resctrl_res *hw_res;
+
+ hw_res = container_of(res, struct cbqri_resctrl_res, resctrl_res);
+
+ return hw_res->max_rcid;
+}
+
+u32 resctrl_arch_system_num_rmid_idx(void)
+{
+ return max_rmid;
+}
+
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
+{
+ return rmid;
+}
+
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
+{
+ *closid = ((u32)~0); /* refer to X86_RESCTRL_BAD_CLOSID */
+ *rmid = idx;
+}
+
+/* RISC-V resctrl interface does not maintain a default srmcfg value for a given CPU */
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid) { }
+
+void resctrl_arch_sched_in(struct task_struct *tsk)
+{
+ __switch_to_srmcfg(tsk);
+}
+
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+ u32 srmcfg;
+
+ WARN_ON_ONCE((closid & SRMCFG_RCID_MASK) != closid);
+ WARN_ON_ONCE((rmid & SRMCFG_MCID_MASK) != rmid);
+
+ srmcfg = rmid << SRMCFG_MCID_SHIFT;
+ srmcfg |= closid;
+ WRITE_ONCE(tsk->thread.srmcfg, srmcfg);
+}
+
+void resctrl_arch_sync_cpu_closid_rmid(void *info)
+{
+ struct resctrl_cpu_defaults *r = info;
+
+ lockdep_assert_preemption_disabled();
+
+ if (r) {
+ resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
+ r->closid, r->rmid);
+ }
+
+ resctrl_arch_sched_in(current);
+}
+
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
+{
+ u32 srmcfg;
+ bool match;
+
+ srmcfg = READ_ONCE(tsk->thread.srmcfg);
+ match = (srmcfg & SRMCFG_RCID_MASK) == closid;
+ return match;
+}
+
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+ u32 tsk_rmid;
+
+ tsk_rmid = READ_ONCE(tsk->thread.srmcfg);
+ tsk_rmid >>= SRMCFG_MCID_SHIFT;
+ tsk_rmid &= SRMCFG_MCID_MASK;
+
+ return tsk_rmid == rmid;
+}
+
+int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
+ u32 closid, u32 rmid, enum resctrl_event_id eventid,
+ u64 *val, void *arch_mon_ctx)
+{
+ /*
+ * The current Qemu implementation of CBQRI capacity and bandwidth
+ * controllers do not emulate the utilization of resources over
+ * time. Therefore, Qemu currently sets the invalid bit in
+ * cc_mon_ctr_val and bc_mon_ctr_val, and there is no meaningful
+ * value other than 0 to return for reading an RMID (e.g. MCID in
+ * CBQRI terminology)
+ */
+
+ return 0;
+}
+
+void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
+ u32 closid, u32 rmid, enum resctrl_event_id eventid)
+{
+ /* not implemented for the RISC-V resctrl interface */
+}
+
+void resctrl_arch_mon_event_config_read(void *info)
+{
+ /* not implemented for the RISC-V resctrl interface */
+}
+
+void resctrl_arch_mon_event_config_write(void *info)
+{
+ /* not implemented for the RISC-V resctrl interface */
+}
+
+void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+}
+
+void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+}
+
+/* Set capacity block mask (cc_block_mask) */
+static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
+{
+ int reg_offset;
+ u64 reg;
+
+ reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
+ reg = ioread64(ctrl->base + reg_offset);
+
+ reg = cbm;
+ iowrite64(reg, ctrl->base + reg_offset);
+}
+
+/* Set the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
+static void cbqri_set_rbwb(struct cbqri_controller *ctrl, u64 rbwb)
+{
+ int reg_offset;
+ u64 reg;
+
+ reg_offset = CBQRI_BC_BW_ALLOC_OFF;
+ reg = ioread64(ctrl->base + reg_offset);
+ reg &= ~CBQRI_CONTROL_REGISTERS_RBWB_MASK;
+ rbwb &= CBQRI_CONTROL_REGISTERS_RBWB_MASK;
+ reg |= rbwb;
+ iowrite64(reg, ctrl->base + reg_offset);
+}
+
+/* Get the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
+static u64 cbqri_get_rbwb(struct cbqri_controller *ctrl)
+{
+ int reg_offset;
+ u64 reg;
+
+ reg_offset = CBQRI_BC_BW_ALLOC_OFF;
+ reg = ioread64(ctrl->base + reg_offset);
+ reg &= CBQRI_CONTROL_REGISTERS_RBWB_MASK;
+ return reg;
+}
+
+static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset)
+{
+ unsigned long timeout = jiffies + usecs_to_jiffies(1000);
+ int busy;
+ u64 reg;
+
+ while (time_before(jiffies, timeout)) {
+ reg = ioread64(ctrl->base + reg_offset);
+ busy = (reg >> CBQRI_CONTROL_REGISTERS_BUSY_SHIFT) &
+ CBQRI_CONTROL_REGISTERS_BUSY_MASK;
+ if (!busy)
+ return 0;
+ }
+
+ pr_warn("%s(): busy timeout", __func__);
+ return -EIO;
+}
+
+/* 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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
+ reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) <<
+ CBQRI_CONTROL_REGISTERS_OP_SHIFT;
+ reg &= ~(CBQRI_CONTROL_REGISTERS_RCID_MASK <<
+ CBQRI_CONTROL_REGISTERS_RCID_SHIFT);
+ reg |= (rcid & CBQRI_CONTROL_REGISTERS_RCID_MASK) <<
+ CBQRI_CONTROL_REGISTERS_RCID_SHIFT;
+
+ /* CBQRI capacity AT is only supported on L2 and L3 caches for now */
+ if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
+ ((ctrl->ctrl_info->cache.cache_level == 2 && is_cdp_l2_enabled) ||
+ (ctrl->ctrl_info->cache.cache_level == 3 && is_cdp_l3_enabled))) {
+ reg &= ~(CBQRI_CONTROL_REGISTERS_AT_MASK <<
+ CBQRI_CONTROL_REGISTERS_AT_SHIFT);
+ switch (type) {
+ case CDP_CODE:
+ reg |= (CBQRI_CONTROL_REGISTERS_AT_CODE &
+ CBQRI_CONTROL_REGISTERS_AT_MASK) <<
+ CBQRI_CONTROL_REGISTERS_AT_SHIFT;
+ break;
+ case CDP_DATA:
+ default:
+ reg |= (CBQRI_CONTROL_REGISTERS_AT_DATA &
+ CBQRI_CONTROL_REGISTERS_AT_MASK) <<
+ CBQRI_CONTROL_REGISTERS_AT_SHIFT;
+ 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", __func__);
+ return -EIO;
+ }
+
+ reg = ioread64(ctrl->base + reg_offset);
+ status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
+ CBQRI_CONTROL_REGISTERS_STATUS_MASK;
+ if (status != 1) {
+ pr_err("%s(): operation %d failed: status=%d", __func__, operation, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+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 reg_offset;
+ int err = 0;
+ u64 reg;
+
+ if (cfg->cbm != hw_dom->ctrl_val[closid]) {
+ /* Store the new cbm in the ctrl_val array for this closid in this domain */
+ hw_dom->ctrl_val[closid] = cfg->cbm;
+
+ /* 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", __func__, err);
+ return err;
+ }
+
+ /* Clear cc_block_mask before read limit to verify op works*/
+ cbqri_set_cbm(ctrl, 0);
+
+ /* Performa 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", __func__, err);
+ return err;
+ }
+
+ /* Read capacity blockmask to verify it matches the requested config */
+ reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
+ reg = ioread64(ctrl->base + reg_offset);
+ if (reg != cfg->cbm) {
+ pr_warn("%s(): failed to verify allocation (reg:%llx != cbm:%llx)",
+ __func__, reg, cfg->cbm);
+ return -EIO;
+ }
+ }
+
+ 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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
+ reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) <<
+ CBQRI_CONTROL_REGISTERS_OP_SHIFT;
+ reg &= ~(CBQRI_CONTROL_REGISTERS_RCID_MASK << CBQRI_CONTROL_REGISTERS_RCID_SHIFT);
+ reg |= (rcid & CBQRI_CONTROL_REGISTERS_RCID_MASK) <<
+ CBQRI_CONTROL_REGISTERS_RCID_SHIFT;
+ iowrite64(reg, ctrl->base + reg_offset);
+
+ if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
+ pr_err("%s(): BUSY timeout when executing the operation", __func__);
+ return -EIO;
+ }
+
+ reg = ioread64(ctrl->base + reg_offset);
+ status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
+ CBQRI_CONTROL_REGISTERS_STATUS_MASK;
+ if (status != 1) {
+ pr_err("%s(): operation %d failed with status = %d",
+ __func__, operation, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+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;
+
+ if (cfg->rbwb != hw_dom->ctrl_val[closid]) {
+ /* Store the new rbwb in the ctrl_val array for this closid in this domain */
+ hw_dom->ctrl_val[closid] = cfg->rbwb;
+
+ /* Set reserved bandwidth blocks */
+ cbqri_set_rbwb(ctrl, cfg->rbwb);
+
+ /* Bandwidth config limit operation */
+ ret = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, closid);
+ if (ret < 0) {
+ pr_err("%s(): operation failed: ret = %d", __func__, ret);
+ return ret;
+ }
+
+ /* 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_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
+ if (ret < 0) {
+ pr_err("%s(): operation failed: ret = %d", __func__, ret);
+ return ret;
+ }
+
+ /* Read bandwidth allocation to verify it matches the requested config */
+ reg = cbqri_get_rbwb(ctrl);
+ if (reg != cfg->rbwb) {
+ pr_warn("%s(): failed to verify allocation (reg:%llx != rbwb:%llu)",
+ __func__, reg, cfg->rbwb);
+ return -EIO;
+ }
+ }
+
+ return ret;
+}
+
+int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+ u32 closid, enum resctrl_conf_type t, u32 cfg_val)
+{
+ struct cbqri_controller *ctrl;
+ struct cbqri_resctrl_dom *dom;
+ struct cbqri_config cfg;
+ int err = 0;
+
+ dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+ ctrl = dom->hw_ctrl;
+
+ if (!r->alloc_capable)
+ return -EINVAL;
+
+ switch (r->rid) {
+ case RDT_RESOURCE_L2:
+ case RDT_RESOURCE_L3:
+ cfg.cbm = cfg_val;
+ err = cbqri_apply_cache_config(dom, closid, t, &cfg);
+ break;
+ case RDT_RESOURCE_MBA:
+ /* covert from percentage to bandwidth blocks */
+ cfg.rbwb = cfg_val * ctrl->bc.nbwblks / 100;
+ err = cbqri_apply_bw_config(dom, closid, t, &cfg);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
+{
+ struct resctrl_staged_config *cfg;
+ enum resctrl_conf_type t;
+ struct rdt_ctrl_domain *d;
+ int err = 0;
+
+ list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+ for (t = 0; t < CDP_NUM_TYPES; t++) {
+ cfg = &d->staged_config[t];
+ if (!cfg->have_new_ctrl)
+ continue;
+ err = resctrl_arch_update_one(r, d, closid, t, cfg->new_ctrl);
+ if (err) {
+ pr_warn("%s(): update failed (err=%d)", __func__, err);
+ return err;
+ }
+ }
+ }
+ return err;
+}
+
+u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+ u32 closid, enum resctrl_conf_type type)
+{
+ struct cbqri_resctrl_dom *hw_dom;
+ struct cbqri_controller *ctrl;
+ int reg_offset;
+ u32 percent;
+ u32 rbwb;
+ u64 reg;
+ int err;
+
+ hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+
+ ctrl = hw_dom->hw_ctrl;
+
+ if (!r->alloc_capable)
+ return resctrl_get_default_ctrl(r);
+
+ switch (r->rid) {
+ case RDT_RESOURCE_L2:
+ case RDT_RESOURCE_L3:
+ /* Clear cc_block_mask before read limit operation */
+ cbqri_set_cbm(ctrl, 0);
+
+ /* Capacity read limit operation for RCID (closid) */
+ err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
+ if (err < 0) {
+ pr_err("%s(): operation failed: err = %d", __func__, err);
+ return resctrl_get_default_ctrl(r);
+ }
+
+ /* Read capacity block mask for RCID (closid) */
+ reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
+ reg = ioread64(ctrl->base + reg_offset);
+
+ /* Update the config value for the closid in this domain */
+ hw_dom->ctrl_val[closid] = reg;
+ return hw_dom->ctrl_val[closid];
+
+ case RDT_RESOURCE_MBA:
+ /* Capacity read limit operation for RCID (closid) */
+ err = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
+ if (err < 0) {
+ pr_err("%s(): operation failed: err = %d", __func__, err);
+ return resctrl_get_default_ctrl(r);
+ }
+
+ hw_dom->ctrl_val[closid] = cbqri_get_rbwb(ctrl);
+
+ /* Convert from bandwidth blocks to percent */
+ rbwb = hw_dom->ctrl_val[closid];
+ rbwb *= 100;
+ percent = rbwb / ctrl->bc.nbwblks;
+ if (rbwb % ctrl->bc.nbwblks)
+ percent++;
+ return percent;
+
+ default:
+ return resctrl_get_default_ctrl(r);
+ }
+}
+
+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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
+ reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) << CBQRI_CONTROL_REGISTERS_OP_SHIFT;
+ iowrite64(reg, ctrl->base + reg_offset);
+ if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
+ pr_err("%s(): BUSY timeout when executing the operation", __func__);
+ return -EIO;
+ }
+
+ /* Get the operation status */
+ reg = ioread64(ctrl->base + reg_offset);
+ *status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
+ CBQRI_CONTROL_REGISTERS_STATUS_MASK;
+
+ /*
+ * 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 << CBQRI_CONTROL_REGISTERS_AT_SHIFT);
+ reg |= CBQRI_CONTROL_REGISTERS_AT_CODE << CBQRI_CONTROL_REGISTERS_AT_SHIFT;
+ iowrite64(reg, ctrl->base + reg_offset);
+ if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
+ pr_err("%s(): BUSY timeout when setting AT field", __func__);
+ return -EIO;
+ }
+
+ /*
+ * If the AT field value has been reset to zero,
+ * then the AT support is not present
+ */
+ reg = ioread64(ctrl->base + reg_offset);
+ at = (reg >> CBQRI_CONTROL_REGISTERS_AT_SHIFT) & CBQRI_CONTROL_REGISTERS_AT_MASK;
+ 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) < 0) {
+ pr_err("%s(): BUSY timeout when restoring the original register value", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Note: for the purposes of the CBQRI proof-of-concept, debug logging
+ * has been left in this function that detects the properties of CBQRI
+ * capable controllers in the system. pr_info calls would be removed
+ * before submitting non-RFC patches.
+ */
+static int cbqri_probe_controller(struct cbqri_controller_info *ctrl_info,
+ struct cbqri_controller *ctrl)
+{
+ int err = 0, status;
+ u64 reg;
+
+ pr_info("controller info: type=%d addr=0x%lx size=%lu max-rcid=%u max-mcid=%u",
+ ctrl_info->type, ctrl_info->addr, ctrl_info->size,
+ ctrl_info->rcid_count, ctrl_info->mcid_count);
+
+ /* max_rmid is used by resctrl_arch_system_num_rmid_idx() */
+ max_rmid = ctrl_info->mcid_count;
+
+ ctrl->ctrl_info = ctrl_info;
+
+ /* Try to access the memory-mapped CBQRI registers */
+ if (!request_mem_region(ctrl_info->addr, ctrl_info->size, "cbqri_controller")) {
+ pr_warn("%s(): request_mem_region failed for cbqri_controller at 0x%lx",
+ __func__, ctrl_info->addr);
+ return -EBUSY;
+ }
+ ctrl->base = ioremap(ctrl_info->addr, ctrl_info->size);
+ if (!ctrl->base) {
+ pr_warn("%s(): goto err_release_mem_region", __func__);
+ goto err_release_mem_region;
+ }
+
+ ctrl->alloc_capable = false;
+ ctrl->mon_capable = false;
+
+ /* Probe capacity allocation and monitoring features */
+ if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
+ pr_info("probe capacity controller");
+
+ /* Make sure the register is implemented */
+ reg = ioread64(ctrl->base + CBQRI_CC_CAPABILITIES_OFF);
+ if (reg == 0) {
+ err = -ENODEV;
+ goto err_iounmap;
+ }
+
+ ctrl->ver_minor = reg & CBQRI_CC_CAPABILITIES_VER_MINOR_MASK;
+ ctrl->ver_major = reg & CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK;
+
+ ctrl->cc.supports_alloc_op_flush_rcid = (reg >> CBQRI_CC_CAPABILITIES_FRCID_SHIFT)
+ & CBQRI_CC_CAPABILITIES_FRCID_MASK;
+
+ ctrl->cc.ncblks = (reg >> CBQRI_CC_CAPABILITIES_NCBLKS_SHIFT) &
+ CBQRI_CC_CAPABILITIES_NCBLKS_MASK;
+
+ /* Calculate size of capacity block in bytes */
+ ctrl->cc.blk_size = ctrl_info->cache.cache_size / ctrl->cc.ncblks;
+ ctrl->cc.cache_level = ctrl_info->cache.cache_level;
+
+ pr_info("version=%d.%d ncblks=%d blk_size=%d cache_level=%d",
+ ctrl->ver_major, ctrl->ver_minor,
+ ctrl->cc.ncblks, ctrl->cc.blk_size, ctrl->cc.cache_level);
+
+ /* Probe monitoring features */
+ err = cbqri_probe_feature(ctrl, CBQRI_CC_MON_CTL_OFF,
+ CBQRI_CC_MON_CTL_OP_READ_COUNTER, &status,
+ &ctrl->cc.supports_mon_at_code);
+ if (err) {
+ pr_warn("%s() failed to probe cc_mon_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_CC_MON_CTL_STATUS_SUCCESS) {
+ pr_info("cc_mon_ctl is supported");
+ ctrl->cc.supports_mon_op_config_event = true;
+ ctrl->cc.supports_mon_op_read_counter = true;
+ ctrl->mon_capable = true;
+ } else {
+ pr_info("cc_mon_ctl is NOT supported");
+ ctrl->cc.supports_mon_op_config_event = false;
+ ctrl->cc.supports_mon_op_read_counter = false;
+ ctrl->mon_capable = false;
+ }
+ /*
+ * AT data is "always" supported as it has the same value
+ * than when AT field is not supported.
+ */
+ ctrl->cc.supports_mon_at_data = true;
+ pr_info("supports_mon_at_data: %d, supports_mon_at_code: %d",
+ ctrl->cc.supports_mon_at_data, ctrl->cc.supports_mon_at_code);
+
+ /* Probe allocation features */
+ 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) {
+ pr_warn("%s() failed to probe cc_alloc_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
+ pr_info("cc_alloc_ctl is supported");
+ ctrl->cc.supports_alloc_op_config_limit = true;
+ ctrl->cc.supports_alloc_op_read_limit = true;
+ ctrl->alloc_capable = true;
+ exposed_alloc_capable = true;
+ } else {
+ pr_info("cc_alloc_ctl is NOT supported");
+ ctrl->cc.supports_alloc_op_config_limit = false;
+ ctrl->cc.supports_alloc_op_read_limit = false;
+ ctrl->alloc_capable = false;
+ }
+ /*
+ * AT data is "always" supported as it has the same value
+ * than when AT field is not supported
+ */
+ ctrl->cc.supports_alloc_at_data = true;
+ pr_info("supports_alloc_at_data: %d, supports_alloc_at_code: %d",
+ ctrl->cc.supports_alloc_at_data,
+ ctrl->cc.supports_alloc_at_code);
+ } else if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
+ pr_info("probe bandwidth controller");
+
+ /* Make sure the register is implemented */
+ reg = ioread64(ctrl->base + CBQRI_BC_CAPABILITIES_OFF);
+ if (reg == 0) {
+ err = -ENODEV;
+ goto err_iounmap;
+ }
+
+ ctrl->ver_minor = reg & CBQRI_BC_CAPABILITIES_VER_MINOR_MASK;
+ ctrl->ver_major = reg & CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK;
+
+ ctrl->bc.nbwblks = (reg >> CBQRI_BC_CAPABILITIES_NBWBLKS_SHIFT) &
+ CBQRI_BC_CAPABILITIES_NBWBLKS_MASK;
+ ctrl->bc.mrbwb = (reg >> CBQRI_BC_CAPABILITIES_MRBWB_SHIFT) &
+ CBQRI_BC_CAPABILITIES_MRBWB_MASK;
+
+ pr_info("version=%d.%d nbwblks=%d mrbwb=%d",
+ ctrl->ver_major, ctrl->ver_minor,
+ ctrl->bc.nbwblks, ctrl->bc.mrbwb);
+
+ /* Probe monitoring features */
+ err = cbqri_probe_feature(ctrl, CBQRI_BC_MON_CTL_OFF,
+ CBQRI_BC_MON_CTL_OP_READ_COUNTER,
+ &status, &ctrl->bc.supports_mon_at_code);
+ if (err) {
+ pr_warn("%s() failed to probe bc_mon_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_BC_MON_CTL_STATUS_SUCCESS) {
+ pr_info("bc_mon_ctl is supported");
+ ctrl->bc.supports_mon_op_config_event = true;
+ ctrl->bc.supports_mon_op_read_counter = true;
+ ctrl->mon_capable = true;
+ exposed_mon_capable = true;
+ } else {
+ pr_info("bc_mon_ctl is NOT supported");
+ ctrl->bc.supports_mon_op_config_event = false;
+ ctrl->bc.supports_mon_op_read_counter = false;
+ ctrl->mon_capable = false;
+ }
+ /*
+ * AT data is "always" supported as it has the same value
+ * than when AT field is not supported
+ */
+ ctrl->bc.supports_mon_at_data = true;
+ pr_info("supports_mon_at_data: %d, supports_mon_at_code: %d",
+ ctrl->bc.supports_mon_at_data, ctrl->bc.supports_mon_at_code);
+
+ /* Probe allocation features */
+ 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) {
+ pr_warn("%s() failed to probe bc_alloc_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
+ pr_warn("bc_alloc_ctl is supported");
+ ctrl->bc.supports_alloc_op_config_limit = true;
+ ctrl->bc.supports_alloc_op_read_limit = true;
+ ctrl->alloc_capable = true;
+ exposed_alloc_capable = true;
+ } else {
+ pr_warn("bc_alloc_ctl is NOT supported");
+ ctrl->bc.supports_alloc_op_config_limit = false;
+ ctrl->bc.supports_alloc_op_read_limit = false;
+ ctrl->alloc_capable = false;
+ }
+
+ /*
+ * AT data is "always" supported as it has the same value
+ * than when AT field is not supported
+ */
+ ctrl->bc.supports_alloc_at_data = true;
+ pr_warn("supports_alloc_at_data: %d, supports_alloc_at_code: %d",
+ ctrl->bc.supports_alloc_at_data, ctrl->bc.supports_alloc_at_code);
+ } else {
+ pr_warn("controller type is UNKNOWN");
+ err = -ENODEV;
+ goto err_release_mem_region;
+ }
+
+ return 0;
+
+err_iounmap:
+ pr_warn("%s(): err_iounmap", __func__);
+ iounmap(ctrl->base);
+
+err_release_mem_region:
+ pr_warn("%s(): err_release_mem_region", __func__);
+ release_mem_region(ctrl_info->addr, ctrl_info->size);
+
+ return err;
+}
+
+static struct rdt_ctrl_domain *qos_new_domain(struct cbqri_controller *ctrl)
+{
+ struct cbqri_resctrl_dom *hw_dom;
+ struct rdt_ctrl_domain *domain;
+
+ hw_dom = kzalloc(sizeof(*hw_dom), GFP_KERNEL);
+ if (!hw_dom)
+ return NULL;
+
+ /* associate this cbqri_controller with the domain */
+ hw_dom->hw_ctrl = ctrl;
+
+ /* the rdt_domain struct from inside the cbqri_resctrl_dom struct */
+ domain = &hw_dom->resctrl_ctrl_dom;
+
+ INIT_LIST_HEAD(&domain->hdr.list);
+
+ return domain;
+}
+
+static int qos_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
+{
+ struct cbqri_resctrl_res *hw_res;
+ struct cbqri_resctrl_dom *hw_dom;
+ u64 *dc;
+ int err = 0;
+ int i;
+
+ hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+ if (!hw_res)
+ return -ENOMEM;
+
+ hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+ if (!hw_dom)
+ return -ENOMEM;
+
+ dc = kmalloc_array(hw_res->max_rcid, sizeof(*hw_dom->ctrl_val),
+ GFP_KERNEL);
+ if (!dc)
+ return -ENOMEM;
+
+ hw_dom->ctrl_val = dc;
+
+ for (i = 0; i < hw_res->max_rcid; i++, dc++) {
+ err = resctrl_arch_update_one(r, d, i, 0, resctrl_get_default_ctrl(r));
+ if (err)
+ return 0;
+ *dc = resctrl_get_default_ctrl(r);
+ }
+ return 0;
+}
+
+static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
+{
+ struct rdt_ctrl_domain *domain = NULL;
+ struct cbqri_resctrl_res *cbqri_res = NULL;
+ struct rdt_resource *res = NULL;
+ int internal_id = *id;
+ int err = 0;
+
+ domain = qos_new_domain(ctrl);
+ if (!domain)
+ return -ENOSPC;
+ if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
+ cpumask_copy(&domain->hdr.cpu_mask, &ctrl->ctrl_info->cache.cpu_mask);
+ if (ctrl->ctrl_info->cache.cache_level == 2) {
+ cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
+ cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
+ cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
+ res = &cbqri_res->resctrl_res;
+ res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
+ res->rid = RDT_RESOURCE_L2;
+ res->name = "L2";
+ res->alloc_capable = ctrl->alloc_capable;
+ res->mon_capable = ctrl->mon_capable;
+ res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
+ res->ctrl_scope = RESCTRL_L2_CACHE;
+ res->cache.arch_has_sparse_bitmasks = false;
+ res->cache.arch_has_per_cpu_cfg = false;
+ res->cache.cbm_len = ctrl->cc.ncblks;
+ res->cache.shareable_bits = resctrl_get_default_ctrl(res);
+ res->cache.min_cbm_bits = 1;
+ } else if (ctrl->ctrl_info->cache.cache_level == 3) {
+ cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
+ cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
+ cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
+ res = &cbqri_res->resctrl_res;
+ res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
+ res->rid = RDT_RESOURCE_L3;
+ res->name = "L3";
+ res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
+ res->ctrl_scope = RESCTRL_L3_CACHE;
+ res->alloc_capable = ctrl->alloc_capable;
+ res->mon_capable = ctrl->mon_capable;
+ res->cache.arch_has_sparse_bitmasks = false;
+ res->cache.arch_has_per_cpu_cfg = false;
+ res->cache.cbm_len = ctrl->cc.ncblks;
+ res->cache.shareable_bits = resctrl_get_default_ctrl(res);
+ res->cache.min_cbm_bits = 1;
+ } else {
+ pr_warn("%s(): unknown cache level %d", __func__,
+ ctrl->ctrl_info->cache.cache_level);
+ err = -ENODEV;
+ goto err_free_domain;
+ }
+ } else if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
+ if (ctrl->alloc_capable) {
+ cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_MBA];
+ cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
+ cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
+ res = &cbqri_res->resctrl_res;
+ res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
+ res->rid = RDT_RESOURCE_MBA;
+ res->name = "MB";
+ res->schema_fmt = RESCTRL_SCHEMA_RANGE;
+ res->ctrl_scope = RESCTRL_L3_CACHE;
+ res->alloc_capable = ctrl->alloc_capable;
+ res->mon_capable = false;
+ res->membw.delay_linear = true;
+ res->membw.arch_needs_linear = true;
+ res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+ // The minimum percentage allowed by the CBQRI spec
+ res->membw.min_bw = 1;
+ // The maximum percentage allowed by the CBQRI spec
+ res->membw.max_bw = 80;
+ res->membw.bw_gran = 1;
+ }
+ } else {
+ pr_warn("%s(): unknown resource %d", __func__, ctrl->ctrl_info->type);
+ err = -ENODEV;
+ goto err_free_domain;
+ }
+
+ domain->hdr.id = internal_id;
+ err = qos_init_domain_ctrlval(res, domain);
+ if (err)
+ goto err_free_domain;
+
+ if (cbqri_res) {
+ list_add_tail(&domain->hdr.list, &cbqri_res->resctrl_res.ctrl_domains);
+ *id = internal_id;
+ err = resctrl_online_ctrl_domain(res, domain);
+ if (err) {
+ pr_warn("%s(): failed to online cbqri_res domain", __func__);
+ goto err_free_domain;
+ }
+ }
+
+ return 0;
+
+err_free_domain:
+ pr_warn("%s(): err_free_domain", __func__);
+ kfree(container_of(domain, struct cbqri_resctrl_dom, resctrl_ctrl_dom));
+
+ return err;
+}
+
+int qos_resctrl_setup(void)
+{
+ struct rdt_ctrl_domain *domain, *domain_temp;
+ struct cbqri_controller_info *ctrl_info;
+ struct cbqri_controller *ctrl;
+ struct cbqri_resctrl_res *res;
+ static int found_controllers;
+ int err = 0;
+ int id = 0;
+ int i;
+
+ list_for_each_entry(ctrl_info, &cbqri_controllers, list) {
+ err = cbqri_probe_controller(ctrl_info, &controllers[found_controllers]);
+ if (err) {
+ pr_warn("%s(): failed (%d)", __func__, err);
+ goto err_unmap_controllers;
+ }
+
+ found_controllers++;
+ if (found_controllers > MAX_CONTROLLERS) {
+ pr_warn("%s(): increase MAX_CONTROLLERS value", __func__);
+ break;
+ }
+ }
+
+ for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+ res = &cbqri_resctrl_resources[i];
+ INIT_LIST_HEAD(&res->resctrl_res.ctrl_domains);
+ INIT_LIST_HEAD(&res->resctrl_res.mon_domains);
+ res->resctrl_res.rid = i;
+ }
+
+ for (i = 0; i < found_controllers; i++) {
+ ctrl = &controllers[i];
+ err = qos_resctrl_add_controller_domain(ctrl, &id);
+ if (err) {
+ pr_warn("%s(): failed to add controller domain (%d)", __func__, err);
+ goto err_free_controllers_list;
+ }
+ id++;
+
+ /*
+ * CDP (code data prioritization) on x86 is similar to
+ * the AT (access type) field in CBQRI. CDP only supports
+ * caches so this must be a CBQRI capacity controller.
+ */
+ if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
+ ctrl->cc.supports_alloc_at_code &&
+ ctrl->cc.supports_alloc_at_data) {
+ if (ctrl->ctrl_info->cache.cache_level == 2)
+ exposed_cdp_l2_capable = true;
+ else
+ exposed_cdp_l3_capable = true;
+ }
+ }
+
+ pr_info("exposed_alloc_capable = %d", exposed_alloc_capable);
+ pr_info("exposed_mon_capable = %d", exposed_mon_capable);
+ pr_info("exposed_cdp_l2_capable = %d", exposed_cdp_l2_capable);
+ pr_info("exposed_cdp_l3_capable = %d", exposed_cdp_l3_capable);
+
+ return resctrl_init();
+
+err_free_controllers_list:
+ for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+ res = &cbqri_resctrl_resources[i];
+ list_for_each_entry_safe(domain, domain_temp, &res->resctrl_res.ctrl_domains,
+ hdr.list) {
+ kfree(domain);
+ }
+ }
+
+err_unmap_controllers:
+ for (i = 0; i < found_controllers; i++) {
+ iounmap(controllers[i].base);
+ release_mem_region(controllers[i].ctrl_info->addr, controllers[i].ctrl_info->size);
+ }
+
+ return err;
+}
+
+int qos_resctrl_online_cpu(unsigned int cpu)
+{
+ resctrl_online_cpu(cpu);
+ return 0;
+}
+
+int qos_resctrl_offline_cpu(unsigned int cpu)
+{
+ resctrl_offline_cpu(cpu);
+ return 0;
+}
+
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 09/17] RISC-V: QoS: expose implementation to resctrl
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (7 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 10/17] RISC-V: QoS: add late_initcall to setup resctrl interface Drew Fustini
` (7 subsequent siblings)
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
The generic resctrl header include/linux/resctrl.h includes
linux/riscv_qos.h when CONFIG_ARCH_HAS_CPU_RESCTRL is set.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 1 +
arch/riscv/include/asm/resctrl.h | 2 ++
2 files changed, 3 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 31e536304972..96ead357a634 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22510,6 +22510,7 @@ M: Drew Fustini <fustini@kernel.org>
L: linux-riscv@lists.infradead.org
S: Supported
F: arch/riscv/include/asm/qos.h
+F: arch/riscv/include/asm/resctrl.h
F: arch/riscv/kernel/qos/
F: include/linux/riscv_qos.h
diff --git a/arch/riscv/include/asm/resctrl.h b/arch/riscv/include/asm/resctrl.h
new file mode 100644
index 000000000000..7d247d87dab9
--- /dev/null
+++ b/arch/riscv/include/asm/resctrl.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <linux/riscv_qos.h>
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 10/17] RISC-V: QoS: add late_initcall to setup resctrl interface
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (8 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 09/17] RISC-V: QoS: expose implementation to resctrl Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 11/17] RISC-V: QoS: add to build when CONFIG_RISCV_ISA_SSQOSID set Drew Fustini
` (6 subsequent siblings)
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Add late_initcall which checks if the Ssqosid extension is present, and
if so, calls resctrl setup and sets cpu hotplug state to "qos:online".
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/kernel/qos/qos.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/riscv/kernel/qos/qos.c b/arch/riscv/kernel/qos/qos.c
index 7b06f7ae9056..2cd5d7be1d10 100644
--- a/arch/riscv/kernel/qos/qos.c
+++ b/arch/riscv/kernel/qos/qos.c
@@ -1,5 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/riscv_qos.h>
+
+#include <asm/csr.h>
#include <asm/qos.h>
+#include "internal.h"
+
/* cached value of sqoscfg csr for each cpu */
DEFINE_PER_CPU(u32, cpu_srmcfg);
+
+static int __init qos_arch_late_init(void)
+{
+ int err;
+
+ if (!riscv_isa_extension_available(NULL, SSQOSID))
+ return -ENODEV;
+
+ err = qos_resctrl_setup();
+ if (err != 0)
+ return err;
+
+ cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "qos:online", qos_resctrl_online_cpu,
+ qos_resctrl_offline_cpu);
+
+ return err;
+}
+late_initcall(qos_arch_late_init);
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 11/17] RISC-V: QoS: add to build when CONFIG_RISCV_ISA_SSQOSID set
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (9 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 10/17] RISC-V: QoS: add late_initcall to setup resctrl interface Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 12/17] RISC-V: QoS: make CONFIG_RISCV_ISA_SSQOSID select resctrl Drew Fustini
` (5 subsequent siblings)
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Add the srmcfg CSR handling and the resctrl interface to the build when
CONFIG_RISCV_ISA_SSQOSID is set.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/kernel/qos/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/riscv/kernel/qos/Makefile b/arch/riscv/kernel/qos/Makefile
index 9f996263a86d..9ed0c13a854d 100644
--- a/arch/riscv/kernel/qos/Makefile
+++ b/arch/riscv/kernel/qos/Makefile
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o qos_resctrl.o
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 12/17] RISC-V: QoS: make CONFIG_RISCV_ISA_SSQOSID select resctrl
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (10 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 11/17] RISC-V: QoS: add to build when CONFIG_RISCV_ISA_SSQOSID set Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 13/17] acpi: pptt: Add helper to find a cache from id Drew Fustini
` (4 subsequent siblings)
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Make CONFIG_RISCV_ISA_SSQOSID select the config options for resctrl:
ARCH_HAS_CPU_RESCTRL, RESCTRL_FS and MISC_FILESYSTEMS.
Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
arch/riscv/Kconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 35a6238b02c5..8ff6d962b6b2 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -598,6 +598,9 @@ config RISCV_ISA_SVNAPOT
config RISCV_ISA_SSQOSID
bool "Ssqosid extension support for supervisor mode Quality of Service ID"
default y
+ select ARCH_HAS_CPU_RESCTRL
+ select RESCTRL_FS
+ select MISC_FILESYSTEMS
help
Adds support for the Ssqosid ISA extension (Supervisor-mode
Quality of Service ID).
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 13/17] acpi: pptt: Add helper to find a cache from id
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (11 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 12/17] RISC-V: QoS: make CONFIG_RISCV_ISA_SSQOSID select resctrl Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-03-25 1:34 ` [External] " yunhui cui
2026-01-28 20:27 ` [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table Drew Fustini
` (3 subsequent siblings)
16 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Add function to find the pointer to an instance of acpi_pptt_cache.
find_acpi_cache_from_id() is based on find_acpi_cache_level_from_id()
from commit c4170570cc7f ("ACPI / PPTT: Find PPTT cache level by ID") in
the morse/mpam/snapshot/v6.14-rc1 branch.
TODO: find_acpi_cache_level_from_id() has changed since then so this
function should be updated. In additon, there may be a simpler way for
acpi_parse_rqsc() than adding this function to get a pointer to
acpi_pptt_cache.
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
drivers/acpi/pptt.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 8 +++++++
2 files changed, 71 insertions(+)
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index de5f8c018333..d1002673dc39 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -1063,3 +1063,66 @@ int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus)
return 0;
}
+
+/*
+ * find_acpi_cache_from_id() is adapted from find_acpi_cache_level_from_id()
+ * introduced by c4170570cc7f ("ACPI / PPTT: Find PPTT cache level by ID")
+ * in the morse/mpam/snapshot/v6.14-rc1 branch.
+ *
+ * TODO: find_acpi_cache_level_from_id() has changed since then so this
+ * function should be updated. In additon, there may be a simpler way for
+ * acpi_parse_rqsc() than adding this function to get a pointer to
+ * acpi_pptt_cache.
+ */
+struct acpi_pptt_cache *find_acpi_cache_from_id(u32 cache_id)
+{
+ u32 acpi_cpu_id;
+ acpi_status status;
+ int level, cpu, num_levels;
+ struct acpi_pptt_cache *cache;
+ struct acpi_table_header *table;
+ struct acpi_pptt_cache_v1 *cache_v1;
+ struct acpi_pptt_processor *cpu_node;
+
+ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+ if (ACPI_FAILURE(status)) {
+ acpi_pptt_warn_missing();
+ return NULL;
+ }
+
+ if (table->revision < 3) {
+ acpi_put_table(table);
+ return NULL;
+ }
+
+ for_each_possible_cpu(cpu) {
+ num_levels = 0;
+ acpi_cpu_id = get_acpi_id_for_cpu(cpu);
+
+ cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
+ if (!cpu_node)
+ break;
+ num_levels = acpi_count_levels(table, cpu_node, NULL);
+
+ for (level = 1; level <= num_levels; level++) {
+ cache = acpi_find_cache_node(table, acpi_cpu_id,
+ ACPI_PPTT_CACHE_TYPE_UNIFIED,
+ level, &cpu_node);
+ if (!cache)
+ continue;
+
+ cache_v1 = ACPI_ADD_PTR(struct acpi_pptt_cache_v1,
+ cache,
+ sizeof(struct acpi_pptt_cache));
+
+ if (cache->flags & ACPI_PPTT_CACHE_ID_VALID &&
+ cache_v1->cache_id == cache_id) {
+ acpi_put_table(table);
+ return cache;
+ }
+ }
+ }
+
+ acpi_put_table(table);
+ return NULL;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index fbf0c3a65f59..fee6a5059a46 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1546,6 +1546,7 @@ int find_acpi_cpu_topology_package(unsigned int cpu);
int find_acpi_cpu_topology_hetero_id(unsigned int cpu);
void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id, cpumask_t *cpus);
int find_acpi_cache_level_from_id(u32 cache_id);
+struct acpi_pptt_cache *find_acpi_cache_from_id(u32 cache_id);
int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus);
#else
static inline int acpi_pptt_cpu_is_thread(unsigned int cpu)
@@ -1570,10 +1571,17 @@ static inline int find_acpi_cpu_topology_hetero_id(unsigned int cpu)
}
static inline void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id,
cpumask_t *cpus) { }
+
static inline int find_acpi_cache_level_from_id(u32 cache_id)
{
return -ENOENT;
}
+
+static inline struct acpi_pptt_cache *find_acpi_cache_from_id(u32 cache_id)
+{
+ return NULL;
+}
+
static inline int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id,
cpumask_t *cpus)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (12 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 13/17] acpi: pptt: Add helper to find a cache from id Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:31 ` Rafael J. Wysocki
` (2 more replies)
2026-01-28 20:27 ` [PATCH RFC v2 15/17] RISC-V: QoS: add Cache ID and Prox Dom to CBQRI controllers Drew Fustini
` (2 subsequent siblings)
16 siblings, 3 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Add structs for the RQSC table which describes the properties of the
RISC-V QoS controllers (CBQRI) in the system. The table also describes
the topological arrangement of the QoS controllers and resources in the
system. The topology is expressed in terms of the location of the
resources within the system and the relation between the QoS Controller
and the resource it manages.
Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
include/acpi/actbl2.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index f726bce3eb84..7367990349ee 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -53,6 +53,7 @@
#define ACPI_SIG_RGRT "RGRT" /* Regulatory Graphics Resource Table */
#define ACPI_SIG_RHCT "RHCT" /* RISC-V Hart Capabilities Table */
#define ACPI_SIG_RIMT "RIMT" /* RISC-V IO Mapping Table */
+#define ACPI_SIG_RQSC "RQSC" /* RISC-V RISC-V Quality of Service Controller */
#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
#define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
#define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
@@ -3165,6 +3166,97 @@ enum acpi_rgrt_image_type {
ACPI_RGRT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
};
+/*******************************************************************************
+ *
+ * RQSC - RISC-V Quality of Service Controller
+ * Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_rqsc_fields_res {
+ u8 type; // 1
+ u8 resv; // 1
+ u16 length; // 2
+ u16 flags; // 2
+ u8 resv2; // 1
+ u8 id_type; // 1
+ u64 id1; // 8
+ u32 id2; // 4
+};
+
+struct acpi_table_rqsc_fields {
+ u8 type; // 1
+ u8 resv; // 1
+ u16 length; // 2
+ u32 reg[3]; // 12
+ u32 rcid; // 4
+ u32 mcid; // 4
+ u16 flags; // 2
+ u16 nres; // 2
+ struct acpi_table_rqsc_fields_res res; // 20
+};
+
+struct acpi_table_rqsc {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 num;
+ struct acpi_table_rqsc_fields f[6];
+};
+
+/* RQSC Flags */
+#define ACPI_RQSC_TIMER_CANNOT_WAKEUP_CPU (1)
+
+/*
+ * RQSC subtables
+ */
+struct acpi_rqsc_node_header {
+ u16 type;
+ u16 length;
+ u16 revision;
+};
+
+/* Values for RQSC subtable Type above */
+enum acpi_rqsc_node_type {
+ ACPI_RQSC_NODE_TYPE_ISA_STRING = 0x0000,
+ ACPI_RQSC_NODE_TYPE_CMO = 0x0001,
+ ACPI_RQSC_NODE_TYPE_MMU = 0x0002,
+ ACPI_RQSC_NODE_TYPE_RESERVED = 0x0003,
+ ACPI_RQSC_NODE_TYPE_HART_INFO = 0xFFFF,
+};
+
+/*
+ * RQSC node specific subtables
+ */
+
+/* ISA string node structure */
+struct acpi_rqsc_isa_string {
+ u16 isa_length;
+ char isa[];
+};
+
+struct acpi_rqsc_cmo_node {
+ u8 reserved; /* Must be zero */
+ u8 cbom_size; /* CBOM size in powerof 2 */
+ u8 cbop_size; /* CBOP size in powerof 2 */
+ u8 cboz_size; /* CBOZ size in powerof 2 */
+};
+
+struct acpi_rqsc_mmu_node {
+ u8 reserved; /* Must be zero */
+ u8 mmu_type; /* Virtual Address Scheme */
+};
+
+enum acpi_rqsc_mmu_type {
+ ACPI_RQSC_MMU_TYPE_SV39 = 0,
+ ACPI_RQSC_MMU_TYPE_SV48 = 1,
+ ACPI__MMU_TYPE_SV57 = 2
+};
+
+/* Hart Info node structure */
+struct acpi_rqsc_hart_info {
+ u16 num_offsets;
+ u32 uid; /* ACPI processor UID */
+};
+
/*******************************************************************************
*
* RHCT - RISC-V Hart Capabilities Table
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 15/17] RISC-V: QoS: add Cache ID and Prox Dom to CBQRI controllers
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (13 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 17/17] acpi: riscv: Add support for RISC-V Quality of Service Controller (RQSC) Drew Fustini
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Expand cbqri_controller_info to contain:
- Cache ID from the PPTT table's Cache Type Structure
- Proximity Domain from SRAT table Memory Affifinty Controller
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
include/linux/riscv_qos.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
index 0c551ed85fe1..4812b6811327 100644
--- a/include/linux/riscv_qos.h
+++ b/include/linux/riscv_qos.h
@@ -27,7 +27,14 @@ struct cbqri_controller_info {
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 Affifinty Controller
+ u32 prox_dom;
+ } mem;
};
extern struct list_head cbqri_controllers;
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (14 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 15/17] RISC-V: QoS: add Cache ID and Prox Dom to CBQRI controllers Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
2026-02-02 11:08 ` [External] " yunhui cui
2026-01-28 20:27 ` [PATCH RFC v2 17/17] acpi: riscv: Add support for RISC-V Quality of Service Controller (RQSC) Drew Fustini
16 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Add driver to parse the ACPI RISC-V Quality of Service Controller (RQSC)
table which describes the capacity and bandwidth QoS controllers in a
system. The QoS controllers implement the RISC-V Capacity and Bandwidth
Controller QoS Register Interface (CBQRI) specification.
Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
MAINTAINERS | 1 +
arch/riscv/include/asm/acpi.h | 10 ++++
drivers/acpi/riscv/Makefile | 2 +-
drivers/acpi/riscv/rqsc.c | 112 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 96ead357a634..e96a83dc9a02 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22512,6 +22512,7 @@ S: Supported
F: arch/riscv/include/asm/qos.h
F: arch/riscv/include/asm/resctrl.h
F: arch/riscv/kernel/qos/
+F: drivers/acpi/riscv/rqsc.c
F: include/linux/riscv_qos.h
RISC-V RPMI AND MPXY DRIVERS
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 6e13695120bc..16c6e25eed1e 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -71,6 +71,16 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
u32 *cboz_size, u32 *cbop_size);
+
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+int acpi_parse_rqsc(struct acpi_table_header *table);
+#else
+static inline int acpi_parse_rqsc(struct acpi_table_header *table)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
+
#else
static inline void acpi_init_rintc_map(void) { }
static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
index 1284a076fa88..cf0f38c93a9f 100644
--- a/drivers/acpi/riscv/Makefile
+++ b/drivers/acpi/riscv/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += rhct.o init.o irq.o
+obj-y += rhct.o rqsc.o init.o irq.o
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
obj-$(CONFIG_ACPI_RIMT) += rimt.o
diff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c
new file mode 100644
index 000000000000..a86ddb39fae4
--- /dev/null
+++ b/drivers/acpi/riscv/rqsc.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Tenstorrent
+ * Author: Drew Fustini <fustini@kernel.org>
+ *
+ */
+
+#define pr_fmt(fmt) "ACPI: RQSC: " fmt
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/riscv_qos.h>
+
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+
+#define CBQRI_CTRL_SIZE 0x1000
+
+static struct acpi_table_rqsc *acpi_get_rqsc(void)
+{
+ static struct acpi_table_header *rqsc;
+ acpi_status status;
+
+ /*
+ * RQSC will be used at runtime on every CPU, so we
+ * don't need to call acpi_put_table() to release the table mapping.
+ */
+ if (!rqsc) {
+ status = acpi_get_table(ACPI_SIG_RQSC, 0, &rqsc);
+ if (ACPI_FAILURE(status)) {
+ pr_warn_once("No RQSC table found\n");
+ return NULL;
+ }
+ }
+
+ return (struct acpi_table_rqsc *)rqsc;
+}
+
+int acpi_parse_rqsc(struct acpi_table_header *table)
+{
+ struct acpi_table_rqsc *rqsc;
+ int err;
+
+ BUG_ON(acpi_disabled);
+ if (!table) {
+ rqsc = acpi_get_rqsc();
+ if (!rqsc)
+ return -ENOENT;
+ } else {
+ rqsc = (struct acpi_table_rqsc *)table;
+ }
+
+ for (int i = 0; i < rqsc->num; i++) {
+ struct cbqri_controller_info *ctrl_info;
+
+ ctrl_info = kzalloc(sizeof(*ctrl_info), GFP_KERNEL);
+ if (!ctrl_info)
+ return -ENOMEM;
+
+ ctrl_info->type = rqsc->f[i].type;
+ ctrl_info->addr = rqsc->f[i].reg[1];
+ ctrl_info->size = CBQRI_CTRL_SIZE;
+ ctrl_info->rcid_count = rqsc->f[i].rcid;
+ ctrl_info->mcid_count = rqsc->f[i].mcid;
+
+ pr_info("Found controller with type %u addr 0x%lx size %lu rcid %u mcid %u",
+ ctrl_info->type, ctrl_info->addr, ctrl_info->size,
+ ctrl_info->rcid_count, ctrl_info->mcid_count);
+
+ if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
+ ctrl_info->cache.cache_id = rqsc->f[i].res.id1;
+ ctrl_info->cache.cache_level =
+ find_acpi_cache_level_from_id(ctrl_info->cache.cache_id);
+
+ struct acpi_pptt_cache *cache;
+
+ cache = find_acpi_cache_from_id(ctrl_info->cache.cache_id);
+ if (cache) {
+ ctrl_info->cache.cache_size = cache->size;
+ } else {
+ pr_warn("%s(): failed to determine size for cache id 0x%x",
+ __func__, ctrl_info->cache.cache_id);
+ ctrl_info->cache.cache_size = 0;
+ }
+
+ pr_info("Cache controller has ID 0x%x level %u size %u ",
+ ctrl_info->cache.cache_id, ctrl_info->cache.cache_level,
+ ctrl_info->cache.cache_size);
+
+ /*
+ * For CBQRI, any cpu (technically a hart in RISC-V terms)
+ * can access the memory-mapped registers of any CBQRI
+ * controller in the system.
+ */
+ err = cpumask_parse("FF", &ctrl_info->cache.cpu_mask);
+ if (err)
+ pr_err("Failed to convert cores mask string to cpumask (%d)", err);
+
+ } else if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
+ ctrl_info->mem.prox_dom = rqsc->f[i].res.id1;
+ pr_info("Memory controller with proximity domain %u",
+ ctrl_info->mem.prox_dom);
+ }
+
+ /* Fill the list shared with RISC-V QoS resctrl */
+ INIT_LIST_HEAD(&ctrl_info->list);
+ list_add_tail(&ctrl_info->list, &cbqri_controllers);
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH RFC v2 17/17] acpi: riscv: Add support for RISC-V Quality of Service Controller (RQSC)
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
` (15 preceding siblings ...)
2026-01-28 20:27 ` [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table Drew Fustini
@ 2026-01-28 20:27 ` Drew Fustini
16 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:27 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, Drew Fustini, linux-kernel,
linux-riscv, x86, Rob Herring, Rafael J. Wysocki, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Enable support for the RQSC table which describes the capacity and
bandwidth QoS (CBQRI) controllers in a system.
Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
Signed-off-by: Drew Fustini <fustini@kernel.org>
---
drivers/acpi/riscv/init.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
index 7c00f7995e86..784fa0c56516 100644
--- a/drivers/acpi/riscv/init.c
+++ b/drivers/acpi/riscv/init.c
@@ -6,10 +6,29 @@
#include <linux/acpi.h>
#include "init.h"
+#include <linux/riscv_qos.h>
void __init acpi_arch_init(void)
{
+ struct acpi_table_header *rqsc;
+ acpi_status status;
+ int rc;
+
riscv_acpi_init_gsi_mapping();
+
if (IS_ENABLED(CONFIG_ACPI_RIMT))
riscv_acpi_rimt_init();
+
+ if (!acpi_disabled) {
+ status = acpi_get_table(ACPI_SIG_RQSC, 0, &rqsc);
+ if (ACPI_FAILURE(status)) {
+ pr_err("%s(): failed to find ACPI RQSC table: %d", __func__,
+ ACPI_FAILURE(status));
+ } else {
+ rc = acpi_parse_rqsc(rqsc);
+ if (rc < 0)
+ pr_err("%s(): failed to parse ACPI RQSC table: %d", __func__, rc);
+ }
+ acpi_put_table((struct acpi_table_header *)rqsc);
+ }
}
--
2.43.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-01-28 20:27 ` [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table Drew Fustini
@ 2026-01-28 20:31 ` Rafael J. Wysocki
2026-01-28 20:44 ` Drew Fustini
2026-03-25 1:43 ` [External] " yunhui cui
2026-03-25 1:48 ` yunhui cui
2 siblings, 1 reply; 57+ messages in thread
From: Rafael J. Wysocki @ 2026-01-28 20:31 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, linux-kernel, linux-riscv,
x86, Rob Herring, Rafael J. Wysocki, Len Brown, Robert Moore,
Sunil V L, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
linux-acpi, acpica-devel, devicetree
On Wed, Jan 28, 2026 at 9:28 PM Drew Fustini <fustini@kernel.org> wrote:
>
> Add structs for the RQSC table which describes the properties of the
> RISC-V QoS controllers (CBQRI) in the system. The table also describes
> the topological arrangement of the QoS controllers and resources in the
> system. The topology is expressed in terms of the location of the
> resources within the system and the relation between the QoS Controller
> and the resource it manages.
>
> Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
> Signed-off-by: Drew Fustini <fustini@kernel.org>
Of course, this change needs to go through upstream ACPICA.
> ---
> include/acpi/actbl2.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> index f726bce3eb84..7367990349ee 100644
> --- a/include/acpi/actbl2.h
> +++ b/include/acpi/actbl2.h
> @@ -53,6 +53,7 @@
> #define ACPI_SIG_RGRT "RGRT" /* Regulatory Graphics Resource Table */
> #define ACPI_SIG_RHCT "RHCT" /* RISC-V Hart Capabilities Table */
> #define ACPI_SIG_RIMT "RIMT" /* RISC-V IO Mapping Table */
> +#define ACPI_SIG_RQSC "RQSC" /* RISC-V RISC-V Quality of Service Controller */
> #define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
> #define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
> #define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
> @@ -3165,6 +3166,97 @@ enum acpi_rgrt_image_type {
> ACPI_RGRT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
> };
>
> +/*******************************************************************************
> + *
> + * RQSC - RISC-V Quality of Service Controller
> + * Version 1
> + *
> + ******************************************************************************/
> +
> +struct acpi_table_rqsc_fields_res {
> + u8 type; // 1
> + u8 resv; // 1
> + u16 length; // 2
> + u16 flags; // 2
> + u8 resv2; // 1
> + u8 id_type; // 1
> + u64 id1; // 8
> + u32 id2; // 4
> +};
> +
> +struct acpi_table_rqsc_fields {
> + u8 type; // 1
> + u8 resv; // 1
> + u16 length; // 2
> + u32 reg[3]; // 12
> + u32 rcid; // 4
> + u32 mcid; // 4
> + u16 flags; // 2
> + u16 nres; // 2
> + struct acpi_table_rqsc_fields_res res; // 20
> +};
> +
> +struct acpi_table_rqsc {
> + struct acpi_table_header header; /* Common ACPI table header */
> + u32 num;
> + struct acpi_table_rqsc_fields f[6];
> +};
> +
> +/* RQSC Flags */
> +#define ACPI_RQSC_TIMER_CANNOT_WAKEUP_CPU (1)
> +
> +/*
> + * RQSC subtables
> + */
> +struct acpi_rqsc_node_header {
> + u16 type;
> + u16 length;
> + u16 revision;
> +};
> +
> +/* Values for RQSC subtable Type above */
> +enum acpi_rqsc_node_type {
> + ACPI_RQSC_NODE_TYPE_ISA_STRING = 0x0000,
> + ACPI_RQSC_NODE_TYPE_CMO = 0x0001,
> + ACPI_RQSC_NODE_TYPE_MMU = 0x0002,
> + ACPI_RQSC_NODE_TYPE_RESERVED = 0x0003,
> + ACPI_RQSC_NODE_TYPE_HART_INFO = 0xFFFF,
> +};
> +
> +/*
> + * RQSC node specific subtables
> + */
> +
> +/* ISA string node structure */
> +struct acpi_rqsc_isa_string {
> + u16 isa_length;
> + char isa[];
> +};
> +
> +struct acpi_rqsc_cmo_node {
> + u8 reserved; /* Must be zero */
> + u8 cbom_size; /* CBOM size in powerof 2 */
> + u8 cbop_size; /* CBOP size in powerof 2 */
> + u8 cboz_size; /* CBOZ size in powerof 2 */
> +};
> +
> +struct acpi_rqsc_mmu_node {
> + u8 reserved; /* Must be zero */
> + u8 mmu_type; /* Virtual Address Scheme */
> +};
> +
> +enum acpi_rqsc_mmu_type {
> + ACPI_RQSC_MMU_TYPE_SV39 = 0,
> + ACPI_RQSC_MMU_TYPE_SV48 = 1,
> + ACPI__MMU_TYPE_SV57 = 2
> +};
> +
> +/* Hart Info node structure */
> +struct acpi_rqsc_hart_info {
> + u16 num_offsets;
> + u32 uid; /* ACPI processor UID */
> +};
> +
> /*******************************************************************************
> *
> * RHCT - RISC-V Hart Capabilities Table
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-01-28 20:31 ` Rafael J. Wysocki
@ 2026-01-28 20:44 ` Drew Fustini
2026-01-28 20:50 ` Rafael J. Wysocki
0 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-01-28 20:44 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2,
Reinette Chatre, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, linux-kernel, linux-riscv,
x86, Rob Herring, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Wed, Jan 28, 2026 at 09:31:16PM +0100, Rafael J. Wysocki wrote:
> On Wed, Jan 28, 2026 at 9:28 PM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add structs for the RQSC table which describes the properties of the
> > RISC-V QoS controllers (CBQRI) in the system. The table also describes
> > the topological arrangement of the QoS controllers and resources in the
> > system. The topology is expressed in terms of the location of the
> > resources within the system and the relation between the QoS Controller
> > and the resource it manages.
> >
> > Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> > Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
>
> Of course, this change needs to go through upstream ACPICA.
Thank you for pointing this out. I've not worked with ACPI prior to
dealing with the RQSC table.
Is the pull request for RISC-V RIMT a good example of how to do that?
https://github.com/acpica/acpica/pull/1003
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-01-28 20:44 ` Drew Fustini
@ 2026-01-28 20:50 ` Rafael J. Wysocki
0 siblings, 0 replies; 57+ messages in thread
From: Rafael J. Wysocki @ 2026-01-28 20:50 UTC (permalink / raw)
To: Drew Fustini
Cc: Rafael J. Wysocki, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Radim Krčmář, Samuel Holland,
Adrien Ricciardi, Nicolas Pitre, Kornel Dulęba, Atish Patra,
Atish Kumar Patra, Vasudevan Srinivasan, Ved Shanbhogue,
yunhui cui, Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23,
liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
linux-kernel, linux-riscv, x86, Rob Herring, Len Brown,
Robert Moore, Sunil V L, Krzysztof Kozlowski, Conor Dooley,
Paul Walmsley, linux-acpi, acpica-devel, devicetree
On Wed, Jan 28, 2026 at 9:44 PM Drew Fustini <fustini@kernel.org> wrote:
>
> On Wed, Jan 28, 2026 at 09:31:16PM +0100, Rafael J. Wysocki wrote:
> > On Wed, Jan 28, 2026 at 9:28 PM Drew Fustini <fustini@kernel.org> wrote:
> > >
> > > Add structs for the RQSC table which describes the properties of the
> > > RISC-V QoS controllers (CBQRI) in the system. The table also describes
> > > the topological arrangement of the QoS controllers and resources in the
> > > system. The topology is expressed in terms of the location of the
> > > resources within the system and the relation between the QoS Controller
> > > and the resource it manages.
> > >
> > > Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> > > Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
> > > Signed-off-by: Drew Fustini <fustini@kernel.org>
> >
> > Of course, this change needs to go through upstream ACPICA.
>
> Thank you for pointing this out. I've not worked with ACPI prior to
> dealing with the RQSC table.
>
> Is the pull request for RISC-V RIMT a good example of how to do that?
> https://github.com/acpica/acpica/pull/1003
I think so.
You may also have a look at
Documentation/driver-api/acpi/linuxized-acpica.rst (sorry for the
counter-intuitive location).
As a general rule, Linux patches that change the ACPICA code need to
be auto-generated from the corresponding upstream ACPICA commits (and
when you do so, please add a Link: tag pointing to the source ACPICA
commit to the Linux patch).
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext
2026-01-28 20:27 ` [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext Drew Fustini
@ 2026-02-02 3:17 ` yunhui cui
2026-02-08 1:31 ` Drew Fustini
2026-02-02 4:27 ` yunhui cui
1 sibling, 1 reply; 57+ messages in thread
From: yunhui cui @ 2026-02-02 3:17 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add support for the srmcfg CSR defined in the Ssqosid ISA extension
> (Supervisor-mode Quality of Service ID). The CSR contains two fields:
>
> - Resource Control ID (RCID) used determine resource allocation
> - Monitoring Counter ID (MCID) used to track resource usage
>
> Requests from a hart to shared resources like cache will be tagged with
> these IDs. This allows the usage of shared resources to be associated
> with the task currently running on the hart.
>
> A srmcfg field is added to thread_struct and has the same format as the
> srmcfg CSR. This allows the scheduler to set the hart's srmcfg CSR to
> contain the RCID and MCID for the task that is being scheduled in. The
> srmcfg CSR is only written to if the thread_struct.srmcfg is different
> than the current value of the CSR.
>
> A per-cpu variable cpu_srmcfg is used to mirror that state of the CSR.
> This is because access to L1D hot memory should be several times faster
> than a CSR read. Also, in the case of virtualization, accesses to this
> CSR are trapped in the hypervisor.
>
> Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
> Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
> Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
> [fustini: rename csr, refactor switch_to, rebase on upstream]
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> MAINTAINERS | 7 +++++++
> arch/riscv/Kconfig | 17 ++++++++++++++++
> arch/riscv/include/asm/csr.h | 8 ++++++++
> arch/riscv/include/asm/processor.h | 3 +++
> arch/riscv/include/asm/qos.h | 41 ++++++++++++++++++++++++++++++++++++++
> arch/riscv/include/asm/switch_to.h | 3 +++
> arch/riscv/kernel/Makefile | 2 ++
> arch/riscv/kernel/qos/Makefile | 2 ++
> arch/riscv/kernel/qos/qos.c | 5 +++++
> 9 files changed, 88 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 765ad2daa218..e98d553bd0ca 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22505,6 +22505,13 @@ F: drivers/perf/riscv_pmu.c
> F: drivers/perf/riscv_pmu_legacy.c
> F: drivers/perf/riscv_pmu_sbi.c
>
> +RISC-V QOS RESCTRL SUPPORT
> +M: Drew Fustini <fustini@kernel.org>
> +L: linux-riscv@lists.infradead.org
> +S: Supported
> +F: arch/riscv/include/asm/qos.h
> +F: arch/riscv/kernel/qos/
> +
> RISC-V RPMI AND MPXY DRIVERS
> M: Rahul Pathak <rahul@summations.net>
> M: Anup Patel <anup@brainfault.org>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 6b39f37f769a..35a6238b02c5 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -595,6 +595,23 @@ config RISCV_ISA_SVNAPOT
>
> If you don't know what to do here, say Y.
>
> +config RISCV_ISA_SSQOSID
> + bool "Ssqosid extension support for supervisor mode Quality of Service ID"
> + default y
> + help
> + Adds support for the Ssqosid ISA extension (Supervisor-mode
> + Quality of Service ID).
> +
> + Ssqosid defines the srmcfg CSR which allows the system to tag the
> + running process with an RCID (Resource Control ID) and MCID
> + (Monitoring Counter ID). The RCID is used to determine resource
> + allocation. The MCID is used to track resource usage in event
> + counters.
> +
> + For example, a cache controller may use the RCID to apply a
> + cache partitioning scheme and use the MCID to track how much
> + cache a process, or a group of processes, is using.
> +
> config RISCV_ISA_SVPBMT
> bool "Svpbmt extension support for supervisor mode page-based memory types"
> depends on 64BIT && MMU
> diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
> index 4a37a98398ad..2590b89b8f72 100644
> --- a/arch/riscv/include/asm/csr.h
> +++ b/arch/riscv/include/asm/csr.h
> @@ -75,6 +75,13 @@
> #define SATP_ASID_MASK _AC(0xFFFF, UL)
> #endif
>
> +/* SRMCFG fields */
> +#define SRMCFG_RCID_MASK _AC(0x00000FFF, UL)
> +#define SRMCFG_MCID_MASK SRMCFG_RCID_MASK
> +#define SRMCFG_MCID_SHIFT 16
> +#define SRMCFG_MASK ((SRMCFG_MCID_MASK << SRMCFG_MCID_SHIFT) | \
> + SRMCFG_RCID_MASK)
> +
> /* Exception cause high bit - is an interrupt if set */
> #define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
>
> @@ -317,6 +324,7 @@
> #define CSR_STVAL 0x143
> #define CSR_SIP 0x144
> #define CSR_SATP 0x180
> +#define CSR_SRMCFG 0x181
>
> #define CSR_STIMECMP 0x14D
> #define CSR_STIMECMPH 0x15D
> diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
> index da5426122d28..183c55e32b96 100644
> --- a/arch/riscv/include/asm/processor.h
> +++ b/arch/riscv/include/asm/processor.h
> @@ -122,6 +122,9 @@ struct thread_struct {
> /* A forced icache flush is not needed if migrating to the previous cpu. */
> unsigned int prev_cpu;
> #endif
> +#ifdef CONFIG_RISCV_ISA_SSQOSID
> + u32 srmcfg;
> +#endif
> };
>
> /* Whitelist the fstate from the task_struct for hardened usercopy */
> diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h
> new file mode 100644
> index 000000000000..84830d7c6dc4
> --- /dev/null
> +++ b/arch/riscv/include/asm/qos.h
> @@ -0,0 +1,41 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_RISCV_QOS_H
> +#define _ASM_RISCV_QOS_H
> +
> +#ifdef CONFIG_RISCV_ISA_SSQOSID
> +
> +#include <linux/sched.h>
> +#include <linux/jump_label.h>
> +
> +#include <asm/barrier.h>
> +#include <asm/csr.h>
> +#include <asm/hwcap.h>
> +
> +/* cached value of srmcfg csr for each cpu */
> +DECLARE_PER_CPU(u32, cpu_srmcfg);
> +
> +static inline void __switch_to_srmcfg(struct task_struct *next)
> +{
> + u32 *cpu_srmcfg_ptr = this_cpu_ptr(&cpu_srmcfg);
> + u32 thread_srmcfg;
> +
> + thread_srmcfg = READ_ONCE(next->thread.srmcfg);
First set the cpu_list, and then the condition thread_srmcfg !=
*cpu_srmcfg_ptr will not be satisfied. Is a default value required
here? Both code paths for cpu_list and tasks are compared against the
default value; you may refer to the implementation of mpam.
> +
> + if (thread_srmcfg != *cpu_srmcfg_ptr) {
> + *cpu_srmcfg_ptr = thread_srmcfg;
> + csr_write(CSR_SRMCFG, thread_srmcfg);
> + }
> +}
> +
> +static __always_inline bool has_srmcfg(void)
> +{
> + return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID);
> +}
> +
> +#else /* ! CONFIG_RISCV_ISA_SSQOSID */
> +
> +static __always_inline bool has_srmcfg(void) { return false; }
> +#define __switch_to_srmcfg(__next) do { } while (0)
> +
> +#endif /* CONFIG_RISCV_ISA_SSQOSID */
> +#endif /* _ASM_RISCV_QOS_H */
> diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
> index 0e71eb82f920..a684a3795d3d 100644
> --- a/arch/riscv/include/asm/switch_to.h
> +++ b/arch/riscv/include/asm/switch_to.h
> @@ -14,6 +14,7 @@
> #include <asm/processor.h>
> #include <asm/ptrace.h>
> #include <asm/csr.h>
> +#include <asm/qos.h>
>
> #ifdef CONFIG_FPU
> extern void __fstate_save(struct task_struct *save_to);
> @@ -119,6 +120,8 @@ do { \
> __switch_to_fpu(__prev, __next); \
> if (has_vector() || has_xtheadvector()) \
> __switch_to_vector(__prev, __next); \
> + if (has_srmcfg()) \
> + __switch_to_srmcfg(__next); \
> if (switch_to_should_flush_icache(__next)) \
> local_flush_icache_all(); \
> __switch_to_envcfg(__next); \
> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> index f60fce69b725..a3c36d18145c 100644
> --- a/arch/riscv/kernel/Makefile
> +++ b/arch/riscv/kernel/Makefile
> @@ -125,3 +125,5 @@ obj-$(CONFIG_ACPI) += acpi.o
> obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o
>
> obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
> +
> +obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos/
> diff --git a/arch/riscv/kernel/qos/Makefile b/arch/riscv/kernel/qos/Makefile
> new file mode 100644
> index 000000000000..9f996263a86d
> --- /dev/null
> +++ b/arch/riscv/kernel/qos/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
> diff --git a/arch/riscv/kernel/qos/qos.c b/arch/riscv/kernel/qos/qos.c
> new file mode 100644
> index 000000000000..7b06f7ae9056
> --- /dev/null
> +++ b/arch/riscv/kernel/qos/qos.c
> @@ -0,0 +1,5 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +#include <asm/qos.h>
> +
> +/* cached value of sqoscfg csr for each cpu */
> +DEFINE_PER_CPU(u32, cpu_srmcfg);
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
@ 2026-02-02 4:12 ` yunhui cui
2026-02-20 19:54 ` Drew Fustini
2026-02-09 7:20 ` Gong Shuai
` (4 subsequent siblings)
5 siblings, 1 reply; 57+ messages in thread
From: yunhui cui @ 2026-02-02 4:12 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add interface for CBQRI controller drivers to make use of the resctrl
> filesystem.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> arch/riscv/kernel/qos/qos_resctrl.c | 1192 +++++++++++++++++++++++++++++++++++
> 1 file changed, 1192 insertions(+)
>
> diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
> new file mode 100644
> index 000000000000..d500098599d2
> --- /dev/null
> +++ b/arch/riscv/kernel/qos/qos_resctrl.c
> @@ -0,0 +1,1192 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#define pr_fmt(fmt) "qos: resctrl: " fmt
> +
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/riscv_qos.h>
> +#include <linux/resctrl.h>
> +#include <linux/types.h>
> +#include <asm/csr.h>
> +#include <asm/qos.h>
> +#include "internal.h"
> +
> +#define MAX_CONTROLLERS 6
> +static struct cbqri_controller controllers[MAX_CONTROLLERS];
Switch to dynamic allocation? Remove MAX_CONTROLLERS.
> +static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
> +
> +static bool exposed_alloc_capable;
> +static bool exposed_mon_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);
> +
> +bool resctrl_arch_alloc_capable(void)
> +{
> + return exposed_alloc_capable;
> +}
> +
> +bool resctrl_arch_mon_capable(void)
> +{
> + return exposed_mon_capable;
> +}
> +
> +bool resctrl_arch_is_llc_occupancy_enabled(void)
> +{
> + return true;
> +}
> +
> +bool resctrl_arch_is_mbm_local_enabled(void)
> +{
> + return false;
> +}
> +
> +bool resctrl_arch_is_mbm_total_enabled(void)
> +{
> + return false;
> +}
> +
> +bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
> +{
> + switch (rid) {
> + case RDT_RESOURCE_L2:
> + return is_cdp_l2_enabled;
> +
> + case RDT_RESOURCE_L3:
> + return is_cdp_l3_enabled;
> +
> + default:
> + return false;
> + }
> +}
> +
> +int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
> +{
> + switch (rid) {
> + case RDT_RESOURCE_L2:
> + if (!exposed_cdp_l2_capable)
> + return -ENODEV;
> + is_cdp_l2_enabled = enable;
> + break;
> +
> + case RDT_RESOURCE_L3:
> + if (!exposed_cdp_l3_capable)
> + return -ENODEV;
> + is_cdp_l3_enabled = enable;
> + break;
> +
> + default:
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
> +{
> + if (l >= RDT_NUM_RESOURCES)
> + return NULL;
> +
> + return &cbqri_resctrl_resources[l].resctrl_res;
> +}
> +
> +struct rdt_domain_hdr *resctrl_arch_find_domain(struct list_head *domain_list, int id)
> +{
> + struct rdt_domain_hdr *hdr;
> +
> + lockdep_assert_cpus_held();
> +
> + list_for_each_entry(hdr, domain_list, list) {
> + if (hdr->id == id)
> + return hdr;
> + }
> +
> + return NULL;
> +}
> +
> +bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
> +{
> + return false;
> +}
> +
> +void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
> + enum resctrl_event_id evtid)
> +{
> + /* RISC-V can always read an rmid, nothing needs allocating */
> + return NULL;
> +}
> +
> +void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
> + enum resctrl_event_id evtid, void *arch_mon_ctx)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_reset_resources(void)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
> + enum resctrl_event_id evtid, u32 rmid, u32 closid,
> + u32 cntr_id, bool assign)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 unused, u32 rmid, int cntr_id,
> + enum resctrl_event_id eventid, u64 *val)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return 0;
> +}
> +
> +bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return false;
> +}
> +
> +int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return 0;
> +}
> +
> +void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 unused, u32 rmid, int cntr_id,
> + enum resctrl_event_id eventid)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return false;
> +}
> +
> +int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return 0;
> +}
> +
> +/*
> + * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
> + * CLOSID on x86 is RCID on RISC-V
> + * RMID on x86 is MCID on RISC-V
> + */
> +u32 resctrl_arch_get_num_closid(struct rdt_resource *res)
> +{
> + struct cbqri_resctrl_res *hw_res;
> +
> + hw_res = container_of(res, struct cbqri_resctrl_res, resctrl_res);
> +
> + return hw_res->max_rcid;
> +}
> +
> +u32 resctrl_arch_system_num_rmid_idx(void)
> +{
> + return max_rmid;
> +}
> +
> +u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
> +{
> + return rmid;
> +}
> +
> +void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
> +{
> + *closid = ((u32)~0); /* refer to X86_RESCTRL_BAD_CLOSID */
> + *rmid = idx;
> +}
> +
> +/* RISC-V resctrl interface does not maintain a default srmcfg value for a given CPU */
> +void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid) { }
> +
> +void resctrl_arch_sched_in(struct task_struct *tsk)
> +{
> + __switch_to_srmcfg(tsk);
> +}
> +
> +void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
> +{
> + u32 srmcfg;
> +
> + WARN_ON_ONCE((closid & SRMCFG_RCID_MASK) != closid);
> + WARN_ON_ONCE((rmid & SRMCFG_MCID_MASK) != rmid);
> +
> + srmcfg = rmid << SRMCFG_MCID_SHIFT;
> + srmcfg |= closid;
> + WRITE_ONCE(tsk->thread.srmcfg, srmcfg);
> +}
> +
> +void resctrl_arch_sync_cpu_closid_rmid(void *info)
> +{
> + struct resctrl_cpu_defaults *r = info;
> +
> + lockdep_assert_preemption_disabled();
> +
> + if (r) {
> + resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
> + r->closid, r->rmid);
> + }
> +
> + resctrl_arch_sched_in(current);
> +}
> +
> +bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
> +{
> + u32 srmcfg;
> + bool match;
> +
> + srmcfg = READ_ONCE(tsk->thread.srmcfg);
> + match = (srmcfg & SRMCFG_RCID_MASK) == closid;
> + return match;
> +}
> +
> +bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
> +{
> + u32 tsk_rmid;
> +
> + tsk_rmid = READ_ONCE(tsk->thread.srmcfg);
> + tsk_rmid >>= SRMCFG_MCID_SHIFT;
> + tsk_rmid &= SRMCFG_MCID_MASK;
> +
> + return tsk_rmid == rmid;
> +}
> +
> +int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 closid, u32 rmid, enum resctrl_event_id eventid,
> + u64 *val, void *arch_mon_ctx)
> +{
> + /*
> + * The current Qemu implementation of CBQRI capacity and bandwidth
> + * controllers do not emulate the utilization of resources over
> + * time. Therefore, Qemu currently sets the invalid bit in
> + * cc_mon_ctr_val and bc_mon_ctr_val, and there is no meaningful
> + * value other than 0 to return for reading an RMID (e.g. MCID in
> + * CBQRI terminology)
> + */
> +
> + return 0;
Implement per the spec's description directly, not as this comment states?
> +}
> +
> +void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 closid, u32 rmid, enum resctrl_event_id eventid)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_mon_event_config_read(void *info)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_mon_event_config_write(void *info)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +/* Set capacity block mask (cc_block_mask) */
> +static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
> +{
> + int reg_offset;
> + u64 reg;
> +
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> +
> + reg = cbm;
> + iowrite64(reg, ctrl->base + reg_offset);
> +}
> +
> +/* Set the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
> +static void cbqri_set_rbwb(struct cbqri_controller *ctrl, u64 rbwb)
> +{
> + int reg_offset;
> + u64 reg;
> +
> + reg_offset = CBQRI_BC_BW_ALLOC_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> + reg &= ~CBQRI_CONTROL_REGISTERS_RBWB_MASK;
> + rbwb &= CBQRI_CONTROL_REGISTERS_RBWB_MASK;
> + reg |= rbwb;
> + iowrite64(reg, ctrl->base + reg_offset);
> +}
> +
> +/* Get the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
> +static u64 cbqri_get_rbwb(struct cbqri_controller *ctrl)
> +{
> + int reg_offset;
> + u64 reg;
> +
> + reg_offset = CBQRI_BC_BW_ALLOC_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> + reg &= CBQRI_CONTROL_REGISTERS_RBWB_MASK;
> + return reg;
> +}
> +
> +static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset)
> +{
> + unsigned long timeout = jiffies + usecs_to_jiffies(1000);
> + int busy;
> + u64 reg;
> +
> + while (time_before(jiffies, timeout)) {
> + reg = ioread64(ctrl->base + reg_offset);
> + busy = (reg >> CBQRI_CONTROL_REGISTERS_BUSY_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_BUSY_MASK;
> + if (!busy)
> + return 0;
> + }
> +
> + pr_warn("%s(): busy timeout", __func__);
> + return -EIO;
> +}
> +
> +/* 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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
> + reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) <<
> + CBQRI_CONTROL_REGISTERS_OP_SHIFT;
> + reg &= ~(CBQRI_CONTROL_REGISTERS_RCID_MASK <<
> + CBQRI_CONTROL_REGISTERS_RCID_SHIFT);
> + reg |= (rcid & CBQRI_CONTROL_REGISTERS_RCID_MASK) <<
> + CBQRI_CONTROL_REGISTERS_RCID_SHIFT;
> +
> + /* CBQRI capacity AT is only supported on L2 and L3 caches for now */
> + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
> + ((ctrl->ctrl_info->cache.cache_level == 2 && is_cdp_l2_enabled) ||
> + (ctrl->ctrl_info->cache.cache_level == 3 && is_cdp_l3_enabled))) {
> + reg &= ~(CBQRI_CONTROL_REGISTERS_AT_MASK <<
> + CBQRI_CONTROL_REGISTERS_AT_SHIFT);
> + switch (type) {
> + case CDP_CODE:
> + reg |= (CBQRI_CONTROL_REGISTERS_AT_CODE &
> + CBQRI_CONTROL_REGISTERS_AT_MASK) <<
> + CBQRI_CONTROL_REGISTERS_AT_SHIFT;
> + break;
> + case CDP_DATA:
> + default:
> + reg |= (CBQRI_CONTROL_REGISTERS_AT_DATA &
> + CBQRI_CONTROL_REGISTERS_AT_MASK) <<
> + CBQRI_CONTROL_REGISTERS_AT_SHIFT;
> + 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", __func__);
> + return -EIO;
> + }
> +
> + reg = ioread64(ctrl->base + reg_offset);
> + status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_STATUS_MASK;
> + if (status != 1) {
> + pr_err("%s(): operation %d failed: status=%d", __func__, operation, status);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +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 reg_offset;
> + int err = 0;
> + u64 reg;
> +
> + if (cfg->cbm != hw_dom->ctrl_val[closid]) {
> + /* Store the new cbm in the ctrl_val array for this closid in this domain */
> + hw_dom->ctrl_val[closid] = cfg->cbm;
> +
> + /* 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", __func__, err);
> + return err;
> + }
> +
> + /* Clear cc_block_mask before read limit to verify op works*/
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Performa 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", __func__, err);
> + return err;
> + }
> +
> + /* Read capacity blockmask to verify it matches the requested config */
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> + if (reg != cfg->cbm) {
> + pr_warn("%s(): failed to verify allocation (reg:%llx != cbm:%llx)",
> + __func__, reg, cfg->cbm);
> + return -EIO;
> + }
> + }
> +
> + 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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
> + reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) <<
> + CBQRI_CONTROL_REGISTERS_OP_SHIFT;
> + reg &= ~(CBQRI_CONTROL_REGISTERS_RCID_MASK << CBQRI_CONTROL_REGISTERS_RCID_SHIFT);
> + reg |= (rcid & CBQRI_CONTROL_REGISTERS_RCID_MASK) <<
> + CBQRI_CONTROL_REGISTERS_RCID_SHIFT;
> + iowrite64(reg, ctrl->base + reg_offset);
> +
> + if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
> + pr_err("%s(): BUSY timeout when executing the operation", __func__);
> + return -EIO;
> + }
> +
> + reg = ioread64(ctrl->base + reg_offset);
> + status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_STATUS_MASK;
> + if (status != 1) {
> + pr_err("%s(): operation %d failed with status = %d",
> + __func__, operation, status);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +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;
> +
> + if (cfg->rbwb != hw_dom->ctrl_val[closid]) {
> + /* Store the new rbwb in the ctrl_val array for this closid in this domain */
> + hw_dom->ctrl_val[closid] = cfg->rbwb;
> +
> + /* Set reserved bandwidth blocks */
> + cbqri_set_rbwb(ctrl, cfg->rbwb);
> +
> + /* Bandwidth config limit operation */
> + ret = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, closid);
> + if (ret < 0) {
> + pr_err("%s(): operation failed: ret = %d", __func__, ret);
> + return ret;
> + }
> +
> + /* 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_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
> + if (ret < 0) {
> + pr_err("%s(): operation failed: ret = %d", __func__, ret);
> + return ret;
> + }
> +
> + /* Read bandwidth allocation to verify it matches the requested config */
> + reg = cbqri_get_rbwb(ctrl);
> + if (reg != cfg->rbwb) {
> + pr_warn("%s(): failed to verify allocation (reg:%llx != rbwb:%llu)",
> + __func__, reg, cfg->rbwb);
> + return -EIO;
> + }
> + }
> +
> + return ret;
> +}
> +
> +int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type t, u32 cfg_val)
> +{
> + struct cbqri_controller *ctrl;
> + struct cbqri_resctrl_dom *dom;
> + struct cbqri_config cfg;
> + int err = 0;
> +
> + dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> + ctrl = dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return -EINVAL;
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + cfg.cbm = cfg_val;
> + err = cbqri_apply_cache_config(dom, closid, t, &cfg);
> + break;
> + case RDT_RESOURCE_MBA:
> + /* covert from percentage to bandwidth blocks */
> + cfg.rbwb = cfg_val * ctrl->bc.nbwblks / 100;
> + err = cbqri_apply_bw_config(dom, closid, t, &cfg);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return err;
> +}
> +
> +int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
> +{
> + struct resctrl_staged_config *cfg;
> + enum resctrl_conf_type t;
> + struct rdt_ctrl_domain *d;
> + int err = 0;
> +
> + list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
> + for (t = 0; t < CDP_NUM_TYPES; t++) {
> + cfg = &d->staged_config[t];
> + if (!cfg->have_new_ctrl)
> + continue;
> + err = resctrl_arch_update_one(r, d, closid, t, cfg->new_ctrl);
> + if (err) {
> + pr_warn("%s(): update failed (err=%d)", __func__, err);
> + return err;
> + }
> + }
> + }
> + return err;
> +}
> +
> +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type type)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct cbqri_controller *ctrl;
> + int reg_offset;
> + u32 percent;
> + u32 rbwb;
> + u64 reg;
> + int err;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> +
> + ctrl = hw_dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return resctrl_get_default_ctrl(r);
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + /* Clear cc_block_mask before read limit operation */
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> +
> + /* Read capacity block mask for RCID (closid) */
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> +
> + /* Update the config value for the closid in this domain */
> + hw_dom->ctrl_val[closid] = reg;
> + return hw_dom->ctrl_val[closid];
> +
> + case RDT_RESOURCE_MBA:
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> +
> + hw_dom->ctrl_val[closid] = cbqri_get_rbwb(ctrl);
> +
> + /* Convert from bandwidth blocks to percent */
> + rbwb = hw_dom->ctrl_val[closid];
> + rbwb *= 100;
> + percent = rbwb / ctrl->bc.nbwblks;
> + if (rbwb % ctrl->bc.nbwblks)
> + percent++;
> + return percent;
> +
> + default:
> + return resctrl_get_default_ctrl(r);
> + }
> +}
> +
> +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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
> + reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) << CBQRI_CONTROL_REGISTERS_OP_SHIFT;
> + iowrite64(reg, ctrl->base + reg_offset);
> + if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
> + pr_err("%s(): BUSY timeout when executing the operation", __func__);
> + return -EIO;
> + }
> +
> + /* Get the operation status */
> + reg = ioread64(ctrl->base + reg_offset);
> + *status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_STATUS_MASK;
> +
> + /*
> + * 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 << CBQRI_CONTROL_REGISTERS_AT_SHIFT);
> + reg |= CBQRI_CONTROL_REGISTERS_AT_CODE << CBQRI_CONTROL_REGISTERS_AT_SHIFT;
> + iowrite64(reg, ctrl->base + reg_offset);
> + if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
> + pr_err("%s(): BUSY timeout when setting AT field", __func__);
> + return -EIO;
> + }
> +
> + /*
> + * If the AT field value has been reset to zero,
> + * then the AT support is not present
> + */
> + reg = ioread64(ctrl->base + reg_offset);
> + at = (reg >> CBQRI_CONTROL_REGISTERS_AT_SHIFT) & CBQRI_CONTROL_REGISTERS_AT_MASK;
> + 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) < 0) {
> + pr_err("%s(): BUSY timeout when restoring the original register value", __func__);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Note: for the purposes of the CBQRI proof-of-concept, debug logging
> + * has been left in this function that detects the properties of CBQRI
> + * capable controllers in the system. pr_info calls would be removed
> + * before submitting non-RFC patches.
> + */
> +static int cbqri_probe_controller(struct cbqri_controller_info *ctrl_info,
> + struct cbqri_controller *ctrl)
> +{
> + int err = 0, status;
> + u64 reg;
> +
> + pr_info("controller info: type=%d addr=0x%lx size=%lu max-rcid=%u max-mcid=%u",
> + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> + ctrl_info->rcid_count, ctrl_info->mcid_count);
> +
> + /* max_rmid is used by resctrl_arch_system_num_rmid_idx() */
> + max_rmid = ctrl_info->mcid_count;
Get the min of all controllers?
> +
> + ctrl->ctrl_info = ctrl_info;
> +
> + /* Try to access the memory-mapped CBQRI registers */
> + if (!request_mem_region(ctrl_info->addr, ctrl_info->size, "cbqri_controller")) {
> + pr_warn("%s(): request_mem_region failed for cbqri_controller at 0x%lx",
> + __func__, ctrl_info->addr);
> + return -EBUSY;
> + }
> + ctrl->base = ioremap(ctrl_info->addr, ctrl_info->size);
> + if (!ctrl->base) {
> + pr_warn("%s(): goto err_release_mem_region", __func__);
> + goto err_release_mem_region;
> + }
> +
> + ctrl->alloc_capable = false;
> + ctrl->mon_capable = false;
> +
> + /* Probe capacity allocation and monitoring features */
> + if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> + pr_info("probe capacity controller");
> +
> + /* Make sure the register is implemented */
> + reg = ioread64(ctrl->base + CBQRI_CC_CAPABILITIES_OFF);
> + if (reg == 0) {
> + err = -ENODEV;
> + goto err_iounmap;
> + }
> +
> + ctrl->ver_minor = reg & CBQRI_CC_CAPABILITIES_VER_MINOR_MASK;
> + ctrl->ver_major = reg & CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK;
> +
> + ctrl->cc.supports_alloc_op_flush_rcid = (reg >> CBQRI_CC_CAPABILITIES_FRCID_SHIFT)
> + & CBQRI_CC_CAPABILITIES_FRCID_MASK;
> +
> + ctrl->cc.ncblks = (reg >> CBQRI_CC_CAPABILITIES_NCBLKS_SHIFT) &
> + CBQRI_CC_CAPABILITIES_NCBLKS_MASK;
> +
> + /* Calculate size of capacity block in bytes */
> + ctrl->cc.blk_size = ctrl_info->cache.cache_size / ctrl->cc.ncblks;
> + ctrl->cc.cache_level = ctrl_info->cache.cache_level;
> +
> + pr_info("version=%d.%d ncblks=%d blk_size=%d cache_level=%d",
> + ctrl->ver_major, ctrl->ver_minor,
> + ctrl->cc.ncblks, ctrl->cc.blk_size, ctrl->cc.cache_level);
> +
> + /* Probe monitoring features */
> + err = cbqri_probe_feature(ctrl, CBQRI_CC_MON_CTL_OFF,
> + CBQRI_CC_MON_CTL_OP_READ_COUNTER, &status,
> + &ctrl->cc.supports_mon_at_code);
> + if (err) {
> + pr_warn("%s() failed to probe cc_mon_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_CC_MON_CTL_STATUS_SUCCESS) {
> + pr_info("cc_mon_ctl is supported");
> + ctrl->cc.supports_mon_op_config_event = true;
> + ctrl->cc.supports_mon_op_read_counter = true;
> + ctrl->mon_capable = true;
> + } else {
> + pr_info("cc_mon_ctl is NOT supported");
> + ctrl->cc.supports_mon_op_config_event = false;
> + ctrl->cc.supports_mon_op_read_counter = false;
> + ctrl->mon_capable = false;
> + }
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported.
> + */
> + ctrl->cc.supports_mon_at_data = true;
> + pr_info("supports_mon_at_data: %d, supports_mon_at_code: %d",
> + ctrl->cc.supports_mon_at_data, ctrl->cc.supports_mon_at_code);
> +
> + /* Probe allocation features */
> + 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) {
> + pr_warn("%s() failed to probe cc_alloc_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
> + pr_info("cc_alloc_ctl is supported");
> + ctrl->cc.supports_alloc_op_config_limit = true;
> + ctrl->cc.supports_alloc_op_read_limit = true;
> + ctrl->alloc_capable = true;
> + exposed_alloc_capable = true;
> + } else {
> + pr_info("cc_alloc_ctl is NOT supported");
> + ctrl->cc.supports_alloc_op_config_limit = false;
> + ctrl->cc.supports_alloc_op_read_limit = false;
> + ctrl->alloc_capable = false;
> + }
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported
> + */
> + ctrl->cc.supports_alloc_at_data = true;
> + pr_info("supports_alloc_at_data: %d, supports_alloc_at_code: %d",
> + ctrl->cc.supports_alloc_at_data,
> + ctrl->cc.supports_alloc_at_code);
> + } else if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
> + pr_info("probe bandwidth controller");
> +
> + /* Make sure the register is implemented */
> + reg = ioread64(ctrl->base + CBQRI_BC_CAPABILITIES_OFF);
> + if (reg == 0) {
> + err = -ENODEV;
> + goto err_iounmap;
> + }
> +
> + ctrl->ver_minor = reg & CBQRI_BC_CAPABILITIES_VER_MINOR_MASK;
> + ctrl->ver_major = reg & CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK;
> +
> + ctrl->bc.nbwblks = (reg >> CBQRI_BC_CAPABILITIES_NBWBLKS_SHIFT) &
> + CBQRI_BC_CAPABILITIES_NBWBLKS_MASK;
> + ctrl->bc.mrbwb = (reg >> CBQRI_BC_CAPABILITIES_MRBWB_SHIFT) &
> + CBQRI_BC_CAPABILITIES_MRBWB_MASK;
> +
> + pr_info("version=%d.%d nbwblks=%d mrbwb=%d",
> + ctrl->ver_major, ctrl->ver_minor,
> + ctrl->bc.nbwblks, ctrl->bc.mrbwb);
> +
> + /* Probe monitoring features */
> + err = cbqri_probe_feature(ctrl, CBQRI_BC_MON_CTL_OFF,
> + CBQRI_BC_MON_CTL_OP_READ_COUNTER,
> + &status, &ctrl->bc.supports_mon_at_code);
> + if (err) {
> + pr_warn("%s() failed to probe bc_mon_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_BC_MON_CTL_STATUS_SUCCESS) {
> + pr_info("bc_mon_ctl is supported");
> + ctrl->bc.supports_mon_op_config_event = true;
> + ctrl->bc.supports_mon_op_read_counter = true;
> + ctrl->mon_capable = true;
> + exposed_mon_capable = true;
> + } else {
> + pr_info("bc_mon_ctl is NOT supported");
> + ctrl->bc.supports_mon_op_config_event = false;
> + ctrl->bc.supports_mon_op_read_counter = false;
> + ctrl->mon_capable = false;
> + }
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported
> + */
> + ctrl->bc.supports_mon_at_data = true;
> + pr_info("supports_mon_at_data: %d, supports_mon_at_code: %d",
> + ctrl->bc.supports_mon_at_data, ctrl->bc.supports_mon_at_code);
> +
> + /* Probe allocation features */
> + 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) {
> + pr_warn("%s() failed to probe bc_alloc_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
> + pr_warn("bc_alloc_ctl is supported");
> + ctrl->bc.supports_alloc_op_config_limit = true;
> + ctrl->bc.supports_alloc_op_read_limit = true;
> + ctrl->alloc_capable = true;
> + exposed_alloc_capable = true;
> + } else {
> + pr_warn("bc_alloc_ctl is NOT supported");
> + ctrl->bc.supports_alloc_op_config_limit = false;
> + ctrl->bc.supports_alloc_op_read_limit = false;
> + ctrl->alloc_capable = false;
> + }
> +
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported
> + */
> + ctrl->bc.supports_alloc_at_data = true;
> + pr_warn("supports_alloc_at_data: %d, supports_alloc_at_code: %d",
> + ctrl->bc.supports_alloc_at_data, ctrl->bc.supports_alloc_at_code);
> + } else {
> + pr_warn("controller type is UNKNOWN");
> + err = -ENODEV;
> + goto err_release_mem_region;
> + }
> +
> + return 0;
> +
> +err_iounmap:
> + pr_warn("%s(): err_iounmap", __func__);
> + iounmap(ctrl->base);
> +
> +err_release_mem_region:
> + pr_warn("%s(): err_release_mem_region", __func__);
> + release_mem_region(ctrl_info->addr, ctrl_info->size);
> +
> + return err;
> +}
> +
> +static struct rdt_ctrl_domain *qos_new_domain(struct cbqri_controller *ctrl)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct rdt_ctrl_domain *domain;
> +
> + hw_dom = kzalloc(sizeof(*hw_dom), GFP_KERNEL);
> + if (!hw_dom)
> + return NULL;
> +
> + /* associate this cbqri_controller with the domain */
> + hw_dom->hw_ctrl = ctrl;
> +
> + /* the rdt_domain struct from inside the cbqri_resctrl_dom struct */
> + domain = &hw_dom->resctrl_ctrl_dom;
> +
> + INIT_LIST_HEAD(&domain->hdr.list);
> +
> + return domain;
> +}
> +
> +static int qos_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
> +{
> + struct cbqri_resctrl_res *hw_res;
> + struct cbqri_resctrl_dom *hw_dom;
> + u64 *dc;
> + int err = 0;
> + int i;
> +
> + hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
> + if (!hw_res)
> + return -ENOMEM;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> + if (!hw_dom)
> + return -ENOMEM;
> +
> + dc = kmalloc_array(hw_res->max_rcid, sizeof(*hw_dom->ctrl_val),
> + GFP_KERNEL);
> + if (!dc)
> + return -ENOMEM;
> +
> + hw_dom->ctrl_val = dc;
> +
> + for (i = 0; i < hw_res->max_rcid; i++, dc++) {
> + err = resctrl_arch_update_one(r, d, i, 0, resctrl_get_default_ctrl(r));
> + if (err)
> + return 0;
return 0 ?
> + *dc = resctrl_get_default_ctrl(r);
> + }
> + return 0;
> +}
> +
> +static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
> +{
> + struct rdt_ctrl_domain *domain = NULL;
> + struct cbqri_resctrl_res *cbqri_res = NULL;
> + struct rdt_resource *res = NULL;
> + int internal_id = *id;
> + int err = 0;
> +
> + domain = qos_new_domain(ctrl);
> + if (!domain)
> + return -ENOSPC;
> + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> + cpumask_copy(&domain->hdr.cpu_mask, &ctrl->ctrl_info->cache.cpu_mask);
> + if (ctrl->ctrl_info->cache.cache_level == 2) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_L2;
> + res->name = "L2";
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = ctrl->mon_capable;
> + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> + res->ctrl_scope = RESCTRL_L2_CACHE;
> + res->cache.arch_has_sparse_bitmasks = false;
> + res->cache.arch_has_per_cpu_cfg = false;
> + res->cache.cbm_len = ctrl->cc.ncblks;
> + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> + res->cache.min_cbm_bits = 1;
> + } else if (ctrl->ctrl_info->cache.cache_level == 3) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_L3;
> + res->name = "L3";
> + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> + res->ctrl_scope = RESCTRL_L3_CACHE;
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = ctrl->mon_capable;
> + res->cache.arch_has_sparse_bitmasks = false;
> + res->cache.arch_has_per_cpu_cfg = false;
> + res->cache.cbm_len = ctrl->cc.ncblks;
> + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> + res->cache.min_cbm_bits = 1;
> + } else {
> + pr_warn("%s(): unknown cache level %d", __func__,
> + ctrl->ctrl_info->cache.cache_level);
> + err = -ENODEV;
> + goto err_free_domain;
> + }
> + } else if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
> + if (ctrl->alloc_capable) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_MBA];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_MBA;
> + res->name = "MB";
> + res->schema_fmt = RESCTRL_SCHEMA_RANGE;
> + res->ctrl_scope = RESCTRL_L3_CACHE;
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = false;
> + res->membw.delay_linear = true;
> + res->membw.arch_needs_linear = true;
> + res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
> + // The minimum percentage allowed by the CBQRI spec
> + res->membw.min_bw = 1;
> + // The maximum percentage allowed by the CBQRI spec
> + res->membw.max_bw = 80;
> + res->membw.bw_gran = 1;
> + }
Wrap a function.
> + } else {
> + pr_warn("%s(): unknown resource %d", __func__, ctrl->ctrl_info->type);
> + err = -ENODEV;
> + goto err_free_domain;
> + }
> +
> + domain->hdr.id = internal_id;
> + err = qos_init_domain_ctrlval(res, domain);
> + if (err)
> + goto err_free_domain;
> +
> + if (cbqri_res) {
> + list_add_tail(&domain->hdr.list, &cbqri_res->resctrl_res.ctrl_domains);
> + *id = internal_id;
> + err = resctrl_online_ctrl_domain(res, domain);
> + if (err) {
> + pr_warn("%s(): failed to online cbqri_res domain", __func__);
> + goto err_free_domain;
> + }
> + }
> +
> + return 0;
> +
> +err_free_domain:
> + pr_warn("%s(): err_free_domain", __func__);
> + kfree(container_of(domain, struct cbqri_resctrl_dom, resctrl_ctrl_dom));
free hw_dom->ctrl_val ?
> +
> + return err;
> +}
> +
> +int qos_resctrl_setup(void)
> +{
> + struct rdt_ctrl_domain *domain, *domain_temp;
> + struct cbqri_controller_info *ctrl_info;
> + struct cbqri_controller *ctrl;
> + struct cbqri_resctrl_res *res;
> + static int found_controllers;
> + int err = 0;
> + int id = 0;
> + int i;
> +
> + list_for_each_entry(ctrl_info, &cbqri_controllers, list) {
> + err = cbqri_probe_controller(ctrl_info, &controllers[found_controllers]);
> + if (err) {
> + pr_warn("%s(): failed (%d)", __func__, err);
> + goto err_unmap_controllers;
> + }
> +
> + found_controllers++;
> + if (found_controllers > MAX_CONTROLLERS) {
> + pr_warn("%s(): increase MAX_CONTROLLERS value", __func__);
> + break;
> + }
> + }
> +
> + for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> + res = &cbqri_resctrl_resources[i];
> + INIT_LIST_HEAD(&res->resctrl_res.ctrl_domains);
> + INIT_LIST_HEAD(&res->resctrl_res.mon_domains);
> + res->resctrl_res.rid = i;
> + }
> +
> + for (i = 0; i < found_controllers; i++) {
> + ctrl = &controllers[i];
> + err = qos_resctrl_add_controller_domain(ctrl, &id);
> + if (err) {
> + pr_warn("%s(): failed to add controller domain (%d)", __func__, err);
> + goto err_free_controllers_list;
> + }
> + id++;
> +
> + /*
> + * CDP (code data prioritization) on x86 is similar to
> + * the AT (access type) field in CBQRI. CDP only supports
> + * caches so this must be a CBQRI capacity controller.
> + */
> + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
> + ctrl->cc.supports_alloc_at_code &&
> + ctrl->cc.supports_alloc_at_data) {
> + if (ctrl->ctrl_info->cache.cache_level == 2)
> + exposed_cdp_l2_capable = true;
> + else
> + exposed_cdp_l3_capable = true;
> + }
> + }
> +
> + pr_info("exposed_alloc_capable = %d", exposed_alloc_capable);
> + pr_info("exposed_mon_capable = %d", exposed_mon_capable);
> + pr_info("exposed_cdp_l2_capable = %d", exposed_cdp_l2_capable);
> + pr_info("exposed_cdp_l3_capable = %d", exposed_cdp_l3_capable);
> +
> + return resctrl_init();
> +
> +err_free_controllers_list:
> + for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> + res = &cbqri_resctrl_resources[i];
> + list_for_each_entry_safe(domain, domain_temp, &res->resctrl_res.ctrl_domains,
> + hdr.list) {
> + kfree(domain);
> + }
> + }
> +
> +err_unmap_controllers:
> + for (i = 0; i < found_controllers; i++) {
> + iounmap(controllers[i].base);
> + release_mem_region(controllers[i].ctrl_info->addr, controllers[i].ctrl_info->size);
> + }
> +
> + return err;
> +}
> +
> +int qos_resctrl_online_cpu(unsigned int cpu)
> +{
> + resctrl_online_cpu(cpu);
> + return 0;
> +}
> +
> +int qos_resctrl_offline_cpu(unsigned int cpu)
> +{
> + resctrl_offline_cpu(cpu);
> + return 0;
> +}
> +
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext
2026-01-28 20:27 ` [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext Drew Fustini
2026-02-02 3:17 ` [External] " yunhui cui
@ 2026-02-02 4:27 ` yunhui cui
2026-02-03 19:43 ` Drew Fustini
1 sibling, 1 reply; 57+ messages in thread
From: yunhui cui @ 2026-02-02 4:27 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add support for the srmcfg CSR defined in the Ssqosid ISA extension
> (Supervisor-mode Quality of Service ID). The CSR contains two fields:
>
> - Resource Control ID (RCID) used determine resource allocation
> - Monitoring Counter ID (MCID) used to track resource usage
>
> Requests from a hart to shared resources like cache will be tagged with
> these IDs. This allows the usage of shared resources to be associated
> with the task currently running on the hart.
>
> A srmcfg field is added to thread_struct and has the same format as the
> srmcfg CSR. This allows the scheduler to set the hart's srmcfg CSR to
> contain the RCID and MCID for the task that is being scheduled in. The
> srmcfg CSR is only written to if the thread_struct.srmcfg is different
> than the current value of the CSR.
>
> A per-cpu variable cpu_srmcfg is used to mirror that state of the CSR.
> This is because access to L1D hot memory should be several times faster
> than a CSR read. Also, in the case of virtualization, accesses to this
> CSR are trapped in the hypervisor.
>
> Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
> Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
> Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
> [fustini: rename csr, refactor switch_to, rebase on upstream]
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> MAINTAINERS | 7 +++++++
> arch/riscv/Kconfig | 17 ++++++++++++++++
> arch/riscv/include/asm/csr.h | 8 ++++++++
> arch/riscv/include/asm/processor.h | 3 +++
> arch/riscv/include/asm/qos.h | 41 ++++++++++++++++++++++++++++++++++++++
> arch/riscv/include/asm/switch_to.h | 3 +++
> arch/riscv/kernel/Makefile | 2 ++
> arch/riscv/kernel/qos/Makefile | 2 ++
> arch/riscv/kernel/qos/qos.c | 5 +++++
> 9 files changed, 88 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 765ad2daa218..e98d553bd0ca 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22505,6 +22505,13 @@ F: drivers/perf/riscv_pmu.c
> F: drivers/perf/riscv_pmu_legacy.c
> F: drivers/perf/riscv_pmu_sbi.c
>
> +RISC-V QOS RESCTRL SUPPORT
> +M: Drew Fustini <fustini@kernel.org>
If you don’t mind, to help support RISC-V QoS resctrl development and
ensure interface stability, could you please add an 'R:' entry with my
email address?
> +L: linux-riscv@lists.infradead.org
> +S: Supported
> +F: arch/riscv/include/asm/qos.h
> +F: arch/riscv/kernel/qos/
> +
> RISC-V RPMI AND MPXY DRIVERS
> M: Rahul Pathak <rahul@summations.net>
> M: Anup Patel <anup@brainfault.org>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 6b39f37f769a..35a6238b02c5 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -595,6 +595,23 @@ config RISCV_ISA_SVNAPOT
>
> If you don't know what to do here, say Y.
>
> +config RISCV_ISA_SSQOSID
> + bool "Ssqosid extension support for supervisor mode Quality of Service ID"
> + default y
> + help
> + Adds support for the Ssqosid ISA extension (Supervisor-mode
> + Quality of Service ID).
> +
> + Ssqosid defines the srmcfg CSR which allows the system to tag the
> + running process with an RCID (Resource Control ID) and MCID
> + (Monitoring Counter ID). The RCID is used to determine resource
> + allocation. The MCID is used to track resource usage in event
> + counters.
> +
> + For example, a cache controller may use the RCID to apply a
> + cache partitioning scheme and use the MCID to track how much
> + cache a process, or a group of processes, is using.
> +
> config RISCV_ISA_SVPBMT
> bool "Svpbmt extension support for supervisor mode page-based memory types"
> depends on 64BIT && MMU
> diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
> index 4a37a98398ad..2590b89b8f72 100644
> --- a/arch/riscv/include/asm/csr.h
> +++ b/arch/riscv/include/asm/csr.h
> @@ -75,6 +75,13 @@
> #define SATP_ASID_MASK _AC(0xFFFF, UL)
> #endif
>
> +/* SRMCFG fields */
> +#define SRMCFG_RCID_MASK _AC(0x00000FFF, UL)
> +#define SRMCFG_MCID_MASK SRMCFG_RCID_MASK
> +#define SRMCFG_MCID_SHIFT 16
> +#define SRMCFG_MASK ((SRMCFG_MCID_MASK << SRMCFG_MCID_SHIFT) | \
> + SRMCFG_RCID_MASK)
> +
> /* Exception cause high bit - is an interrupt if set */
> #define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
>
> @@ -317,6 +324,7 @@
> #define CSR_STVAL 0x143
> #define CSR_SIP 0x144
> #define CSR_SATP 0x180
> +#define CSR_SRMCFG 0x181
>
> #define CSR_STIMECMP 0x14D
> #define CSR_STIMECMPH 0x15D
> diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
> index da5426122d28..183c55e32b96 100644
> --- a/arch/riscv/include/asm/processor.h
> +++ b/arch/riscv/include/asm/processor.h
> @@ -122,6 +122,9 @@ struct thread_struct {
> /* A forced icache flush is not needed if migrating to the previous cpu. */
> unsigned int prev_cpu;
> #endif
> +#ifdef CONFIG_RISCV_ISA_SSQOSID
> + u32 srmcfg;
> +#endif
> };
>
> /* Whitelist the fstate from the task_struct for hardened usercopy */
> diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h
> new file mode 100644
> index 000000000000..84830d7c6dc4
> --- /dev/null
> +++ b/arch/riscv/include/asm/qos.h
> @@ -0,0 +1,41 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_RISCV_QOS_H
> +#define _ASM_RISCV_QOS_H
> +
> +#ifdef CONFIG_RISCV_ISA_SSQOSID
> +
> +#include <linux/sched.h>
> +#include <linux/jump_label.h>
> +
> +#include <asm/barrier.h>
> +#include <asm/csr.h>
> +#include <asm/hwcap.h>
> +
> +/* cached value of srmcfg csr for each cpu */
> +DECLARE_PER_CPU(u32, cpu_srmcfg);
> +
> +static inline void __switch_to_srmcfg(struct task_struct *next)
> +{
> + u32 *cpu_srmcfg_ptr = this_cpu_ptr(&cpu_srmcfg);
> + u32 thread_srmcfg;
> +
> + thread_srmcfg = READ_ONCE(next->thread.srmcfg);
> +
> + if (thread_srmcfg != *cpu_srmcfg_ptr) {
> + *cpu_srmcfg_ptr = thread_srmcfg;
> + csr_write(CSR_SRMCFG, thread_srmcfg);
> + }
> +}
> +
> +static __always_inline bool has_srmcfg(void)
> +{
> + return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID);
> +}
> +
> +#else /* ! CONFIG_RISCV_ISA_SSQOSID */
> +
> +static __always_inline bool has_srmcfg(void) { return false; }
> +#define __switch_to_srmcfg(__next) do { } while (0)
> +
> +#endif /* CONFIG_RISCV_ISA_SSQOSID */
> +#endif /* _ASM_RISCV_QOS_H */
> diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
> index 0e71eb82f920..a684a3795d3d 100644
> --- a/arch/riscv/include/asm/switch_to.h
> +++ b/arch/riscv/include/asm/switch_to.h
> @@ -14,6 +14,7 @@
> #include <asm/processor.h>
> #include <asm/ptrace.h>
> #include <asm/csr.h>
> +#include <asm/qos.h>
>
> #ifdef CONFIG_FPU
> extern void __fstate_save(struct task_struct *save_to);
> @@ -119,6 +120,8 @@ do { \
> __switch_to_fpu(__prev, __next); \
> if (has_vector() || has_xtheadvector()) \
> __switch_to_vector(__prev, __next); \
> + if (has_srmcfg()) \
> + __switch_to_srmcfg(__next); \
> if (switch_to_should_flush_icache(__next)) \
> local_flush_icache_all(); \
> __switch_to_envcfg(__next); \
> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> index f60fce69b725..a3c36d18145c 100644
> --- a/arch/riscv/kernel/Makefile
> +++ b/arch/riscv/kernel/Makefile
> @@ -125,3 +125,5 @@ obj-$(CONFIG_ACPI) += acpi.o
> obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o
>
> obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
> +
> +obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos/
> diff --git a/arch/riscv/kernel/qos/Makefile b/arch/riscv/kernel/qos/Makefile
> new file mode 100644
> index 000000000000..9f996263a86d
> --- /dev/null
> +++ b/arch/riscv/kernel/qos/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
> diff --git a/arch/riscv/kernel/qos/qos.c b/arch/riscv/kernel/qos/qos.c
> new file mode 100644
> index 000000000000..7b06f7ae9056
> --- /dev/null
> +++ b/arch/riscv/kernel/qos/qos.c
> @@ -0,0 +1,5 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +#include <asm/qos.h>
> +
> +/* cached value of sqoscfg csr for each cpu */
> +DEFINE_PER_CPU(u32, cpu_srmcfg);
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table
2026-01-28 20:27 ` [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table Drew Fustini
@ 2026-02-02 11:08 ` yunhui cui
2026-02-03 20:00 ` Drew Fustini
2026-02-14 4:48 ` Drew Fustini
0 siblings, 2 replies; 57+ messages in thread
From: yunhui cui @ 2026-02-02 11:08 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add driver to parse the ACPI RISC-V Quality of Service Controller (RQSC)
> table which describes the capacity and bandwidth QoS controllers in a
> system. The QoS controllers implement the RISC-V Capacity and Bandwidth
> Controller QoS Register Interface (CBQRI) specification.
>
> Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> MAINTAINERS | 1 +
> arch/riscv/include/asm/acpi.h | 10 ++++
> drivers/acpi/riscv/Makefile | 2 +-
> drivers/acpi/riscv/rqsc.c | 112 ++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 124 insertions(+), 1 deletion(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 96ead357a634..e96a83dc9a02 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22512,6 +22512,7 @@ S: Supported
> F: arch/riscv/include/asm/qos.h
> F: arch/riscv/include/asm/resctrl.h
> F: arch/riscv/kernel/qos/
> +F: drivers/acpi/riscv/rqsc.c
> F: include/linux/riscv_qos.h
>
> RISC-V RPMI AND MPXY DRIVERS
> diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
> index 6e13695120bc..16c6e25eed1e 100644
> --- a/arch/riscv/include/asm/acpi.h
> +++ b/arch/riscv/include/asm/acpi.h
> @@ -71,6 +71,16 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
>
> void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
> u32 *cboz_size, u32 *cbop_size);
> +
> +#ifdef CONFIG_RISCV_ISA_SSQOSID
> +int acpi_parse_rqsc(struct acpi_table_header *table);
> +#else
> +static inline int acpi_parse_rqsc(struct acpi_table_header *table)
> +{
> + return -EINVAL;
> +}
> +#endif /* CONFIG_RISCV_ISA_SSQOSID */
> +
> #else
> static inline void acpi_init_rintc_map(void) { }
> static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
> diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
> index 1284a076fa88..cf0f38c93a9f 100644
> --- a/drivers/acpi/riscv/Makefile
> +++ b/drivers/acpi/riscv/Makefile
> @@ -1,5 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-y += rhct.o init.o irq.o
> +obj-y += rhct.o rqsc.o init.o irq.o
> obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
> obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
> obj-$(CONFIG_ACPI_RIMT) += rimt.o
> diff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c
> new file mode 100644
> index 000000000000..a86ddb39fae4
> --- /dev/null
> +++ b/drivers/acpi/riscv/rqsc.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2025 Tenstorrent
> + * Author: Drew Fustini <fustini@kernel.org>
> + *
> + */
> +
> +#define pr_fmt(fmt) "ACPI: RQSC: " fmt
> +
> +#include <linux/acpi.h>
> +#include <linux/bits.h>
> +#include <linux/riscv_qos.h>
> +
> +#ifdef CONFIG_RISCV_ISA_SSQOSID
> +
> +#define CBQRI_CTRL_SIZE 0x1000
> +
> +static struct acpi_table_rqsc *acpi_get_rqsc(void)
> +{
> + static struct acpi_table_header *rqsc;
> + acpi_status status;
> +
> + /*
> + * RQSC will be used at runtime on every CPU, so we
> + * don't need to call acpi_put_table() to release the table mapping.
> + */
> + if (!rqsc) {
> + status = acpi_get_table(ACPI_SIG_RQSC, 0, &rqsc);
> + if (ACPI_FAILURE(status)) {
> + pr_warn_once("No RQSC table found\n");
> + return NULL;
> + }
> + }
> +
> + return (struct acpi_table_rqsc *)rqsc;
> +}
> +
> +int acpi_parse_rqsc(struct acpi_table_header *table)
> +{
> + struct acpi_table_rqsc *rqsc;
> + int err;
> +
> + BUG_ON(acpi_disabled);
> + if (!table) {
> + rqsc = acpi_get_rqsc();
> + if (!rqsc)
> + return -ENOENT;
> + } else {
> + rqsc = (struct acpi_table_rqsc *)table;
> + }
> +
> + for (int i = 0; i < rqsc->num; i++) {
> + struct cbqri_controller_info *ctrl_info;
> +
> + ctrl_info = kzalloc(sizeof(*ctrl_info), GFP_KERNEL);
> + if (!ctrl_info)
> + return -ENOMEM;
> +
> + ctrl_info->type = rqsc->f[i].type;
> + ctrl_info->addr = rqsc->f[i].reg[1];
> + ctrl_info->size = CBQRI_CTRL_SIZE;
> + ctrl_info->rcid_count = rqsc->f[i].rcid;
> + ctrl_info->mcid_count = rqsc->f[i].mcid;
> +
> + pr_info("Found controller with type %u addr 0x%lx size %lu rcid %u mcid %u",
> + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> + ctrl_info->rcid_count, ctrl_info->mcid_count);
> +
> + if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> + ctrl_info->cache.cache_id = rqsc->f[i].res.id1;
> + ctrl_info->cache.cache_level =
> + find_acpi_cache_level_from_id(ctrl_info->cache.cache_id);
> +
> + struct acpi_pptt_cache *cache;
> +
> + cache = find_acpi_cache_from_id(ctrl_info->cache.cache_id);
> + if (cache) {
> + ctrl_info->cache.cache_size = cache->size;
> + } else {
> + pr_warn("%s(): failed to determine size for cache id 0x%x",
> + __func__, ctrl_info->cache.cache_id);
> + ctrl_info->cache.cache_size = 0;
> + }
> +
> + pr_info("Cache controller has ID 0x%x level %u size %u ",
> + ctrl_info->cache.cache_id, ctrl_info->cache.cache_level,
> + ctrl_info->cache.cache_size);
> +
> + /*
> + * For CBQRI, any cpu (technically a hart in RISC-V terms)
> + * can access the memory-mapped registers of any CBQRI
> + * controller in the system.
> + */
> + err = cpumask_parse("FF", &ctrl_info->cache.cpu_mask);
Hardcode? acpi_pptt_get_cpumask_from_cache_id(ctrl_info->cache.cache_id,
&ctrl_info->cache.cpu_mask); ?
> + if (err)
> + pr_err("Failed to convert cores mask string to cpumask (%d)", err);
> +
> + } else if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
> + ctrl_info->mem.prox_dom = rqsc->f[i].res.id1;
> + pr_info("Memory controller with proximity domain %u",
> + ctrl_info->mem.prox_dom);
> + }
> +
> + /* Fill the list shared with RISC-V QoS resctrl */
> + INIT_LIST_HEAD(&ctrl_info->list);
> + list_add_tail(&ctrl_info->list, &cbqri_controllers);
> + }
> +
> + return 0;
> +}
> +
> +#endif /* CONFIG_RISCV_ISA_SSQOSID */
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext
2026-02-02 4:27 ` yunhui cui
@ 2026-02-03 19:43 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-02-03 19:43 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Mon, Feb 02, 2026 at 12:27:59PM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add support for the srmcfg CSR defined in the Ssqosid ISA extension
> > (Supervisor-mode Quality of Service ID). The CSR contains two fields:
> >
> > - Resource Control ID (RCID) used determine resource allocation
> > - Monitoring Counter ID (MCID) used to track resource usage
> >
> > Requests from a hart to shared resources like cache will be tagged with
> > these IDs. This allows the usage of shared resources to be associated
> > with the task currently running on the hart.
> >
> > A srmcfg field is added to thread_struct and has the same format as the
> > srmcfg CSR. This allows the scheduler to set the hart's srmcfg CSR to
> > contain the RCID and MCID for the task that is being scheduled in. The
> > srmcfg CSR is only written to if the thread_struct.srmcfg is different
> > than the current value of the CSR.
> >
> > A per-cpu variable cpu_srmcfg is used to mirror that state of the CSR.
> > This is because access to L1D hot memory should be several times faster
> > than a CSR read. Also, in the case of virtualization, accesses to this
> > CSR are trapped in the hypervisor.
> >
> > Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
> > Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
> > Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
> > [fustini: rename csr, refactor switch_to, rebase on upstream]
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > MAINTAINERS | 7 +++++++
> > arch/riscv/Kconfig | 17 ++++++++++++++++
> > arch/riscv/include/asm/csr.h | 8 ++++++++
> > arch/riscv/include/asm/processor.h | 3 +++
> > arch/riscv/include/asm/qos.h | 41 ++++++++++++++++++++++++++++++++++++++
> > arch/riscv/include/asm/switch_to.h | 3 +++
> > arch/riscv/kernel/Makefile | 2 ++
> > arch/riscv/kernel/qos/Makefile | 2 ++
> > arch/riscv/kernel/qos/qos.c | 5 +++++
> > 9 files changed, 88 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 765ad2daa218..e98d553bd0ca 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -22505,6 +22505,13 @@ F: drivers/perf/riscv_pmu.c
> > F: drivers/perf/riscv_pmu_legacy.c
> > F: drivers/perf/riscv_pmu_sbi.c
> >
> > +RISC-V QOS RESCTRL SUPPORT
> > +M: Drew Fustini <fustini@kernel.org>
>
> If you don’t mind, to help support RISC-V QoS resctrl development and
> ensure interface stability, could you please add an 'R:' entry with my
> email address?
Sure, I will add in next revision.
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table
2026-02-02 11:08 ` [External] " yunhui cui
@ 2026-02-03 20:00 ` Drew Fustini
2026-02-14 4:48 ` Drew Fustini
1 sibling, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-02-03 20:00 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Mon, Feb 02, 2026 at 07:08:48PM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add driver to parse the ACPI RISC-V Quality of Service Controller (RQSC)
> > table which describes the capacity and bandwidth QoS controllers in a
> > system. The QoS controllers implement the RISC-V Capacity and Bandwidth
> > Controller QoS Register Interface (CBQRI) specification.
> >
> > Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> > Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > MAINTAINERS | 1 +
> > arch/riscv/include/asm/acpi.h | 10 ++++
> > drivers/acpi/riscv/Makefile | 2 +-
> > drivers/acpi/riscv/rqsc.c | 112 ++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 124 insertions(+), 1 deletion(-)
> >
[..]
> > +int acpi_parse_rqsc(struct acpi_table_header *table)
> > +{
> > + struct acpi_table_rqsc *rqsc;
> > + int err;
> > +
> > + BUG_ON(acpi_disabled);
> > + if (!table) {
> > + rqsc = acpi_get_rqsc();
> > + if (!rqsc)
> > + return -ENOENT;
> > + } else {
> > + rqsc = (struct acpi_table_rqsc *)table;
> > + }
> > +
> > + for (int i = 0; i < rqsc->num; i++) {
> > + struct cbqri_controller_info *ctrl_info;
> > +
> > + ctrl_info = kzalloc(sizeof(*ctrl_info), GFP_KERNEL);
> > + if (!ctrl_info)
> > + return -ENOMEM;
> > +
> > + ctrl_info->type = rqsc->f[i].type;
> > + ctrl_info->addr = rqsc->f[i].reg[1];
> > + ctrl_info->size = CBQRI_CTRL_SIZE;
> > + ctrl_info->rcid_count = rqsc->f[i].rcid;
> > + ctrl_info->mcid_count = rqsc->f[i].mcid;
> > +
> > + pr_info("Found controller with type %u addr 0x%lx size %lu rcid %u mcid %u",
> > + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> > + ctrl_info->rcid_count, ctrl_info->mcid_count);
> > +
> > + if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> > + ctrl_info->cache.cache_id = rqsc->f[i].res.id1;
> > + ctrl_info->cache.cache_level =
> > + find_acpi_cache_level_from_id(ctrl_info->cache.cache_id);
> > +
> > + struct acpi_pptt_cache *cache;
> > +
> > + cache = find_acpi_cache_from_id(ctrl_info->cache.cache_id);
> > + if (cache) {
> > + ctrl_info->cache.cache_size = cache->size;
> > + } else {
> > + pr_warn("%s(): failed to determine size for cache id 0x%x",
> > + __func__, ctrl_info->cache.cache_id);
> > + ctrl_info->cache.cache_size = 0;
> > + }
> > +
> > + pr_info("Cache controller has ID 0x%x level %u size %u ",
> > + ctrl_info->cache.cache_id, ctrl_info->cache.cache_level,
> > + ctrl_info->cache.cache_size);
> > +
> > + /*
> > + * For CBQRI, any cpu (technically a hart in RISC-V terms)
> > + * can access the memory-mapped registers of any CBQRI
> > + * controller in the system.
> > + */
> > + err = cpumask_parse("FF", &ctrl_info->cache.cpu_mask);
>
> Hardcode? acpi_pptt_get_cpumask_from_cache_id(ctrl_info->cache.cache_id,
> &ctrl_info->cache.cpu_mask); ?
Thanks, I will give that a try as the current value 0xFF is not flexible.
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext
2026-02-02 3:17 ` [External] " yunhui cui
@ 2026-02-08 1:31 ` Drew Fustini
2026-02-09 3:36 ` yunhui cui
0 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-02-08 1:31 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Mon, Feb 02, 2026 at 11:17:52AM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add support for the srmcfg CSR defined in the Ssqosid ISA extension
> > (Supervisor-mode Quality of Service ID). The CSR contains two fields:
> >
> > - Resource Control ID (RCID) used determine resource allocation
> > - Monitoring Counter ID (MCID) used to track resource usage
> >
> > Requests from a hart to shared resources like cache will be tagged with
> > these IDs. This allows the usage of shared resources to be associated
> > with the task currently running on the hart.
> >
> > A srmcfg field is added to thread_struct and has the same format as the
> > srmcfg CSR. This allows the scheduler to set the hart's srmcfg CSR to
> > contain the RCID and MCID for the task that is being scheduled in. The
> > srmcfg CSR is only written to if the thread_struct.srmcfg is different
> > than the current value of the CSR.
> >
> > A per-cpu variable cpu_srmcfg is used to mirror that state of the CSR.
> > This is because access to L1D hot memory should be several times faster
> > than a CSR read. Also, in the case of virtualization, accesses to this
> > CSR are trapped in the hypervisor.
> >
> > Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
> > Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
> > Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
> > [fustini: rename csr, refactor switch_to, rebase on upstream]
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
[..]
> > diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h
> > new file mode 100644
> > index 000000000000..84830d7c6dc4
> > --- /dev/null
> > +++ b/arch/riscv/include/asm/qos.h
> > @@ -0,0 +1,41 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_RISCV_QOS_H
> > +#define _ASM_RISCV_QOS_H
> > +
> > +#ifdef CONFIG_RISCV_ISA_SSQOSID
> > +
> > +#include <linux/sched.h>
> > +#include <linux/jump_label.h>
> > +
> > +#include <asm/barrier.h>
> > +#include <asm/csr.h>
> > +#include <asm/hwcap.h>
> > +
> > +/* cached value of srmcfg csr for each cpu */
> > +DECLARE_PER_CPU(u32, cpu_srmcfg);
> > +
> > +static inline void __switch_to_srmcfg(struct task_struct *next)
> > +{
> > + u32 *cpu_srmcfg_ptr = this_cpu_ptr(&cpu_srmcfg);
> > + u32 thread_srmcfg;
> > +
> > + thread_srmcfg = READ_ONCE(next->thread.srmcfg);
>
>
> First set the cpu_list, and then the condition thread_srmcfg !=
> *cpu_srmcfg_ptr will not be satisfied. Is a default value required
> here? Both code paths for cpu_list and tasks are compared against the
> default value; you may refer to the implementation of mpam.
I'm having trouble finding cpu_list but I think that it does make sense
to set the initial value.
Were you thinking I should look at mpam_set_cpu_defaults() in
the mpam_resctrl_glue_v4 [1] branch?
Thanks,
Drew
[1] https://gitlab.arm.com/linux-arm/linux-bh.git
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext
2026-02-08 1:31 ` Drew Fustini
@ 2026-02-09 3:36 ` yunhui cui
0 siblings, 0 replies; 57+ messages in thread
From: yunhui cui @ 2026-02-09 3:36 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Sun, Feb 8, 2026 at 9:31 AM Drew Fustini <fustini@kernel.org> wrote:
>
> On Mon, Feb 02, 2026 at 11:17:52AM +0800, yunhui cui wrote:
> > Hi Drew,
> >
> > On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> > >
> > > Add support for the srmcfg CSR defined in the Ssqosid ISA extension
> > > (Supervisor-mode Quality of Service ID). The CSR contains two fields:
> > >
> > > - Resource Control ID (RCID) used determine resource allocation
> > > - Monitoring Counter ID (MCID) used to track resource usage
> > >
> > > Requests from a hart to shared resources like cache will be tagged with
> > > these IDs. This allows the usage of shared resources to be associated
> > > with the task currently running on the hart.
> > >
> > > A srmcfg field is added to thread_struct and has the same format as the
> > > srmcfg CSR. This allows the scheduler to set the hart's srmcfg CSR to
> > > contain the RCID and MCID for the task that is being scheduled in. The
> > > srmcfg CSR is only written to if the thread_struct.srmcfg is different
> > > than the current value of the CSR.
> > >
> > > A per-cpu variable cpu_srmcfg is used to mirror that state of the CSR.
> > > This is because access to L1D hot memory should be several times faster
> > > than a CSR read. Also, in the case of virtualization, accesses to this
> > > CSR are trapped in the hypervisor.
> > >
> > > Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
> > > Co-developed-by: Kornel Dulęba <mindal@semihalf.com>
> > > Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
> > > [fustini: rename csr, refactor switch_to, rebase on upstream]
> > > Signed-off-by: Drew Fustini <fustini@kernel.org>
> [..]
> > > diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h
> > > new file mode 100644
> > > index 000000000000..84830d7c6dc4
> > > --- /dev/null
> > > +++ b/arch/riscv/include/asm/qos.h
> > > @@ -0,0 +1,41 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +#ifndef _ASM_RISCV_QOS_H
> > > +#define _ASM_RISCV_QOS_H
> > > +
> > > +#ifdef CONFIG_RISCV_ISA_SSQOSID
> > > +
> > > +#include <linux/sched.h>
> > > +#include <linux/jump_label.h>
> > > +
> > > +#include <asm/barrier.h>
> > > +#include <asm/csr.h>
> > > +#include <asm/hwcap.h>
> > > +
> > > +/* cached value of srmcfg csr for each cpu */
> > > +DECLARE_PER_CPU(u32, cpu_srmcfg);
> > > +
> > > +static inline void __switch_to_srmcfg(struct task_struct *next)
> > > +{
> > > + u32 *cpu_srmcfg_ptr = this_cpu_ptr(&cpu_srmcfg);
> > > + u32 thread_srmcfg;
> > > +
> > > + thread_srmcfg = READ_ONCE(next->thread.srmcfg);
> >
> >
> > First set the cpu_list, and then the condition thread_srmcfg !=
> > *cpu_srmcfg_ptr will not be satisfied. Is a default value required
> > here? Both code paths for cpu_list and tasks are compared against the
> > default value; you may refer to the implementation of mpam.
>
> I'm having trouble finding cpu_list but I think that it does make sense
> to set the initial value.
>
> Were you thinking I should look at mpam_set_cpu_defaults() in
> the mpam_resctrl_glue_v4 [1] branch?
To be exact, it's "cpus_list". yep, we need logic similar to that of
arm64_mpam_default.
>
> Thanks,
> Drew
>
> [1] https://gitlab.arm.com/linux-arm/linux-bh.git
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
2026-02-02 4:12 ` [External] " yunhui cui
@ 2026-02-09 7:20 ` Gong Shuai
2026-02-09 10:07 ` Gong Shuai
` (3 subsequent siblings)
5 siblings, 0 replies; 57+ messages in thread
From: Gong Shuai @ 2026-02-09 7:20 UTC (permalink / raw)
To: fustini
Cc: gong.shuai, Dave.Martin, acpica-devel, alex, aou, aricciardi,
atish.patra, atishp, babu.moger, ben.horgan, conor+dt, cp0613,
cuiyunhui, devicetree, fenghua.yu, guo.wenjia23, james.morse,
krzk+dt, lenb, linux-acpi, linux-kernel, linux-riscv,
liu.qingtao2, liwei1518, mindal, npitre, palmer, paul.walmsley,
peternewman, pjw, rafael, reinette.chatre, rkrcmar, robert.moore,
robh, samuel.holland, sunilvl, tony.luck, vasu, ved, x86,
zhiwei_liu
[-- Attachment #1.1.1: Type: text/plain, Size: 1460 bytes --]
Hi, Drew
> Add interface for CBQRI controller drivers to make use of the resctrl
> filesystem.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
>
> ...
>
> +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type type)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct cbqri_controller *ctrl;
> + int reg_offset;
> + u32 percent;
> + u32 rbwb;
> + u64 reg;
> + int err;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> +
> + ctrl = hw_dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return resctrl_get_default_ctrl(r);
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + /* Clear cc_block_mask before read limit operation */
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
It looks like the parameter order might be incorrect. I believe it should be:
cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, type)
Could you please double-check?
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> ...
Thanks,
Shuai
[-- Attachment #1.1.2: Type: text/html , Size: 3406 bytes --]
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
2026-02-02 4:12 ` [External] " yunhui cui
2026-02-09 7:20 ` Gong Shuai
@ 2026-02-09 10:07 ` Gong Shuai
2026-02-09 14:16 ` Gong Shuai
` (2 subsequent siblings)
5 siblings, 0 replies; 57+ messages in thread
From: Gong Shuai @ 2026-02-09 10:07 UTC (permalink / raw)
To: fustini
Cc: gong.shuai, Dave.Martin, acpica-devel, alex, aou, aricciardi,
atish.patra, atishp, babu.moger, ben.horgan, conor+dt, cp0613,
cuiyunhui, devicetree, fenghua.yu, guo.wenjia23, james.morse,
krzk+dt, lenb, linux-acpi, linux-kernel, linux-riscv,
liu.qingtao2, liwei1518, mindal, npitre, palmer, paul.walmsley,
peternewman, pjw, rafael, reinette.chatre, rkrcmar, robert.moore,
robh, samuel.holland, sunilvl, tony.luck, vasu, ved, x86,
zhiwei_liu
[-- Attachment #1.1.1: Type: text/plain, Size: 1460 bytes --]
Hi, Drew
> Add interface for CBQRI controller drivers to make use of the resctrl
> filesystem.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
>
> ...
>
> +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type type)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct cbqri_controller *ctrl;
> + int reg_offset;
> + u32 percent;
> + u32 rbwb;
> + u64 reg;
> + int err;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> +
> + ctrl = hw_dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return resctrl_get_default_ctrl(r);
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + /* Clear cc_block_mask before read limit operation */
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
It looks like the parameter order might be incorrect. I believe it should be:
cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, type)
Could you please double-check?
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> ...
Thanks,
Shuai
[-- Attachment #1.1.2: Type: text/html , Size: 3406 bytes --]
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
` (2 preceding siblings ...)
2026-02-09 10:07 ` Gong Shuai
@ 2026-02-09 14:16 ` Gong Shuai
2026-02-11 0:57 ` Drew Fustini
2026-02-13 23:30 ` Reinette Chatre
2026-03-25 2:09 ` [External] " yunhui cui
5 siblings, 1 reply; 57+ messages in thread
From: Gong Shuai @ 2026-02-09 14:16 UTC (permalink / raw)
To: fustini
Cc: Dave.Martin, acpica-devel, alex, aou, aricciardi, atish.patra,
atishp, babu.moger, ben.horgan, conor+dt, cp0613, cuiyunhui,
devicetree, fenghua.yu, guo.wenjia23, james.morse, krzk+dt, lenb,
linux-acpi, linux-kernel, linux-riscv, liu.qingtao2, liwei1518,
mindal, npitre, palmer, paul.walmsley, peternewman, pjw, rafael,
reinette.chatre, rkrcmar, robert.moore, robh, samuel.holland,
sunilvl, tony.luck, vasu, ved, x86, zhiwei_liu, gong.shuai
Hi, Drew
> Add interface for CBQRI controller drivers to make use of the resctrl
> filesystem.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
>
> ...
>
> +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type type)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct cbqri_controller *ctrl;
> + int reg_offset;
> + u32 percent;
> + u32 rbwb;
> + u64 reg;
> + int err;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> +
> + ctrl = hw_dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return resctrl_get_default_ctrl(r);
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + /* Clear cc_block_mask before read limit operation */
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
It looks like the parameter order might be incorrect. I believe it
should be:
cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, type);
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> ...
Sorry for the resend, my company email had some formatting issues,
so I'm sending this from my personal address.
Hope it doesn't cause any trouble!
Thanks,
Shuai
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-02-09 14:16 ` Gong Shuai
@ 2026-02-11 0:57 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-02-11 0:57 UTC (permalink / raw)
To: Gong Shuai
Cc: Dave.Martin, acpica-devel, alex, aou, aricciardi, atish.patra,
atishp, babu.moger, ben.horgan, conor+dt, cp0613, cuiyunhui,
devicetree, fenghua.yu, guo.wenjia23, james.morse, krzk+dt, lenb,
linux-acpi, linux-kernel, linux-riscv, liu.qingtao2, liwei1518,
mindal, npitre, palmer, paul.walmsley, peternewman, pjw, rafael,
reinette.chatre, rkrcmar, robert.moore, robh, samuel.holland,
sunilvl, tony.luck, vasu, ved, x86, zhiwei_liu, gong.shuai
On Mon, Feb 09, 2026 at 10:16:49PM +0800, Gong Shuai wrote:
> Hi, Drew
>
> > Add interface for CBQRI controller drivers to make use of the resctrl
> > filesystem.
> >
> > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> >
> > ...
> >
> > +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> > + u32 closid, enum resctrl_conf_type type)
> > +{
> > + struct cbqri_resctrl_dom *hw_dom;
> > + struct cbqri_controller *ctrl;
> > + int reg_offset;
> > + u32 percent;
> > + u32 rbwb;
> > + u64 reg;
> > + int err;
> > +
> > + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> > +
> > + ctrl = hw_dom->hw_ctrl;
> > +
> > + if (!r->alloc_capable)
> > + return resctrl_get_default_ctrl(r);
> > +
> > + switch (r->rid) {
> > + case RDT_RESOURCE_L2:
> > + case RDT_RESOURCE_L3:
> > + /* Clear cc_block_mask before read limit operation */
> > + cbqri_set_cbm(ctrl, 0);
> > +
> > + /* Capacity read limit operation for RCID (closid) */
> > + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
>
> It looks like the parameter order might be incorrect. I believe it
> should be:
> cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, type);
Thanks, I will fix so that closid and type are the correct order.
>
> > + if (err < 0) {
> > + pr_err("%s(): operation failed: err = %d", __func__, err);
> > + return resctrl_get_default_ctrl(r);
> > + }
> > ...
>
> Sorry for the resend, my company email had some formatting issues,
> so I'm sending this from my personal address.
>
> Hope it doesn't cause any trouble!
No problem.
Thanks
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
2026-01-28 20:27 ` [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities Drew Fustini
@ 2026-02-13 23:13 ` Reinette Chatre
2026-02-14 16:25 ` Drew Fustini
0 siblings, 1 reply; 57+ messages in thread
From: Reinette Chatre @ 2026-02-13 23:13 UTC (permalink / raw)
To: Drew Fustini, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Radim Krčmář, Samuel Holland,
Adrien Ricciardi, Nicolas Pitre, Kornel Dulęba, Atish Patra,
Atish Kumar Patra, Vasudevan Srinivasan, Ved Shanbhogue,
yunhui cui, Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23,
liu.qingtao2, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, linux-kernel, linux-riscv,
x86, Rob Herring, Rafael J. Wysocki, Len Brown, Robert Moore,
Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Hi Drew,
On 1/28/26 12:27 PM, Drew Fustini wrote:
> Define data structures to store the capacity and bandwidth capabilities
> that are discovered for a CBQRI-capable controller.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> arch/riscv/kernel/qos/internal.h | 128 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 128 insertions(+)
>
> diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> new file mode 100644
> index 000000000000..ff2c7eff50be
> --- /dev/null
> +++ b/arch/riscv/kernel/qos/internal.h
> @@ -0,0 +1,128 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _ASM_RISCV_QOS_INTERNAL_H
> +#define _ASM_RISCV_QOS_INTERNAL_H
> +
> +#include <linux/resctrl.h>
The include caught my eye but I did not notice any additions in this patch
refer to it.
Reinette
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains
2026-01-28 20:27 ` [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains Drew Fustini
@ 2026-02-13 23:15 ` Reinette Chatre
2026-02-14 16:34 ` Drew Fustini
2026-03-25 2:31 ` [External] " yunhui cui
1 sibling, 1 reply; 57+ messages in thread
From: Reinette Chatre @ 2026-02-13 23:15 UTC (permalink / raw)
To: Drew Fustini, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Radim Krčmář, Samuel Holland,
Adrien Ricciardi, Nicolas Pitre, Kornel Dulęba, Atish Patra,
Atish Kumar Patra, Vasudevan Srinivasan, Ved Shanbhogue,
yunhui cui, Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23,
liu.qingtao2, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, linux-kernel, linux-riscv,
x86, Rob Herring, Rafael J. Wysocki, Len Brown, Robert Moore,
Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Hi Drew,
(caveat for all my comments)
I scanned this series for resctrl interactions and my comments are
focused around that instead of a thorough review of all the code
within.
On 1/28/26 12:27 PM, Drew Fustini wrote:
> diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> index ff2c7eff50be..c0402dd06cfa 100644
> --- a/arch/riscv/kernel/qos/internal.h
> +++ b/arch/riscv/kernel/qos/internal.h
> @@ -65,6 +65,11 @@
> #define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2
> #define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1
>
> +int qos_resctrl_setup(void);
> +void qos_resctrl_exit(void);
> +int qos_resctrl_online_cpu(unsigned int cpu);
> +int qos_resctrl_offline_cpu(unsigned int cpu);
> +
> /* Capacity Controller hardware capabilities */
> struct riscv_cbqri_capacity_caps {
> u16 ncblks; /* number of capacity blocks */
> @@ -125,4 +130,26 @@ struct cbqri_controller {
> bool mon_capable;
> };
>
> +struct cbqri_resctrl_res {
> + struct rdt_resource resctrl_res;
> + struct cbqri_controller controller;
> + u32 max_rcid;
> + u32 max_mcid;
> +};
> +
> +struct cbqri_resctrl_dom {
> + struct rdt_domain_hdr resctrl_dom_hdr;
The resctrl_dom_hdr above should not be needed and indeed does
not seem to be used in this series. The two members below it,
struct rdt_ctrl_domain and struct rdt_mon_domain (now named
rdt_l3_mon_domain), have the necessary struct rdt_domain_hdr as
their first member.
Without any comments or changelog that describes the other members
I am not able to really consider their inclusion here. From the
names it seems that most members are intended to support the
control domain usage so it is not clear to me why the cbqri domain
contains both a control and monitor domain while they are interacted
with separately by resctrl. From what I can tell resctrl_mon_dom
is not used by this implementation.
As hinted above, when you rebase you will find that struct rdt_mon_domain
is now named struct rdt_l3_mon_domain (see commit 4bc3ef46ff41
("x86,fs/resctrl: Rename struct rdt_mon_domain and rdt_hw_mon_domain")) to
make it obvious that it is specific to L3 monitoring. Having this
as a member for all cbqri domains will then become increasingly confusing
since the cbqri_resctrl_dom is also used for L2 cache allocation as well as the
memory bandwidth allocation that are not at L3 scope.
I think it may be simplest to drop the resctrl_mon_dom member until
monitoring is supported?
> + struct rdt_ctrl_domain resctrl_ctrl_dom;
> + struct rdt_mon_domain resctrl_mon_dom;
> + u64 cbm;
> + u64 rbwb;
> + u64 *ctrl_val;
> + struct cbqri_controller *hw_ctrl;
> +};
> +
> +struct cbqri_config {
> + u64 cbm; /* capacity block mask */
> + u64 rbwb; /* reserved bandwidth blocks */
> +};
> +
> #endif /* _ASM_RISCV_QOS_INTERNAL_H */
>
Reinette
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 07/17] RISC-V: QoS: define prototypes for resctrl interface
2026-01-28 20:27 ` [PATCH RFC v2 07/17] RISC-V: QoS: define prototypes for resctrl interface Drew Fustini
@ 2026-02-13 23:21 ` Reinette Chatre
0 siblings, 0 replies; 57+ messages in thread
From: Reinette Chatre @ 2026-02-13 23:21 UTC (permalink / raw)
To: Drew Fustini, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Radim Krčmář, Samuel Holland,
Adrien Ricciardi, Nicolas Pitre, Kornel Dulęba, Atish Patra,
Atish Kumar Patra, Vasudevan Srinivasan, Ved Shanbhogue,
yunhui cui, Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23,
liu.qingtao2, Tony Luck, Babu Moger, Peter Newman, Fenghua Yu,
James Morse, Ben Horgan, Dave Martin, linux-kernel, linux-riscv,
x86, Rob Herring, Rafael J. Wysocki, Len Brown, Robert Moore,
Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Hi Drew,
On 1/28/26 12:27 PM, Drew Fustini wrote:
> Define the prototypes for the resctrl interface functions that are
> implemented on RISC-V.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> [fustini: rebased on current upstream]
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> include/linux/riscv_qos.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
> diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
> index 51c3a96bbcd0..0c551ed85fe1 100644
> --- a/include/linux/riscv_qos.h
> +++ b/include/linux/riscv_qos.h
> @@ -3,6 +3,7 @@
> #ifndef __LINUX_RISCV_QOS_H
> #define __LINUX_RISCV_QOS_H
>
> +#include <linux/resctrl_types.h>
> #include <linux/iommu.h>
> #include <linux/types.h>
>
> @@ -31,4 +32,47 @@ struct cbqri_controller_info {
>
> extern struct list_head cbqri_controllers;
>
> +bool resctrl_arch_alloc_capable(void);
> +bool resctrl_arch_mon_capable(void);
> +bool resctrl_arch_is_llc_occupancy_enabled(void);
> +bool resctrl_arch_is_mbm_local_enabled(void);
> +bool resctrl_arch_is_mbm_total_enabled(void);
These individual event checks are no longer needed. Please refer to commit
d257cc2e5c8b ("x86,fs/resctrl: Replace architecture event enabled checks")
that can be found in your base commit.
> +
> +struct rdt_resource;
> +/*
> + * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
> + * CLOSID on x86 is RCID on RISC-V
> + * RMID on x86 is MCID on RISC-V
> + * CDP on x86 is AT (access type) on RISC-V
> + */
> +u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
> +void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
> +void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 pmg);
nit: the x86 and RISC-V terms are already plenty. It should not be necessary to add
MPAM terms (pmg) to the mix?
> +void resctrl_arch_sched_in(struct task_struct *tsk);
> +void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
> +bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
> +bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
> +void resctrl_arch_reset_resources(void);
hmmm ... the baseline of this work is v6.19-rc4 that contains the resctrl fs/arch
split. resctrl_arch_reset_resources() seems to be based on some earlier version of
the split work that did not make it upstream.
> +void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
> +void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid,
> + void *arch_mon_ctx);
> +struct rdt_domain_hdr *resctrl_arch_find_domain(struct list_head *domain_list, int id);
resctrl_arch_find_domain() does not exist in resctrl. Would resctrl's resctrl_find_domain()
suffice?
> +
> +static inline bool resctrl_arch_event_is_free_running(enum resctrl_event_id evt)
resctrl_arch_event_is_free_running() also does not exist in resctrl.
> +{
> + /* must be true for resctrl L3 monitoring files to be created */
> + return true;
> +}
> +
> +static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
> +{
> + return val;
> +}
> +
> +/* Not needed for RISC-V */
> +static inline void resctrl_arch_enable_mon(void) { }
> +static inline void resctrl_arch_disable_mon(void) { }
> +static inline void resctrl_arch_enable_alloc(void) { }
> +static inline void resctrl_arch_disable_alloc(void) { }
> +
> #endif /* __LINUX_RISCV_QOS_H */
>
Reinette
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
` (3 preceding siblings ...)
2026-02-09 14:16 ` Gong Shuai
@ 2026-02-13 23:30 ` Reinette Chatre
2026-02-18 21:49 ` Drew Fustini
2026-03-25 2:09 ` [External] " yunhui cui
5 siblings, 1 reply; 57+ messages in thread
From: Reinette Chatre @ 2026-02-13 23:30 UTC (permalink / raw)
To: Drew Fustini, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Radim Krčmář, Samuel Holland,
Adrien Ricciardi, Nicolas Pitre, Kornel Dulęba, Atish Patra,
Atish Kumar Patra, Vasudevan Srinivasan, Ved Shanbhogue,
yunhui cui, Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23,
liu.qingtao2, Tony Luck, Babu Moger, Peter Newman, James Morse,
Ben Horgan, Dave Martin, linux-kernel, linux-riscv, x86,
Rob Herring, Rafael J. Wysocki, Len Brown, Robert Moore,
Sunil V L, Krzysztof Kozlowski, Conor Dooley
Cc: Paul Walmsley, linux-acpi, acpica-devel, devicetree
Hi Drew,
On 1/28/26 12:27 PM, Drew Fustini wrote:
...
> +
> +struct rdt_domain_hdr *resctrl_arch_find_domain(struct list_head *domain_list, int id)
> +{
> + struct rdt_domain_hdr *hdr;
> +
> + lockdep_assert_cpus_held();
> +
> + list_for_each_entry(hdr, domain_list, list) {
> + if (hdr->id == id)
> + return hdr;
> + }
> +
> + return NULL;
> +}
This indeed looks like a duplicate of resctrl_find_domain(). From what I can tell it
is not used in this series nor is it an arch call called by resctrl fs so can be dropped?
> +
> +void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
> +{
> + *closid = ((u32)~0); /* refer to X86_RESCTRL_BAD_CLOSID */
The name is actually X86_RESCTRL_EMPTY_CLOSID - and if RISC-V also needs it we could
make it generally available.
> + *rmid = idx;
> +}
> +
> +/* RISC-V resctrl interface does not maintain a default srmcfg value for a given CPU */
This means that when user space uses resctrl fs to assign a CPU to a resource group and
then run a task belonging to the default resource group on that CPU then the task will not
obtain the allocations that user assigned to that resource group. Here is what the resctrl
docs currently contain wrt "Resource allocation rules"
Resource allocation rules
-------------------------
When a task is running the following rules define which resources are
available to it:
1) If the task is a member of a non-default group, then the schemata
for that group is used.
2) Else if the task belongs to the default group, but is running on a
CPU that is assigned to some specific group, then the schemata for the
CPU's group is used.
3) Otherwise the schemata for the default group is used.
If I understand correctly RISC-V thus does not support CPU assignment but user space cannot
tell. That is, user may write to the cpus/cpus_list file and resctrl will show that it
succeeds and actually display the new cpumask but underneath it all the actual allocations will
not reflect that?
> +void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid) { }
> +
> +void resctrl_arch_sched_in(struct task_struct *tsk)
> +{
> + __switch_to_srmcfg(tsk);
> +}
> +
> +void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
> +{
> + u32 srmcfg;
> +
> + WARN_ON_ONCE((closid & SRMCFG_RCID_MASK) != closid);
> + WARN_ON_ONCE((rmid & SRMCFG_MCID_MASK) != rmid);
> +
> + srmcfg = rmid << SRMCFG_MCID_SHIFT;
> + srmcfg |= closid;
> + WRITE_ONCE(tsk->thread.srmcfg, srmcfg);
> +}
> +
> +void resctrl_arch_sync_cpu_closid_rmid(void *info)
> +{
> + struct resctrl_cpu_defaults *r = info;
> +
> + lockdep_assert_preemption_disabled();
> +
> + if (r) {
> + resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
> + r->closid, r->rmid);
This just calls the empty function above?
> + }
> +
> + resctrl_arch_sched_in(current);
> +}
> +
> +bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
> +{
> + u32 srmcfg;
> + bool match;
> +
> + srmcfg = READ_ONCE(tsk->thread.srmcfg);
> + match = (srmcfg & SRMCFG_RCID_MASK) == closid;
> + return match;
> +}
> +
> +bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
> +{
> + u32 tsk_rmid;
> +
> + tsk_rmid = READ_ONCE(tsk->thread.srmcfg);
> + tsk_rmid >>= SRMCFG_MCID_SHIFT;
> + tsk_rmid &= SRMCFG_MCID_MASK;
> +
> + return tsk_rmid == rmid;
> +}
> +
> +int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 closid, u32 rmid, enum resctrl_event_id eventid,
> + u64 *val, void *arch_mon_ctx)
> +{
> + /*
> + * The current Qemu implementation of CBQRI capacity and bandwidth
> + * controllers do not emulate the utilization of resources over
> + * time. Therefore, Qemu currently sets the invalid bit in
> + * cc_mon_ctr_val and bc_mon_ctr_val, and there is no meaningful
> + * value other than 0 to return for reading an RMID (e.g. MCID in
> + * CBQRI terminology)
> + */
> +
> + return 0;
> +}
> +
> +void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 closid, u32 rmid, enum resctrl_event_id eventid)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_mon_event_config_read(void *info)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_mon_event_config_write(void *info)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +/* Set capacity block mask (cc_block_mask) */
> +static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
> +{
> + int reg_offset;
> + u64 reg;
> +
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> +
> + reg = cbm;
> + iowrite64(reg, ctrl->base + reg_offset);
This just writes the new 64bit value without any modifications. Is it necessary to
read it first?
> +}
...
> +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 reg_offset;
> + int err = 0;
> + u64 reg;
> +
> + if (cfg->cbm != hw_dom->ctrl_val[closid]) {
> + /* Store the new cbm in the ctrl_val array for this closid in this domain */
> + hw_dom->ctrl_val[closid] = cfg->cbm;
How this hw_dom->ctrl_val[] is used is not clear ... it almost seems unnecessary? It seems to
resemble the x86 rdt_hw_ctrl_domain::ctrl_val that essentially contains a copy of the values
set on hardware but its use during config read and write does not reflect that.
In cbqri_apply_cache_config() hw_dom->ctrl_val[closid] is set before any attempt is made to
write it to hardware and below it is clear that code doing the writing may fail. Does this mean
that the driver may think that it set the control value correctly (because it will not retry
based on the cfg->cbm != hw_dom->ctrl_val[closid] check) but that is actually not the case?
Jumping ahead to the partner code in resctrl_arch_get_config() that reads the current
configuration value it is unexpected that the implementation refers to the hardware and
not hw_dom->ctrl_val[closid] ... but actually sets hw_dom->ctrl_val[closid] there also
to reflect the hardware when the configuration is *read*?
As I understand there can be two possibilities, either cache the hardware value or don't:
One possibility could thus be to move hw_dom->ctrl_val[closid] assignment in this function to
be after hardware is configured so that it reflects accurate state and then resctrl_arch_get_config()
could just get the value from it instead of hardware.
Another possibility may be to drop hw_dom->ctrl_val[] entirely and just read from/write to
hardware every time, something that is much cheaper to do with this design that does not require IPIs.
This implementation seems to be a bit of both?
> +
> + /* 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", __func__, err);
> + return err;
> + }
> +
> + /* Clear cc_block_mask before read limit to verify op works*/
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Performa 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", __func__, err);
> + return err;
> + }
> +
> + /* Read capacity blockmask to verify it matches the requested config */
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> + if (reg != cfg->cbm) {
> + pr_warn("%s(): failed to verify allocation (reg:%llx != cbm:%llx)",
> + __func__, reg, cfg->cbm);
> + return -EIO;
> + }
> + }
> +
> + return err;
> +}
> +
...
> +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;
> +
> + if (cfg->rbwb != hw_dom->ctrl_val[closid]) {
> + /* Store the new rbwb in the ctrl_val array for this closid in this domain */
> + hw_dom->ctrl_val[closid] = cfg->rbwb;
(similar comment as above about ctrl_val[])
> +
> + /* Set reserved bandwidth blocks */
> + cbqri_set_rbwb(ctrl, cfg->rbwb);
> +
> + /* Bandwidth config limit operation */
> + ret = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, closid);
> + if (ret < 0) {
> + pr_err("%s(): operation failed: ret = %d", __func__, ret);
> + return ret;
> + }
> +
> + /* 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_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
> + if (ret < 0) {
> + pr_err("%s(): operation failed: ret = %d", __func__, ret);
> + return ret;
> + }
> +
> + /* Read bandwidth allocation to verify it matches the requested config */
> + reg = cbqri_get_rbwb(ctrl);
> + if (reg != cfg->rbwb) {
> + pr_warn("%s(): failed to verify allocation (reg:%llx != rbwb:%llu)",
> + __func__, reg, cfg->rbwb);
> + return -EIO;
> + }
> + }
> +
> + return ret;
> +}
...
> +
> +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type type)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct cbqri_controller *ctrl;
> + int reg_offset;
> + u32 percent;
> + u32 rbwb;
> + u64 reg;
> + int err;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> +
> + ctrl = hw_dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return resctrl_get_default_ctrl(r);
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + /* Clear cc_block_mask before read limit operation */
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> +
> + /* Read capacity block mask for RCID (closid) */
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> +
> + /* Update the config value for the closid in this domain */
> + hw_dom->ctrl_val[closid] = reg;
This is what I refer to above, why is it necessary to read from hardware here and not
just return hw_dom->ctrl_val[closid] directly?
> + return hw_dom->ctrl_val[closid];
> +
> + case RDT_RESOURCE_MBA:
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> +
> + hw_dom->ctrl_val[closid] = cbqri_get_rbwb(ctrl);
> +
> + /* Convert from bandwidth blocks to percent */
> + rbwb = hw_dom->ctrl_val[closid];
> + rbwb *= 100;
> + percent = rbwb / ctrl->bc.nbwblks;
> + if (rbwb % ctrl->bc.nbwblks)
> + percent++;
> + return percent;
> +
> + default:
> + return resctrl_get_default_ctrl(r);
> + }
> +}
> +
...
> +
> +/*
> + * Note: for the purposes of the CBQRI proof-of-concept, debug logging
> + * has been left in this function that detects the properties of CBQRI
> + * capable controllers in the system. pr_info calls would be removed
> + * before submitting non-RFC patches.
> + */
> +static int cbqri_probe_controller(struct cbqri_controller_info *ctrl_info,
> + struct cbqri_controller *ctrl)
> +{
> + int err = 0, status;
> + u64 reg;
> +
> + pr_info("controller info: type=%d addr=0x%lx size=%lu max-rcid=%u max-mcid=%u",
> + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> + ctrl_info->rcid_count, ctrl_info->mcid_count);
> +
> + /* max_rmid is used by resctrl_arch_system_num_rmid_idx() */
> + max_rmid = ctrl_info->mcid_count;
It looks like the max is just the MCID count of the last probed controller as opposed to
the maximum among all controllers.
...
> +
> +static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
> +{
> + struct rdt_ctrl_domain *domain = NULL;
> + struct cbqri_resctrl_res *cbqri_res = NULL;
> + struct rdt_resource *res = NULL;
> + int internal_id = *id;
> + int err = 0;
> +
> + domain = qos_new_domain(ctrl);
> + if (!domain)
> + return -ENOSPC;
> + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> + cpumask_copy(&domain->hdr.cpu_mask, &ctrl->ctrl_info->cache.cpu_mask);
> + if (ctrl->ctrl_info->cache.cache_level == 2) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_L2;
> + res->name = "L2";
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = ctrl->mon_capable;
> + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> + res->ctrl_scope = RESCTRL_L2_CACHE;
> + res->cache.arch_has_sparse_bitmasks = false;
> + res->cache.arch_has_per_cpu_cfg = false;
> + res->cache.cbm_len = ctrl->cc.ncblks;
> + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> + res->cache.min_cbm_bits = 1;
> + } else if (ctrl->ctrl_info->cache.cache_level == 3) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_L3;
> + res->name = "L3";
> + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> + res->ctrl_scope = RESCTRL_L3_CACHE;
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = ctrl->mon_capable;
> + res->cache.arch_has_sparse_bitmasks = false;
> + res->cache.arch_has_per_cpu_cfg = false;
> + res->cache.cbm_len = ctrl->cc.ncblks;
> + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> + res->cache.min_cbm_bits = 1;
> + } else {
> + pr_warn("%s(): unknown cache level %d", __func__,
> + ctrl->ctrl_info->cache.cache_level);
> + err = -ENODEV;
> + goto err_free_domain;
> + }
> + } else if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
> + if (ctrl->alloc_capable) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_MBA];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_MBA;
> + res->name = "MB";
> + res->schema_fmt = RESCTRL_SCHEMA_RANGE;
> + res->ctrl_scope = RESCTRL_L3_CACHE;
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = false;
> + res->membw.delay_linear = true;
> + res->membw.arch_needs_linear = true;
> + res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
> + // The minimum percentage allowed by the CBQRI spec
> + res->membw.min_bw = 1;
> + // The maximum percentage allowed by the CBQRI spec
> + res->membw.max_bw = 80;
> + res->membw.bw_gran = 1;
> + }
> + } else {
> + pr_warn("%s(): unknown resource %d", __func__, ctrl->ctrl_info->type);
> + err = -ENODEV;
> + goto err_free_domain;
> + }
> +
> + domain->hdr.id = internal_id;
I am missing something here. For the cache resources I expected the ID to be initialized
to ctrl->ctrl_info->cache_id instead (which is only introduced later in patch 15 though).
When interacting with the L2 and L3 resources the domain ID should be the cache ID since that
is the ID printed to user space where the cache ID is expected.
How is this "internal id" used?
Also please note there are a couple of other fields in the header that needs initializing.
> + err = qos_init_domain_ctrlval(res, domain);
> + if (err)
> + goto err_free_domain;
> +
> + if (cbqri_res) {
> + list_add_tail(&domain->hdr.list, &cbqri_res->resctrl_res.ctrl_domains);
There is an expectation that the domain list be sorted. For reference, resctrl_find_domain().
> + *id = internal_id;
> + err = resctrl_online_ctrl_domain(res, domain);
> + if (err) {
> + pr_warn("%s(): failed to online cbqri_res domain", __func__);
> + goto err_free_domain;
> + }
> + }
Reinette
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table
2026-02-02 11:08 ` [External] " yunhui cui
2026-02-03 20:00 ` Drew Fustini
@ 2026-02-14 4:48 ` Drew Fustini
1 sibling, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-02-14 4:48 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Mon, Feb 02, 2026 at 07:08:48PM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add driver to parse the ACPI RISC-V Quality of Service Controller (RQSC)
> > table which describes the capacity and bandwidth QoS controllers in a
> > system. The QoS controllers implement the RISC-V Capacity and Bandwidth
> > Controller QoS Register Interface (CBQRI) specification.
> >
> > Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> > Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > MAINTAINERS | 1 +
> > arch/riscv/include/asm/acpi.h | 10 ++++
> > drivers/acpi/riscv/Makefile | 2 +-
> > drivers/acpi/riscv/rqsc.c | 112 ++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 124 insertions(+), 1 deletion(-)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 96ead357a634..e96a83dc9a02 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -22512,6 +22512,7 @@ S: Supported
> > F: arch/riscv/include/asm/qos.h
> > F: arch/riscv/include/asm/resctrl.h
> > F: arch/riscv/kernel/qos/
> > +F: drivers/acpi/riscv/rqsc.c
> > F: include/linux/riscv_qos.h
> >
> > RISC-V RPMI AND MPXY DRIVERS
> > diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
> > index 6e13695120bc..16c6e25eed1e 100644
> > --- a/arch/riscv/include/asm/acpi.h
> > +++ b/arch/riscv/include/asm/acpi.h
> > @@ -71,6 +71,16 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
> >
> > void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
> > u32 *cboz_size, u32 *cbop_size);
> > +
> > +#ifdef CONFIG_RISCV_ISA_SSQOSID
> > +int acpi_parse_rqsc(struct acpi_table_header *table);
> > +#else
> > +static inline int acpi_parse_rqsc(struct acpi_table_header *table)
> > +{
> > + return -EINVAL;
> > +}
> > +#endif /* CONFIG_RISCV_ISA_SSQOSID */
> > +
> > #else
> > static inline void acpi_init_rintc_map(void) { }
> > static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
> > diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
> > index 1284a076fa88..cf0f38c93a9f 100644
> > --- a/drivers/acpi/riscv/Makefile
> > +++ b/drivers/acpi/riscv/Makefile
> > @@ -1,5 +1,5 @@
> > # SPDX-License-Identifier: GPL-2.0-only
> > -obj-y += rhct.o init.o irq.o
> > +obj-y += rhct.o rqsc.o init.o irq.o
> > obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
> > obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
> > obj-$(CONFIG_ACPI_RIMT) += rimt.o
> > diff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c
> > new file mode 100644
> > index 000000000000..a86ddb39fae4
> > --- /dev/null
> > +++ b/drivers/acpi/riscv/rqsc.c
> > @@ -0,0 +1,112 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2025 Tenstorrent
> > + * Author: Drew Fustini <fustini@kernel.org>
> > + *
> > + */
> > +
> > +#define pr_fmt(fmt) "ACPI: RQSC: " fmt
> > +
> > +#include <linux/acpi.h>
> > +#include <linux/bits.h>
> > +#include <linux/riscv_qos.h>
> > +
> > +#ifdef CONFIG_RISCV_ISA_SSQOSID
> > +
> > +#define CBQRI_CTRL_SIZE 0x1000
> > +
> > +static struct acpi_table_rqsc *acpi_get_rqsc(void)
> > +{
> > + static struct acpi_table_header *rqsc;
> > + acpi_status status;
> > +
> > + /*
> > + * RQSC will be used at runtime on every CPU, so we
> > + * don't need to call acpi_put_table() to release the table mapping.
> > + */
> > + if (!rqsc) {
> > + status = acpi_get_table(ACPI_SIG_RQSC, 0, &rqsc);
> > + if (ACPI_FAILURE(status)) {
> > + pr_warn_once("No RQSC table found\n");
> > + return NULL;
> > + }
> > + }
> > +
> > + return (struct acpi_table_rqsc *)rqsc;
> > +}
> > +
> > +int acpi_parse_rqsc(struct acpi_table_header *table)
> > +{
> > + struct acpi_table_rqsc *rqsc;
> > + int err;
> > +
> > + BUG_ON(acpi_disabled);
> > + if (!table) {
> > + rqsc = acpi_get_rqsc();
> > + if (!rqsc)
> > + return -ENOENT;
> > + } else {
> > + rqsc = (struct acpi_table_rqsc *)table;
> > + }
> > +
> > + for (int i = 0; i < rqsc->num; i++) {
> > + struct cbqri_controller_info *ctrl_info;
> > +
> > + ctrl_info = kzalloc(sizeof(*ctrl_info), GFP_KERNEL);
> > + if (!ctrl_info)
> > + return -ENOMEM;
> > +
> > + ctrl_info->type = rqsc->f[i].type;
> > + ctrl_info->addr = rqsc->f[i].reg[1];
> > + ctrl_info->size = CBQRI_CTRL_SIZE;
> > + ctrl_info->rcid_count = rqsc->f[i].rcid;
> > + ctrl_info->mcid_count = rqsc->f[i].mcid;
> > +
> > + pr_info("Found controller with type %u addr 0x%lx size %lu rcid %u mcid %u",
> > + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> > + ctrl_info->rcid_count, ctrl_info->mcid_count);
> > +
> > + if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> > + ctrl_info->cache.cache_id = rqsc->f[i].res.id1;
> > + ctrl_info->cache.cache_level =
> > + find_acpi_cache_level_from_id(ctrl_info->cache.cache_id);
> > +
> > + struct acpi_pptt_cache *cache;
> > +
> > + cache = find_acpi_cache_from_id(ctrl_info->cache.cache_id);
> > + if (cache) {
> > + ctrl_info->cache.cache_size = cache->size;
> > + } else {
> > + pr_warn("%s(): failed to determine size for cache id 0x%x",
> > + __func__, ctrl_info->cache.cache_id);
> > + ctrl_info->cache.cache_size = 0;
> > + }
> > +
> > + pr_info("Cache controller has ID 0x%x level %u size %u ",
> > + ctrl_info->cache.cache_id, ctrl_info->cache.cache_level,
> > + ctrl_info->cache.cache_size);
> > +
> > + /*
> > + * For CBQRI, any cpu (technically a hart in RISC-V terms)
> > + * can access the memory-mapped registers of any CBQRI
> > + * controller in the system.
> > + */
> > + err = cpumask_parse("FF", &ctrl_info->cache.cpu_mask);
>
> Hardcode? acpi_pptt_get_cpumask_from_cache_id(ctrl_info->cache.cache_id,
> &ctrl_info->cache.cpu_mask); ?
Thank you, I'll switch to using that.
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
2026-02-13 23:13 ` Reinette Chatre
@ 2026-02-14 16:25 ` Drew Fustini
2026-02-17 16:32 ` Reinette Chatre
0 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-02-14 16:25 UTC (permalink / raw)
To: Reinette Chatre
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Fri, Feb 13, 2026 at 03:13:42PM -0800, Reinette Chatre wrote:
> Hi Drew,
Hi! Thanks for your detailed feedback on this series.
> On 1/28/26 12:27 PM, Drew Fustini wrote:
> > Define data structures to store the capacity and bandwidth capabilities
> > that are discovered for a CBQRI-capable controller.
> >
> > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > arch/riscv/kernel/qos/internal.h | 128 +++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 128 insertions(+)
> >
> > diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> > new file mode 100644
> > index 000000000000..ff2c7eff50be
> > --- /dev/null
> > +++ b/arch/riscv/kernel/qos/internal.h
> > @@ -0,0 +1,128 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +#ifndef _ASM_RISCV_QOS_INTERNAL_H
> > +#define _ASM_RISCV_QOS_INTERNAL_H
> > +
> > +#include <linux/resctrl.h>
>
> The include caught my eye but I did not notice any additions in this patch
> refer to it.
>
> Reinette
>
I was using this to make resctrl structs available in the code that
includdes this header:
arch/riscv/kernel/qos/qos.c
arch/riscv/kernel/qos/qos_resctrl.c
Should I rearrange to include resctrl.h directly where it is needed?
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains
2026-02-13 23:15 ` Reinette Chatre
@ 2026-02-14 16:34 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-02-14 16:34 UTC (permalink / raw)
To: Reinette Chatre
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Fri, Feb 13, 2026 at 03:15:57PM -0800, Reinette Chatre wrote:
> Hi Drew,
>
> (caveat for all my comments)
> I scanned this series for resctrl interactions and my comments are
> focused around that instead of a thorough review of all the code
> within.
Thanks for spending the time to review. It has helped me to realize that
there is a lot cruft leftover from when I was developing based on the
mpam snapshot at the time (2023) and never reorganized after rebasing on
upstream.
>
> On 1/28/26 12:27 PM, Drew Fustini wrote:
> > diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> > index ff2c7eff50be..c0402dd06cfa 100644
> > --- a/arch/riscv/kernel/qos/internal.h
> > +++ b/arch/riscv/kernel/qos/internal.h
> > @@ -65,6 +65,11 @@
> > #define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2
> > #define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1
> >
> > +int qos_resctrl_setup(void);
> > +void qos_resctrl_exit(void);
> > +int qos_resctrl_online_cpu(unsigned int cpu);
> > +int qos_resctrl_offline_cpu(unsigned int cpu);
> > +
> > /* Capacity Controller hardware capabilities */
> > struct riscv_cbqri_capacity_caps {
> > u16 ncblks; /* number of capacity blocks */
> > @@ -125,4 +130,26 @@ struct cbqri_controller {
> > bool mon_capable;
> > };
> >
> > +struct cbqri_resctrl_res {
> > + struct rdt_resource resctrl_res;
> > + struct cbqri_controller controller;
> > + u32 max_rcid;
> > + u32 max_mcid;
> > +};
> > +
> > +struct cbqri_resctrl_dom {
> > + struct rdt_domain_hdr resctrl_dom_hdr;
>
> The resctrl_dom_hdr above should not be needed and indeed does
> not seem to be used in this series. The two members below it,
> struct rdt_ctrl_domain and struct rdt_mon_domain (now named
> rdt_l3_mon_domain), have the necessary struct rdt_domain_hdr as
> their first member.
Thank you for the insight. I think added this when trying get the code
working again after rebasing from an old mpam snapshot to upstream last
year. It does seem like I didn't understand the data structures well
enough and should clean up cbqri_resctrl_dom.
>
> Without any comments or changelog that describes the other members
> I am not able to really consider their inclusion here. From the
> names it seems that most members are intended to support the
> control domain usage so it is not clear to me why the cbqri domain
> contains both a control and monitor domain while they are interacted
> with separately by resctrl. From what I can tell resctrl_mon_dom
> is not used by this implementation.
>
> As hinted above, when you rebase you will find that struct rdt_mon_domain
> is now named struct rdt_l3_mon_domain (see commit 4bc3ef46ff41
> ("x86,fs/resctrl: Rename struct rdt_mon_domain and rdt_hw_mon_domain")) to
> make it obvious that it is specific to L3 monitoring. Having this
> as a member for all cbqri domains will then become increasingly confusing
> since the cbqri_resctrl_dom is also used for L2 cache allocation as well as the
> memory bandwidth allocation that are not at L3 scope.
>
> I think it may be simplest to drop the resctrl_mon_dom member until
> monitoring is supported?
Thanks for the suggestion. Monitoring broke when rebasing on upstream
and also the realization that my approach to MBM was too much of a hack.
I think that does make sense for me to remove all the monitoring code
until I have a working implementation based on the current upstream.
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
2026-02-14 16:25 ` Drew Fustini
@ 2026-02-17 16:32 ` Reinette Chatre
2026-02-17 18:28 ` Drew Fustini
0 siblings, 1 reply; 57+ messages in thread
From: Reinette Chatre @ 2026-02-17 16:32 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On 2/14/26 8:25 AM, Drew Fustini wrote:
> On Fri, Feb 13, 2026 at 03:13:42PM -0800, Reinette Chatre wrote:
>> Hi Drew,
>
> Hi! Thanks for your detailed feedback on this series.
>
>> On 1/28/26 12:27 PM, Drew Fustini wrote:
>>> Define data structures to store the capacity and bandwidth capabilities
>>> that are discovered for a CBQRI-capable controller.
>>>
>>> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
>>> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
>>> Signed-off-by: Drew Fustini <fustini@kernel.org>
>>> ---
>>> arch/riscv/kernel/qos/internal.h | 128 +++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 128 insertions(+)
>>>
>>> diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
>>> new file mode 100644
>>> index 000000000000..ff2c7eff50be
>>> --- /dev/null
>>> +++ b/arch/riscv/kernel/qos/internal.h
>>> @@ -0,0 +1,128 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +#ifndef _ASM_RISCV_QOS_INTERNAL_H
>>> +#define _ASM_RISCV_QOS_INTERNAL_H
>>> +
>>> +#include <linux/resctrl.h>
>>
>> The include caught my eye but I did not notice any additions in this patch
>> refer to it.
>>
>> Reinette
>>
>
> I was using this to make resctrl structs available in the code that
> includdes this header:
>
> arch/riscv/kernel/qos/qos.c
> arch/riscv/kernel/qos/qos_resctrl.c
I see. The changelog made me believe that this patch defines new data structures
used by the patches that follow and the inclusion of resctrl.h created expectation
that some of these new data structures contain resctrl members that I was interested
in seeing used. If keeping this style then a snippet in changelog that explains the
header inclusion/organization would be helpful.
> Should I rearrange to include resctrl.h directly where it is needed?
I'll defer to the RISC-V folks since I understand that not all subsystems follow/enforce
rule #1 of Documentation/process/submit-checklist.rst the same (also called "Include
What You Use (IWYU)") quoted for convenience:
1) If you use a facility then #include the file that defines/declares
that facility. Don't depend on other header files pulling in ones
that you use.
I have worked with code following different customs and personally I do find code
following IWYU easier to maintain.
Reinette
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
2026-02-17 16:32 ` Reinette Chatre
@ 2026-02-17 18:28 ` Drew Fustini
2026-02-17 19:02 ` Reinette Chatre
0 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-02-17 18:28 UTC (permalink / raw)
To: Reinette Chatre
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Tue, Feb 17, 2026 at 08:32:41AM -0800, Reinette Chatre wrote:
> Hi Drew,
>
> On 2/14/26 8:25 AM, Drew Fustini wrote:
> > On Fri, Feb 13, 2026 at 03:13:42PM -0800, Reinette Chatre wrote:
> >> Hi Drew,
> >
> > Hi! Thanks for your detailed feedback on this series.
> >
> >> On 1/28/26 12:27 PM, Drew Fustini wrote:
> >>> Define data structures to store the capacity and bandwidth capabilities
> >>> that are discovered for a CBQRI-capable controller.
> >>>
> >>> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> >>> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> >>> Signed-off-by: Drew Fustini <fustini@kernel.org>
> >>> ---
> >>> arch/riscv/kernel/qos/internal.h | 128 +++++++++++++++++++++++++++++++++++++++
> >>> 1 file changed, 128 insertions(+)
> >>>
> >>> diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> >>> new file mode 100644
> >>> index 000000000000..ff2c7eff50be
> >>> --- /dev/null
> >>> +++ b/arch/riscv/kernel/qos/internal.h
> >>> @@ -0,0 +1,128 @@
> >>> +/* SPDX-License-Identifier: GPL-2.0-only */
> >>> +#ifndef _ASM_RISCV_QOS_INTERNAL_H
> >>> +#define _ASM_RISCV_QOS_INTERNAL_H
> >>> +
> >>> +#include <linux/resctrl.h>
> >>
> >> The include caught my eye but I did not notice any additions in this patch
> >> refer to it.
> >>
> >> Reinette
> >>
> >
> > I was using this to make resctrl structs available in the code that
> > includdes this header:
> >
> > arch/riscv/kernel/qos/qos.c
> > arch/riscv/kernel/qos/qos_resctrl.c
>
> I see. The changelog made me believe that this patch defines new data structures
> used by the patches that follow and the inclusion of resctrl.h created expectation
> that some of these new data structures contain resctrl members that I was interested
> in seeing used. If keeping this style then a snippet in changelog that explains the
> header inclusion/organization would be helpful.
>
> > Should I rearrange to include resctrl.h directly where it is needed?
> I'll defer to the RISC-V folks since I understand that not all subsystems follow/enforce
> rule #1 of Documentation/process/submit-checklist.rst the same (also called "Include
> What You Use (IWYU)") quoted for convenience:
>
> 1) If you use a facility then #include the file that defines/declares
> that facility. Don't depend on other header files pulling in ones
> that you use.
>
> I have worked with code following different customs and personally I do find code
> following IWYU easier to maintain.
Thank you for the explanation. I agree that IWYU makes more sense so
I'll rearrange how I do includes in the series.
BTW, I'm working through all the comments in patch 8. In short, there
are a lot of shortcomings in my current implementation that need to be
fixed and I will explain in my reply how I plan to address them.
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
2026-02-17 18:28 ` Drew Fustini
@ 2026-02-17 19:02 ` Reinette Chatre
2026-02-17 22:36 ` Drew Fustini
0 siblings, 1 reply; 57+ messages in thread
From: Reinette Chatre @ 2026-02-17 19:02 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On 2/17/26 10:28 AM, Drew Fustini wrote:
> BTW, I'm working through all the comments in patch 8. In short, there
> are a lot of shortcomings in my current implementation that need to be
> fixed and I will explain in my reply how I plan to address them.
Thank you very much for considering the feedback. Could you please also
consider splitting patch 8 up into more manageable chunks that have
descriptive changelogs? Even for an RFC it would help digest this work.
Reinette
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
2026-02-17 19:02 ` Reinette Chatre
@ 2026-02-17 22:36 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-02-17 22:36 UTC (permalink / raw)
To: Reinette Chatre
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Tue, Feb 17, 2026 at 11:02:30AM -0800, Reinette Chatre wrote:
> Hi Drew,
>
> On 2/17/26 10:28 AM, Drew Fustini wrote:
>
> > BTW, I'm working through all the comments in patch 8. In short, there
> > are a lot of shortcomings in my current implementation that need to be
> > fixed and I will explain in my reply how I plan to address them.
>
> Thank you very much for considering the feedback. Could you please also
> consider splitting patch 8 up into more manageable chunks that have
> descriptive changelogs? Even for an RFC it would help digest this work.
That's a good idea. I'll think about how I can divide up the code into a
larger series.
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-02-13 23:30 ` Reinette Chatre
@ 2026-02-18 21:49 ` Drew Fustini
2026-02-18 23:18 ` Reinette Chatre
0 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-02-18 21:49 UTC (permalink / raw)
To: Reinette Chatre
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, James Morse, Ben Horgan, Dave Martin,
linux-kernel, linux-riscv, x86, Rob Herring, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Krzysztof Kozlowski,
Conor Dooley, Paul Walmsley, linux-acpi, acpica-devel, devicetree
On Fri, Feb 13, 2026 at 03:30:44PM -0800, Reinette Chatre wrote:
> Hi Drew,
>
> On 1/28/26 12:27 PM, Drew Fustini wrote:
> > +struct rdt_domain_hdr *resctrl_arch_find_domain(struct list_head *domain_list, int id)
> > +{
> > + struct rdt_domain_hdr *hdr;
> > +
> > + lockdep_assert_cpus_held();
> > +
> > + list_for_each_entry(hdr, domain_list, list) {
> > + if (hdr->id == id)
> > + return hdr;
> > + }
> > +
> > + return NULL;
> > +}
>
> This indeed looks like a duplicate of resctrl_find_domain(). From what I can tell it
> is not used in this series nor is it an arch call called by resctrl fs so can be dropped?
Yes, this does not seem to be needed so I've will drop it.
> > +void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
> > +{
> > + *closid = ((u32)~0); /* refer to X86_RESCTRL_BAD_CLOSID */
>
> The name is actually X86_RESCTRL_EMPTY_CLOSID - and if RISC-V also needs it we could
> make it generally available.A
There is no dependency between closid (RCID for CBQRI) and rmid (MCID
for CBQRI), so resctrl_arch_rmid_idx_decode() is essentially the same
for RISC-V.
What do you think would be the best way to share that between X86 and
RISC-V?
Or is it is simpler to just defiend RISCV_RESCTRL_EMPTY_CLOSID?
> > + *rmid = idx;
> > +}
> > +
> > +/* RISC-V resctrl interface does not maintain a default srmcfg value for a given CPU */
>
> This means that when user space uses resctrl fs to assign a CPU to a resource group and
> then run a task belonging to the default resource group on that CPU then the task will not
> obtain the allocations that user assigned to that resource group. Here is what the resctrl
> docs currently contain wrt "Resource allocation rules"
>
> Resource allocation rules
> -------------------------
>
> When a task is running the following rules define which resources are
> available to it:
>
> 1) If the task is a member of a non-default group, then the schemata
> for that group is used.
>
> 2) Else if the task belongs to the default group, but is running on a
> CPU that is assigned to some specific group, then the schemata for the
> CPU's group is used.
>
> 3) Otherwise the schemata for the default group is used.
>
> If I understand correctly RISC-V thus does not support CPU assignment but user space cannot
> tell. That is, user may write to the cpus/cpus_list file and resctrl will show that it
> succeeds and actually display the new cpumask but underneath it all the actual allocations will
> not reflect that?
RISC-V should be able to support this but my implementation is too
simplistic. I will work on adding this capability.
> > +void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid) { }
> > +
> > +void resctrl_arch_sched_in(struct task_struct *tsk)
> > +{
> > + __switch_to_srmcfg(tsk);
> > +}
> > +
> > +void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
> > +{
> > + u32 srmcfg;
> > +
> > + WARN_ON_ONCE((closid & SRMCFG_RCID_MASK) != closid);
> > + WARN_ON_ONCE((rmid & SRMCFG_MCID_MASK) != rmid);
> > +
> > + srmcfg = rmid << SRMCFG_MCID_SHIFT;
> > + srmcfg |= closid;
> > + WRITE_ONCE(tsk->thread.srmcfg, srmcfg);
> > +}
> > +
> > +void resctrl_arch_sync_cpu_closid_rmid(void *info)
> > +{
> > + struct resctrl_cpu_defaults *r = info;
> > +
> > + lockdep_assert_preemption_disabled();
> > +
> > + if (r) {
> > + resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
> > + r->closid, r->rmid);
>
> This just calls the empty function above?
I'll improve the implementation to add real logic to
resctrl_arch_set_cpu_default_closid_rmid().
> > +/* Set capacity block mask (cc_block_mask) */
> > +static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
> > +{
> > + int reg_offset;
> > + u64 reg;
> > +
> > + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> > + reg = ioread64(ctrl->base + reg_offset);
> > +
> > + reg = cbm;
> > + iowrite64(reg, ctrl->base + reg_offset);
>
> This just writes the new 64bit value without any modifications. Is it necessary to
> read it first?
No, I believe it was left over from when I was printing the value in
debug logging. I will cleanup the function.
> > +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 reg_offset;
> > + int err = 0;
> > + u64 reg;
> > +
> > + if (cfg->cbm != hw_dom->ctrl_val[closid]) {
> > + /* Store the new cbm in the ctrl_val array for this closid in this domain */
> > + hw_dom->ctrl_val[closid] = cfg->cbm;
>
> How this hw_dom->ctrl_val[] is used is not clear ... it almost seems unnecessary? It seems to
> resemble the x86 rdt_hw_ctrl_domain::ctrl_val that essentially contains a copy of the values
> set on hardware but its use during config read and write does not reflect that.
>
> In cbqri_apply_cache_config() hw_dom->ctrl_val[closid] is set before any attempt is made to
> write it to hardware and below it is clear that code doing the writing may fail. Does this mean
> that the driver may think that it set the control value correctly (because it will not retry
> based on the cfg->cbm != hw_dom->ctrl_val[closid] check) but that is actually not the case?
This is a flaw in my implementation.
> Jumping ahead to the partner code in resctrl_arch_get_config() that reads the current
> configuration value it is unexpected that the implementation refers to the hardware and
> not hw_dom->ctrl_val[closid] ... but actually sets hw_dom->ctrl_val[closid] there also
> to reflect the hardware when the configuration is *read*?
>
> As I understand there can be two possibilities, either cache the hardware value or don't:
> One possibility could thus be to move hw_dom->ctrl_val[closid] assignment in this function to
> be after hardware is configured so that it reflects accurate state and then resctrl_arch_get_config()
> could just get the value from it instead of hardware.
> Another possibility may be to drop hw_dom->ctrl_val[] entirely and just read from/write to
> hardware every time, something that is much cheaper to do with this design that does not require IPIs.
>
> This implementation seems to be a bit of both?
Thanks for pointing out these flaws as now I realize that this
implementation does not make sense. I had been looking at the x86 code
alot when working on proof of concept and never reconsidered whether it
was necessary to cache values in ctrl_val.
CBQRI controllers are accessible by all harts (e.g. cpus) through mmio
registers so access should not burden other harts. I think I will modify
the implementation to just directly read/write the mmio registers when
necessary rather than caching them in ctrl_val.
> > +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;
> > +
> > + if (cfg->rbwb != hw_dom->ctrl_val[closid]) {
> > + /* Store the new rbwb in the ctrl_val array for this closid in this domain */
> > + hw_dom->ctrl_val[closid] = cfg->rbwb;
>
> (similar comment as above about ctrl_val[])
I'll drop ctrl_val[] and read/write directly to the CBQRI registers.
> > +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> > + u32 closid, enum resctrl_conf_type type)
> > +{
> > + struct cbqri_resctrl_dom *hw_dom;
> > + struct cbqri_controller *ctrl;
> > + int reg_offset;
> > + u32 percent;
> > + u32 rbwb;
> > + u64 reg;
> > + int err;
> > +
> > + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> > +
> > + ctrl = hw_dom->hw_ctrl;
> > +
> > + if (!r->alloc_capable)
> > + return resctrl_get_default_ctrl(r);
> > +
> > + switch (r->rid) {
> > + case RDT_RESOURCE_L2:
> > + case RDT_RESOURCE_L3:
> > + /* Clear cc_block_mask before read limit operation */
> > + cbqri_set_cbm(ctrl, 0);
> > +
> > + /* Capacity read limit operation for RCID (closid) */
> > + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
> > + if (err < 0) {
> > + pr_err("%s(): operation failed: err = %d", __func__, err);
> > + return resctrl_get_default_ctrl(r);
> > + }
> > +
> > + /* Read capacity block mask for RCID (closid) */
> > + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> > + reg = ioread64(ctrl->base + reg_offset);
> > +
> > + /* Update the config value for the closid in this domain */
> > + hw_dom->ctrl_val[closid] = reg;
>
> This is what I refer to above, why is it necessary to read from hardware here and not
> just return hw_dom->ctrl_val[closid] directly?
I will drop ctrl_val[] and just do direct read/write as needed.
> > +static int cbqri_probe_controller(struct cbqri_controller_info *ctrl_info,
> > + struct cbqri_controller *ctrl)
> > +{
> > + int err = 0, status;
> > + u64 reg;
> > +
> > + pr_info("controller info: type=%d addr=0x%lx size=%lu max-rcid=%u max-mcid=%u",
> > + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> > + ctrl_info->rcid_count, ctrl_info->mcid_count);
> > +
> > + /* max_rmid is used by resctrl_arch_system_num_rmid_idx() */
> > + max_rmid = ctrl_info->mcid_count;
>
> It looks like the max is just the MCID count of the last probed controller as opposed to
> the maximum among all controllers.
Good point, I will modify the logic to take the max among all
controllers.
> > +static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
> > +{
> > + struct rdt_ctrl_domain *domain = NULL;
> > + struct cbqri_resctrl_res *cbqri_res = NULL;
> > + struct rdt_resource *res = NULL;
> > + int internal_id = *id;
> > + int err = 0;
> > +
> > + domain = qos_new_domain(ctrl);
> > + if (!domain)
> > + return -ENOSPC;
> > +
[..]
> > + domain->hdr.id = internal_id;
>
> I am missing something here. For the cache resources I expected the ID to be initialized
> to ctrl->ctrl_info->cache_id instead (which is only introduced later in patch 15 though).
> When interacting with the L2 and L3 resources the domain ID should be the cache ID since that
> is the ID printed to user space where the cache ID is expected.
>
> How is this "internal id" used?
>
> Also please note there are a couple of other fields in the header that needs initializing.
You are right that hdr.id should be ctrl->ctrl_info->cache.cache_id for
a cache. I need to figure out how to order this patch with the rqsc
driver which populates the cache_id field in acpi_parse_rqsc
> > + err = qos_init_domain_ctrlval(res, domain);
> > + if (err)
> > + goto err_free_domain;
> > +
> > + if (cbqri_res) {
> > + list_add_tail(&domain->hdr.list, &cbqri_res->resctrl_res.ctrl_domains);
>
> There is an expectation that the domain list be sorted. For reference, resctrl_find_domain().
Thank you for letting me know. I'll work on sorting the domains before
adding to the list.
-Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-02-18 21:49 ` Drew Fustini
@ 2026-02-18 23:18 ` Reinette Chatre
0 siblings, 0 replies; 57+ messages in thread
From: Reinette Chatre @ 2026-02-18 23:18 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, yunhui cui, Chen Pei,
Liu Zhiwei, Weiwei Li, guo.wenjia23, liu.qingtao2, Tony Luck,
Babu Moger, Peter Newman, James Morse, Ben Horgan, Dave Martin,
linux-kernel, linux-riscv, x86, Rob Herring, Rafael J. Wysocki,
Len Brown, Robert Moore, Sunil V L, Krzysztof Kozlowski,
Conor Dooley, Paul Walmsley, linux-acpi, acpica-devel, devicetree
Hi Drew,
On 2/18/26 1:49 PM, Drew Fustini wrote:
> On Fri, Feb 13, 2026 at 03:30:44PM -0800, Reinette Chatre wrote:
>> On 1/28/26 12:27 PM, Drew Fustini wrote:
>>> +void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
>>> +{
>>> + *closid = ((u32)~0); /* refer to X86_RESCTRL_BAD_CLOSID */
>>
>> The name is actually X86_RESCTRL_EMPTY_CLOSID - and if RISC-V also needs it we could
>> make it generally available.A
>
> There is no dependency between closid (RCID for CBQRI) and rmid (MCID
> for CBQRI), so resctrl_arch_rmid_idx_decode() is essentially the same
> for RISC-V.
>
> What do you think would be the best way to share that between X86 and
> RISC-V?
>
> Or is it is simpler to just defiend RISCV_RESCTRL_EMPTY_CLOSID?
Thinking about this more, yes, I do think this will be simplest since
a central define would force this on MPAM that does not seem appropriate.
...
>
> CBQRI controllers are accessible by all harts (e.g. cpus) through mmio
> registers so access should not burden other harts. I think I will modify
> the implementation to just directly read/write the mmio registers when
> necessary rather than caching them in ctrl_val.
fyi ... resctrl is starting to show some signs of support for this. Please see
ab0308aee381 ("x86,fs/resctrl: Handle events that can be read from any CPU")
related to the monitoring code. Support for monitoring is not general yet
though since the default L3 events are still assumed to require reading from
CPU in the domain.
...
>>> + err = qos_init_domain_ctrlval(res, domain);
>>> + if (err)
>>> + goto err_free_domain;
>>> +
>>> + if (cbqri_res) {
>>> + list_add_tail(&domain->hdr.list, &cbqri_res->resctrl_res.ctrl_domains);
>>
>> There is an expectation that the domain list be sorted. For reference, resctrl_find_domain().
>
> Thank you for letting me know. I'll work on sorting the domains before
> adding to the list.
resctrl_find_domain() can help with this. If the domain is not found it returns
NULL and also returns the first domain with id bigger than the input id via a
parameter that can be used to insert a new domain in the right place.
Reinette
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-02-02 4:12 ` [External] " yunhui cui
@ 2026-02-20 19:54 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-02-20 19:54 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Mon, Feb 02, 2026 at 12:12:28PM +0800, yunhui cui wrote:
> Hi Drew,
Hi, thanks for your review, sorry I had this reply in draft for awhile
and failed to actually send it. All good points from you and I've been
working on fixing up the code.
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add interface for CBQRI controller drivers to make use of the resctrl
> > filesystem.
> >
> > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > arch/riscv/kernel/qos/qos_resctrl.c | 1192 +++++++++++++++++++++++++++++++++++
> > 1 file changed, 1192 insertions(+)
> >
> > diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
> > new file mode 100644
> > index 000000000000..d500098599d2
> > --- /dev/null
> > +++ b/arch/riscv/kernel/qos/qos_resctrl.c
> > @@ -0,0 +1,1192 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +#define pr_fmt(fmt) "qos: resctrl: " fmt
> > +
> > +#include <linux/slab.h>
> > +#include <linux/err.h>
> > +#include <linux/riscv_qos.h>
> > +#include <linux/resctrl.h>
> > +#include <linux/types.h>
> > +#include <asm/csr.h>
> > +#include <asm/qos.h>
> > +#include "internal.h"
> > +
> > +#define MAX_CONTROLLERS 6
> > +static struct cbqri_controller controllers[MAX_CONTROLLERS];
>
> Switch to dynamic allocation? Remove MAX_CONTROLLERS.
Yes, I am reworking the implementation to dynamically allocate the
cbqri_controller array based on the number of controllers actually in
the system.
> > +int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
> > + u32 closid, u32 rmid, enum resctrl_event_id eventid,
> > + u64 *val, void *arch_mon_ctx)
> > +{
> > + /*
> > + * The current Qemu implementation of CBQRI capacity and bandwidth
> > + * controllers do not emulate the utilization of resources over
> > + * time. Therefore, Qemu currently sets the invalid bit in
> > + * cc_mon_ctr_val and bc_mon_ctr_val, and there is no meaningful
> > + * value other than 0 to return for reading an RMID (e.g. MCID in
> > + * CBQRI terminology)
> > + */
> > +
> > + return 0;
>
> Implement per the spec's description directly, not as this comment states?
Good point that this should actually perform the operation to read the
value, even if Qemu is just setting the invalid bit as there is no real
value implemented in Qemu.
> > +/*
> > + * Note: for the purposes of the CBQRI proof-of-concept, debug logging
> > + * has been left in this function that detects the properties of CBQRI
> > + * capable controllers in the system. pr_info calls would be removed
> > + * before submitting non-RFC patches.
> > + */
> > +static int cbqri_probe_controller(struct cbqri_controller_info *ctrl_info,
> > + struct cbqri_controller *ctrl)
> > +{
> > + int err = 0, status;
> > + u64 reg;
> > +
> > + pr_info("controller info: type=%d addr=0x%lx size=%lu max-rcid=%u max-mcid=%u",
> > + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> > + ctrl_info->rcid_count, ctrl_info->mcid_count);
> > +
> > + /* max_rmid is used by resctrl_arch_system_num_rmid_idx() */
> > + max_rmid = ctrl_info->mcid_count;
>
> Get the min of all controllers?
Yes, I will change the logic to do that.
> > +static int qos_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
> > +{
> > + struct cbqri_resctrl_res *hw_res;
> > + struct cbqri_resctrl_dom *hw_dom;
> > + u64 *dc;
> > + int err = 0;
> > + int i;
> > +
> > + hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
> > + if (!hw_res)
> > + return -ENOMEM;
> > +
> > + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> > + if (!hw_dom)
> > + return -ENOMEM;
> > +
> > + dc = kmalloc_array(hw_res->max_rcid, sizeof(*hw_dom->ctrl_val),
> > + GFP_KERNEL);
> > + if (!dc)
> > + return -ENOMEM;
> > +
> > + hw_dom->ctrl_val = dc;
> > +
> > + for (i = 0; i < hw_res->max_rcid; i++, dc++) {
> > + err = resctrl_arch_update_one(r, d, i, 0, resctrl_get_default_ctrl(r));
> > + if (err)
> > + return 0;
>
> return 0 ?
Ah, yes, I will update to return error instead of silencing it.
> > +static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
> > +{
> > + struct rdt_ctrl_domain *domain = NULL;
> > + struct cbqri_resctrl_res *cbqri_res = NULL;
> > + struct rdt_resource *res = NULL;
> > + int internal_id = *id;
> > + int err = 0;
> > +
> > + domain = qos_new_domain(ctrl);
> > + if (!domain)
> > + return -ENOSPC;
> > + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> > + cpumask_copy(&domain->hdr.cpu_mask, &ctrl->ctrl_info->cache.cpu_mask);
> > + if (ctrl->ctrl_info->cache.cache_level == 2) {
> > + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
> > + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> > + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> > + res = &cbqri_res->resctrl_res;
> > + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> > + res->rid = RDT_RESOURCE_L2;
> > + res->name = "L2";
> > + res->alloc_capable = ctrl->alloc_capable;
> > + res->mon_capable = ctrl->mon_capable;
> > + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> > + res->ctrl_scope = RESCTRL_L2_CACHE;
> > + res->cache.arch_has_sparse_bitmasks = false;
> > + res->cache.arch_has_per_cpu_cfg = false;
> > + res->cache.cbm_len = ctrl->cc.ncblks;
> > + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> > + res->cache.min_cbm_bits = 1;
> > + } else if (ctrl->ctrl_info->cache.cache_level == 3) {
> > + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
> > + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> > + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> > + res = &cbqri_res->resctrl_res;
> > + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> > + res->rid = RDT_RESOURCE_L3;
> > + res->name = "L3";
> > + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> > + res->ctrl_scope = RESCTRL_L3_CACHE;
> > + res->alloc_capable = ctrl->alloc_capable;
> > + res->mon_capable = ctrl->mon_capable;
> > + res->cache.arch_has_sparse_bitmasks = false;
> > + res->cache.arch_has_per_cpu_cfg = false;
> > + res->cache.cbm_len = ctrl->cc.ncblks;
> > + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> > + res->cache.min_cbm_bits = 1;
> > + } else {
> > + pr_warn("%s(): unknown cache level %d", __func__,
> > + ctrl->ctrl_info->cache.cache_level);
> > + err = -ENODEV;
> > + goto err_free_domain;
> > + }
> > + } else if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
> > + if (ctrl->alloc_capable) {
> > + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_MBA];
> > + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> > + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> > + res = &cbqri_res->resctrl_res;
> > + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> > + res->rid = RDT_RESOURCE_MBA;
> > + res->name = "MB";
> > + res->schema_fmt = RESCTRL_SCHEMA_RANGE;
> > + res->ctrl_scope = RESCTRL_L3_CACHE;
> > + res->alloc_capable = ctrl->alloc_capable;
> > + res->mon_capable = false;
> > + res->membw.delay_linear = true;
> > + res->membw.arch_needs_linear = true;
> > + res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
> > + // The minimum percentage allowed by the CBQRI spec
> > + res->membw.min_bw = 1;
> > + // The maximum percentage allowed by the CBQRI spec
> > + res->membw.max_bw = 80;
> > + res->membw.bw_gran = 1;
> > + }
>
> Wrap a function.
I am guessing you mean to break up this long function into a couple of
smaller functions? I will give that a try for the next rev.
> > + } else {
> > + pr_warn("%s(): unknown resource %d", __func__, ctrl->ctrl_info->type);
> > + err = -ENODEV;
> > + goto err_free_domain;
> > + }
> > +
> > + domain->hdr.id = internal_id;
> > + err = qos_init_domain_ctrlval(res, domain);
> > + if (err)
> > + goto err_free_domain;
> > +
> > + if (cbqri_res) {
> > + list_add_tail(&domain->hdr.list, &cbqri_res->resctrl_res.ctrl_domains);
> > + *id = internal_id;
> > + err = resctrl_online_ctrl_domain(res, domain);
> > + if (err) {
> > + pr_warn("%s(): failed to online cbqri_res domain", __func__);
> > + goto err_free_domain;
> > + }
> > + }
> > +
> > + return 0;
> > +
> > +err_free_domain:
> > + pr_warn("%s(): err_free_domain", __func__);
> > + kfree(container_of(domain, struct cbqri_resctrl_dom, resctrl_ctrl_dom));
>
> free hw_dom->ctrl_val ?
I'll take a closer look at the error cleanup path and fix in the next
rev.
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 13/17] acpi: pptt: Add helper to find a cache from id
2026-01-28 20:27 ` [PATCH RFC v2 13/17] acpi: pptt: Add helper to find a cache from id Drew Fustini
@ 2026-03-25 1:34 ` yunhui cui
0 siblings, 0 replies; 57+ messages in thread
From: yunhui cui @ 2026-03-25 1:34 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add function to find the pointer to an instance of acpi_pptt_cache.
>
> find_acpi_cache_from_id() is based on find_acpi_cache_level_from_id()
> from commit c4170570cc7f ("ACPI / PPTT: Find PPTT cache level by ID") in
> the morse/mpam/snapshot/v6.14-rc1 branch.
>
> TODO: find_acpi_cache_level_from_id() has changed since then so this
> function should be updated. In additon, there may be a simpler way for
> acpi_parse_rqsc() than adding this function to get a pointer to
> acpi_pptt_cache.
>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> drivers/acpi/pptt.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/acpi.h | 8 +++++++
> 2 files changed, 71 insertions(+)
>
> diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
> index de5f8c018333..d1002673dc39 100644
> --- a/drivers/acpi/pptt.c
> +++ b/drivers/acpi/pptt.c
> @@ -1063,3 +1063,66 @@ int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus)
>
> return 0;
> }
> +
> +/*
> + * find_acpi_cache_from_id() is adapted from find_acpi_cache_level_from_id()
> + * introduced by c4170570cc7f ("ACPI / PPTT: Find PPTT cache level by ID")
> + * in the morse/mpam/snapshot/v6.14-rc1 branch.
> + *
> + * TODO: find_acpi_cache_level_from_id() has changed since then so this
> + * function should be updated. In additon, there may be a simpler way for
> + * acpi_parse_rqsc() than adding this function to get a pointer to
> + * acpi_pptt_cache.
> + */
> +struct acpi_pptt_cache *find_acpi_cache_from_id(u32 cache_id)
> +{
> + u32 acpi_cpu_id;
> + acpi_status status;
> + int level, cpu, num_levels;
> + struct acpi_pptt_cache *cache;
> + struct acpi_table_header *table;
> + struct acpi_pptt_cache_v1 *cache_v1;
> + struct acpi_pptt_processor *cpu_node;
> +
> + status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
> + if (ACPI_FAILURE(status)) {
> + acpi_pptt_warn_missing();
> + return NULL;
> + }
> +
> + if (table->revision < 3) {
> + acpi_put_table(table);
> + return NULL;
> + }
> +
> + for_each_possible_cpu(cpu) {
> + num_levels = 0;
> + acpi_cpu_id = get_acpi_id_for_cpu(cpu);
> +
> + cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
> + if (!cpu_node)
> + break;
break or continue?
> + num_levels = acpi_count_levels(table, cpu_node, NULL);
> +
> + for (level = 1; level <= num_levels; level++) {
> + cache = acpi_find_cache_node(table, acpi_cpu_id,
> + ACPI_PPTT_CACHE_TYPE_UNIFIED,
> + level, &cpu_node);
> + if (!cache)
> + continue;
> +
> + cache_v1 = ACPI_ADD_PTR(struct acpi_pptt_cache_v1,
> + cache,
> + sizeof(struct acpi_pptt_cache));
> +
> + if (cache->flags & ACPI_PPTT_CACHE_ID_VALID &&
> + cache_v1->cache_id == cache_id) {
> + acpi_put_table(table);
> + return cache;
> + }
> + }
> + }
> +
> + acpi_put_table(table);
> + return NULL;
> +}
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index fbf0c3a65f59..fee6a5059a46 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -1546,6 +1546,7 @@ int find_acpi_cpu_topology_package(unsigned int cpu);
> int find_acpi_cpu_topology_hetero_id(unsigned int cpu);
> void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id, cpumask_t *cpus);
> int find_acpi_cache_level_from_id(u32 cache_id);
> +struct acpi_pptt_cache *find_acpi_cache_from_id(u32 cache_id);
> int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus);
> #else
> static inline int acpi_pptt_cpu_is_thread(unsigned int cpu)
> @@ -1570,10 +1571,17 @@ static inline int find_acpi_cpu_topology_hetero_id(unsigned int cpu)
> }
> static inline void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id,
> cpumask_t *cpus) { }
> +
> static inline int find_acpi_cache_level_from_id(u32 cache_id)
> {
> return -ENOENT;
> }
> +
> +static inline struct acpi_pptt_cache *find_acpi_cache_from_id(u32 cache_id)
> +{
> + return NULL;
> +}
> +
> static inline int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id,
> cpumask_t *cpus)
> {
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-01-28 20:27 ` [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table Drew Fustini
2026-01-28 20:31 ` Rafael J. Wysocki
@ 2026-03-25 1:43 ` yunhui cui
2026-03-25 7:09 ` Drew Fustini
2026-03-25 1:48 ` yunhui cui
2 siblings, 1 reply; 57+ messages in thread
From: yunhui cui @ 2026-03-25 1:43 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add structs for the RQSC table which describes the properties of the
> RISC-V QoS controllers (CBQRI) in the system. The table also describes
> the topological arrangement of the QoS controllers and resources in the
> system. The topology is expressed in terms of the location of the
> resources within the system and the relation between the QoS Controller
> and the resource it manages.
>
> Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> include/acpi/actbl2.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> index f726bce3eb84..7367990349ee 100644
> --- a/include/acpi/actbl2.h
> +++ b/include/acpi/actbl2.h
> @@ -53,6 +53,7 @@
> #define ACPI_SIG_RGRT "RGRT" /* Regulatory Graphics Resource Table */
> #define ACPI_SIG_RHCT "RHCT" /* RISC-V Hart Capabilities Table */
> #define ACPI_SIG_RIMT "RIMT" /* RISC-V IO Mapping Table */
> +#define ACPI_SIG_RQSC "RQSC" /* RISC-V RISC-V Quality of Service Controller */
> #define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
> #define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
> #define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
> @@ -3165,6 +3166,97 @@ enum acpi_rgrt_image_type {
> ACPI_RGRT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
> };
>
> +/*******************************************************************************
> + *
> + * RQSC - RISC-V Quality of Service Controller
> + * Version 1
> + *
> + ******************************************************************************/
> +
> +struct acpi_table_rqsc_fields_res {
> + u8 type; // 1
> + u8 resv; // 1
> + u16 length; // 2
> + u16 flags; // 2
> + u8 resv2; // 1
> + u8 id_type; // 1
> + u64 id1; // 8
> + u32 id2; // 4
> +};
> +
> +struct acpi_table_rqsc_fields {
> + u8 type; // 1
> + u8 resv; // 1
> + u16 length; // 2
> + u32 reg[3]; // 12
> + u32 rcid; // 4
> + u32 mcid; // 4
> + u16 flags; // 2
> + u16 nres; // 2
> + struct acpi_table_rqsc_fields_res res; // 20
> +};
> +
> +struct acpi_table_rqsc {
> + struct acpi_table_header header; /* Common ACPI table header */
> + u32 num;
> + struct acpi_table_rqsc_fields f[6];
Is a fixed array f[6] appropriate here ?
> +};
> +
> +/* RQSC Flags */
> +#define ACPI_RQSC_TIMER_CANNOT_WAKEUP_CPU (1)
> +
> +/*
> + * RQSC subtables
> + */
> +struct acpi_rqsc_node_header {
> + u16 type;
> + u16 length;
> + u16 revision;
> +};
> +
> +/* Values for RQSC subtable Type above */
> +enum acpi_rqsc_node_type {
> + ACPI_RQSC_NODE_TYPE_ISA_STRING = 0x0000,
> + ACPI_RQSC_NODE_TYPE_CMO = 0x0001,
> + ACPI_RQSC_NODE_TYPE_MMU = 0x0002,
> + ACPI_RQSC_NODE_TYPE_RESERVED = 0x0003,
> + ACPI_RQSC_NODE_TYPE_HART_INFO = 0xFFFF,
> +};
> +
> +/*
> + * RQSC node specific subtables
> + */
> +
> +/* ISA string node structure */
> +struct acpi_rqsc_isa_string {
> + u16 isa_length;
> + char isa[];
> +};
> +
> +struct acpi_rqsc_cmo_node {
> + u8 reserved; /* Must be zero */
> + u8 cbom_size; /* CBOM size in powerof 2 */
> + u8 cbop_size; /* CBOP size in powerof 2 */
> + u8 cboz_size; /* CBOZ size in powerof 2 */
> +};
> +
> +struct acpi_rqsc_mmu_node {
> + u8 reserved; /* Must be zero */
> + u8 mmu_type; /* Virtual Address Scheme */
> +};
> +
> +enum acpi_rqsc_mmu_type {
> + ACPI_RQSC_MMU_TYPE_SV39 = 0,
> + ACPI_RQSC_MMU_TYPE_SV48 = 1,
> + ACPI__MMU_TYPE_SV57 = 2
ACPI_RQSC_MMU_TYPE_SV57 = 2 ?
> +};
> +
> +/* Hart Info node structure */
> +struct acpi_rqsc_hart_info {
> + u16 num_offsets;
> + u32 uid; /* ACPI processor UID */
> +};
> +
> /*******************************************************************************
> *
> * RHCT - RISC-V Hart Capabilities Table
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-01-28 20:27 ` [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table Drew Fustini
2026-01-28 20:31 ` Rafael J. Wysocki
2026-03-25 1:43 ` [External] " yunhui cui
@ 2026-03-25 1:48 ` yunhui cui
2026-03-25 7:14 ` Drew Fustini
2 siblings, 1 reply; 57+ messages in thread
From: yunhui cui @ 2026-03-25 1:48 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add structs for the RQSC table which describes the properties of the
> RISC-V QoS controllers (CBQRI) in the system. The table also describes
> the topological arrangement of the QoS controllers and resources in the
> system. The topology is expressed in terms of the location of the
> resources within the system and the relation between the QoS Controller
> and the resource it manages.
>
> Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> include/acpi/actbl2.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> index f726bce3eb84..7367990349ee 100644
> --- a/include/acpi/actbl2.h
> +++ b/include/acpi/actbl2.h
> @@ -53,6 +53,7 @@
> #define ACPI_SIG_RGRT "RGRT" /* Regulatory Graphics Resource Table */
> #define ACPI_SIG_RHCT "RHCT" /* RISC-V Hart Capabilities Table */
> #define ACPI_SIG_RIMT "RIMT" /* RISC-V IO Mapping Table */
> +#define ACPI_SIG_RQSC "RQSC" /* RISC-V RISC-V Quality of Service Controller */
> #define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
> #define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
> #define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
> @@ -3165,6 +3166,97 @@ enum acpi_rgrt_image_type {
> ACPI_RGRT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
> };
>
> +/*******************************************************************************
> + *
> + * RQSC - RISC-V Quality of Service Controller
> + * Version 1
> + *
> + ******************************************************************************/
> +
> +struct acpi_table_rqsc_fields_res {
> + u8 type; // 1
> + u8 resv; // 1
> + u16 length; // 2
> + u16 flags; // 2
> + u8 resv2; // 1
> + u8 id_type; // 1
> + u64 id1; // 8
> + u32 id2; // 4
> +};
> +
> +struct acpi_table_rqsc_fields {
> + u8 type; // 1
> + u8 resv; // 1
> + u16 length; // 2
> + u32 reg[3]; // 12
> + u32 rcid; // 4
> + u32 mcid; // 4
The spec appears to specify a length of 2 bytes for this field?
> + u16 flags; // 2
> + u16 nres; // 2
> + struct acpi_table_rqsc_fields_res res; // 20
> +};
> +
> +struct acpi_table_rqsc {
> + struct acpi_table_header header; /* Common ACPI table header */
> + u32 num;
> + struct acpi_table_rqsc_fields f[6];
> +};
> +
> +/* RQSC Flags */
> +#define ACPI_RQSC_TIMER_CANNOT_WAKEUP_CPU (1)
> +
> +/*
> + * RQSC subtables
> + */
> +struct acpi_rqsc_node_header {
> + u16 type;
> + u16 length;
> + u16 revision;
> +};
> +
> +/* Values for RQSC subtable Type above */
> +enum acpi_rqsc_node_type {
> + ACPI_RQSC_NODE_TYPE_ISA_STRING = 0x0000,
> + ACPI_RQSC_NODE_TYPE_CMO = 0x0001,
> + ACPI_RQSC_NODE_TYPE_MMU = 0x0002,
> + ACPI_RQSC_NODE_TYPE_RESERVED = 0x0003,
> + ACPI_RQSC_NODE_TYPE_HART_INFO = 0xFFFF,
> +};
> +
> +/*
> + * RQSC node specific subtables
> + */
> +
> +/* ISA string node structure */
> +struct acpi_rqsc_isa_string {
> + u16 isa_length;
> + char isa[];
> +};
> +
> +struct acpi_rqsc_cmo_node {
> + u8 reserved; /* Must be zero */
> + u8 cbom_size; /* CBOM size in powerof 2 */
> + u8 cbop_size; /* CBOP size in powerof 2 */
> + u8 cboz_size; /* CBOZ size in powerof 2 */
> +};
> +
> +struct acpi_rqsc_mmu_node {
> + u8 reserved; /* Must be zero */
> + u8 mmu_type; /* Virtual Address Scheme */
> +};
> +
> +enum acpi_rqsc_mmu_type {
> + ACPI_RQSC_MMU_TYPE_SV39 = 0,
> + ACPI_RQSC_MMU_TYPE_SV48 = 1,
> + ACPI__MMU_TYPE_SV57 = 2
> +};
> +
> +/* Hart Info node structure */
> +struct acpi_rqsc_hart_info {
> + u16 num_offsets;
> + u32 uid; /* ACPI processor UID */
> +};
> +
> /*******************************************************************************
> *
> * RHCT - RISC-V Hart Capabilities Table
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
` (4 preceding siblings ...)
2026-02-13 23:30 ` Reinette Chatre
@ 2026-03-25 2:09 ` yunhui cui
2026-03-25 6:37 ` Drew Fustini
5 siblings, 1 reply; 57+ messages in thread
From: yunhui cui @ 2026-03-25 2:09 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add interface for CBQRI controller drivers to make use of the resctrl
> filesystem.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> arch/riscv/kernel/qos/qos_resctrl.c | 1192 +++++++++++++++++++++++++++++++++++
> 1 file changed, 1192 insertions(+)
>
> diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
> new file mode 100644
> index 000000000000..d500098599d2
> --- /dev/null
> +++ b/arch/riscv/kernel/qos/qos_resctrl.c
> @@ -0,0 +1,1192 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#define pr_fmt(fmt) "qos: resctrl: " fmt
> +
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/riscv_qos.h>
> +#include <linux/resctrl.h>
> +#include <linux/types.h>
> +#include <asm/csr.h>
> +#include <asm/qos.h>
> +#include "internal.h"
> +
> +#define MAX_CONTROLLERS 6
> +static struct cbqri_controller controllers[MAX_CONTROLLERS];
We can get the total number of controllers, so we'll allocate dynamically.
> +static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
> +
> +static bool exposed_alloc_capable;
> +static bool exposed_mon_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);
> +
> +bool resctrl_arch_alloc_capable(void)
> +{
> + return exposed_alloc_capable;
> +}
> +
> +bool resctrl_arch_mon_capable(void)
> +{
> + return exposed_mon_capable;
> +}
> +
> +bool resctrl_arch_is_llc_occupancy_enabled(void)
> +{
> + return true;
> +}
> +
> +bool resctrl_arch_is_mbm_local_enabled(void)
> +{
> + return false;
> +}
> +
> +bool resctrl_arch_is_mbm_total_enabled(void)
> +{
> + return false;
> +}
> +
> +bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
> +{
> + switch (rid) {
> + case RDT_RESOURCE_L2:
> + return is_cdp_l2_enabled;
> +
> + case RDT_RESOURCE_L3:
> + return is_cdp_l3_enabled;
> +
> + default:
> + return false;
> + }
> +}
> +
> +int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
> +{
> + switch (rid) {
> + case RDT_RESOURCE_L2:
> + if (!exposed_cdp_l2_capable)
> + return -ENODEV;
> + is_cdp_l2_enabled = enable;
> + break;
> +
> + case RDT_RESOURCE_L3:
> + if (!exposed_cdp_l3_capable)
> + return -ENODEV;
> + is_cdp_l3_enabled = enable;
> + break;
> +
> + default:
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
> +{
> + if (l >= RDT_NUM_RESOURCES)
> + return NULL;
> +
> + return &cbqri_resctrl_resources[l].resctrl_res;
> +}
> +
> +struct rdt_domain_hdr *resctrl_arch_find_domain(struct list_head *domain_list, int id)
> +{
> + struct rdt_domain_hdr *hdr;
> +
> + lockdep_assert_cpus_held();
> +
> + list_for_each_entry(hdr, domain_list, list) {
> + if (hdr->id == id)
> + return hdr;
> + }
> +
> + return NULL;
> +}
> +
> +bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
> +{
> + return false;
> +}
> +
> +void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
> + enum resctrl_event_id evtid)
> +{
> + /* RISC-V can always read an rmid, nothing needs allocating */
> + return NULL;
> +}
> +
> +void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
> + enum resctrl_event_id evtid, void *arch_mon_ctx)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_reset_resources(void)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
> + enum resctrl_event_id evtid, u32 rmid, u32 closid,
> + u32 cntr_id, bool assign)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 unused, u32 rmid, int cntr_id,
> + enum resctrl_event_id eventid, u64 *val)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return 0;
> +}
> +
> +bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return false;
> +}
> +
> +int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return 0;
> +}
> +
> +void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 unused, u32 rmid, int cntr_id,
> + enum resctrl_event_id eventid)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return false;
> +}
> +
> +int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> + return 0;
> +}
> +
> +/*
> + * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
> + * CLOSID on x86 is RCID on RISC-V
> + * RMID on x86 is MCID on RISC-V
> + */
> +u32 resctrl_arch_get_num_closid(struct rdt_resource *res)
> +{
> + struct cbqri_resctrl_res *hw_res;
> +
> + hw_res = container_of(res, struct cbqri_resctrl_res, resctrl_res);
> +
> + return hw_res->max_rcid;
> +}
> +
> +u32 resctrl_arch_system_num_rmid_idx(void)
> +{
> + return max_rmid;
> +}
> +
> +u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
> +{
> + return rmid;
> +}
> +
> +void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
> +{
> + *closid = ((u32)~0); /* refer to X86_RESCTRL_BAD_CLOSID */
> + *rmid = idx;
> +}
> +
> +/* RISC-V resctrl interface does not maintain a default srmcfg value for a given CPU */
> +void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid) { }
> +
> +void resctrl_arch_sched_in(struct task_struct *tsk)
> +{
> + __switch_to_srmcfg(tsk);
> +}
> +
> +void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
> +{
> + u32 srmcfg;
> +
> + WARN_ON_ONCE((closid & SRMCFG_RCID_MASK) != closid);
> + WARN_ON_ONCE((rmid & SRMCFG_MCID_MASK) != rmid);
> +
> + srmcfg = rmid << SRMCFG_MCID_SHIFT;
> + srmcfg |= closid;
> + WRITE_ONCE(tsk->thread.srmcfg, srmcfg);
> +}
> +
> +void resctrl_arch_sync_cpu_closid_rmid(void *info)
> +{
> + struct resctrl_cpu_defaults *r = info;
> +
> + lockdep_assert_preemption_disabled();
> +
> + if (r) {
> + resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
> + r->closid, r->rmid);
> + }
> +
> + resctrl_arch_sched_in(current);
> +}
> +
> +bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
> +{
> + u32 srmcfg;
> + bool match;
> +
> + srmcfg = READ_ONCE(tsk->thread.srmcfg);
> + match = (srmcfg & SRMCFG_RCID_MASK) == closid;
> + return match;
> +}
> +
> +bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
> +{
> + u32 tsk_rmid;
> +
> + tsk_rmid = READ_ONCE(tsk->thread.srmcfg);
> + tsk_rmid >>= SRMCFG_MCID_SHIFT;
> + tsk_rmid &= SRMCFG_MCID_MASK;
> +
> + return tsk_rmid == rmid;
> +}
> +
> +int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 closid, u32 rmid, enum resctrl_event_id eventid,
> + u64 *val, void *arch_mon_ctx)
> +{
> + /*
> + * The current Qemu implementation of CBQRI capacity and bandwidth
> + * controllers do not emulate the utilization of resources over
> + * time. Therefore, Qemu currently sets the invalid bit in
> + * cc_mon_ctr_val and bc_mon_ctr_val, and there is no meaningful
> + * value other than 0 to return for reading an RMID (e.g. MCID in
> + * CBQRI terminology)
> + */
> +
> + return 0;
> +}
> +
> +void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
> + u32 closid, u32 rmid, enum resctrl_event_id eventid)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_mon_event_config_read(void *info)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_mon_event_config_write(void *info)
> +{
> + /* not implemented for the RISC-V resctrl interface */
> +}
> +
> +void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
> +{
> + /* not implemented for the RISC-V resctrl implementation */
> +}
> +
> +/* Set capacity block mask (cc_block_mask) */
> +static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
> +{
> + int reg_offset;
> + u64 reg;
> +
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> +
> + reg = cbm;
> + iowrite64(reg, ctrl->base + reg_offset);
> +}
> +
> +/* Set the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
> +static void cbqri_set_rbwb(struct cbqri_controller *ctrl, u64 rbwb)
> +{
> + int reg_offset;
> + u64 reg;
> +
> + reg_offset = CBQRI_BC_BW_ALLOC_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> + reg &= ~CBQRI_CONTROL_REGISTERS_RBWB_MASK;
> + rbwb &= CBQRI_CONTROL_REGISTERS_RBWB_MASK;
> + reg |= rbwb;
> + iowrite64(reg, ctrl->base + reg_offset);
> +}
> +
> +/* Get the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
> +static u64 cbqri_get_rbwb(struct cbqri_controller *ctrl)
> +{
> + int reg_offset;
> + u64 reg;
> +
> + reg_offset = CBQRI_BC_BW_ALLOC_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> + reg &= CBQRI_CONTROL_REGISTERS_RBWB_MASK;
> + return reg;
> +}
> +
> +static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset)
> +{
> + unsigned long timeout = jiffies + usecs_to_jiffies(1000);
> + int busy;
> + u64 reg;
> +
> + while (time_before(jiffies, timeout)) {
> + reg = ioread64(ctrl->base + reg_offset);
> + busy = (reg >> CBQRI_CONTROL_REGISTERS_BUSY_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_BUSY_MASK;
> + if (!busy)
> + return 0;
> + }
> +
> + pr_warn("%s(): busy timeout", __func__);
> + return -EIO;
> +}
> +
> +/* 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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
> + reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) <<
> + CBQRI_CONTROL_REGISTERS_OP_SHIFT;
> + reg &= ~(CBQRI_CONTROL_REGISTERS_RCID_MASK <<
> + CBQRI_CONTROL_REGISTERS_RCID_SHIFT);
> + reg |= (rcid & CBQRI_CONTROL_REGISTERS_RCID_MASK) <<
> + CBQRI_CONTROL_REGISTERS_RCID_SHIFT;
> +
> + /* CBQRI capacity AT is only supported on L2 and L3 caches for now */
> + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
> + ((ctrl->ctrl_info->cache.cache_level == 2 && is_cdp_l2_enabled) ||
> + (ctrl->ctrl_info->cache.cache_level == 3 && is_cdp_l3_enabled))) {
> + reg &= ~(CBQRI_CONTROL_REGISTERS_AT_MASK <<
> + CBQRI_CONTROL_REGISTERS_AT_SHIFT);
> + switch (type) {
> + case CDP_CODE:
> + reg |= (CBQRI_CONTROL_REGISTERS_AT_CODE &
> + CBQRI_CONTROL_REGISTERS_AT_MASK) <<
> + CBQRI_CONTROL_REGISTERS_AT_SHIFT;
> + break;
> + case CDP_DATA:
> + default:
> + reg |= (CBQRI_CONTROL_REGISTERS_AT_DATA &
> + CBQRI_CONTROL_REGISTERS_AT_MASK) <<
> + CBQRI_CONTROL_REGISTERS_AT_SHIFT;
> + 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", __func__);
> + return -EIO;
> + }
> +
> + reg = ioread64(ctrl->base + reg_offset);
> + status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_STATUS_MASK;
> + if (status != 1) {
> + pr_err("%s(): operation %d failed: status=%d", __func__, operation, status);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +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 reg_offset;
> + int err = 0;
> + u64 reg;
> +
> + if (cfg->cbm != hw_dom->ctrl_val[closid]) {
> + /* Store the new cbm in the ctrl_val array for this closid in this domain */
> + hw_dom->ctrl_val[closid] = cfg->cbm;
> +
> + /* 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", __func__, err);
> + return err;
> + }
> +
> + /* Clear cc_block_mask before read limit to verify op works*/
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Performa 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", __func__, err);
> + return err;
> + }
> +
> + /* Read capacity blockmask to verify it matches the requested config */
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> + if (reg != cfg->cbm) {
> + pr_warn("%s(): failed to verify allocation (reg:%llx != cbm:%llx)",
> + __func__, reg, cfg->cbm);
> + return -EIO;
> + }
> + }
> +
> + 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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
> + reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) <<
> + CBQRI_CONTROL_REGISTERS_OP_SHIFT;
> + reg &= ~(CBQRI_CONTROL_REGISTERS_RCID_MASK << CBQRI_CONTROL_REGISTERS_RCID_SHIFT);
> + reg |= (rcid & CBQRI_CONTROL_REGISTERS_RCID_MASK) <<
> + CBQRI_CONTROL_REGISTERS_RCID_SHIFT;
> + iowrite64(reg, ctrl->base + reg_offset);
> +
> + if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
> + pr_err("%s(): BUSY timeout when executing the operation", __func__);
> + return -EIO;
> + }
> +
> + reg = ioread64(ctrl->base + reg_offset);
> + status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_STATUS_MASK;
> + if (status != 1) {
> + pr_err("%s(): operation %d failed with status = %d",
> + __func__, operation, status);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +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;
> +
> + if (cfg->rbwb != hw_dom->ctrl_val[closid]) {
> + /* Store the new rbwb in the ctrl_val array for this closid in this domain */
> + hw_dom->ctrl_val[closid] = cfg->rbwb;
> +
> + /* Set reserved bandwidth blocks */
> + cbqri_set_rbwb(ctrl, cfg->rbwb);
> +
> + /* Bandwidth config limit operation */
> + ret = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, closid);
> + if (ret < 0) {
> + pr_err("%s(): operation failed: ret = %d", __func__, ret);
> + return ret;
> + }
> +
> + /* 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_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
> + if (ret < 0) {
> + pr_err("%s(): operation failed: ret = %d", __func__, ret);
> + return ret;
> + }
> +
> + /* Read bandwidth allocation to verify it matches the requested config */
> + reg = cbqri_get_rbwb(ctrl);
> + if (reg != cfg->rbwb) {
> + pr_warn("%s(): failed to verify allocation (reg:%llx != rbwb:%llu)",
> + __func__, reg, cfg->rbwb);
> + return -EIO;
> + }
> + }
> +
> + return ret;
> +}
> +
> +int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type t, u32 cfg_val)
> +{
> + struct cbqri_controller *ctrl;
> + struct cbqri_resctrl_dom *dom;
> + struct cbqri_config cfg;
> + int err = 0;
> +
> + dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> + ctrl = dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return -EINVAL;
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + cfg.cbm = cfg_val;
> + err = cbqri_apply_cache_config(dom, closid, t, &cfg);
> + break;
> + case RDT_RESOURCE_MBA:
> + /* covert from percentage to bandwidth blocks */
> + cfg.rbwb = cfg_val * ctrl->bc.nbwblks / 100;
> + err = cbqri_apply_bw_config(dom, closid, t, &cfg);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return err;
> +}
> +
> +int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
> +{
> + struct resctrl_staged_config *cfg;
> + enum resctrl_conf_type t;
> + struct rdt_ctrl_domain *d;
> + int err = 0;
> +
> + list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
> + for (t = 0; t < CDP_NUM_TYPES; t++) {
> + cfg = &d->staged_config[t];
> + if (!cfg->have_new_ctrl)
> + continue;
> + err = resctrl_arch_update_one(r, d, closid, t, cfg->new_ctrl);
> + if (err) {
> + pr_warn("%s(): update failed (err=%d)", __func__, err);
> + return err;
> + }
> + }
> + }
> + return err;
> +}
> +
> +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> + u32 closid, enum resctrl_conf_type type)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct cbqri_controller *ctrl;
> + int reg_offset;
> + u32 percent;
> + u32 rbwb;
> + u64 reg;
> + int err;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> +
> + ctrl = hw_dom->hw_ctrl;
> +
> + if (!r->alloc_capable)
> + return resctrl_get_default_ctrl(r);
> +
> + switch (r->rid) {
> + case RDT_RESOURCE_L2:
> + case RDT_RESOURCE_L3:
> + /* Clear cc_block_mask before read limit operation */
> + cbqri_set_cbm(ctrl, 0);
> +
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> +
> + /* Read capacity block mask for RCID (closid) */
> + reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
> + reg = ioread64(ctrl->base + reg_offset);
> +
> + /* Update the config value for the closid in this domain */
> + hw_dom->ctrl_val[closid] = reg;
> + return hw_dom->ctrl_val[closid];
> +
> + case RDT_RESOURCE_MBA:
> + /* Capacity read limit operation for RCID (closid) */
> + err = cbqri_bc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
> + if (err < 0) {
> + pr_err("%s(): operation failed: err = %d", __func__, err);
> + return resctrl_get_default_ctrl(r);
> + }
> +
> + hw_dom->ctrl_val[closid] = cbqri_get_rbwb(ctrl);
> +
> + /* Convert from bandwidth blocks to percent */
> + rbwb = hw_dom->ctrl_val[closid];
> + rbwb *= 100;
> + percent = rbwb / ctrl->bc.nbwblks;
> + if (rbwb % ctrl->bc.nbwblks)
> + percent++;
> + return percent;
> +
> + default:
> + return resctrl_get_default_ctrl(r);
> + }
> +}
> +
> +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 << CBQRI_CONTROL_REGISTERS_OP_SHIFT);
> + reg |= (operation & CBQRI_CONTROL_REGISTERS_OP_MASK) << CBQRI_CONTROL_REGISTERS_OP_SHIFT;
> + iowrite64(reg, ctrl->base + reg_offset);
> + if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
> + pr_err("%s(): BUSY timeout when executing the operation", __func__);
> + return -EIO;
> + }
> +
> + /* Get the operation status */
> + reg = ioread64(ctrl->base + reg_offset);
> + *status = (reg >> CBQRI_CONTROL_REGISTERS_STATUS_SHIFT) &
> + CBQRI_CONTROL_REGISTERS_STATUS_MASK;
> +
> + /*
> + * 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 << CBQRI_CONTROL_REGISTERS_AT_SHIFT);
> + reg |= CBQRI_CONTROL_REGISTERS_AT_CODE << CBQRI_CONTROL_REGISTERS_AT_SHIFT;
> + iowrite64(reg, ctrl->base + reg_offset);
> + if (cbqri_wait_busy_flag(ctrl, reg_offset) < 0) {
> + pr_err("%s(): BUSY timeout when setting AT field", __func__);
> + return -EIO;
> + }
> +
> + /*
> + * If the AT field value has been reset to zero,
> + * then the AT support is not present
> + */
> + reg = ioread64(ctrl->base + reg_offset);
> + at = (reg >> CBQRI_CONTROL_REGISTERS_AT_SHIFT) & CBQRI_CONTROL_REGISTERS_AT_MASK;
> + 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) < 0) {
> + pr_err("%s(): BUSY timeout when restoring the original register value", __func__);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Note: for the purposes of the CBQRI proof-of-concept, debug logging
> + * has been left in this function that detects the properties of CBQRI
> + * capable controllers in the system. pr_info calls would be removed
> + * before submitting non-RFC patches.
> + */
> +static int cbqri_probe_controller(struct cbqri_controller_info *ctrl_info,
> + struct cbqri_controller *ctrl)
> +{
> + int err = 0, status;
> + u64 reg;
> +
> + pr_info("controller info: type=%d addr=0x%lx size=%lu max-rcid=%u max-mcid=%u",
> + ctrl_info->type, ctrl_info->addr, ctrl_info->size,
> + ctrl_info->rcid_count, ctrl_info->mcid_count);
> +
> + /* max_rmid is used by resctrl_arch_system_num_rmid_idx() */
> + max_rmid = ctrl_info->mcid_count;
> +
> + ctrl->ctrl_info = ctrl_info;
> +
> + /* Try to access the memory-mapped CBQRI registers */
> + if (!request_mem_region(ctrl_info->addr, ctrl_info->size, "cbqri_controller")) {
> + pr_warn("%s(): request_mem_region failed for cbqri_controller at 0x%lx",
> + __func__, ctrl_info->addr);
> + return -EBUSY;
> + }
> + ctrl->base = ioremap(ctrl_info->addr, ctrl_info->size);
> + if (!ctrl->base) {
> + pr_warn("%s(): goto err_release_mem_region", __func__);
> + goto err_release_mem_region;
> + }
> +
> + ctrl->alloc_capable = false;
> + ctrl->mon_capable = false;
> +
> + /* Probe capacity allocation and monitoring features */
> + if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> + pr_info("probe capacity controller");
> +
> + /* Make sure the register is implemented */
> + reg = ioread64(ctrl->base + CBQRI_CC_CAPABILITIES_OFF);
> + if (reg == 0) {
> + err = -ENODEV;
> + goto err_iounmap;
> + }
> +
> + ctrl->ver_minor = reg & CBQRI_CC_CAPABILITIES_VER_MINOR_MASK;
> + ctrl->ver_major = reg & CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK;
> +
> + ctrl->cc.supports_alloc_op_flush_rcid = (reg >> CBQRI_CC_CAPABILITIES_FRCID_SHIFT)
> + & CBQRI_CC_CAPABILITIES_FRCID_MASK;
> +
> + ctrl->cc.ncblks = (reg >> CBQRI_CC_CAPABILITIES_NCBLKS_SHIFT) &
> + CBQRI_CC_CAPABILITIES_NCBLKS_MASK;
> +
> + /* Calculate size of capacity block in bytes */
> + ctrl->cc.blk_size = ctrl_info->cache.cache_size / ctrl->cc.ncblks;
> + ctrl->cc.cache_level = ctrl_info->cache.cache_level;
> +
> + pr_info("version=%d.%d ncblks=%d blk_size=%d cache_level=%d",
> + ctrl->ver_major, ctrl->ver_minor,
> + ctrl->cc.ncblks, ctrl->cc.blk_size, ctrl->cc.cache_level);
> +
> + /* Probe monitoring features */
> + err = cbqri_probe_feature(ctrl, CBQRI_CC_MON_CTL_OFF,
> + CBQRI_CC_MON_CTL_OP_READ_COUNTER, &status,
> + &ctrl->cc.supports_mon_at_code);
> + if (err) {
> + pr_warn("%s() failed to probe cc_mon_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_CC_MON_CTL_STATUS_SUCCESS) {
> + pr_info("cc_mon_ctl is supported");
> + ctrl->cc.supports_mon_op_config_event = true;
> + ctrl->cc.supports_mon_op_read_counter = true;
> + ctrl->mon_capable = true;
> + } else {
> + pr_info("cc_mon_ctl is NOT supported");
> + ctrl->cc.supports_mon_op_config_event = false;
> + ctrl->cc.supports_mon_op_read_counter = false;
> + ctrl->mon_capable = false;
> + }
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported.
> + */
> + ctrl->cc.supports_mon_at_data = true;
> + pr_info("supports_mon_at_data: %d, supports_mon_at_code: %d",
> + ctrl->cc.supports_mon_at_data, ctrl->cc.supports_mon_at_code);
> +
> + /* Probe allocation features */
> + 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) {
> + pr_warn("%s() failed to probe cc_alloc_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
> + pr_info("cc_alloc_ctl is supported");
> + ctrl->cc.supports_alloc_op_config_limit = true;
> + ctrl->cc.supports_alloc_op_read_limit = true;
> + ctrl->alloc_capable = true;
> + exposed_alloc_capable = true;
> + } else {
> + pr_info("cc_alloc_ctl is NOT supported");
> + ctrl->cc.supports_alloc_op_config_limit = false;
> + ctrl->cc.supports_alloc_op_read_limit = false;
> + ctrl->alloc_capable = false;
> + }
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported
> + */
> + ctrl->cc.supports_alloc_at_data = true;
> + pr_info("supports_alloc_at_data: %d, supports_alloc_at_code: %d",
> + ctrl->cc.supports_alloc_at_data,
> + ctrl->cc.supports_alloc_at_code);
> + } else if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
> + pr_info("probe bandwidth controller");
> +
> + /* Make sure the register is implemented */
> + reg = ioread64(ctrl->base + CBQRI_BC_CAPABILITIES_OFF);
> + if (reg == 0) {
> + err = -ENODEV;
> + goto err_iounmap;
> + }
> +
> + ctrl->ver_minor = reg & CBQRI_BC_CAPABILITIES_VER_MINOR_MASK;
> + ctrl->ver_major = reg & CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK;
> +
> + ctrl->bc.nbwblks = (reg >> CBQRI_BC_CAPABILITIES_NBWBLKS_SHIFT) &
> + CBQRI_BC_CAPABILITIES_NBWBLKS_MASK;
> + ctrl->bc.mrbwb = (reg >> CBQRI_BC_CAPABILITIES_MRBWB_SHIFT) &
> + CBQRI_BC_CAPABILITIES_MRBWB_MASK;
> +
> + pr_info("version=%d.%d nbwblks=%d mrbwb=%d",
> + ctrl->ver_major, ctrl->ver_minor,
> + ctrl->bc.nbwblks, ctrl->bc.mrbwb);
> +
> + /* Probe monitoring features */
> + err = cbqri_probe_feature(ctrl, CBQRI_BC_MON_CTL_OFF,
> + CBQRI_BC_MON_CTL_OP_READ_COUNTER,
> + &status, &ctrl->bc.supports_mon_at_code);
> + if (err) {
> + pr_warn("%s() failed to probe bc_mon_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_BC_MON_CTL_STATUS_SUCCESS) {
> + pr_info("bc_mon_ctl is supported");
> + ctrl->bc.supports_mon_op_config_event = true;
> + ctrl->bc.supports_mon_op_read_counter = true;
> + ctrl->mon_capable = true;
> + exposed_mon_capable = true;
> + } else {
> + pr_info("bc_mon_ctl is NOT supported");
> + ctrl->bc.supports_mon_op_config_event = false;
> + ctrl->bc.supports_mon_op_read_counter = false;
> + ctrl->mon_capable = false;
> + }
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported
> + */
> + ctrl->bc.supports_mon_at_data = true;
> + pr_info("supports_mon_at_data: %d, supports_mon_at_code: %d",
> + ctrl->bc.supports_mon_at_data, ctrl->bc.supports_mon_at_code);
> +
> + /* Probe allocation features */
> + 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) {
> + pr_warn("%s() failed to probe bc_alloc_ctl feature", __func__);
> + goto err_iounmap;
> + }
> +
> + if (status == CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
> + pr_warn("bc_alloc_ctl is supported");
> + ctrl->bc.supports_alloc_op_config_limit = true;
> + ctrl->bc.supports_alloc_op_read_limit = true;
> + ctrl->alloc_capable = true;
> + exposed_alloc_capable = true;
> + } else {
> + pr_warn("bc_alloc_ctl is NOT supported");
> + ctrl->bc.supports_alloc_op_config_limit = false;
> + ctrl->bc.supports_alloc_op_read_limit = false;
> + ctrl->alloc_capable = false;
> + }
> +
> + /*
> + * AT data is "always" supported as it has the same value
> + * than when AT field is not supported
> + */
> + ctrl->bc.supports_alloc_at_data = true;
> + pr_warn("supports_alloc_at_data: %d, supports_alloc_at_code: %d",
> + ctrl->bc.supports_alloc_at_data, ctrl->bc.supports_alloc_at_code);
> + } else {
> + pr_warn("controller type is UNKNOWN");
> + err = -ENODEV;
> + goto err_release_mem_region;
> + }
> +
> + return 0;
> +
> +err_iounmap:
> + pr_warn("%s(): err_iounmap", __func__);
> + iounmap(ctrl->base);
> +
> +err_release_mem_region:
> + pr_warn("%s(): err_release_mem_region", __func__);
> + release_mem_region(ctrl_info->addr, ctrl_info->size);
> +
> + return err;
> +}
> +
> +static struct rdt_ctrl_domain *qos_new_domain(struct cbqri_controller *ctrl)
> +{
> + struct cbqri_resctrl_dom *hw_dom;
> + struct rdt_ctrl_domain *domain;
> +
> + hw_dom = kzalloc(sizeof(*hw_dom), GFP_KERNEL);
> + if (!hw_dom)
> + return NULL;
> +
> + /* associate this cbqri_controller with the domain */
> + hw_dom->hw_ctrl = ctrl;
> +
> + /* the rdt_domain struct from inside the cbqri_resctrl_dom struct */
> + domain = &hw_dom->resctrl_ctrl_dom;
> +
> + INIT_LIST_HEAD(&domain->hdr.list);
> +
> + return domain;
> +}
> +
> +static int qos_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
> +{
> + struct cbqri_resctrl_res *hw_res;
> + struct cbqri_resctrl_dom *hw_dom;
> + u64 *dc;
> + int err = 0;
> + int i;
> +
> + hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
> + if (!hw_res)
> + return -ENOMEM;
> +
> + hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
> + if (!hw_dom)
> + return -ENOMEM;
> +
> + dc = kmalloc_array(hw_res->max_rcid, sizeof(*hw_dom->ctrl_val),
> + GFP_KERNEL);
> + if (!dc)
> + return -ENOMEM;
> +
> + hw_dom->ctrl_val = dc;
> +
> + for (i = 0; i < hw_res->max_rcid; i++, dc++) {
> + err = resctrl_arch_update_one(r, d, i, 0, resctrl_get_default_ctrl(r));
> + if (err)
> + return 0;
> + *dc = resctrl_get_default_ctrl(r);
> + }
> + return 0;
> +}
> +
> +static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
> +{
> + struct rdt_ctrl_domain *domain = NULL;
> + struct cbqri_resctrl_res *cbqri_res = NULL;
> + struct rdt_resource *res = NULL;
> + int internal_id = *id;
> + int err = 0;
> +
> + domain = qos_new_domain(ctrl);
> + if (!domain)
> + return -ENOSPC;
> + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
> + cpumask_copy(&domain->hdr.cpu_mask, &ctrl->ctrl_info->cache.cpu_mask);
> + if (ctrl->ctrl_info->cache.cache_level == 2) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_L2;
> + res->name = "L2";
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = ctrl->mon_capable;
> + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> + res->ctrl_scope = RESCTRL_L2_CACHE;
> + res->cache.arch_has_sparse_bitmasks = false;
> + res->cache.arch_has_per_cpu_cfg = false;
> + res->cache.cbm_len = ctrl->cc.ncblks;
> + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> + res->cache.min_cbm_bits = 1;
> + } else if (ctrl->ctrl_info->cache.cache_level == 3) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_L3;
> + res->name = "L3";
> + res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> + res->ctrl_scope = RESCTRL_L3_CACHE;
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = ctrl->mon_capable;
> + res->cache.arch_has_sparse_bitmasks = false;
> + res->cache.arch_has_per_cpu_cfg = false;
> + res->cache.cbm_len = ctrl->cc.ncblks;
> + res->cache.shareable_bits = resctrl_get_default_ctrl(res);
> + res->cache.min_cbm_bits = 1;
> + } else {
> + pr_warn("%s(): unknown cache level %d", __func__,
> + ctrl->ctrl_info->cache.cache_level);
> + err = -ENODEV;
> + goto err_free_domain;
> + }
> + } else if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
> + if (ctrl->alloc_capable) {
> + cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_MBA];
> + cbqri_res->max_rcid = ctrl->ctrl_info->rcid_count;
> + cbqri_res->max_mcid = ctrl->ctrl_info->mcid_count;
> + res = &cbqri_res->resctrl_res;
> + res->mon.num_rmid = ctrl->ctrl_info->mcid_count;
> + res->rid = RDT_RESOURCE_MBA;
> + res->name = "MB";
> + res->schema_fmt = RESCTRL_SCHEMA_RANGE;
> + res->ctrl_scope = RESCTRL_L3_CACHE;
> + res->alloc_capable = ctrl->alloc_capable;
> + res->mon_capable = false;
> + res->membw.delay_linear = true;
> + res->membw.arch_needs_linear = true;
> + res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
> + // The minimum percentage allowed by the CBQRI spec
> + res->membw.min_bw = 1;
> + // The maximum percentage allowed by the CBQRI spec
> + res->membw.max_bw = 80;
> + res->membw.bw_gran = 1;
1. Wrap this into a function.
2. Also, mweight controller support needs to be added here.
We may need to add RDT_RESOURCE_MB_WEIGHT to the enumeration:
enum resctrl_res_level {
...
RDT_RESOURCE_MB_WEIGHT,
...
};
3. We need to implement cbqri_set_mweight() and cbqri_get_mweight().
4. We need to add monitor controllers (domains) for both capacity and MBW.
> + }
> + } else {
> + pr_warn("%s(): unknown resource %d", __func__, ctrl->ctrl_info->type);
> + err = -ENODEV;
> + goto err_free_domain;
> + }
> +
> + domain->hdr.id = internal_id;
> + err = qos_init_domain_ctrlval(res, domain);
> + if (err)
> + goto err_free_domain;
> +
> + if (cbqri_res) {
> + list_add_tail(&domain->hdr.list, &cbqri_res->resctrl_res.ctrl_domains);
> + *id = internal_id;
> + err = resctrl_online_ctrl_domain(res, domain);
> + if (err) {
> + pr_warn("%s(): failed to online cbqri_res domain", __func__);
> + goto err_free_domain;
> + }
> + }
> +
> + return 0;
> +
> +err_free_domain:
> + pr_warn("%s(): err_free_domain", __func__);
> + kfree(container_of(domain, struct cbqri_resctrl_dom, resctrl_ctrl_dom));
> +
> + return err;
> +}
> +
> +int qos_resctrl_setup(void)
> +{
> + struct rdt_ctrl_domain *domain, *domain_temp;
> + struct cbqri_controller_info *ctrl_info;
> + struct cbqri_controller *ctrl;
> + struct cbqri_resctrl_res *res;
> + static int found_controllers;
> + int err = 0;
> + int id = 0;
> + int i;
> +
> + list_for_each_entry(ctrl_info, &cbqri_controllers, list) {
> + err = cbqri_probe_controller(ctrl_info, &controllers[found_controllers]);
> + if (err) {
> + pr_warn("%s(): failed (%d)", __func__, err);
> + goto err_unmap_controllers;
> + }
> +
> + found_controllers++;
> + if (found_controllers > MAX_CONTROLLERS) {
> + pr_warn("%s(): increase MAX_CONTROLLERS value", __func__);
> + break;
> + }
> + }
> +
> + for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> + res = &cbqri_resctrl_resources[i];
> + INIT_LIST_HEAD(&res->resctrl_res.ctrl_domains);
> + INIT_LIST_HEAD(&res->resctrl_res.mon_domains);
> + res->resctrl_res.rid = i;
> + }
> +
> + for (i = 0; i < found_controllers; i++) {
> + ctrl = &controllers[i];
> + err = qos_resctrl_add_controller_domain(ctrl, &id);
> + if (err) {
> + pr_warn("%s(): failed to add controller domain (%d)", __func__, err);
> + goto err_free_controllers_list;
> + }
> + id++;
> +
> + /*
> + * CDP (code data prioritization) on x86 is similar to
> + * the AT (access type) field in CBQRI. CDP only supports
> + * caches so this must be a CBQRI capacity controller.
> + */
> + if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&
> + ctrl->cc.supports_alloc_at_code &&
> + ctrl->cc.supports_alloc_at_data) {
> + if (ctrl->ctrl_info->cache.cache_level == 2)
> + exposed_cdp_l2_capable = true;
> + else
> + exposed_cdp_l3_capable = true;
> + }
> + }
> +
> + pr_info("exposed_alloc_capable = %d", exposed_alloc_capable);
> + pr_info("exposed_mon_capable = %d", exposed_mon_capable);
> + pr_info("exposed_cdp_l2_capable = %d", exposed_cdp_l2_capable);
> + pr_info("exposed_cdp_l3_capable = %d", exposed_cdp_l3_capable);
One line of pr_info? Print total controllers, capacity and MBW counts
> +
> + return resctrl_init();
> +
> +err_free_controllers_list:
> + for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> + res = &cbqri_resctrl_resources[i];
> + list_for_each_entry_safe(domain, domain_temp, &res->resctrl_res.ctrl_domains,
> + hdr.list) {
> + kfree(domain);
> + }
> + }
> +
> +err_unmap_controllers:
> + for (i = 0; i < found_controllers; i++) {
> + iounmap(controllers[i].base);
> + release_mem_region(controllers[i].ctrl_info->addr, controllers[i].ctrl_info->size);
> + }
> +
> + return err;
> +}
> +
> +int qos_resctrl_online_cpu(unsigned int cpu)
> +{
> + resctrl_online_cpu(cpu);
> + return 0;
> +}
> +
> +int qos_resctrl_offline_cpu(unsigned int cpu)
> +{
> + resctrl_offline_cpu(cpu);
> + return 0;
> +}
> +
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains
2026-01-28 20:27 ` [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains Drew Fustini
2026-02-13 23:15 ` Reinette Chatre
@ 2026-03-25 2:31 ` yunhui cui
2026-03-25 6:49 ` Drew Fustini
1 sibling, 1 reply; 57+ messages in thread
From: yunhui cui @ 2026-03-25 2:31 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Define data structures to encapsulate the resctrl resource
> and domain structures.
>
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> [fustini: rebased current upstream]
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
> arch/riscv/kernel/qos/internal.h | 27 +++++++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
>
> diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> index ff2c7eff50be..c0402dd06cfa 100644
> --- a/arch/riscv/kernel/qos/internal.h
> +++ b/arch/riscv/kernel/qos/internal.h
> @@ -65,6 +65,11 @@
> #define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2
> #define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1
>
> +int qos_resctrl_setup(void);
> +void qos_resctrl_exit(void);
> +int qos_resctrl_online_cpu(unsigned int cpu);
> +int qos_resctrl_offline_cpu(unsigned int cpu);
> +
> /* Capacity Controller hardware capabilities */
> struct riscv_cbqri_capacity_caps {
> u16 ncblks; /* number of capacity blocks */
> @@ -125,4 +130,26 @@ struct cbqri_controller {
> bool mon_capable;
> };
>
> +struct cbqri_resctrl_res {
> + struct rdt_resource resctrl_res;
> + struct cbqri_controller controller;
> + u32 max_rcid;
> + u32 max_mcid;
> +};
> +
> +struct cbqri_resctrl_dom {
> + struct rdt_domain_hdr resctrl_dom_hdr;
> + struct rdt_ctrl_domain resctrl_ctrl_dom;
> + struct rdt_mon_domain resctrl_mon_dom;
> + u64 cbm;
> + u64 rbwb;
> + u64 *ctrl_val;
> + struct cbqri_controller *hw_ctrl;
> +};
> +
Can we trim down some fields? For example:
struct cbqri_resctrl_res {
struct rdt_resource resctrl_res;
- struct cbqri_controller controller;
u32 max_rcid;
u32 max_mcid;
};
struct cbqri_resctrl_dom {
- struct rdt_domain_hdr resctrl_dom_hdr;
struct rdt_ctrl_domain resctrl_ctrl_dom;
struct rdt_mon_domain resctrl_mon_dom;
- u64 cbm;
- u64 rbwb;
u64 *ctrl_val;
struct cbqri_controller *hw_ctrl;
};
> +struct cbqri_config {
> + u64 cbm; /* capacity block mask */
> + u64 rbwb; /* reserved bandwidth blocks */
> +};
> +
> #endif /* _ASM_RISCV_QOS_INTERNAL_H */
>
> --
> 2.43.0
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers
2026-03-25 2:09 ` [External] " yunhui cui
@ 2026-03-25 6:37 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-03-25 6:37 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Wed, Mar 25, 2026 at 10:09:01AM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add interface for CBQRI controller drivers to make use of the resctrl
> > filesystem.
> >
> > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > arch/riscv/kernel/qos/qos_resctrl.c | 1192 +++++++++++++++++++++++++++++++++++
> > 1 file changed, 1192 insertions(+)
> >
> > diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
> > new file mode 100644
> > index 000000000000..d500098599d2
> > --- /dev/null
> > +++ b/arch/riscv/kernel/qos/qos_resctrl.c
> > @@ -0,0 +1,1192 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +#define pr_fmt(fmt) "qos: resctrl: " fmt
> > +
> > +#include <linux/slab.h>
> > +#include <linux/err.h>
> > +#include <linux/riscv_qos.h>
> > +#include <linux/resctrl.h>
> > +#include <linux/types.h>
> > +#include <asm/csr.h>
> > +#include <asm/qos.h>
> > +#include "internal.h"
> > +
> > +#define MAX_CONTROLLERS 6
> > +static struct cbqri_controller controllers[MAX_CONTROLLERS];
>
> We can get the total number of controllers, so we'll allocate dynamically.
I've made a lot of improvements but am still making more changes based
on the feedback from Reinette and you. I'm hoping to finish and send a
new revision of the series but in the meantime my work-in-progress is
b4/ssqosid-cbqri-rqsc [1].
I have dropped this static array and now just use a list of controllers.
It is populated by drivers/acpi/riscv/rqsc.c [2] and iterated through by
qos_resctrl_setup() in arch/riscv/kernel/qos/qos_resctrl.c [3].
[1] https://github.com/tt-fustini/linux/tree/b4/ssqosid-cbqri-rqsc
[2] https://github.com/tt-fustini/linux/blob/b4/ssqosid-cbqri-rqsc/drivers/acpi/riscv/rqsc.c
[3] https://github.com/tt-fustini/linux/blob/b4/ssqosid-cbqri-rqsc/arch/riscv/kernel/qos/qos_resctrl.c
> > +static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
[..]
> 1. Wrap this into a function.
>
> 2. Also, mweight controller support needs to be added here.
> We may need to add RDT_RESOURCE_MB_WEIGHT to the enumeration:
> enum resctrl_res_level {
> ...
> RDT_RESOURCE_MB_WEIGHT,
> ...
> };
>
> 3. We need to implement cbqri_set_mweight() and cbqri_get_mweight().
I think this could be a good way to implement mweight but I am planning
to intiailly support justI think this could be a good way to implement
mweight but I am planning to intiailly support just rbwb
> 4. We need to add monitor controllers (domains) for both capacity and MBW.
I don't want to attempt to support bandwidth monitoring until there is
progress in resctrl for support of cpu-less memory devices as this is a
concern for mpam too. However, it should be possible to support cache
occupancy monitoring.
[..]
> > + pr_info("exposed_alloc_capable = %d", exposed_alloc_capable);
> > + pr_info("exposed_mon_capable = %d", exposed_mon_capable);
> > + pr_info("exposed_cdp_l2_capable = %d", exposed_cdp_l2_capable);
> > + pr_info("exposed_cdp_l3_capable = %d", exposed_cdp_l3_capable);
>
> One line of pr_info? Print total controllers, capacity and MBW counts
Good idea, I'll do that.
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains
2026-03-25 2:31 ` [External] " yunhui cui
@ 2026-03-25 6:49 ` Drew Fustini
2026-03-26 8:32 ` yunhui cui
0 siblings, 1 reply; 57+ messages in thread
From: Drew Fustini @ 2026-03-25 6:49 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Wed, Mar 25, 2026 at 10:31:39AM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Define data structures to encapsulate the resctrl resource
> > and domain structures.
> >
> > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > [fustini: rebased current upstream]
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > arch/riscv/kernel/qos/internal.h | 27 +++++++++++++++++++++++++++
> > 1 file changed, 27 insertions(+)
> >
> > diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> > index ff2c7eff50be..c0402dd06cfa 100644
> > --- a/arch/riscv/kernel/qos/internal.h
> > +++ b/arch/riscv/kernel/qos/internal.h
> > @@ -65,6 +65,11 @@
> > #define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2
> > #define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1
> >
> > +int qos_resctrl_setup(void);
> > +void qos_resctrl_exit(void);
> > +int qos_resctrl_online_cpu(unsigned int cpu);
> > +int qos_resctrl_offline_cpu(unsigned int cpu);
> > +
> > /* Capacity Controller hardware capabilities */
> > struct riscv_cbqri_capacity_caps {
> > u16 ncblks; /* number of capacity blocks */
> > @@ -125,4 +130,26 @@ struct cbqri_controller {
> > bool mon_capable;
> > };
> >
> > +struct cbqri_resctrl_res {
> > + struct rdt_resource resctrl_res;
> > + struct cbqri_controller controller;
> > + u32 max_rcid;
> > + u32 max_mcid;
> > +};
> > +
> > +struct cbqri_resctrl_dom {
> > + struct rdt_domain_hdr resctrl_dom_hdr;
> > + struct rdt_ctrl_domain resctrl_ctrl_dom;
> > + struct rdt_mon_domain resctrl_mon_dom;
> > + u64 cbm;
> > + u64 rbwb;
> > + u64 *ctrl_val;
> > + struct cbqri_controller *hw_ctrl;
> > +};
> > +
>
> Can we trim down some fields? For example:
> struct cbqri_resctrl_res {
> struct rdt_resource resctrl_res;
> - struct cbqri_controller controller;
> u32 max_rcid;
> u32 max_mcid;
> };
>
> struct cbqri_resctrl_dom {
> - struct rdt_domain_hdr resctrl_dom_hdr;
> struct rdt_ctrl_domain resctrl_ctrl_dom;
> struct rdt_mon_domain resctrl_mon_dom;
> - u64 cbm;
> - u64 rbwb;
> u64 *ctrl_val;
> struct cbqri_controller *hw_ctrl;
> };
Can you explain why you don't think these are needed??
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-03-25 1:43 ` [External] " yunhui cui
@ 2026-03-25 7:09 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-03-25 7:09 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Wed, Mar 25, 2026 at 09:43:07AM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add structs for the RQSC table which describes the properties of the
> > RISC-V QoS controllers (CBQRI) in the system. The table also describes
> > the topological arrangement of the QoS controllers and resources in the
> > system. The topology is expressed in terms of the location of the
> > resources within the system and the relation between the QoS Controller
> > and the resource it manages.
> >
> > Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> > Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > include/acpi/actbl2.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 92 insertions(+)
> >
> > diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> > index f726bce3eb84..7367990349ee 100644
> > --- a/include/acpi/actbl2.h
> > +++ b/include/acpi/actbl2.h
> > @@ -53,6 +53,7 @@
> > #define ACPI_SIG_RGRT "RGRT" /* Regulatory Graphics Resource Table */
> > #define ACPI_SIG_RHCT "RHCT" /* RISC-V Hart Capabilities Table */
> > #define ACPI_SIG_RIMT "RIMT" /* RISC-V IO Mapping Table */
> > +#define ACPI_SIG_RQSC "RQSC" /* RISC-V RISC-V Quality of Service Controller */
> > #define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
> > #define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
> > #define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
> > @@ -3165,6 +3166,97 @@ enum acpi_rgrt_image_type {
> > ACPI_RGRT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
> > };
> >
> > +/*******************************************************************************
> > + *
> > + * RQSC - RISC-V Quality of Service Controller
> > + * Version 1
> > + *
> > + ******************************************************************************/
> > +
> > +struct acpi_table_rqsc_fields_res {
> > + u8 type; // 1
> > + u8 resv; // 1
> > + u16 length; // 2
> > + u16 flags; // 2
> > + u8 resv2; // 1
> > + u8 id_type; // 1
> > + u64 id1; // 8
> > + u32 id2; // 4
> > +};
> > +
> > +struct acpi_table_rqsc_fields {
> > + u8 type; // 1
> > + u8 resv; // 1
> > + u16 length; // 2
> > + u32 reg[3]; // 12
> > + u32 rcid; // 4
> > + u32 mcid; // 4
> > + u16 flags; // 2
> > + u16 nres; // 2
> > + struct acpi_table_rqsc_fields_res res; // 20
> > +};
> > +
> > +struct acpi_table_rqsc {
> > + struct acpi_table_header header; /* Common ACPI table header */
> > + u32 num;
> > + struct acpi_table_rqsc_fields f[6];
>
> Is a fixed array f[6] appropriate here ?
This was a flaw in the proof of concept where it assumed 6 controllers.
My work-in-progress has solved that problem:
https://github.com/tt-fustini/linux/blob/b4/ssqosid-cbqri/include/acpi/actbl2.h
> > +};
> > +
> > +/* RQSC Flags */
> > +#define ACPI_RQSC_TIMER_CANNOT_WAKEUP_CPU (1)
> > +
> > +/*
> > + * RQSC subtables
> > + */
> > +struct acpi_rqsc_node_header {
> > + u16 type;
> > + u16 length;
> > + u16 revision;
> > +};
> > +
> > +/* Values for RQSC subtable Type above */
> > +enum acpi_rqsc_node_type {
> > + ACPI_RQSC_NODE_TYPE_ISA_STRING = 0x0000,
> > + ACPI_RQSC_NODE_TYPE_CMO = 0x0001,
> > + ACPI_RQSC_NODE_TYPE_MMU = 0x0002,
> > + ACPI_RQSC_NODE_TYPE_RESERVED = 0x0003,
> > + ACPI_RQSC_NODE_TYPE_HART_INFO = 0xFFFF,
> > +};
> > +
> > +/*
> > + * RQSC node specific subtables
> > + */
> > +
> > +/* ISA string node structure */
> > +struct acpi_rqsc_isa_string {
> > + u16 isa_length;
> > + char isa[];
> > +};
> > +
> > +struct acpi_rqsc_cmo_node {
> > + u8 reserved; /* Must be zero */
> > + u8 cbom_size; /* CBOM size in powerof 2 */
> > + u8 cbop_size; /* CBOP size in powerof 2 */
> > + u8 cboz_size; /* CBOZ size in powerof 2 */
> > +};
> > +
> > +struct acpi_rqsc_mmu_node {
> > + u8 reserved; /* Must be zero */
> > + u8 mmu_type; /* Virtual Address Scheme */
> > +};
> > +
> > +enum acpi_rqsc_mmu_type {
> > + ACPI_RQSC_MMU_TYPE_SV39 = 0,
> > + ACPI_RQSC_MMU_TYPE_SV48 = 1,
> > + ACPI__MMU_TYPE_SV57 = 2
>
> ACPI_RQSC_MMU_TYPE_SV57 = 2 ?
These fields were all included by mistake. The only structs that rqsc
needs are: acpi_table_rqsc_fields_res, struct acpi_table_rqsc_fields and
struct acpi_table_rqsc
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table
2026-03-25 1:48 ` yunhui cui
@ 2026-03-25 7:14 ` Drew Fustini
0 siblings, 0 replies; 57+ messages in thread
From: Drew Fustini @ 2026-03-25 7:14 UTC (permalink / raw)
To: yunhui cui
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
On Wed, Mar 25, 2026 at 09:48:37AM +0800, yunhui cui wrote:
> Hi Drew,
>
> On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> >
> > Add structs for the RQSC table which describes the properties of the
> > RISC-V QoS controllers (CBQRI) in the system. The table also describes
> > the topological arrangement of the QoS controllers and resources in the
> > system. The topology is expressed in terms of the location of the
> > resources within the system and the relation between the QoS Controller
> > and the resource it manages.
> >
> > Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
> > Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/chapter2.adoc
> > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > ---
> > include/acpi/actbl2.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 92 insertions(+)
> >
> > diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> > index f726bce3eb84..7367990349ee 100644
> > --- a/include/acpi/actbl2.h
> > +++ b/include/acpi/actbl2.h
> > @@ -53,6 +53,7 @@
> > #define ACPI_SIG_RGRT "RGRT" /* Regulatory Graphics Resource Table */
> > #define ACPI_SIG_RHCT "RHCT" /* RISC-V Hart Capabilities Table */
> > #define ACPI_SIG_RIMT "RIMT" /* RISC-V IO Mapping Table */
> > +#define ACPI_SIG_RQSC "RQSC" /* RISC-V RISC-V Quality of Service Controller */
> > #define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
> > #define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
> > #define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
> > @@ -3165,6 +3166,97 @@ enum acpi_rgrt_image_type {
> > ACPI_RGRT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
> > };
> >
> > +/*******************************************************************************
> > + *
> > + * RQSC - RISC-V Quality of Service Controller
> > + * Version 1
> > + *
> > + ******************************************************************************/
> > +
> > +struct acpi_table_rqsc_fields_res {
> > + u8 type; // 1
> > + u8 resv; // 1
> > + u16 length; // 2
> > + u16 flags; // 2
> > + u8 resv2; // 1
> > + u8 id_type; // 1
> > + u64 id1; // 8
> > + u32 id2; // 4
> > +};
> > +
> > +struct acpi_table_rqsc_fields {
> > + u8 type; // 1
> > + u8 resv; // 1
> > + u16 length; // 2
> > + u32 reg[3]; // 12
> > + u32 rcid; // 4
> > + u32 mcid; // 4
>
> The spec appears to specify a length of 2 bytes for this field?
Yes, this was a bug. I have changed rcid and mcid to u16:
https://github.com/tt-fustini/linux/blob/b4/ssqosid-cbqri/include/acpi/actbl2.h
Thanks,
Drew
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [External] [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains
2026-03-25 6:49 ` Drew Fustini
@ 2026-03-26 8:32 ` yunhui cui
0 siblings, 0 replies; 57+ messages in thread
From: yunhui cui @ 2026-03-26 8:32 UTC (permalink / raw)
To: Drew Fustini
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Radim Krčmář, Samuel Holland, Adrien Ricciardi,
Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
Vasudevan Srinivasan, Ved Shanbhogue, Chen Pei, Liu Zhiwei,
Weiwei Li, guo.wenjia23, liu.qingtao2, Reinette Chatre, Tony Luck,
Babu Moger, Peter Newman, Fenghua Yu, James Morse, Ben Horgan,
Dave Martin, linux-kernel, linux-riscv, x86, Rob Herring,
Rafael J. Wysocki, Len Brown, Robert Moore, Sunil V L,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, linux-acpi,
acpica-devel, devicetree
Hi Drew,
On Wed, Mar 25, 2026 at 2:49 PM Drew Fustini <fustini@kernel.org> wrote:
>
> On Wed, Mar 25, 2026 at 10:31:39AM +0800, yunhui cui wrote:
> > Hi Drew,
> >
> > On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini <fustini@kernel.org> wrote:
> > >
> > > Define data structures to encapsulate the resctrl resource
> > > and domain structures.
> > >
> > > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > > [fustini: rebased current upstream]
> > > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > > ---
> > > arch/riscv/kernel/qos/internal.h | 27 +++++++++++++++++++++++++++
> > > 1 file changed, 27 insertions(+)
> > >
> > > diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
> > > index ff2c7eff50be..c0402dd06cfa 100644
> > > --- a/arch/riscv/kernel/qos/internal.h
> > > +++ b/arch/riscv/kernel/qos/internal.h
> > > @@ -65,6 +65,11 @@
> > > #define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT 2
> > > #define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS 1
> > >
> > > +int qos_resctrl_setup(void);
> > > +void qos_resctrl_exit(void);
> > > +int qos_resctrl_online_cpu(unsigned int cpu);
> > > +int qos_resctrl_offline_cpu(unsigned int cpu);
> > > +
> > > /* Capacity Controller hardware capabilities */
> > > struct riscv_cbqri_capacity_caps {
> > > u16 ncblks; /* number of capacity blocks */
> > > @@ -125,4 +130,26 @@ struct cbqri_controller {
> > > bool mon_capable;
> > > };
> > >
> > > +struct cbqri_resctrl_res {
> > > + struct rdt_resource resctrl_res;
> > > + struct cbqri_controller controller;
> > > + u32 max_rcid;
> > > + u32 max_mcid;
> > > +};
> > > +
> > > +struct cbqri_resctrl_dom {
> > > + struct rdt_domain_hdr resctrl_dom_hdr;
> > > + struct rdt_ctrl_domain resctrl_ctrl_dom;
> > > + struct rdt_mon_domain resctrl_mon_dom;
> > > + u64 cbm;
> > > + u64 rbwb;
> > > + u64 *ctrl_val;
> > > + struct cbqri_controller *hw_ctrl;
> > > +};
> > > +
> >
> > Can we trim down some fields? For example:
> > struct cbqri_resctrl_res {
> > struct rdt_resource resctrl_res;
> > - struct cbqri_controller controller;
> > u32 max_rcid;
> > u32 max_mcid;
> > };
> >
> > struct cbqri_resctrl_dom {
> > - struct rdt_domain_hdr resctrl_dom_hdr;
> > struct rdt_ctrl_domain resctrl_ctrl_dom;
> > struct rdt_mon_domain resctrl_mon_dom;
> > - u64 cbm;
> > - u64 rbwb;
> > u64 *ctrl_val;
> > struct cbqri_controller *hw_ctrl;
> > };
>
> Can you explain why you don't think these are needed??
The functionality works well without those fields, feel free to try.
Btw, when do you plan to send the next revision?
>
> Thanks,
> Drew
>
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 57+ messages in thread
end of thread, other threads:[~2026-03-26 8:32 UTC | newest]
Thread overview: 57+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-28 20:27 [PATCH RFC v2 00/17] RISC-V: QoS: add CBQRI resctrl interface Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 01/17] dt-bindings: riscv: Add Ssqosid extension description Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 02/17] RISC-V: Detect the Ssqosid extension Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 03/17] RISC-V: Add support for srmcfg CSR from Ssqosid ext Drew Fustini
2026-02-02 3:17 ` [External] " yunhui cui
2026-02-08 1:31 ` Drew Fustini
2026-02-09 3:36 ` yunhui cui
2026-02-02 4:27 ` yunhui cui
2026-02-03 19:43 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 04/17] RISC-V: QoS: define properties of CBQRI controllers Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 05/17] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities Drew Fustini
2026-02-13 23:13 ` Reinette Chatre
2026-02-14 16:25 ` Drew Fustini
2026-02-17 16:32 ` Reinette Chatre
2026-02-17 18:28 ` Drew Fustini
2026-02-17 19:02 ` Reinette Chatre
2026-02-17 22:36 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 06/17] RISC-V: QoS: define CBQRI resctrl resources and domains Drew Fustini
2026-02-13 23:15 ` Reinette Chatre
2026-02-14 16:34 ` Drew Fustini
2026-03-25 2:31 ` [External] " yunhui cui
2026-03-25 6:49 ` Drew Fustini
2026-03-26 8:32 ` yunhui cui
2026-01-28 20:27 ` [PATCH RFC v2 07/17] RISC-V: QoS: define prototypes for resctrl interface Drew Fustini
2026-02-13 23:21 ` Reinette Chatre
2026-01-28 20:27 ` [PATCH RFC v2 08/17] RISC-V: QoS: add resctrl interface for CBQRI controllers Drew Fustini
2026-02-02 4:12 ` [External] " yunhui cui
2026-02-20 19:54 ` Drew Fustini
2026-02-09 7:20 ` Gong Shuai
2026-02-09 10:07 ` Gong Shuai
2026-02-09 14:16 ` Gong Shuai
2026-02-11 0:57 ` Drew Fustini
2026-02-13 23:30 ` Reinette Chatre
2026-02-18 21:49 ` Drew Fustini
2026-02-18 23:18 ` Reinette Chatre
2026-03-25 2:09 ` [External] " yunhui cui
2026-03-25 6:37 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 09/17] RISC-V: QoS: expose implementation to resctrl Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 10/17] RISC-V: QoS: add late_initcall to setup resctrl interface Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 11/17] RISC-V: QoS: add to build when CONFIG_RISCV_ISA_SSQOSID set Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 12/17] RISC-V: QoS: make CONFIG_RISCV_ISA_SSQOSID select resctrl Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 13/17] acpi: pptt: Add helper to find a cache from id Drew Fustini
2026-03-25 1:34 ` [External] " yunhui cui
2026-01-28 20:27 ` [PATCH RFC v2 14/17] include: acpi: actbl2: Add structs for RQSC table Drew Fustini
2026-01-28 20:31 ` Rafael J. Wysocki
2026-01-28 20:44 ` Drew Fustini
2026-01-28 20:50 ` Rafael J. Wysocki
2026-03-25 1:43 ` [External] " yunhui cui
2026-03-25 7:09 ` Drew Fustini
2026-03-25 1:48 ` yunhui cui
2026-03-25 7:14 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 15/17] RISC-V: QoS: add Cache ID and Prox Dom to CBQRI controllers Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table Drew Fustini
2026-02-02 11:08 ` [External] " yunhui cui
2026-02-03 20:00 ` Drew Fustini
2026-02-14 4:48 ` Drew Fustini
2026-01-28 20:27 ` [PATCH RFC v2 17/17] acpi: riscv: Add support for RISC-V Quality of Service Controller (RQSC) Drew Fustini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox