2023-04-19 11:11:11

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 00/21] RISC-V: QoS: add CBQRI resctrl interface

This RFC series adds a resctrl interface for resource controllers that
implement the RISC-V Capacity and Bandwidth QoS Register Interface
(CBQRI) specification [1].

These patches are also available as a branch [2]. Please note that they
are based on a 6.3-rc1 branch by James Morse [3] for reasons that will
be explained below.

There is a complimentary RFC patch series for Qemu [4] that implements
CBQRI, and there is a qemu branch with those patches too [5].

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 Ssqosid extension (supervisor-mode QoS ID) defines the sqoscfg CSR
which consists of a resource control identifier (RCID) and a monitoring
counter identifier (MCID). This allows a software workload, such as a
process or a set of processes, to be associated with each request made
by a hart to shared resources like cache.

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 resources to be differentiated between
data and code.

x86 comparison
--------------
Intel RDT and AMD QoS features have already been present in some x86
processors for several years. The existing QoS identifiers on x86 map
well to the RISC-V Ssqoid extension:

  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.


resctrl beyond x86
------------------
The resctrl virtual filesystem [6] is an established userspace ABI for
QoS features on x86. However, the resctrl code is tightly coupled to
arch/x6, and it is not currently possible to use it with another
architecture in mainline.

James Morse has been working to separate resctrl out into an independent
virtual filesystem that can be used by any arch that implements a
resctrl interface. The most recent patch series is v3 of "x86/resctrl:
monitored closid+rmid together, separate arch/fs locking" [7].

The motivation behind this work from James Morse is to support the Arm
Memory System Resource Partitioning and Monitoring (MPAM) extension [8].
James maintains a "snapshot" branch for each mainline release [9] that
has a cohesive implementation of MPAM support. It includes the ability
to enable the resctrl filesystem for non-x86 architectures. Therefore,
the RISC-V support for resctrl in this RFC patch series relies on the
fs/resctrl code in the snapshot branch.

However, the current mpam snapshot branch on kernel.org is for 6.2. That
is too old to base this RFC on because RISC-V extension handling has
changed a lot since then. As result, this RFC patches series is based on
this 6.3 mpam snapshot branch [3] by James, but it won't be pushed to
kernel.org until 6.3 is officially released.

Limitations of resctrl
----------------------
Both MPAM and CBQRI are generic enough to offer a lot of flexibility for
hardware implementations. This is in contrast to the fixed functionality
of Intel RDT and AMD QoS features.

For example, Intel RDT only considers L2 and L3 cache resources. The
memory bandwidth resource (MBA) is assumed to be sitting at the L3 cache
level. In addition, CDP only supports caches so the usage of the CBQRI
Access Types (AT field) has to be limited to CBQRI capacity controllers.

This RFC patch series follows that same philosophy as the MPAM support
by James Morse [10]. Support only the functionality that is already
possible with the existing resctrl interface. There is much more
functionality that both MPAM and CBQRI offer, but that will be deferred
until after the decoupling of resctrl from x86 is merged.

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 that unlike with RDT and MPAM, it does not matter
which cpu runs the resctrl code.        

Example SoC
-----------
This series also includes example drivers for a hypothetical SoC with a
cache controller that implements CBQRI capacity operations and a memory
controller that implements CBQRI bandwidth operations. The drivers are
intended to work with the Qemu branch [5] which instantiates:

- 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.

Status of CBQRI
---------------
The CBQRI spec is still in a draft state and is undergoing review [11].
It is possible there will be changes to the Ssqosid extension and the
CBQRI spec. For example, the sqoscfg CSR address is not yet finalized.

The goal of this RFC patch series, along with the complimentary Qemu
patch series, is to satisfy the software proof of concept requirement
for CBQRI to become frozen.

[1] https://github.com/riscv-non-isa/riscv-cbqri/blob/main/riscv-cbqri.pdf
[2] https://gitlab.baylibre.com/baylibre/linux/-/tree/riscv-cbqri-rfc
[3] https://gitlab.arm.com/linux-arm/linux-jm/-/tree/mpam/snaphot/20230406
[4] https://lore.kernel.org/qemu-devel/[email protected]/
[5] https://gitlab.baylibre.com/baylibre/qemu/-/tree/riscv-cbqri-rfc
[6] https://docs.kernel.org/x86/resctrl.html
[7] https://lore.kernel.org/lkml/[email protected]/
[8] https://developer.arm.com/documentation/107768/0100/Arm-Memory-System-Resource-Partitioning-and-Monitoring--MPAM--Extension
[9] https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git/log/?h=mpam/snapshot/v6.2
[10] https://gitlab.arm.com/linux-arm/linux-jm/-/blob/mpam/snaphot/20230406/KNOWN_ISSUES
[11] https://lists.riscv.org/g/tech-cbqri/message/38

Drew Fustini (21):
RISC-V: Detect the Ssqosid extension
RISC-V: Add support for sqoscfg CSR
RISC-V: QoS: define properties of CBQRI controllers
RISC-V: QoS: define CBQRI capacity and bandwidth capabilities
RISC-V: QoS: define prototypes for resctrl interface
RISC-V: QoS: define CBQRI resctrl resources and domains
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: make CONFIG_RISCV_ISA_SSQOSID select resctrl
RISC-V: QoS: add to build when CONFIG_RISCV_ISA_SSQOSID set
dt-bindings: riscv: add riscv,cbqri bindings
DO_NOT_MERGE dt-bindings: add foobar vendor-prefix
DO_NOT_MERGE dt-bindings: soc: add Foobar SoC cache controller
DO_NOT_MERGE dt-bindings: soc: add Foobar SoC memory controller
DO_NOT_MERGE soc: add Foobar SoC cache controller driver
DO_NOT_MERGE soc: add Foobar SoC memory controller driver
DO_NOT_MERGE soc: build Foobar SoC drivers
DO_NOT_MERGE riscv: dts: qemu: add dump from riscv-cbqri-rfc
DO_NOT_MERGE riscv: dts: qemu: add cbqri-capable controllers
DO_NOT_MERGE riscv: dts: build qemu virt device tree

.../bindings/riscv/riscv,cbqri.yaml | 28 +
.../soc/foobar/foobar,cache-controller.yaml | 51 +
.../soc/foobar/foobar,memory-controller.yaml | 49 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
arch/riscv/Kconfig | 22 +
arch/riscv/boot/dts/Makefile | 1 +
arch/riscv/boot/dts/qemu/Makefile | 3 +
arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts | 430 ++++++
arch/riscv/include/asm/csr.h | 8 +
arch/riscv/include/asm/hwcap.h | 2 +
arch/riscv/include/asm/processor.h | 3 +
arch/riscv/include/asm/qos.h | 40 +
arch/riscv/include/asm/resctrl.h | 2 +
arch/riscv/include/asm/switch_to.h | 2 +
arch/riscv/kernel/Makefile | 2 +
arch/riscv/kernel/cpu.c | 1 +
arch/riscv/kernel/cpufeature.c | 1 +
arch/riscv/kernel/qos/Makefile | 2 +
arch/riscv/kernel/qos/internal.h | 157 +++
arch/riscv/kernel/qos/qos.c | 31 +
arch/riscv/kernel/qos/qos_resctrl.c | 1231 +++++++++++++++++
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/foobar/Kconfig | 21 +
drivers/soc/foobar/Makefile | 4 +
drivers/soc/foobar/foobar_cbqri_cache.c | 110 ++
drivers/soc/foobar/foobar_cbqri_memory.c | 83 ++
include/linux/riscv_qos.h | 92 ++
28 files changed, 2380 insertions(+)
create mode 100644 Documentation/devicetree/bindings/riscv/riscv,cbqri.yaml
create mode 100644 Documentation/devicetree/bindings/soc/foobar/foobar,cache-controller.yaml
create mode 100644 Documentation/devicetree/bindings/soc/foobar/foobar,memory-controller.yaml
create mode 100644 arch/riscv/boot/dts/qemu/Makefile
create mode 100644 arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts
create mode 100644 arch/riscv/include/asm/qos.h
create mode 100644 arch/riscv/include/asm/resctrl.h
create mode 100644 arch/riscv/kernel/qos/Makefile
create mode 100644 arch/riscv/kernel/qos/internal.h
create mode 100644 arch/riscv/kernel/qos/qos.c
create mode 100644 arch/riscv/kernel/qos/qos_resctrl.c
create mode 100644 drivers/soc/foobar/Kconfig
create mode 100644 drivers/soc/foobar/Makefile
create mode 100644 drivers/soc/foobar/foobar_cbqri_cache.c
create mode 100644 drivers/soc/foobar/foobar_cbqri_memory.c
create mode 100644 include/linux/riscv_qos.h

--
2.34.1


2023-04-19 11:11:14

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 01/21] RISC-V: Detect the Ssqosid extension

