drivers/mfd/loongson-se.c | 38 +++++++++++++++++++++++++++------ include/linux/mfd/loongson-se.h | 3 +++ 2 files changed, 35 insertions(+), 6 deletions(-)
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.
Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn>
---
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@loongson.cn/#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
Hi, Qunqin,
On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao <zhaoqunqin@loongson.cn> 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?
Huacai
>
> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn>
> ---
> 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@loongson.cn/#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
>
>
在 2026/4/27 下午5:02, Huacai Chen 写道:
> Hi, Qunqin,
>
> On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao <zhaoqunqin@loongson.cn> 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.
Qunqin,
Thanks
>
> Huacai
>
>> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn>
>> ---
>> 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@loongson.cn/#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
>>
>>
On Mon, Apr 27, 2026 at 5:24 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote:
>
>
> 在 2026/4/27 下午5:02, Huacai Chen 写道:
> > Hi, Qunqin,
> >
> > On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao <zhaoqunqin@loongson.cn> 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.
Huacai
>
> Qunqin,
>
> Thanks
>
> >
> > Huacai
> >
> >> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn>
> >> ---
> >> 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@loongson.cn/#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
> >>
> >>
>
>
在 2026/4/27 下午5:37, Huacai Chen 写道:
> On Mon, Apr 27, 2026 at 5:24 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote:
>>
>> 在 2026/4/27 下午5:02, Huacai Chen 写道:
>>> Hi, Qunqin,
>>>
>>> On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao <zhaoqunqin@loongson.cn> 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.
Qunqin,
Thanks.
>
> Huacai
>
>> Qunqin,
>>
>> Thanks
>>
>>> Huacai
>>>
>>>> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn>
>>>> ---
>>>> 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@loongson.cn/#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
>>>>
>>>>
>>
On Mon, Apr 27, 2026 at 5:52 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote:
>
>
> 在 2026/4/27 下午5:37, Huacai Chen 写道:
> > On Mon, Apr 27, 2026 at 5:24 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote:
> >>
> >> 在 2026/4/27 下午5:02, Huacai Chen 写道:
> >>> Hi, Qunqin,
> >>>
> >>> On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao <zhaoqunqin@loongson.cn> 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@loongson.cn>
> >>>> ---
> >>>> 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@loongson.cn/#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
> >>>>
> >>>>
> >>
>
在 2026/4/27 下午6:02, Huacai Chen 写道: > On Mon, Apr 27, 2026 at 5:52 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote: >> >> 在 2026/4/27 下午5:37, Huacai Chen 写道: >>> On Mon, Apr 27, 2026 at 5:24 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote: >>>> 在 2026/4/27 下午5:02, Huacai Chen 写道: >>>>> Hi, Qunqin, >>>>> >>>>> On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao <zhaoqunqin@loongson.cn> 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. Hi, huacai After consulting with hardware team, I learned that while the 3C5000L has four SE devices, only one is utilized due to interrupt constraints. Thanks, Qunqin > > Huacai >
On Mon, 2026-04-27 at 18:02 +0800, Huacai Chen wrote: > On Mon, Apr 27, 2026 at 5:52 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote: > > > > > > 在 2026/4/27 下午5:37, Huacai Chen 写道: > > > On Mon, Apr 27, 2026 at 5:24 PM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote: > > > > > > > > 在 2026/4/27 下午5:02, Huacai Chen 写道: > > > > > Hi, Qunqin, > > > > > > > > > > On Mon, Apr 27, 2026 at 4:55 PM Qunqin Zhao > > > > > <zhaoqunqin@loongson.cn> 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. For a "compatible" example, 3C6000/D has two nodes in a package. -- Xi Ruoyao <xry111@xry111.site>
© 2016 - 2026 Red Hat, Inc.