* [PATCH] mfd: loongson-se: Add multi-node support
@ 2026-02-26 10:22 Qunqin Zhao
2026-03-06 13:35 ` Lee Jones
0 siblings, 1 reply; 3+ messages in thread
From: Qunqin Zhao @ 2026-02-26 10:22 UTC (permalink / raw)
To: lee; +Cc: linux-kernel, linux-crypto, Qunqin Zhao
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>
---
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 3902ba377..40e18c212 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 07afa0c25..a80e06eb0 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
--
2.47.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] mfd: loongson-se: Add multi-node support
2026-02-26 10:22 [PATCH] mfd: loongson-se: Add multi-node support Qunqin Zhao
@ 2026-03-06 13:35 ` Lee Jones
2026-03-07 6:29 ` Qunqin Zhao
0 siblings, 1 reply; 3+ messages in thread
From: Lee Jones @ 2026-03-06 13:35 UTC (permalink / raw)
To: Qunqin Zhao; +Cc: linux-kernel, linux-crypto
On Thu, 26 Feb 2026, Qunqin Zhao 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.
>
> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn>
> ---
> 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 3902ba377..40e18c212 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];
Really not keen on global variables.
Why are they _needed_?
> 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 07afa0c25..a80e06eb0 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
> --
> 2.47.2
>
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] mfd: loongson-se: Add multi-node support
2026-03-06 13:35 ` Lee Jones
@ 2026-03-07 6:29 ` Qunqin Zhao
0 siblings, 0 replies; 3+ messages in thread
From: Qunqin Zhao @ 2026-03-07 6:29 UTC (permalink / raw)
To: Lee Jones; +Cc: linux-kernel, linux-crypto
在 2026/3/6 下午9:35, Lee Jones 写道:
> On Thu, 26 Feb 2026, Qunqin Zhao 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.
>>
>> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn>
>> ---
>> 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 3902ba377..40e18c212 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);
Devices on non-zero nodes rely on the device on node 0, so they need to
wait for the device on node 0 to complete initialization.
>> +static struct loongson_se *se_node[SE_MAX_NODES];
I need to iterate through all devices in interrupt context, so I use a
global variable to track them.
Could I ask if there might be a more suitable method?
Thanks,
Qunqin
> Really not keen on global variables.
>
> Why are they _needed_?
>
>> 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 07afa0c25..a80e06eb0 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
>> --
>> 2.47.2
>>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-07 6:31 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-26 10:22 [PATCH] mfd: loongson-se: Add multi-node support Qunqin Zhao
2026-03-06 13:35 ` Lee Jones
2026-03-07 6:29 ` Qunqin Zhao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox