Re: [PATCH v2] mfd: loongson-se: Add multi-node support

From: Huacai Chen

Date: Mon Apr 27 2026 - 06:09:51 EST


On Mon, Apr 27, 2026 at 5:52 PM Qunqin Zhao <zhaoqunqin@xxxxxxxxxxx> wrote:
>
>
> 在 2026/4/27 下午5:37, Huacai Chen 写道:
> > On Mon, Apr 27, 2026 at 5:24 PM Qunqin Zhao <zhaoqunqin@xxxxxxxxxxx> wrote:
> >>
> >> 在 2026/4/27 下午5:02, Huacai Chen 写道:
> >>> Hi, Qunqin,
> >>>
> >>> On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao <zhaoqunqin@xxxxxxxxxxx> wrote:
> >>>> On the Loongson platform, each node is equipped with a security engine
> >>>> device. However, due to a hardware flaw, only the device on node 0 can
> >>>> trigger interrupts. Therefore, interrupts from other nodes are forwarded
> >>>> by node 0. We need to check in the interrupt handler of node 0 whether
> >>>> this interrupt is intended for other nodes.
> >>> Multi-node or multi-package? In my opinion SE has no relationship with
> >>> NUMA node, so maybe package?
> >> Here is the output of lscpu from my machine:
> >>
> >> [loongson@localhost ~]$ lscpu
> >> Architecture: loongarch64
> >> CPU op-mode(s): 32-bit, 64-bit
> >> Address sizes: 48 bits physical, 48 bits virtual
> >> Byte Order: Little Endian
> >> CPU(s): 128
> >> On-line CPU(s) list: 0-127
> >> Model name: Loongson-3C6000/D
> >> CPU family: Loongson-64bit
> >> Model: 0x11
> >> Thread(s) per core: 2
> >> Core(s) per socket: 32
> >> Socket(s): 2
> >> BogoMIPS: 4200.00
> >> Flags: cpucfg lam ual fpu lsx lasx crc32 complex crypto
> >> lvz lbt_x86 lbt_arm lbt_mips
> >> Caches (sum of all):
> >> L1d: 4 MiB (64 instances)
> >> L1i: 4 MiB (64 instances)
> >> L2: 16 MiB (64 instances)
> >> L3: 128 MiB (4 instances)
> >> NUMA:
> >> NUMA node(s): 4
> >> NUMA node0 CPU(s): 0-31
> >> NUMA node1 CPU(s): 32-63
> >> NUMA node2 CPU(s): 64-95
> >> NUMA node3 CPU(s): 96-127
> >>
> >> There are four SE devices in my system, one for each NUMA node.
> > For Loongson-3C6000 node is the same as package. You should consider
> > Loongson-3C5000L, one package contains four nodes.
>
> I am not familiar with the SE-related components on the 3C5000L, and
> this driver is not compatible with the 5000 series.
Whether it is compatible to Loongson-3C5000L is not important. The
importance is package is not always equal to node, and we should
consider whether SE is per-node or per-package.

Huacai