Ssqosid is the Supervisor QoS ID extension defined in the RISC-V CBQRI
(Capacity and Bandwidth QoS Register Interface) specification.

Link: https://github.com/riscv-non-isa/riscv-cbqri/blob/main/riscv-cbqri.pdf
Signed-off-by: Kornel Dulęba <[email protected]>
[dfustini: rebase from v6.0 to v6.3]
Signed-off-by: Drew Fustini <[email protected]>
---
Note:
- A version of this patch rebased on riscv/for-next was already
submitted as an RFC to linux-riscv [1] with Message-ID:
[email protected]
- This patch is included in this RFC series so as to provide a cohesive
demonstration in one series.

[1] https://lore.kernel.org/lkml/[email protected]/

arch/riscv/include/asm/hwcap.h | 2 ++
arch/riscv/kernel/cpu.c | 1 +
arch/riscv/kernel/cpufeature.c | 1 +
3 files changed, 4 insertions(+)

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index e3021b2590de..255c5c4d0a24 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -42,6 +42,8 @@
#define RISCV_ISA_EXT_ZBB 30
#define RISCV_ISA_EXT_ZICBOM 31
#define RISCV_ISA_EXT_ZIHINTPAUSE 32
+#define RISCV_ISA_EXT_SSQOSID 35
+

#define RISCV_ISA_EXT_MAX 64
#define RISCV_ISA_EXT_NAME_LEN_MAX 32
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index 8400f0cc9704..d1441872f173 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -189,6 +189,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = {
__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
__RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
+ __RISCV_ISA_EXT_DATA(ssqosid, RISCV_ISA_EXT_SSQOSID),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 59d58ee0f68d..80317d2d3975 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -222,6 +222,7 @@ void __init riscv_fill_hwcap(void)
} else {
/* sorted alphabetically */
SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
+ SET_ISA_EXT_MAP("ssqosid", RISCV_ISA_EXT_SSQOSID);
SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC);
SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL);
SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
--
2.34.1

2023-04-19 11:11:18

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 02/21] RISC-V: Add support for sqoscfg CSR

Add support for the sqoscfg 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 sqoscfg field is added to thread_struct and has the same format as the
sqoscfg CSR. This allows the scheduler to set the hart's sqoscfg CSR to
contain the RCID and MCID for the task that is being scheduled in. The
sqoscfg CSR is only written to if the thread_struct.sqoscfg is different
than the current value of the CSR.

A per-cpu variable cpu_sqoscfg 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-non-isa/riscv-cbqri/blob/main/riscv-cbqri.pdf
Co-developed-by: Kornel Dulęba <[email protected]>
Signed-off-by: Kornel Dulęba <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
Note:
- A version of this patch rebased on riscv/for-next was already
submitted as an RFC to linux-riscv [1] with Message-ID:
[email protected]
- This patch is included in this RFC series so as to provide a cohesive
demonstration in one series.

[1] https://lore.kernel.org/lkml/[email protected]/

arch/riscv/Kconfig | 19 ++++++++++++++
arch/riscv/include/asm/csr.h | 8 ++++++
arch/riscv/include/asm/processor.h | 3 +++
arch/riscv/include/asm/qos.h | 40 ++++++++++++++++++++++++++++++
arch/riscv/include/asm/switch_to.h | 2 ++
5 files changed, 72 insertions(+)
create mode 100644 arch/riscv/include/asm/qos.h

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index c5e42cc37604..9d4c8c505191 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -398,6 +398,25 @@ config RISCV_ISA_C

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 sqoscfg CSR which allows the system to tag
+ the running process with 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.
+
+ If you don't know what to do here, say Y.
+
config RISCV_ISA_SVPBMT
bool "SVPBMT extension support"
depends on 64BIT && MMU
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 0e571f6483d9..ab222ca15799 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -60,6 +60,13 @@
#define SATP_ASID_MASK _AC(0xFFFF, UL)
#endif

+/* SQOSCFG fields */
+#define SQOSCFG_RCID_MASK _AC(0x00000FFF, UL)
+#define SQOSCFG_MCID_MASK SQOSCFG_RCID_MASK
+#define SQOSCFG_MCID_SHIFT 16
+#define SQOSCFG_MASK ((SQOSCFG_MCID_MASK << SQOSCFG_MCID_SHIFT) | \
+ SQOSCFG_RCID_MASK)
+
/* Exception cause high bit - is an interrupt if set */
#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))

@@ -246,6 +253,7 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
+#define CSR_SQOSCFG 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 94a0590c6971..724b2aa2732d 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -39,6 +39,9 @@ struct thread_struct {
unsigned long s[12]; /* s[0]: frame pointer */
struct __riscv_d_ext_state fstate;
unsigned long bad_cause;
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+ u32 sqoscfg;
+#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..297e7fb64d80
--- /dev/null
+++ b/arch/riscv/include/asm/qos.h
@@ -0,0 +1,40 @@
+/* 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 sqoscfg csr for each cpu */
+static DEFINE_PER_CPU(u32, cpu_sqoscfg);
+
+static void __qos_sched_in(struct task_struct *task)
+{
+ u32 *cpu_sqoscfg_ptr = this_cpu_ptr(&cpu_sqoscfg);
+ u32 thread_sqoscfg;
+
+ thread_sqoscfg = READ_ONCE(task->thread.sqoscfg);
+
+ if (thread_sqoscfg != *cpu_sqoscfg_ptr) {
+ *cpu_sqoscfg_ptr = thread_sqoscfg;
+ csr_write(CSR_SQOSCFG, thread_sqoscfg);
+ }
+}
+
+static inline void qos_sched_in(struct task_struct *task)
+{
+ if (riscv_has_extension_likely(RISCV_ISA_EXT_SSQOSID))
+ __qos_sched_in(task);
+}
+#else
+
+static inline void qos_sched_in(struct task_struct *task) {}
+
+#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 60f8ca01d36e..75d9bfd766af 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -12,6 +12,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);
@@ -79,6 +80,7 @@ do { \
if (has_fpu()) \
__switch_to_aux(__prev, __next); \
((last) = __switch_to(__prev, __next)); \
+ qos_sched_in(__next); \
} while (0)

#endif /* _ASM_RISCV_SWITCH_TO_H */
--
2.34.1

2023-04-19 11:11:30

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 03/21] RISC-V: QoS: define properties of CBQRI controllers

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 <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
include/linux/riscv_qos.h | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 include/linux/riscv_qos.h

diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
new file mode 100644
index 000000000000..95016810b575
--- /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 {
+ int cache_level;
+ u32 cache_size; /* in bytes */
+ struct cpumask cpu_mask;
+ } cache;
+};
+
+extern struct list_head cbqri_controllers;
+
+#endif /* __LINUX_RISCV_QOS_H */
--
2.34.1

2023-04-19 11:11:34

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 04/21] RISC-V: QoS: define CBQRI capacity and bandwidth capabilities

Define data structures to store the capacity and bandwidth capabilities
that are discovered for a CBQRI-capable controller.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/kernel/qos/internal.h | 130 +++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100644 arch/riscv/kernel/qos/internal.h

diff --git a/arch/riscv/kernel/qos/internal.h b/arch/riscv/kernel/qos/internal.h
new file mode 100644
index 000000000000..e07d7f92e206
--- /dev/null
+++ b/arch/riscv/kernel/qos/internal.h
@@ -0,0 +1,130 @@
+/* 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 0xFF
+
+#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 */
+/* from qemu/include/hw/riscv/cbqri.h */
+struct riscv_cbqri_capacity_caps {
+ u16 ncblks;
+ 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 */
+/* from qemu/include/hw/riscv/cbqri.h */
+struct riscv_cbqri_bandwidth_caps {
+ u16 nbwblks; /* number of bandwidth block */
+ 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.34.1

2023-04-19 11:11:38

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 05/21] RISC-V: QoS: define prototypes for resctrl interface

Define the prototypes for the resctrl interface functions that are
implemented on RISC-V.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
include/linux/riscv_qos.h | 58 +++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)

