[PATCH V2 5/5] cpufreq: loongson3: Replace IOCSR read/write with MMIO ones
From: Huacai Chen
Date: Thu Aug 27 2026 - 23:14:25 EST
Our server productions (e.g. Loongson-3D6000/3E6000) can have multiple
nodes in one package and SMC mailboxes are also per-node. However, IOCSR
read/write can only perform on the current node, while sometimes we want
to perform on other nodes (e.g. when switch governor, the get and target
callbacks are not run on target core). So replace IOCSR read/write with
MMIO ones.
Cc: stable@xxxxxxxxxxxxxxx
Fixes: ccf51454145b ("cpufreq: Add Loongson-3 CPUFreq driver support")
Tested-by: Xi Ruoyao <xry111@xxxxxxxxxxx>
Signed-off-by: Huacai Chen <chenhuacai@xxxxxxxxxxx>
---
drivers/cpufreq/loongson3_cpufreq.c | 34 +++++++++++++++++++++++------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/drivers/cpufreq/loongson3_cpufreq.c b/drivers/cpufreq/loongson3_cpufreq.c
index 3a5bf970077a..dcb6c70c0def 100644
--- a/drivers/cpufreq/loongson3_cpufreq.c
+++ b/drivers/cpufreq/loongson3_cpufreq.c
@@ -16,6 +16,7 @@
#include <asm/loongarch.h>
#include <asm/loongson.h>
#include <asm/smp.h>
+#include <asm/numa.h>
/* Message */
union smc_message {
@@ -164,6 +165,12 @@ union smc_message {
#define FREQ_MAX_LEVEL 16
+#define MMIO_SMCMBX(node) \
+ ((void __iomem *)(nid_to_addrbase(node) | IO_BASE | LOONGSON_REG_BASE | LOONGARCH_IOCSR_SMCMBX))
+
+#define MMIO_MISC_FUNC(node) \
+ ((void __iomem *)(nid_to_addrbase(node) | IO_BASE | LOONGSON_REG_BASE | LOONGARCH_IOCSR_MISC_FUNC))
+
struct loongson3_freq_data {
unsigned int def_freq_level;
struct cpufreq_frequency_table table[];
@@ -176,13 +183,27 @@ static DEFINE_PER_CPU(struct loongson3_freq_data *, freq_data);
static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 extra)
{
int retries;
- unsigned int cpu = raw_smp_processor_id();
- unsigned int nid = cpu_to_node(cpu);
+ unsigned int cpu = 0, nid;
union smc_message msg, last;
+#ifdef CONFIG_SMP
+ switch (cmd) {
+ case CMD_GET_FREQ_INFO:
+ case CMD_SET_FREQ_INFO:
+ case CMD_GET_FREQ_LEVEL_NUM:
+ case CMD_GET_FREQ_LEVEL_INFO:
+ case CMD_GET_FREQ_BOOST_LEVEL:
+ cpu = cpu_number_map(id);
+ break;
+ default:
+ cpu = raw_smp_processor_id();
+ }
+#endif
+ nid = cpu_to_node(cpu);
+
mutex_lock(&cpufreq_mutex[nid]);
- last.value = iocsr_read32(LOONGARCH_IOCSR_SMCMBX);
+ last.value = readl(MMIO_SMCMBX(nid));
if (!last.complete) {
mutex_unlock(&cpufreq_mutex[nid]);
return -EPERM;
@@ -195,12 +216,11 @@ static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 ext
msg.extra = extra;
msg.complete = 0;
- iocsr_write32(msg.value, LOONGARCH_IOCSR_SMCMBX);
- iocsr_write32(iocsr_read32(LOONGARCH_IOCSR_MISC_FUNC) | IOCSR_MISC_FUNC_SOFT_INT,
- LOONGARCH_IOCSR_MISC_FUNC);
+ writel(msg.value, MMIO_SMCMBX(nid));
+ writel(readl(MMIO_MISC_FUNC(nid)) | IOCSR_MISC_FUNC_SOFT_INT, MMIO_MISC_FUNC(nid));
for (retries = 0; retries < 10000; retries++) {
- msg.value = iocsr_read32(LOONGARCH_IOCSR_SMCMBX);
+ msg.value = readl(MMIO_SMCMBX(nid));
if (msg.complete)
break;
--
2.52.0