>
> Qunqin,
>
> Thanks.
>
> >
> > Huacai
> >
> >> Qunqin,
> >>
> >> Thanks
> >>
> >>> Huacai
> >>>
> >>>> Signed-off-by: Qunqin Zhao <zhaoqunqin@xxxxxxxxxxx>
> >>>> ---
> >>>> Changes in v2:
> >>>> -Resending due to no feedback for one month.
> >>>> -Rebased on top of latest mainline (7.1-rc1) to ensure the patch
> >>>> applies cleanly.
> >>>> -No functional changes since the previous submission.
> >>>>
> >>>> Link to v1:
> >>>> https://lore.kernel.org/all/20260226102225.19516-1-zhaoqunqin@xxxxxxxxxxx/#t
> >>>>
> >>>> drivers/mfd/loongson-se.c | 38 +++++++++++++++++++++++++++------
> >>>> include/linux/mfd/loongson-se.h | 3 +++
> >>>> 2 files changed, 35 insertions(+), 6 deletions(-)
> >>>>
> >>>> diff --git a/drivers/mfd/loongson-se.c b/drivers/mfd/loongson-se.c
> >>>> index 3902ba377d6..40e18c21268 100644
> >>>> --- a/drivers/mfd/loongson-se.c
> >>>> +++ b/drivers/mfd/loongson-se.c
> >>>> @@ -37,6 +37,9 @@ struct loongson_se_controller_cmd {
> >>>> u32 info[7];
> >>>> };
> >>>>
> >>>> +static DECLARE_COMPLETION(node0);
> >>>> +static struct loongson_se *se_node[SE_MAX_NODES];
> >>>> +
> >>>> static int loongson_se_poll(struct loongson_se *se, u32 int_bit)
> >>>> {
> >>>> u32 status;
> >>>> @@ -133,8 +136,8 @@ EXPORT_SYMBOL_GPL(loongson_se_init_engine);
> >>>> static irqreturn_t se_irq_handler(int irq, void *dev_id)
> >>>> {
> >>>> struct loongson_se *se = dev_id;
> >>>> - u32 int_status;
> >>>> - int id;
> >>>> + u32 int_status, node_irq = 0;
> >>>> + int id, node;
> >>>>
> >>>> spin_lock(&se->dev_lock);
> >>>>
> >>>> @@ -147,6 +150,11 @@ static irqreturn_t se_irq_handler(int irq, void *dev_id)
> >>>> writel(SE_INT_CONTROLLER, se->base + SE_S2LINT_CL);
> >>>> }
> >>>>
> >>>> + if (int_status & SE_INT_OTHER_NODE) {
> >>>> + int_status &= ~SE_INT_OTHER_NODE;
> >>>> + node_irq = 1;
> >>>> + }
> >>>> +
> >>>> /* For engines */
> >>>> while (int_status) {
> >>>> id = __ffs(int_status);
> >>>> @@ -157,6 +165,14 @@ static irqreturn_t se_irq_handler(int irq, void *dev_id)
> >>>>
> >>>> spin_unlock(&se->dev_lock);
> >>>>
> >>>> + if (node_irq) {
> >>>> + writel(SE_INT_OTHER_NODE, se->base + SE_S2LINT_CL);
> >>>> + for (node = 1; node < SE_MAX_NODES; node++) {
> >>>> + if (se_node[node])
> >>>> + se_irq_handler(irq, se_node[node]);
> >>>> + }
> >>>> + }
> >>>> +
> >>>> return IRQ_HANDLED;
> >>>> }
> >>>>
> >>>> @@ -189,6 +205,7 @@ static int loongson_se_probe(struct platform_device *pdev)
> >>>> struct loongson_se *se;
> >>>> int nr_irq, irq, err, i;
> >>>> dma_addr_t paddr;
> >>>> + int node = dev_to_node(dev);
> >>>>
> >>>> se = devm_kmalloc(dev, sizeof(*se), GFP_KERNEL);
> >>>> if (!se)
> >>>> @@ -213,9 +230,16 @@ static int loongson_se_probe(struct platform_device *pdev)
> >>>>
> >>>> writel(SE_INT_ALL, se->base + SE_S2LINT_EN);
> >>>>
> >>>> - nr_irq = platform_irq_count(pdev);
> >>>> - if (nr_irq <= 0)
> >>>> - return -ENODEV;
> >>>> + if (node == 0 || node == NUMA_NO_NODE) {
> >>>> + nr_irq = platform_irq_count(pdev);
> >>>> + if (nr_irq <= 0)
> >>>> + return -ENODEV;
> >>>> + } else {
> >>>> + /* Only the device on node 0 can trigger interrupts */
> >>>> + nr_irq = 0;
> >>>> + wait_for_completion_interruptible(&node0);
> >>>> + se_node[node] = se;
> >>>> + }
> >>>>
> >>>> for (i = 0; i < nr_irq; i++) {
> >>>> irq = platform_get_irq(pdev, i);
> >>>> @@ -228,7 +252,9 @@ static int loongson_se_probe(struct platform_device *pdev)
> >>>> if (err)
> >>>> return err;
> >>>>
> >>>> - return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, engines,
> >>>> + complete_all(&node0);
> >>>> +
> >>>> + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, engines,
> >>>> ARRAY_SIZE(engines), NULL, 0, NULL);
> >>>> }
> >>>>
> >>>> diff --git a/include/linux/mfd/loongson-se.h b/include/linux/mfd/loongson-se.h
> >>>> index 07afa0c2524..a80e06eb017 100644
> >>>> --- a/include/linux/mfd/loongson-se.h
> >>>> +++ b/include/linux/mfd/loongson-se.h
> >>>> @@ -20,6 +20,9 @@
> >>>>
> >>>> #define SE_INT_ALL 0xffffffff
> >>>> #define SE_INT_CONTROLLER BIT(0)
> >>>> +#define SE_INT_OTHER_NODE BIT(31)
> >>>> +
> >>>> +#define SE_MAX_NODES 8
> >>>>
> >>>> #define SE_ENGINE_MAX 16
> >>>> #define SE_ENGINE_RNG 1
> >>>>
> >>>> base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
> >>>> --
> >>>> 2.47.2
> >>>>
> >>>>
> >>
>