diff --git a/include/linux/riscv_qos.h b/include/linux/riscv_qos.h
index 95016810b575..537e503a8e99 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,61 @@ 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
+ */
+bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level ignored);
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+int resctrl_arch_mon_ctx_alloc_no_wait(struct rdt_resource *r, int evtid);
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r, int evtid, int ctx);
+void resctrl_arch_reset_resources(void);
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
+int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable);
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+void resctrl_arch_set_cpu_default_closid(int cpu, u32 closid);
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 pmg);
+u32 resctrl_arch_system_num_rmid_idx(void);
+void resctrl_sched_in(void);
+
+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;
+}
+
+/* Pseudo lock is not supported on RISC-V */
+static inline int resctrl_arch_pseudo_lock_fn(void *_plr) { return 0; }
+static inline int resctrl_arch_measure_l2_residency(void *_plr) { return 0; }
+static inline int resctrl_arch_measure_l3_residency(void *_plr) { return 0; }
+static inline int resctrl_arch_measure_cycles_lat_fn(void *_plr) { return 0; }
+static inline u64 resctrl_arch_get_prefetch_disable_bits(void) { return 0; }
+
+/* Not needed for RISC-V */
+bool resctrl_arch_match_iommu_closid(struct iommu_group *group, u32 closid);
+bool resctrl_arch_match_iommu_closid_rmid(struct iommu_group *group, u32 closid, u32 rmid);
+int resctrl_arch_set_iommu_closid_rmid(struct iommu_group *group, u32 closid, u32 rmid);
+
+/* 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.34.1

2023-04-19 11:11:40

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 06/21] RISC-V: QoS: define CBQRI resctrl resources and domains

Define data structures to encapsulate the resctrl resource
and domain structures.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
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 e07d7f92e206..a3ed98ce5dd6 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 */
/* from qemu/include/hw/riscv/cbqri.h */
struct riscv_cbqri_capacity_caps {
@@ -127,4 +132,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 resctrl_dom;
+ // NCBLKS is 16 bit which is 2^16 = 65536
+ // If each bit is a block, then cc_block_mask could 1024 times 64 byte
+ 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.34.1

2023-04-19 11:11:44

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 07/21] RISC-V: QoS: add resctrl interface for CBQRI controllers

Add interface for CBQRI controller drivers to make use of the resctrl
filesystem.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/kernel/qos/qos_resctrl.c | 1231 +++++++++++++++++++++++++++
1 file changed, 1231 insertions(+)
create mode 100644 arch/riscv/kernel/qos/qos_resctrl.c

