Re: [PATCH 5/5] cpufreq: loongson3: Replace IOCSR read/write with MMIO ones

Huacai Chen <[email protected]>
Newsgroups dev.linux.lists.loongarch,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm,org.kernel.vger.stable
Message-ID <CAAhV-H5gbyo3CHj+b5YwwU1GZG47hThx3OJRAXCDEoJ2KKSnXw@mail.gmail.com>
Hi, Zhongqiu,

On Thu, Aug 20, 2026 at 8:57 PM Zhongqiu Han
<[email protected]> wrote:
>
> On 8/18/2026 8:39 PM, Huacai Chen wrote:
> > 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: [email protected]
> > Signed-off-by: Huacai Chen <[email protected]>
> > ---
> >   drivers/cpufreq/loongson3_cpufreq.c | 31 ++++++++++++++++++++++-------
> >   1 file changed, 24 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/cpufreq/loongson3_cpufreq.c b/drivers/cpufreq/loongson3_cpufreq.c
> > index c75c0e30e881..e5062cd62390 100644
> > --- a/drivers/cpufreq/loongson3_cpufreq.c
> > +++ b/drivers/cpufreq/loongson3_cpufreq.c
> > @@ -164,6 +164,12 @@ union smc_message {
> >
> >   #define FREQ_MAX_LEVEL                      16
> >
> > +#define MMIO_SMCMBX(node) \
> > +     ((void __iomem *)(IO_BASE | (u64)(node) << NODE_ADDRSPACE_SHIFT | LOONGSON_REG_BASE | LOONGARCH_IOCSR_SMCMBX))
> > +
> > +#define MMIO_MISC_FUNC(node) \
> > +     ((void __iomem *)(IO_BASE | (u64)(node) << NODE_ADDRSPACE_SHIFT | LOONGSON_REG_BASE | LOONGARCH_IOCSR_MISC_FUNC))
> > +
> >   struct loongson3_freq_data {
> >       unsigned int def_freq_level;
> >       struct cpufreq_frequency_table table[];
> > @@ -176,13 +182,25 @@ 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, nid;
> >       union smc_message msg, last;
> >
> > +     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);
>
> cpu_number_map() is undefined when CONFIG_SMP=n. Wouldn't that result in
> a build failure?
Yes, part of the code should be guarded by CONFIG_SMP here.

>
>
> > +             break;
> > +     default:
> > +             cpu = raw_smp_processor_id();
> > +     }
> > +     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 +213,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;
> >
>
>
> Please ignore this comments if you do not think it is worth addressing:
>
> A separate issue, it seems that DVFS and Boost feature is set in
> loongson3_cpufreq_probe(), what if about on other nodes (non-boot cpu
> node) and what if cpu hotplug?
Interesting question. After discussion with the firmware team, They
told me that CMD_SET_FEATURE is a global command, the SMC firmware
will align the settings for all nodes.

Huacai

>
> static int loongson3_cpufreq_probe(struct platform_device *pdev)
> {
>         int i, ret;
>
>         for (i = 0; i < MAX_PACKAGES; i++) {
>                 ret = devm_mutex_init(&pdev->dev, &cpufreq_mutex[i]);
>                 if (ret)
>                         return ret;
>         }
>
>         ret = do_service_request(0, 0, CMD_GET_VERSION, 0, 0);
>         if (ret <= 0)
>                 return -EPERM;
>
>         ret = do_service_request(FEATURE_DVFS, 0, CMD_SET_FEATURE,
>                                  FEATURE_DVFS_ENABLE | FEATURE_DVFS_BOOST, 0);
>         if (ret < 0)
>                 return -EPERM;
>
> ......
>
> }
>
>
> --
> Thx and BRs,
> Zhongqiu Han
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.