Re: [PATCH 20/28] mfd: loongson-se: Stop controller and mask interrupts on teardown and shutdown
From: Qunqin Zhao
Date: Tue Oct 27 2026 - 00:00:03 EST
在 2026/10/21 20:09, Lee Jones 写道:
> loongson_se_probe() enables hardware interrupts before registering IRQ
> handlers and starts the controller via loongson_se_init(), but provides
> no teardown or shutdown handler to stop the controller and mask
> interrupts. If probe fails after loongson_se_init(), if the driver is
> unbound, or during a system reboot or kexec transition, the controller
> remains active with DMA configured to memory that is reclaimed.
>
> Clear pending interrupts before requesting IRQs, unmask interrupts only
> after IRQ handlers are registered, clean up on failure inside
> loongson_se_init(), register a devres action after loongson_se_init()
> succeeds to issue SE_CMD_STOP and mask interrupts on teardown, and wire
> up the platform driver .shutdown callback.
>
> Fixes: e551fa3159e3 ("mfd: Add support for Loongson Security Engine chip controller")
> Closes: https://sashiko.dev/#/bug/linux-15511672-7569-4eac-96a0-c08581925710
> Closes: https://sashiko.dev/#/bug/linux-e6ed8d33-d641-4969-a5ea-959f21ae3696
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Lee Jones <lee@xxxxxxxxxx>
Reviewed-by: Qunqin Zhao <zhaoqunqin@xxxxxxxxxxx>
Thanks for fixing this!
Best Regards,
Qunqin.
> ---
> drivers/mfd/loongson-se.c | 51 +++++++++++++++++++++++++++++----
> include/linux/mfd/loongson-se.h | 1 +
> 2 files changed, 46 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mfd/loongson-se.c b/drivers/mfd/loongson-se.c
> index 10af13c3b7cc..bdbab4b91729 100644
> --- a/drivers/mfd/loongson-se.c
> +++ b/drivers/mfd/loongson-se.c
> @@ -169,6 +169,23 @@ static irqreturn_t se_irq_handler(int irq, void *dev_id)
> return IRQ_HANDLED;
> }
>
> +static void loongson_se_stop(void *data)
> +{
> + struct loongson_se *se = data;
> + struct loongson_se_controller_cmd cmd = {};
> +
> + mutex_lock(&se->engine_init_lock);
> +
> + cmd.command_id = SE_CMD_STOP;
> + loongson_se_send_controller_cmd(se, &cmd);
> +
> + spin_lock_irq(&se->dev_lock);
> + writel(0, se->base + SE_S2LINT_EN);
> + spin_unlock_irq(&se->dev_lock);
> +
> + mutex_unlock(&se->engine_init_lock);
> +}
> +
> static int loongson_se_init(struct loongson_se *se, dma_addr_t addr, int size)
> {
> struct loongson_se_controller_cmd cmd = {};
> @@ -176,15 +193,23 @@ static int loongson_se_init(struct loongson_se *se, dma_addr_t addr, int size)
>
> cmd.command_id = SE_CMD_START;
> err = loongson_se_send_controller_cmd(se, &cmd);
> - if (err)
> + if (err) {
> + writel(0, se->base + SE_S2LINT_EN);
> return err;
> + }
>
> cmd.command_id = SE_CMD_SET_DMA;
> cmd.info[0] = lower_32_bits(addr);
> cmd.info[1] = upper_32_bits(addr);
> cmd.info[2] = size;
>
> - return loongson_se_send_controller_cmd(se, &cmd);
> + err = loongson_se_send_controller_cmd(se, &cmd);
> + if (err) {
> + loongson_se_stop(se);
> + return err;
> + }
> +
> + return 0;
> }
>
> static const struct mfd_cell engines[] = {
> @@ -192,6 +217,13 @@ static const struct mfd_cell engines[] = {
> { .name = "tpm_loongson" },
> };
>
> +static void loongson_se_shutdown(struct platform_device *pdev)
> +{
> + struct loongson_se *se = platform_get_drvdata(pdev);
> +
> + loongson_se_stop(se);
> +}
> +
> static int loongson_se_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -225,12 +257,12 @@ static int loongson_se_probe(struct platform_device *pdev)
> if (IS_ERR(se->base))
> return PTR_ERR(se->base);
>
> - writel(SE_INT_ALL, se->base + SE_S2LINT_EN);
> -
> nr_irq = platform_irq_count(pdev);
> if (nr_irq <= 0)
> return -ENODEV;
>
> + writel(SE_INT_ALL, se->base + SE_S2LINT_CL);
> +
> for (i = 0; i < nr_irq; i++) {
> irq = platform_get_irq(pdev, i);
> err = devm_request_irq(dev, irq, se_irq_handler, 0, "loongson-se", se);
> @@ -238,10 +270,16 @@ static int loongson_se_probe(struct platform_device *pdev)
> dev_err(dev, "failed to request IRQ: %d\n", irq);
> }
>
> + writel(SE_INT_ALL, se->base + SE_S2LINT_EN);
> +
> err = loongson_se_init(se, paddr, se->dmam_size);
> if (err)
> return err;
>
> + err = devm_add_action_or_reset(dev, loongson_se_stop, se);
> + if (err)
> + return err;
> +
> return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, engines,
> ARRAY_SIZE(engines), NULL, 0, NULL);
> }
> @@ -253,8 +291,9 @@ static const struct acpi_device_id loongson_se_acpi_match[] = {
> MODULE_DEVICE_TABLE(acpi, loongson_se_acpi_match);
>
> static struct platform_driver loongson_se_driver = {
> - .probe = loongson_se_probe,
> - .driver = {
> + .probe = loongson_se_probe,
> + .shutdown = loongson_se_shutdown,
> + .driver = {
> .name = "loongson-se",
> .acpi_match_table = loongson_se_acpi_match,
> },
> diff --git a/include/linux/mfd/loongson-se.h b/include/linux/mfd/loongson-se.h
> index 2d0a8b1e5c9e..dbe5992bd435 100644
> --- a/include/linux/mfd/loongson-se.h
> +++ b/include/linux/mfd/loongson-se.h
> @@ -11,6 +11,7 @@
> #define SE_SEND_CMD_REG_LEN 0x8
> /* Controller command ID */
> #define SE_CMD_START 0x0
> +#define SE_CMD_STOP 0x1
> #define SE_CMD_SET_DMA 0x3
> #define SE_CMD_SET_ENGINE_CMDBUF 0x4
>