diff --git a/arch/riscv/kernel/qos/qos_resctrl.c b/arch/riscv/kernel/qos/qos_resctrl.c
new file mode 100644
index 000000000000..f4116d9a9f04
--- /dev/null
+++ b/arch/riscv/kernel/qos/qos_resctrl.c
@@ -0,0 +1,1231 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2023 Rivos Inc.
+
+#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_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
+/*
+ * The size of the controllers array reflects that number of CBQRI controllers
+ * (3x capacity, 3x bandwidth) in the hypothetical SoC that Qemu implements for
+ * the CBQRI proof-of-concept.
+ *
+ * The proper solution will involve dynamically allocating cbqri_controller
+ * structures and adding them to a list of controllers. This avoids having to
+ * make assumptions about the system.
+ */
+static struct cbqri_controller controllers[MAX_CONTROLLERS];
+static int found_controllers;
+
+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 qos_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_mbm_local_enabled(void)
+{
+ /*
+ * Seems to be the bandwidth between a L2 cache and L3 cache
+ * according to Intel resctrl implementation. There is no meaning
+ * in supporting such stat when we use resctrl MON_DATA feature
+ * to support CBQRI bandwidth monitoring.
+ */
+ return false;
+}
+
+bool resctrl_arch_is_mbm_total_enabled(void)
+{
+ return true;
+}
+
+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;
+}
+
+bool resctrl_arch_is_llc_occupancy_enabled(void)
+{
+ /*
+ * There is no occupancy in CBQRI bandwidth controller (resctrl MON_DATA
+ * was the only available way to implement RISC-V memory monitoring).
+ * As we need occupancy for CBQRI capacity controller, this global
+ * setting is true, but the ll_occupancy files of CBQRI bandwidth
+ * controllers will return an error.
+ */
+ return true;
+}
+
+/*
+ * 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 sqoscfg value for a given CPU */
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid) { }
+
+void resctrl_sched_in(void)
+{
+ qos_sched_in(current);
+}
+
+void resctrl_arch_sync_cpu_defaults(void *info)
+{
+ resctrl_sched_in();
+}
+
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+ u32 sqoscfg;
+
+ WARN_ON_ONCE((closid & SQOSCFG_RCID_MASK) != closid);
+ WARN_ON_ONCE((rmid & SQOSCFG_MCID_MASK) != rmid);
+
+ sqoscfg = rmid << SQOSCFG_MCID_SHIFT;
+ sqoscfg |= closid;
+ WRITE_ONCE(tsk->thread.sqoscfg, sqoscfg);
+}
+
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
+{
+ u32 sqoscfg;
+ bool match;
+
+ sqoscfg = READ_ONCE(tsk->thread.sqoscfg);
+ match = (sqoscfg & SQOSCFG_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.sqoscfg);
+ tsk_rmid >>= SQOSCFG_MCID_SHIFT;
+ tsk_rmid &= SQOSCFG_MCID_MASK;
+
+ return tsk_rmid == rmid;
+}
+
+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 *resctrl_arch_find_domain(struct rdt_resource *r, int id)
+{
+ struct rdt_domain *domain;
+ struct list_head *l;
+
+ list_for_each(l, &r->domains) {
+ domain = list_entry(l, struct rdt_domain, list);
+ if (id == domain->id)
+ return domain;
+ }
+
+ return NULL;
+}
+
+void resctrl_arch_reset_resources(void)
+{
+ /* not implemented for the RISC-V resctrl implementation */
+}
+
+int resctrl_arch_mon_ctx_alloc_no_wait(struct rdt_resource *r, int evtid)
+{
+ /* RISC-V can always read an rmid, nothing needs allocating */
+ return 0;
+}
+
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r, int evtid, int ctx)
+{
+ /* not implemented for the RISC-V resctrl interface */
+}
+
+bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
+{
+ return false;
+}
+
+int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
+ u32 closid, u32 rmid, enum resctrl_event_id eventid,
+ u64 *val, int 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_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_domain *d)
+{
+ /* 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);
+
+ reg = ioread64(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 |= rbwb & CBQRI_CONTROL_REGISTERS_RBWB_MASK;
+ 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 qos_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset)
+{
+ unsigned long timeout = jiffies + (HZ / 10); /* Timeout after 100ms */
+ u64 reg;
+ int busy;
+
+ 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 operation on capacity controller */
+static int do_capacity_alloc_op(struct cbqri_controller *ctrl, int operation,
+ enum resctrl_conf_type type, int rcid)
+{
+ 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 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 (qos_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;
+}
+
+/* Perform operation on bandwidth controller */
+static int do_bandwidth_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 (qos_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 rbwb;
+
+ if (cfg->cbm != 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);
+ /* get reserved bandwidth blocks */
+ rbwb = cbqri_get_rbwb(ctrl);
+
+ /* Capacity config limit operation for RCID (closid) */
+ ret = do_capacity_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, type, 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 for RCID (closid) to verify */
+ ret = do_capacity_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, type, closid);
+ if (ret < 0) {
+ pr_err("%s(): operation failed: ret = %d", __func__, ret);
+ return ret;
+ }
+
+ /* Read capacity block mask for RCID (closid) to verify */
+ rbwb = cbqri_get_rbwb(ctrl);
+ }
+
+ return ret;
+}
+
+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, 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 for RCID (closid) */
+ err = do_capacity_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT, type, closid);
+ 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);
+
+ /* Capacity read limit operation for RCID (closid) to verify */
+ err = do_capacity_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 err;
+ }
+
+ /* Read capacity block mask for RCID (closid) to verify */
+ reg_offset = CBQRI_CC_BLOCK_MASK_OFF;
+ reg = ioread64(ctrl->base + reg_offset);
+ }
+
+ return err;
+}
+
+int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d,
+ u32 closid, enum resctrl_conf_type t, u32 cfg_val)
+{
+ struct cbqri_resctrl_res *res;
+ struct cbqri_resctrl_dom *dom;
+ struct cbqri_config cfg;
+ int err = 0;
+
+ res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+ dom = container_of(d, struct cbqri_resctrl_dom, resctrl_dom);
+
+ 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:
+ cfg.rbwb = cfg_val;
+ 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_domain *d;
+ int err = 0;
+
+ list_for_each_entry(d, &r->domains, 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_debug("%s(): return err=%d", __func__, err);
+ return err;
+ }
+ }
+ }
+ return err;
+}
+
+u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d,
+ u32 closid, enum resctrl_conf_type type)
+{
+ struct cbqri_resctrl_res *hw_res;
+ struct cbqri_resctrl_dom *hw_dom;
+ struct cbqri_controller *ctrl;
+ int reg_offset;
+ int err;
+ u64 reg;
+
+ hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+ hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_dom);
+
+ ctrl = hw_dom->hw_ctrl;
+
+ if (!r->alloc_capable)
+ return -EINVAL;
+
+ 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 = do_capacity_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 -EIO;
+ }
+
+ /* 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 = do_bandwidth_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid);
+ if (err < 0) {
+ pr_err("%s(): operation failed: err = %d", __func__, err);
+ return -EIO;
+ }
+
+ hw_dom->ctrl_val[closid] = cbqri_get_rbwb(ctrl);
+
+ return hw_dom->ctrl_val[closid];
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qos_discover_controller_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 (qos_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 (qos_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 (qos_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 discovers the properties of CBQRI
+ * capable controllers in the system. pr_debug calls would be removed
+ * before submitting non-RFC patches.
+ */
+static int qos_resctrl_discover_controller(struct cbqri_controller_info *ctrl_info,
+ struct cbqri_controller *ctrl)
+{
+ int err = 0, status;
+ u64 reg;
+
+ pr_debug("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_debug("%s(): return %d", __func__, err);
+ return err;
+ }
+ ctrl->base = ioremap(ctrl_info->addr, ctrl_info->size);
+ if (!ctrl->base) {
+ pr_debug("%s(): goto err_release_mem_region", __func__);
+ goto err_release_mem_region;
+ }
+
+ ctrl->alloc_capable = false;
+ ctrl->mon_capable = false;
+
+ /* Discover capacity allocation and monitoring features */
+ if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
+ pr_debug("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_debug("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);
+
+ /* Discover monitoring features */
+ err = qos_discover_controller_feature(ctrl, CBQRI_CC_MON_CTL_OFF,
+ CBQRI_CC_MON_CTL_OP_READ_COUNTER,
+ &status, &ctrl->cc.supports_mon_at_code);
+ if (err) {
+ pr_err("%s() failed to discover cc_mon_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_CC_MON_CTL_STATUS_SUCCESS) {
+ pr_debug("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_debug("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_debug("supports_mon_at_data: %d, supports_mon_at_code: %d",
+ ctrl->cc.supports_mon_at_data, ctrl->cc.supports_mon_at_code);
+
+ /* Discover allocation features */
+ err = qos_discover_controller_feature(ctrl, CBQRI_CC_ALLOC_CTL_OFF,
+ CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
+ &status, &ctrl->cc.supports_alloc_at_code);
+ if (err) {
+ pr_err("%s() failed to discover cc_alloc_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
+ pr_debug("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_debug("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_debug("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_debug("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_debug("version=%d.%d nbwblks=%d mrbwb=%d",
+ ctrl->ver_major, ctrl->ver_minor,
+ ctrl->bc.nbwblks, ctrl->bc.mrbwb);
+
+ // Discover monitoring features
+ err = qos_discover_controller_feature(ctrl, CBQRI_BC_MON_CTL_OFF,
+ CBQRI_BC_MON_CTL_OP_READ_COUNTER,
+ &status, &ctrl->bc.supports_mon_at_code);
+ if (err) {
+ pr_err("%s() failed to discover bc_mon_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_BC_MON_CTL_STATUS_SUCCESS) {
+ pr_debug("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_debug("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_debug("supports_mon_at_data: %d, supports_mon_at_code: %d",
+ ctrl->bc.supports_mon_at_data, ctrl->bc.supports_mon_at_code);
+
+ // Discover allocation features
+ err = qos_discover_controller_feature(ctrl, CBQRI_BC_ALLOC_CTL_OFF,
+ CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT,
+ &status, &ctrl->bc.supports_alloc_at_code);
+ if (err) {
+ pr_err("%s() failed to discover bc_alloc_ctl feature", __func__);
+ goto err_iounmap;
+ }
+
+ if (status == CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
+ pr_debug("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_debug("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_debug("supports_alloc_at_data: %d, supports_alloc_at_code: %d",
+ ctrl->bc.supports_alloc_at_data, ctrl->bc.supports_alloc_at_code);
+ } else {
+ pr_err("controller type is UNKNOWN");
+ err = -ENODEV;
+ goto err_release_mem_region;
+ }
+
+ return 0;
+
+err_iounmap:
+ pr_err("%s(): err_iounmap", __func__);
+ iounmap(ctrl->base);
+
+err_release_mem_region:
+ pr_err("%s(): err_release_mem_region", __func__);
+ release_mem_region(ctrl_info->addr, ctrl_info->size);
+
+ return err;
+}
+
+static struct rdt_domain *qos_new_domain(struct cbqri_controller *ctrl)
+{
+ struct cbqri_resctrl_dom *hw_dom;
+ struct rdt_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_dom;
+
+ INIT_LIST_HEAD(&domain->list);
+
+ return domain;
+}
+
+static int qos_bw_blocks_to_percentage(struct cbqri_controller *ctrl, int blocks)
+{
+ int percentage;
+
+ if (ctrl->ctrl_info->type != CBQRI_CONTROLLER_TYPE_BANDWIDTH)
+ return -1;
+
+ blocks *= 100;
+ percentage = blocks / ctrl->bc.nbwblks;
+ if (blocks % ctrl->bc.nbwblks)
+ percentage++;
+
+ return percentage;
+}
+
+static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
+{
+ struct cbqri_resctrl_res *hw_res;
+ struct cbqri_resctrl_dom *hw_dom;
+ u64 *dc;
+ int i;
+
+ hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+ hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_dom);
+
+ 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++)
+ *dc = r->default_ctrl;
+
+ /*
+ * The Qemu implementation for the CBQRI proof-of-concept has
+ * known reset values for all registers. A proper solution would
+ * be to perform a CONFIG_LIMIT operation to set the default for
+ * each RCID
+ */
+ return 0;
+}
+
+static int qos_resctrl_add_controller_domain(struct cbqri_controller *ctrl, int *id)
+{
+ struct rdt_domain *domain, *mon_domain = NULL;
+ struct cbqri_resctrl_res *cbqri_res = NULL;
+ struct cbqri_resctrl_dom *hw_dom_to_free;
+ struct rdt_resource *res;
+ int internal_id = *id;
+ int err;
+
+ domain = qos_new_domain(ctrl);
+ if (!domain)
+ return -ENOSPC;
+
+ if (ctrl->ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) {
+ cpumask_copy(&domain->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->num_rmid = ctrl->ctrl_info->mcid_count;
+ res->fflags = RFTYPE_RES_CACHE;
+ res->rid = RDT_RESOURCE_L2;
+ res->name = "L2";
+ res->alloc_capable = ctrl->alloc_capable;
+ res->mon_capable = ctrl->mon_capable;
+ res->format_str = "%d=%0*x";
+ res->cache_level = 2;
+ res->data_width = 3;
+ res->cache.arch_has_sparse_bitmaps = false;
+ res->cache.arch_has_per_cpu_cfg = false;
+ res->cache.shareable_bits = 0x000;
+ res->cache.min_cbm_bits = 1;
+ res->cache.cbm_len = ctrl->cc.ncblks;
+ res->default_ctrl = BIT_MASK(ctrl->cc.ncblks) - 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->num_rmid = ctrl->ctrl_info->mcid_count;
+ res->fflags = RFTYPE_RES_CACHE;
+ res->rid = RDT_RESOURCE_L3;
+ res->name = "L3";
+ res->cache_level = 3;
+ res->alloc_capable = ctrl->alloc_capable;
+ res->mon_capable = ctrl->mon_capable;
+ res->format_str = "%d=%0*x";
+ res->data_width = 4;
+ res->cache.arch_has_sparse_bitmaps = false;
+ res->cache.arch_has_per_cpu_cfg = false;
+ res->cache.shareable_bits = 0x000;
+ res->cache.min_cbm_bits = 1;
+ res->cache.cbm_len = ctrl->cc.ncblks;
+ res->default_ctrl = BIT_MASK(ctrl->cc.ncblks) - 1;
+ } else {
+ pr_err("%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->num_rmid = ctrl->ctrl_info->mcid_count;
+ res->fflags = RFTYPE_RES_MB;
+ res->rid = RDT_RESOURCE_MBA;
+ res->name = "MB";
+ res->alloc_capable = ctrl->alloc_capable;
+ /*
+ * MBA resource is only for allocation and
+ * monitoring can only be done with L3 resource
+ */
+ res->mon_capable = false;
+ res->format_str = "%d=%*u";
+ res->data_width = 4;
+ /*
+ * MBA schemata expects percentage so convert
+ * maximum reserved bw blocks to percentage
+ */
+ res->default_ctrl = qos_bw_blocks_to_percentage(ctrl, ctrl->bc.mrbwb);
+ /*
+ * Use values from 0 to MBA_MAX instead of power of two values,
+ * see Intel System Programming Guide manual section 18.19.7.2
+ */
+ res->membw.delay_linear = true;
+ res->membw.arch_needs_linear = true;
+ /* Disable non-linear values support */
+ res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+ // The minimum percentage allowed by the CBQRI spec
+ res->membw.min_bw = 1;
+ res->membw.bw_gran = 1;
+ }
+
+ /*
+ * Monitoring is not possible with Intel MBA resource,
+ * so add a L3 domain if monitoring is supported by the CBQRI
+ * bandwidth controller.
+ */
+ if (ctrl->mon_capable) {
+ struct cbqri_resctrl_res *mon_cbqri_res;
+
+ mon_cbqri_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
+ mon_domain = qos_new_domain(ctrl);
+ if (!domain)
+ goto err_free_mon_domain;
+
+ /*
+ * For CBQRI, any cpu (technically a hart in RISC-V terms)
+ * can access the memory-mapped registers of any CBQRI
+ * controller in the system. Thus it does not matter for
+ * RISC-V which cpu runs the resctrl code.
+ */
+ cpumask_setall(&domain->cpu_mask);
+
+ err = domain_setup_ctrlval(&mon_cbqri_res->resctrl_res, mon_domain);
+ if (err)
+ goto err_free_mon_domain;
+
+ mon_domain->id = internal_id;
+ internal_id++;
+ list_add_tail(&mon_domain->list, &mon_cbqri_res->resctrl_res.domains);
+ err = resctrl_online_domain(res, mon_domain);
+ if (err) {
+ pr_debug("%s(): BW monitoring domain online failed", __func__);
+ goto err_free_mon_domain;
+ }
+ }
+ } else {
+ pr_err("%s(): unknown resource %d", __func__, ctrl->ctrl_info->type);
+ err = -ENODEV;
+ goto err_free_domain;
+ }
+
+ domain->id = internal_id;
+ err = domain_setup_ctrlval(res, domain);
+ if (err)
+ goto err_free_mon_domain;
+
+ if (cbqri_res) {
+ list_add_tail(&domain->list, &cbqri_res->resctrl_res.domains);
+ *id = internal_id;
+ err = resctrl_online_domain(res, domain);
+ if (err) {
+ pr_debug("%s(): failed to online cbqri_res domain", __func__);
+ goto err_free_domain;
+ }
+ }
+
+ return 0;
+
+err_free_mon_domain:
+ if (!mon_domain) {
+ /*
+ * mon_domain is a struct rdt_domain which is a member of
+ * struct cbqri_resctrl_dom. That cbqri_resctrl_dom was
+ * allocated in qos_new_domain() and must be freed.
+ */
+ hw_dom_to_free = container_of(mon_domain, struct cbqri_resctrl_dom, resctrl_dom);
+ kfree(hw_dom_to_free);
+ }
+
+err_free_domain:
+ /* similar to err_free_mon_domain but the ptr is 'domain' instead */
+ hw_dom_to_free = container_of(domain, struct cbqri_resctrl_dom, resctrl_dom);
+ kfree(hw_dom_to_free);
+
+ return err;
+}
+
+static int qos_resctrl_setup_resources(void)
+{
+ struct rdt_domain *domain, *domain_temp;
+ struct cbqri_controller_info *ctrl_info;
+ struct cbqri_controller *ctrl;
+ struct cbqri_resctrl_res *res;
+ int err = 0, i, id = 0;
+
+ list_for_each_entry(ctrl_info, &cbqri_controllers, list) {
+ err = qos_resctrl_discover_controller(ctrl_info, &controllers[found_controllers]);
+ if (err) {
+ pr_err("%s(): qos_resctrl_discover_controller 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.domains);
+ INIT_LIST_HEAD(&res->resctrl_res.evt_list);
+ 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_err("%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_debug("exposed_alloc_capable = %d", exposed_alloc_capable);
+ pr_debug("exposed_mon_capable = %d", exposed_mon_capable);
+ pr_debug("exposed_cdp_l2_capable = %d", exposed_cdp_l2_capable);
+ pr_debug("exposed_cdp_l3_capable = %d", exposed_cdp_l3_capable);
+ return 0;
+
+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.domains, 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_setup(void)
+{
+ s32 err;
+
+ err = qos_resctrl_setup_resources();
+ if (err) {
+ pr_err("%s() failed with error %d\n", __func__, err);
+ return err;
+ }
+
+ err = resctrl_init();
+
+ return err;
+}
+
+int qos_resctrl_online_cpu(unsigned int cpu)
+{
+ return resctrl_online_cpu(cpu);
+}
+
+int qos_resctrl_offline_cpu(unsigned int cpu)
+{
+ resctrl_offline_cpu(cpu);
+ return 0;
+}
--
2.34.1

2023-04-19 11:11:56

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 08/21] RISC-V: QoS: expose implementation to resctrl

The generic resctrl header include/linux/resctrl.h includes
asm/resctrl.h when CONFIG_ARCH_HAS_CPU_RESCTRL is set.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/include/asm/resctrl.h | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 arch/riscv/include/asm/resctrl.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.34.1

2023-04-19 11:12:04

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 10/21] RISC-V: QoS: make CONFIG_RISCV_ISA_SSQOSID select resctrl

Make CONFIG_RISCV_ISA_SSQOSID select the config options for resctrl:
ARCH_HAS_CPU_RESCTRL and RESCTRL_FS

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/Kconfig | 3 +++
1 file changed, 3 insertions(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 9d4c8c505191..683349c2e809 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -401,6 +401,9 @@ config RISCV_ISA_C
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.34.1

2023-04-19 11:12:08

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 11/21] RISC-V: QoS: add to build when CONFIG_RISCV_ISA_SSQOSID set

Add the sqoscfg CSR handling and the resctrl interface to the build when
CONFIG_RISCV_ISA_SSQOSID is set.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/kernel/Makefile | 2 ++
arch/riscv/kernel/qos/Makefile | 2 ++
2 files changed, 4 insertions(+)
create mode 100644 arch/riscv/kernel/qos/Makefile

diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 4cf303a779ab..57d57e430fb9 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -89,3 +89,5 @@ obj-$(CONFIG_EFI) += efi.o
obj-$(CONFIG_COMPAT) += compat_syscall_table.o
obj-$(CONFIG_COMPAT) += compat_signal.o
obj-$(CONFIG_COMPAT) += compat_vdso/
+
+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..9ed0c13a854d
--- /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 qos_resctrl.o
--
2.34.1

2023-04-19 11:12:11

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 12/21] dt-bindings: riscv: add riscv,cbqri bindings

Document properties that can be used in the bindings for controllers
that implement the RISC-V CBQRI specification.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
.../bindings/riscv/riscv,cbqri.yaml | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 Documentation/devicetree/bindings/riscv/riscv,cbqri.yaml

diff --git a/Documentation/devicetree/bindings/riscv/riscv,cbqri.yaml b/Documentation/devicetree/bindings/riscv/riscv,cbqri.yaml
new file mode 100644
index 000000000000..3f017c6b1fb1
--- /dev/null
+++ b/Documentation/devicetree/bindings/riscv/riscv,cbqri.yaml
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/riscv/riscv,cbqri.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RISC-V Capacity and Bandwidth Register Interface (CBQRI) properties
+
+description: |
+ Common properties for cache and memory controllers that implement the
+ RISC-V CBQRI specification:
+ https://github.com/riscv-non-isa/riscv-cbqri/blob/main/riscv-cbqri.pdf
+
+maintainers:
+ - Drew Fustini <[email protected]>
+
+properties:
+ riscv,cbqri-rcid:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: The maximum number of RCIDs the controller supports
+
+ riscv,cbqri-mcid:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: The maximum number of MCIDs the controller supports
+
+additionalProperties: true
+
+...
--
2.34.1

2023-04-19 11:12:15

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 13/21] DO_NOT_MERGE dt-bindings: add foobar vendor-prefix

Add prefix for an example SoC vendor whose designs include controllers
that implement CBQRI.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index ed64e06ecca4..426f4eef06eb 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -470,6 +470,8 @@ patternProperties:
description: Shenzhen Fly Young Technology Co.,LTD.
"^fii,.*":
description: Foxconn Industrial Internet
+ "^foobar,.*":
+ description: Foobar Systems
"^firefly,.*":
description: Firefly
"^focaltech,.*":
--
2.34.1

2023-04-19 11:12:20

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 21/21] DO_NOT_MERGE riscv: dts: build qemu virt device tree

Add the device tree for the qemu virt machine to the build. The
resulting dtb will be consumed by qemu-system-riscv64.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/boot/dts/Makefile | 1 +
arch/riscv/boot/dts/qemu/Makefile | 3 +++
2 files changed, 4 insertions(+)
create mode 100644 arch/riscv/boot/dts/qemu/Makefile

diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile
index f0d9f89054f8..74d99d28522f 100644
--- a/arch/riscv/boot/dts/Makefile
+++ b/arch/riscv/boot/dts/Makefile
@@ -5,5 +5,6 @@ subdir-y += starfive
subdir-y += canaan
subdir-y += microchip
subdir-y += renesas
+subdir-y += qemu

obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
diff --git a/arch/riscv/boot/dts/qemu/Makefile b/arch/riscv/boot/dts/qemu/Makefile
new file mode 100644
index 000000000000..07252b4ff455
--- /dev/null
+++ b/arch/riscv/boot/dts/qemu/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_SOC_VIRT) += qemu-virt-cbqri.dtb
+obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y))
--
2.34.1

2023-04-19 11:12:22

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 14/21] DO_NOT_MERGE dt-bindings: soc: add Foobar SoC cache controller

Add bindings for an example SoC cache controller that implements CBQRI.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
.../soc/foobar/foobar,cache-controller.yaml | 51 +++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/foobar/foobar,cache-controller.yaml

diff --git a/Documentation/devicetree/bindings/soc/foobar/foobar,cache-controller.yaml b/Documentation/devicetree/bindings/soc/foobar/foobar,cache-controller.yaml
new file mode 100644
index 000000000000..6348483bbe09
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/foobar/foobar,cache-controller.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/foobar/foobar,cache-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Foobar SoC Cache Controller
+
+maintainers:
+ - Drew Fustini <[email protected]>
+
+description:
+ Foobar SoC cache controller implements the RISC-V CBQRI interface for
+ capacity allocaiton and usage monitoring.
+
+allOf:
+ - $ref: /schemas/cache-controller.yaml#
+ - $ref: /schemas/riscv/riscv,cbqri.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: foobar,cache-controller
+ reg:
+ maxItems: 1
+ description: A memory region containing registers as defined in CBQRI spec
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+
+ cache-controller@fff12000 {
+ compatible = "foobar,cache-controller";
+ reg = <0xfff12000 0x2000>;
+ cache-level = <2>;
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
+
+...
--
2.34.1

2023-04-19 11:12:29

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 16/21] DO_NOT_MERGE soc: add Foobar SoC cache controller driver

Add example driver for a cache controller that implements CBQRI.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
drivers/soc/foobar/foobar_cbqri_cache.c | 110 ++++++++++++++++++++++++
1 file changed, 110 insertions(+)
create mode 100644 drivers/soc/foobar/foobar_cbqri_cache.c

diff --git a/drivers/soc/foobar/foobar_cbqri_cache.c b/drivers/soc/foobar/foobar_cbqri_cache.c
new file mode 100644
index 000000000000..e880488243d8
--- /dev/null
+++ b/drivers/soc/foobar/foobar_cbqri_cache.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Foobar Systems CBQRI cache controller
+ */
+
+#define pr_fmt(fmt) "foobar-cache: " fmt
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/riscv_qos.h>
+
+static const struct of_device_id foobar_cbqri_cache_ids[] = {
+ { .compatible = "foobar,cache-controller" },
+ { }
+};
+
+static int __init foobar_cbqri_cache_init(void)
+{
+ struct device_node *np;
+ int err;
+ u32 value;
+ struct cbqri_controller_info *ctrl_info;
+
+ for_each_matching_node(np, foobar_cbqri_cache_ids) {
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ continue;
+ }
+
+ ctrl_info = kzalloc(sizeof(*ctrl_info), GFP_KERNEL);
+ if (!ctrl_info)
+ goto err_node_put;
+ ctrl_info->type = CBQRI_CONTROLLER_TYPE_CAPACITY;
+
+ err = of_property_read_u32_index(np, "reg", 1, &value);
+ if (err) {
+ pr_err("Failed to read reg base address (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->addr = value;
+
+ err = of_property_read_u32_index(np, "reg", 3, &value);
+ if (err) {
+ pr_err("Failed to read reg size (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->size = value;
+
+ err = of_property_read_u32(np, "cache-level", &value);
+ if (err) {
+ pr_err("Failed to read cache level (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->cache.cache_level = value;
+
+ err = of_property_read_u32(np, "cache-size", &value);
+ if (err) {
+ pr_err("Failed to read cache size (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->cache.cache_size = value;
+
+ err = of_property_read_u32(np, "riscv,cbqri-rcid", &value);
+ if (err) {
+ pr_err("Failed to read RCID count (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->rcid_count = value;
+
+ err = of_property_read_u32(np, "riscv,cbqri-mcid", &value);
+ if (err) {
+ pr_err("Failed to read MCID count (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->mcid_count = value;
+
+ /*
+ * For CBQRI, any cpu (technically a hart in RISC-V terms)
+ * can access the memory-mapped registers of any CBQRI
+ * controller in the system. Therefore, set the CPU mask
+ * to 'FF' to allow all 8 cores in the example Foobar SoC
+ */
+ err = cpumask_parse("FF", &ctrl_info->cache.cpu_mask);
+ if (err) {
+ pr_err("Failed to convert cores mask string to cpumask (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+
+ of_node_put(np);
+
+ pr_debug("addr=0x%lx max-rcid=%u max-mcid=%u level=%d size=%u",
+ ctrl_info->addr, ctrl_info->rcid_count, ctrl_info->mcid_count,
+ ctrl_info->cache.cache_level, ctrl_info->cache.cache_size);
+
+ /* 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;
+
+err_kfree_ctrl_info:
+ kfree(ctrl_info);
+
+err_node_put:
+ of_node_put(np);
+
+ return err;
+}
+device_initcall(foobar_cbqri_cache_init);
--
2.34.1

2023-04-19 11:12:30

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 15/21] DO_NOT_MERGE dt-bindings: soc: add Foobar SoC memory controller

Add bindings for an example SoC memory controller that implements CBQRI.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
.../soc/foobar/foobar,memory-controller.yaml | 49 +++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/foobar/foobar,memory-controller.yaml

diff --git a/Documentation/devicetree/bindings/soc/foobar/foobar,memory-controller.yaml b/Documentation/devicetree/bindings/soc/foobar/foobar,memory-controller.yaml
new file mode 100644
index 000000000000..859ee52680d5
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/foobar/foobar,memory-controller.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/foobar/foobar,memory-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Foobar SoC Memory Controller
+
+maintainers:
+ - Drew Fustini <[email protected]>
+
+description:
+ Foobar SoC memory controller implements the RISC-V CBQRI interface for
+ capacity allocaiton and usage monitoring.
+
+allOf:
+ - $ref: /schemas/riscv/riscv,cbqri.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: foobar,memory-controller
+ reg:
+ maxItems: 1
+ description: A memory region containing registers as defined in CBQRI spec
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+
+ memory-controller@fff12000 {
+ compatible = "foobar,memory-controller";
+ reg = <0xfff12000 0x2000>;
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
+
+...
--
2.34.1

2023-04-19 11:12:40

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 09/21] RISC-V: QoS: add late_initcall to setup resctrl interface

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 <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/kernel/qos/qos.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 arch/riscv/kernel/qos/qos.c

diff --git a/arch/riscv/kernel/qos/qos.c b/arch/riscv/kernel/qos/qos.c
new file mode 100644
index 000000000000..0b5fde06cbe1
--- /dev/null
+++ b/arch/riscv/kernel/qos/qos.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2023 Rivos Inc.
+
+#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"
+
+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.34.1

2023-04-19 11:18:12

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 19/21] DO_NOT_MERGE riscv: dts: qemu: add dump from riscv-cbqri-rfc

Dumped dtb from qemu branch riscv-cbqri-rfc which is on top of qemu
master (tag: v8.0.0-rc4) with qemu/VERSION of 7.2.94 invoked with:

qemu-system-riscv64 \
-M virt \
-nographic \
-smp 8 \
-bios output/images/fw_jump.elf \
-kernel $HOME/kernel/cbqri-linux/arch/riscv/boot/Image \
-append "root=/dev/vda ro" \
-drive file=output/images/rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-machine dumpdtb=qemu.dtb

Link: https://gitlab.baylibre.com/baylibre/qemu/-/tree/riscv-cbqri-rfc
Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
Note: this is necessary as Qemu branch riscv-cbqri-rfc does not yet
support generating a dtb with the nodes and properties needed for CBQRI
controllers. Thus, those lines must be added in the next patch and an
external dtb (qemu-virt-cbqri.dtb) built by Linux is used when
invoking qemu-system-riscv64

arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts | 371 +++++++++++++++++++
1 file changed, 371 insertions(+)
create mode 100644 arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts

diff --git a/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts b/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts
new file mode 100644
index 000000000000..400ed48a06af
--- /dev/null
+++ b/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/dts-v1/;
+
+/ {
+ #address-cells = <0x02>;
+ #size-cells = <0x02>;
+ compatible = "riscv-virtio";
+ model = "riscv-virtio,qemu";
+
+ fw-cfg@10100000 {
+ dma-coherent;
+ reg = <0x00 0x10100000 0x00 0x18>;
+ compatible = "qemu,fw-cfg-mmio";
+ };
+
+ flash@20000000 {
+ bank-width = <0x04>;
+ reg = <0x00 0x20000000 0x00 0x2000000 0x00 0x22000000 0x00 0x2000000>;
+ compatible = "cfi-flash";
+ };
+
+ chosen {
+ bootargs = "root=/dev/vda ro ftrace=function_graph ftrace_filter=\"*resctrl*,*qos*\"";
+ rng-seed = <0xb87c09c5 0xc8f0c713 0x9c217b2a 0xa6f44e14 0xb6e99df6 0x205d482b 0x6d4c34f4 0x6466fc08>;
+ stdout-path = "/soc/serial@10000000";
+ };
+
+ poweroff {
+ value = <0x5555>;
+ offset = <0x00>;
+ regmap = <0x12>;
+ compatible = "syscon-poweroff";
+ };
+
+ reboot {
+ value = <0x7777>;
+ offset = <0x00>;
+ regmap = <0x12>;
+ compatible = "syscon-reboot";
+ };
+
+ platform-bus@4000000 {
+ interrupt-parent = <0x11>;
+ ranges = <0x00 0x00 0x4000000 0x2000000>;
+ #address-cells = <0x01>;
+ #size-cells = <0x01>;
+ compatible = "qemu,platform\0simple-bus";
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x00 0x80000000 0x00 0x8000000>;
+ };
+
+ cpus {
+ #address-cells = <0x01>;
+ #size-cells = <0x00>;
+ timebase-frequency = <0x989680>;
+
+ cpu@0 {
+ phandle = <0x0f>;
+ device_type = "cpu";
+ reg = <0x00>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x10>;
+ };
+ };
+
+ cpu@1 {
+ phandle = <0x0d>;
+ device_type = "cpu";
+ reg = <0x01>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x0e>;
+ };
+ };
+
+ cpu@2 {
+ phandle = <0x0b>;
+ device_type = "cpu";
+ reg = <0x02>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x0c>;
+ };
+ };
+
+ cpu@3 {
+ phandle = <0x09>;
+ device_type = "cpu";
+ reg = <0x03>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x0a>;
+ };
+ };
+
+ cpu@4 {
+ phandle = <0x07>;
+ device_type = "cpu";
+ reg = <0x04>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x08>;
+ };
+ };
+
+ cpu@5 {
+ phandle = <0x05>;
+ device_type = "cpu";
+ reg = <0x05>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x06>;
+ };
+ };
+
+ cpu@6 {
+ phandle = <0x03>;
+ device_type = "cpu";
+ reg = <0x06>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x04>;
+ };
+ };
+
+ cpu@7 {
+ phandle = <0x01>;
+ device_type = "cpu";
+ reg = <0x07>;
+ status = "okay";
+ compatible = "riscv";
+ riscv,cboz-block-size = <0x40>;
+ riscv,cbom-block-size = <0x40>;
+ riscv,isa = "rv64imafdch_zicbom_zicboz_zicsr_zifencei_zihintpause_zawrs_zba_zbb_zbc_zbs_ssqosid_sstc_svadu";
+ mmu-type = "riscv,sv57";
+
+ interrupt-controller {
+ #interrupt-cells = <0x01>;
+ interrupt-controller;
+ compatible = "riscv,cpu-intc";
+ phandle = <0x02>;
+ };
+ };
+
+ cpu-map {
+
+ cluster0 {
+
+ core0 {
+ cpu = <0x0f>;
+ };
+
+ core1 {
+ cpu = <0x0d>;
+ };
+
+ core2 {
+ cpu = <0x0b>;
+ };
+
+ core3 {
+ cpu = <0x09>;
+ };
+
+ core4 {
+ cpu = <0x07>;
+ };
+
+ core5 {
+ cpu = <0x05>;
+ };
+
+ core6 {
+ cpu = <0x03>;
+ };
+
+ core7 {
+ cpu = <0x01>;
+ };
+ };
+ };
+ };
+
+ soc {
+ #address-cells = <0x02>;
+ #size-cells = <0x02>;
+ compatible = "simple-bus";
+ ranges;
+
+ pmu {
+ riscv,event-to-mhpmcounters = <0x01 0x01 0x7fff9 0x02 0x02 0x7fffc 0x10019 0x10019 0x7fff8 0x1001b 0x1001b 0x7fff8 0x10021 0x10021 0x7fff8 0x00 0x00 0x00 0x00 0x00>;
+ compatible = "riscv,pmu";
+ };
+
+ rtc@101000 {
+ interrupts = <0x0b>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x101000 0x00 0x1000>;
+ compatible = "google,goldfish-rtc";
+ };
+
+ serial@10000000 {
+ interrupts = <0x0a>;
+ interrupt-parent = <0x11>;
+ clock-frequency = "\08@";
+ reg = <0x00 0x10000000 0x00 0x100>;
+ compatible = "ns16550a";
+ };
+
+ test@100000 {
+ phandle = <0x12>;
+ reg = <0x00 0x100000 0x00 0x1000>;
+ compatible = "sifive,test1\0sifive,test0\0syscon";
+ };
+
+ pci@30000000 {
+ interrupt-map-mask = <0x1800 0x00 0x00 0x07>;
+ interrupt-map = <0x00 0x00 0x00 0x01 0x11 0x20 0x00 0x00 0x00 0x02 0x11 0x21 0x00 0x00 0x00 0x03 0x11 0x22 0x00 0x00 0x00 0x04 0x11 0x23 0x800 0x00 0x00 0x01 0x11 0x21 0x800 0x00 0x00 0x02 0x11 0x22 0x800 0x00 0x00 0x03 0x11 0x23 0x800 0x00 0x00 0x04 0x11 0x20 0x1000 0x00 0x00 0x01 0x11 0x22 0x1000 0x00 0x00 0x02 0x11 0x23 0x1000 0x00 0x00 0x03 0x11 0x20 0x1000 0x00 0x00 0x04 0x11 0x21 0x1800 0x00 0x00 0x01 0x11 0x23 0x1800 0x00 0x00 0x02 0x11 0x20 0x1800 0x00 0x00 0x03 0x11 0x21 0x1800 0x00 0x00 0x04 0x11 0x22>;
+ ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>;
+ reg = <0x00 0x30000000 0x00 0x10000000>;
+ dma-coherent;
+ bus-range = <0x00 0xff>;
+ linux,pci-domain = <0x00>;
+ device_type = "pci";
+ compatible = "pci-host-ecam-generic";
+ #size-cells = <0x02>;
+ #interrupt-cells = <0x01>;
+ #address-cells = <0x03>;
+ };
+
+ virtio_mmio@10008000 {
+ interrupts = <0x08>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10008000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ virtio_mmio@10007000 {
+ interrupts = <0x07>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10007000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ virtio_mmio@10006000 {
+ interrupts = <0x06>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10006000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ virtio_mmio@10005000 {
+ interrupts = <0x05>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10005000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ virtio_mmio@10004000 {
+ interrupts = <0x04>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10004000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ virtio_mmio@10003000 {
+ interrupts = <0x03>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10003000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ virtio_mmio@10002000 {
+ interrupts = <0x02>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10002000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ virtio_mmio@10001000 {
+ interrupts = <0x01>;
+ interrupt-parent = <0x11>;
+ reg = <0x00 0x10001000 0x00 0x1000>;
+ compatible = "virtio,mmio";
+ };
+
+ plic@c000000 {
+ phandle = <0x11>;
+ riscv,ndev = <0x5f>;
+ reg = <0x00 0xc000000 0x00 0x600000>;
+ interrupts-extended = <0x10 0x0b 0x10 0x09 0x0e 0x0b 0x0e 0x09 0x0c 0x0b 0x0c 0x09 0x0a 0x0b 0x0a 0x09 0x08 0x0b 0x08 0x09 0x06 0x0b 0x06 0x09 0x04 0x0b 0x04 0x09 0x02 0x0b 0x02 0x09>;
+ interrupt-controller;
+ compatible = "sifive,plic-1.0.0\0riscv,plic0";
+ #address-cells = <0x00>;
+ #interrupt-cells = <0x01>;
+ };
+
+ clint@2000000 {
+ interrupts-extended = <0x10 0x03 0x10 0x07 0x0e 0x03 0x0e 0x07 0x0c 0x03 0x0c 0x07 0x0a 0x03 0x0a 0x07 0x08 0x03 0x08 0x07 0x06 0x03 0x06 0x07 0x04 0x03 0x04 0x07 0x02 0x03 0x02 0x07>;
+ reg = <0x00 0x2000000 0x00 0x10000>;
+ compatible = "sifive,clint0\0riscv,clint0";
+ };
+ };
+};
--
2.34.1

2023-04-19 11:20:26

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 17/21] DO_NOT_MERGE soc: add Foobar SoC memory controller driver

Add example driver for a SoC memory controller that implements CBQRI.

Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
drivers/soc/foobar/foobar_cbqri_memory.c | 83 ++++++++++++++++++++++++
1 file changed, 83 insertions(+)
create mode 100644 drivers/soc/foobar/foobar_cbqri_memory.c

diff --git a/drivers/soc/foobar/foobar_cbqri_memory.c b/drivers/soc/foobar/foobar_cbqri_memory.c
new file mode 100644
index 000000000000..0a0c542a25e1
--- /dev/null
+++ b/drivers/soc/foobar/foobar_cbqri_memory.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Foobar Systems CBQRI memory controller
+ */
+
+#define pr_fmt(fmt) "foobar-mem: " fmt
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/riscv_qos.h>
+
+static const struct of_device_id foobar_cbqri_memory_ids[] = {
+ { .compatible = "foobar,memory-controller" },
+ { }
+};
+
+static int __init foobar_cbqri_memory_init(void)
+{
+ struct device_node *np;
+ int err;
+ u32 value;
+ struct cbqri_controller_info *ctrl_info;
+
+ for_each_matching_node(np, foobar_cbqri_memory_ids) {
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ continue;
+ }
+
+ ctrl_info = kzalloc(sizeof(*ctrl_info), GFP_KERNEL);
+ if (!ctrl_info)
+ goto err_node_put;
+ ctrl_info->type = CBQRI_CONTROLLER_TYPE_BANDWIDTH;
+
+ err = of_property_read_u32_index(np, "reg", 1, &value);
+ if (err) {
+ pr_err("Failed to read reg base address (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->addr = value;
+
+ err = of_property_read_u32_index(np, "reg", 3, &value);
+ if (err) {
+ pr_err("Failed to read reg size (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->size = value;
+
+ err = of_property_read_u32(np, "riscv,cbqri-rcid", &value);
+ if (err) {
+ pr_err("Failed to read RCID count (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->rcid_count = value;
+
+ err = of_property_read_u32(np, "riscv,cbqri-mcid", &value);
+ if (err) {
+ pr_err("Failed to read MCID count (%d)", err);
+ goto err_kfree_ctrl_info;
+ }
+ ctrl_info->mcid_count = value;
+
+ of_node_put(np);
+
+ pr_debug("addr=0x%lx max-rcid=%u max-mcid=%u", ctrl_info->addr,
+ ctrl_info->rcid_count, ctrl_info->mcid_count);
+
+ /* 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;
+
+err_kfree_ctrl_info:
+ kfree(ctrl_info);
+
+err_node_put:
+ of_node_put(np);
+
+ return err;
+}
+device_initcall(foobar_cbqri_memory_init);
--
2.34.1

2023-04-19 11:20:49

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 18/21] DO_NOT_MERGE soc: build Foobar SoC drivers

Add Foobar SoC cache and memory controller drivers to the build.

The hypothetical Foobar SoC serves as an example of an SoC with
controllers that implement the RISC-V Capacity and Bandwidth QoS
Register Interface (CBQRI) specification.

Link: https://github.com/riscv-non-isa/riscv-cbqri/blob/main/riscv-cbqri.pdf
Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/foobar/Kconfig | 21 +++++++++++++++++++++
drivers/soc/foobar/Makefile | 4 ++++
4 files changed, 27 insertions(+)
create mode 100644 drivers/soc/foobar/Kconfig
create mode 100644 drivers/soc/foobar/Makefile

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 4e176280113a..8578f8c607ff 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -8,6 +8,7 @@ source "drivers/soc/aspeed/Kconfig"
source "drivers/soc/atmel/Kconfig"
source "drivers/soc/bcm/Kconfig"
source "drivers/soc/canaan/Kconfig"
+source "drivers/soc/foobar/Kconfig"
source "drivers/soc/fsl/Kconfig"
source "drivers/soc/fujitsu/Kconfig"
source "drivers/soc/imx/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 3b0f9fb3b5c8..37a77c2dab94 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -11,6 +11,7 @@ obj-y += bcm/
obj-$(CONFIG_SOC_CANAAN) += canaan/
obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/
+obj-y += foobar/
obj-y += fsl/
obj-y += fujitsu/
obj-$(CONFIG_ARCH_GEMINI) += gemini/
diff --git a/drivers/soc/foobar/Kconfig b/drivers/soc/foobar/Kconfig
new file mode 100644
index 000000000000..4548e822357e
--- /dev/null
+++ b/drivers/soc/foobar/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config FOOBAR_CBQRI_CACHE
+ bool "Foobar cache controller for RISC-V CBQRI testing"
+ default y
+ help
+ Support the cache controller in a hypothetical "Foobar" SoC that
+ implements the RISC-V Capacity and Bandwidth QoS Register Interface
+ (CBQRI) specification.
+
+ If you do not care about testing RISC-V CBQRI, then choose 'N'.
+
+config FOOBAR_CBQRI_MEMORY
+ bool "Foobar memory controller for RISC-V CBQRI testing"
+ default y
+ help
+ Support the memory controller in a hypothetical "Foobar" SoC that
+ implements the RISC-V Capacity and Bandwidth QoS Register Interface
+ (CBQRI) specification.
+
+ If you do not care about testing RISC-V CBQRI, then choose 'N'.
diff --git a/drivers/soc/foobar/Makefile b/drivers/soc/foobar/Makefile
new file mode 100644
index 000000000000..e4f34058e39e
--- /dev/null
+++ b/drivers/soc/foobar/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_FOOBAR_CBQRI_CACHE) += foobar_cbqri_cache.o
+obj-$(CONFIG_FOOBAR_CBQRI_MEMORY) += foobar_cbqri_memory.o
--
2.34.1

2023-04-19 11:22:18

by Drew Fustini

[permalink] [raw]
Subject: [RFC PATCH 20/21] DO_NOT_MERGE riscv: dts: qemu: add cbqri-capable controllers

Add nodes to for CBQRI-capable cache and memory controllers.

This is necessary as the qemu branch riscv-cbqri-rfc (based on
v8.0.0-rc4) does not yet support generating a dtb with the nodes and
properties needed for CBQRI controllers.

Thus, an external dtb (qemu-virt-cbqri.dtb) built by Linux is used when
invoking qemu-system-riscv64:

qemu-system-riscv64 \
-M virt \
-nographic \
-smp 8 \
-bios output/images/fw_jump.elf \
-kernel ${LINUX}/arch/riscv/boot/Image \
-dtb ${LINUX}/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dtb \
-append "root=/dev/vda ro" \
-drive file=output/images/rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \

Link: https://gitlab.baylibre.com/baylibre/qemu/-/tree/riscv-cbqri-rfc
Co-developed-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Adrien Ricciardi <[email protected]>
Signed-off-by: Drew Fustini <[email protected]>
---
arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts | 59 ++++++++++++++++++++
1 file changed, 59 insertions(+)

diff --git a/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts b/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts
index 400ed48a06af..2c4ddc4271cc 100644
--- a/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts
+++ b/arch/riscv/boot/dts/qemu/qemu-virt-cbqri.dts
@@ -367,5 +367,64 @@ clint@2000000 {
reg = <0x00 0x2000000 0x00 0x10000>;
compatible = "sifive,clint0\0riscv,clint0";
};
+
+ cluster0_l2: controller@4820000 {
+ compatible = "foobar,cache-controller";
+ reg = <0x0 0x4820000 0x0 0x1000>; /* 4KB at 0x04820000 */
+ cache-unified;
+ cache-line-size = <64>;
+ cache-level = <2>;
+ cache-sets = <1000>;
+ cache-size = <768000>; /* 750 KiB */
+ next-level-cache = <&shared_llc>;
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
+
+ cluster1_l2: controller@4821000 {
+ compatible = "foobar,cache-controller";
+ reg = <0x0 0x4821000 0x0 0x1000>; /* 4KB at 0x04821000 */
+ cache-unified;
+ cache-line-size = <64>;
+ cache-level = <2>;
+ cache-sets = <1000>;
+ cache-size = <768000>; /* 750 KiB */
+ next-level-cache = <&shared_llc>;
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
+
+ shared_llc: controller@482b000 {
+ compatible = "foobar,cache-controller";
+ reg = <0x0 0x482b000 0x0 0x1000>; /* 4KB at 0x0482B000 */
+ cache-unified;
+ cache-line-size = <64>;
+ cache-level = <3>;
+ cache-sets = <4096>;
+ cache-size = <3145728>; /* 3 MiB */
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
+
+ mem0: controller@4828000 {
+ compatible = "foobar,memory-controller";
+ reg = <0x0 0x4828000 0x0 0x1000>; /* 4KB at 0x04828000 */
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
+
+ mem1: controller@4829000 {
+ compatible = "foobar,memory-controller";
+ reg = <0x0 0x4829000 0x0 0x1000>; /* 4KB at 0x04829000 */
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
+
+ mem2: controller@482a000 {
+ compatible = "foobar,memory-controller";
+ reg = <0x0 0x482a000 0x0 0x1000>; /* 4KB at 0x0482A000 */
+ riscv,cbqri-rcid = <64>;
+ riscv,cbqri-mcid = <256>;
+ };
};
};
--
2.34.1