* [PATCH v7 0/6] Drivers for Loongson security engine
@ 2025-04-03 2:46 Qunqin Zhao
2025-04-03 2:46 ` [PATCH v7 1/6] mfd: Add support for Loongson Security Module Qunqin Zhao
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Qunqin Zhao @ 2025-04-03 2:46 UTC (permalink / raw)
To: lee, herbert, davem, peterhuewe, jarkko
Cc: linux-kernel, loongarch, linux-crypto, jgg, linux-integrity,
pmenzel, Qunqin Zhao
Loongson security engine supports random number generation, hash,
symmetric encryption and asymmetric encryption. Based on these
encryption functions, TPM2 have been implemented in it.
mfd is the baser driver, crypto and tpm are users.
v7: Addressed Huacai's comments.
v6: mfd :MFD_LS6000SE -> MFD_LOONGSON_SE, ls6000se.c -> loongson-se.c
crypto :CRYPTO_DEV_LS6000SE_RNG -> CRYPTO_DEV_LOONGSON_RNG,
ls6000se-rng.c ->loongson-rng.c
tpm: TCG_LSSE -> TCG_LOONGSON, tpm_lsse.c ->tpm_loongson.c
v5: Registered "ls6000se-rng" device in mfd driver.
v4: Please look at changelog in tpm and MAINTAINERS. No changes to mfd
and crypto.
v3: Put the updates to the MAINTAINERS in a separate patch.
v2: Removed misc driver. Added tpm driver.
Qunqin Zhao (6):
mfd: Add support for Loongson Security Module
MAINTAINERS: Add entry for Loongson Security Module driver
crypto: loongson - add Loongson RNG driver support
MAINTAINERS: Add entry for Loongson RNG driver
tpm: Add a driver for Loongson TPM device
MAINTAINERS: Add tpm_loongson.c to LOONGSON CRYPTO DRIVER entry
MAINTAINERS | 14 +
drivers/char/tpm/Kconfig | 9 +
drivers/char/tpm/Makefile | 1 +
drivers/char/tpm/tpm_loongson.c | 103 +++++++
drivers/crypto/Kconfig | 1 +
drivers/crypto/Makefile | 1 +
drivers/crypto/loongson/Kconfig | 6 +
drivers/crypto/loongson/Makefile | 2 +
drivers/crypto/loongson/loongson-rng.c | 190 +++++++++++++
drivers/mfd/Kconfig | 10 +
drivers/mfd/Makefile | 2 +
drivers/mfd/loongson-se.c | 374 +++++++++++++++++++++++++
include/linux/mfd/loongson-se.h | 75 +++++
13 files changed, 788 insertions(+)
create mode 100644 drivers/char/tpm/tpm_loongson.c
create mode 100644 drivers/crypto/loongson/Kconfig
create mode 100644 drivers/crypto/loongson/Makefile
create mode 100644 drivers/crypto/loongson/loongson-rng.c
create mode 100644 drivers/mfd/loongson-se.c
create mode 100644 include/linux/mfd/loongson-se.h
base-commit: b904243247d1acb0ebbd4978feb639441dc51fc1
--
2.45.2
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v7 1/6] mfd: Add support for Loongson Security Module 2025-04-03 2:46 [PATCH v7 0/6] Drivers for Loongson security engine Qunqin Zhao @ 2025-04-03 2:46 ` Qunqin Zhao 2025-04-04 16:06 ` Lee Jones 2025-04-03 2:46 ` [PATCH v7 2/6] MAINTAINERS: Add entry for Loongson Security Module driver Qunqin Zhao ` (2 subsequent siblings) 3 siblings, 1 reply; 11+ messages in thread From: Qunqin Zhao @ 2025-04-03 2:46 UTC (permalink / raw) To: lee, herbert, davem, peterhuewe, jarkko Cc: linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Qunqin Zhao, Yinggang Gu, Huacai Chen This driver supports Loongson Security Module, which provides the control for it's hardware encryption acceleration child devices. Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> --- v7: Moved Kconfig entry between MFD_INTEL_M10_BMC_PMCI and MFD_QNAP_MCU. Renamed se_enable_int_locked() to se_enable_int(), then moved the lock out of se_disable_int(). "se_send_genl_cmd" ---> "se_send_cmd". "struct lsse_ch" ---> "struct se_channel". v6: Replace all "ls6000se" with "loongson" v5: Registered "ls6000se-rng" device. v3-v4: None v2: Removed "ls6000se-sdf" device, added "ls6000se-tpm" device. Passed dmamem size to SE firmware in se_init_hw() function. drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 2 + drivers/mfd/loongson-se.c | 374 ++++++++++++++++++++++++++++++++ include/linux/mfd/loongson-se.h | 75 +++++++ 4 files changed, 461 insertions(+) create mode 100644 drivers/mfd/loongson-se.c create mode 100644 include/linux/mfd/loongson-se.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 22b936310..66889f2a9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2369,6 +2369,16 @@ config MFD_INTEL_M10_BMC_PMCI additional drivers must be enabled in order to use the functionality of the device. +config MFD_LOONGSON_SE + tristate "Loongson Security Module Interface" + depends on LOONGARCH && ACPI + select MFD_CORE + help + The Loongson security module provides the control for hardware + encryption acceleration devices. Each device uses at least one + channel to interact with security module, and each channel may + have its own buffer provided by security module. + config MFD_QNAP_MCU tristate "QNAP microcontroller unit core driver" depends on SERIAL_DEV_BUS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 948cbdf42..fc50601ca 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -290,3 +290,5 @@ obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o + +obj-$(CONFIG_MFD_LOONGSON_SE) += loongson-se.o diff --git a/drivers/mfd/loongson-se.c b/drivers/mfd/loongson-se.c new file mode 100644 index 000000000..4f30695de --- /dev/null +++ b/drivers/mfd/loongson-se.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2025 Loongson Technology Corporation Limited */ + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/mfd/loongson-se.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +/* + * The Loongson Security Module provides the control for hardware + * encryption acceleration child devices. The SE framework is + * shown as follows: + * + * +------------+ + * | CPU | + * +------------+ + * ^ ^ + * DMA | | IRQ + * v v + * +-----------------------------------+ + * | Loongson Security Module | + * +-----------------------------------+ + * ^ ^ + * channel1 | channel2 | + * v v + * +-----------+ +----------+ + * | sub-dev1 | | sub-dev2 | ..... Max sub-dev31 + * +-----------+ +----------+ + * + * The CPU cannot directly communicate with SE's sub devices, + * but sends commands to SE, which processes the commands and + * sends them to the corresponding sub devices. + */ + +struct loongson_se { + void __iomem *base; + u32 version; + spinlock_t dev_lock; + struct completion cmd_completion; + + /* dma memory */ + void *mem_base; + int mem_map_pages; + unsigned long *mem_map; + + /* channel */ + struct mutex ch_init_lock; + struct se_channel chs[SE_CH_MAX]; +}; + +union se_request { + u32 info[8]; + struct se_cmd { + u32 cmd; + u32 info[7]; + } req; + struct se_res { + u32 cmd; + u32 cmd_ret; + u32 info[6]; + } res; +}; + +static inline u32 se_readl(struct loongson_se *se, u32 off) +{ + return readl(se->base + off); +} + +static inline void se_writel(struct loongson_se *se, u32 val, u32 off) +{ + writel(val, se->base + off); +} + +static void se_enable_int(struct loongson_se *se, u32 int_bit) +{ + u32 tmp; + + tmp = se_readl(se, SE_S2LINT_EN); + tmp |= int_bit; + se_writel(se, tmp, SE_S2LINT_EN); +} + +static void se_disable_int(struct loongson_se *se, u32 int_bit) +{ + u32 tmp; + + tmp = se_readl(se, SE_S2LINT_EN); + tmp &= ~(int_bit); + se_writel(se, tmp, SE_S2LINT_EN); +} + +static int se_poll(struct loongson_se *se, u32 int_bit) +{ + u32 status; + int err; + + spin_lock_irq(&se->dev_lock); + + se_enable_int(se, int_bit); + se_writel(se, int_bit, SE_L2SINT_SET); + err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, + !(status & int_bit), 1, 10000); + + spin_unlock_irq(&se->dev_lock); + + return err; +} + +static int se_send_requeset(struct loongson_se *se, union se_request *req) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(req->info); i++) + se_writel(se, req->info[i], SE_DATA_S + i * 4); + + return se_poll(se, SE_INT_SETUP); +} + +/* + * Called by SE's child device driver. + * Send a request to the corresponding device. + */ +int se_send_ch_requeset(struct se_channel *ch) +{ + return se_poll(ch->se, ch->int_bit); +} +EXPORT_SYMBOL_GPL(se_send_ch_requeset); + +static int se_get_res(struct loongson_se *se, u32 cmd, union se_request *res) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(res->info); i++) + res->info[i] = se_readl(se, SE_DATA_L + i * 4); + + if (res->res.cmd != cmd) + return -EFAULT; + + return 0; +} + +static int se_send_cmd(struct loongson_se *se, union se_request *req) +{ + int err; + + err = se_send_requeset(se, req); + if (err) + return err; + + if (!wait_for_completion_timeout(&se->cmd_completion, HZ)) + return -ETIME; + + return se_get_res(se, req->req.cmd, req); +} + +static int se_set_msg(struct se_channel *ch) +{ + struct loongson_se *se = ch->se; + union se_request req; + + req.req.cmd = SE_CMD_SETMSG; + req.req.info[0] = ch->id; + req.req.info[1] = ch->smsg - se->mem_base; + req.req.info[2] = ch->msg_size; + + return se_send_cmd(se, &req); +} + +static irqreturn_t se_irq(int irq, void *dev_id) +{ + struct loongson_se *se = (struct loongson_se *)dev_id; + struct se_channel *ch; + unsigned long flag; + u32 int_status; + int id; + + int_status = se_readl(se, SE_S2LINT_STAT); + + spin_lock_irqsave(&se->dev_lock, flag); + se_disable_int(se, int_status); + spin_unlock_irqrestore(&se->dev_lock, flag); + + if (int_status & SE_INT_SETUP) { + complete(&se->cmd_completion); + int_status &= ~SE_INT_SETUP; + se_writel(se, SE_INT_SETUP, SE_S2LINT_CL); + } + + while (int_status) { + id = __ffs(int_status); + + ch = &se->chs[id]; + if (ch->complete) + ch->complete(ch); + int_status &= ~BIT(id); + se_writel(se, BIT(id), SE_S2LINT_CL); + } + + return IRQ_HANDLED; +} + +static int se_init_hw(struct loongson_se *se, dma_addr_t addr, int size) +{ + union se_request req; + int err; + + /* Start engine */ + req.req.cmd = SE_CMD_START; + err = se_send_cmd(se, &req); + if (err) + return err; + + /* Get Version */ + req.req.cmd = SE_CMD_GETVER; + err = se_send_cmd(se, &req); + if (err) + return err; + se->version = req.res.info[0]; + + /* Setup dma memory */ + req.req.cmd = SE_CMD_SETBUF; + req.req.info[0] = addr & 0xffffffff; + req.req.info[1] = addr >> 32; + req.req.info[2] = size; + + return se_send_cmd(se, &req); +} + +/* + * se_init_ch() - Init the channel used by child device. + * + * Allocate dma memory as agreed upon with SE on SE probe, + * and register the callback function when the data processing + * in this channel is completed. + */ +struct se_channel *se_init_ch(struct device *dev, int id, int data_size, int msg_size, + void *priv, void (*complete)(struct se_channel *se_ch)) +{ + struct loongson_se *se = dev_get_drvdata(dev); + struct se_channel *ch; + int data_first, data_nr; + int msg_first, msg_nr; + + mutex_lock(&se->ch_init_lock); + + ch = &se->chs[id]; + ch->se = se; + ch->id = id; + ch->int_bit = BIT(id); + + data_nr = round_up(data_size, PAGE_SIZE) / PAGE_SIZE; + data_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, + 0, data_nr, 0); + if (data_first >= se->mem_map_pages) { + ch = NULL; + goto out_unlock; + } + + bitmap_set(se->mem_map, data_first, data_nr); + ch->off = data_first * PAGE_SIZE; + ch->data_buffer = se->mem_base + ch->off; + ch->data_size = data_size; + + msg_nr = round_up(msg_size, PAGE_SIZE) / PAGE_SIZE; + msg_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, + 0, msg_nr, 0); + if (msg_first >= se->mem_map_pages) { + ch = NULL; + goto out_unlock; + } + + bitmap_set(se->mem_map, msg_first, msg_nr); + ch->smsg = se->mem_base + msg_first * PAGE_SIZE; + ch->rmsg = ch->smsg + msg_size / 2; + ch->msg_size = msg_size; + ch->complete = complete; + ch->priv = priv; + ch->version = se->version; + + if (se_set_msg(ch)) + ch = NULL; + +out_unlock: + mutex_unlock(&se->ch_init_lock); + + return ch; +} +EXPORT_SYMBOL_GPL(se_init_ch); + +static const struct mfd_cell se_devs[] = { + { .name = "loongson-rng" }, + { .name = "loongson-tpm" }, +}; + +static int loongson_se_probe(struct platform_device *pdev) +{ + struct loongson_se *se; + struct device *dev = &pdev->dev; + int nr_irq, irq, err, size; + dma_addr_t paddr; + + se = devm_kmalloc(dev, sizeof(*se), GFP_KERNEL); + if (!se) + return -ENOMEM; + dev_set_drvdata(dev, se); + init_completion(&se->cmd_completion); + spin_lock_init(&se->dev_lock); + mutex_init(&se->ch_init_lock); + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (device_property_read_u32(dev, "dmam_size", &size)) + return -ENODEV; + size = roundup_pow_of_two(size); + se->mem_base = dmam_alloc_coherent(dev, size, &paddr, GFP_KERNEL); + if (!se->mem_base) + return -ENOMEM; + se->mem_map_pages = size / PAGE_SIZE; + se->mem_map = devm_bitmap_zalloc(dev, se->mem_map_pages, GFP_KERNEL); + if (!se->mem_map) + return -ENOMEM; + + se->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(se->base)) + return PTR_ERR(se->base); + + nr_irq = platform_irq_count(pdev); + if (nr_irq <= 0) + return -ENODEV; + while (nr_irq) { + irq = platform_get_irq(pdev, --nr_irq); + /* Use the same interrupt handler address. + * Determine which irq it is accroding + * SE_S2LINT_STAT register. + */ + err = devm_request_irq(dev, irq, se_irq, 0, "loongson-se", se); + if (err) + dev_err(dev, "failed to request irq: %d\n", irq); + } + + err = se_init_hw(se, paddr, size); + if (err) + return err; + + return devm_mfd_add_devices(dev, 0, se_devs, ARRAY_SIZE(se_devs), + NULL, 0, NULL); +} + +static const struct acpi_device_id loongson_se_acpi_match[] = { + {"LOON0011", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, loongson_se_acpi_match); + +static struct platform_driver loongson_se_driver = { + .probe = loongson_se_probe, + .driver = { + .name = "loongson-se", + .acpi_match_table = loongson_se_acpi_match, + }, +}; +module_platform_driver(loongson_se_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>"); +MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>"); +MODULE_DESCRIPTION("Loongson Security Module driver"); diff --git a/include/linux/mfd/loongson-se.h b/include/linux/mfd/loongson-se.h new file mode 100644 index 000000000..f209b7043 --- /dev/null +++ b/include/linux/mfd/loongson-se.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (C) 2025 Loongson Technology Corporation Limited */ + +#ifndef __LOONGSON_SE_H__ +#define __LOONGSON_SE_H__ + +#define SE_DATA_S 0x0 +#define SE_DATA_L 0x20 +#define SE_S2LINT_STAT 0x88 +#define SE_S2LINT_EN 0x8c +#define SE_S2LINT_SET 0x90 +#define SE_S2LINT_CL 0x94 +#define SE_L2SINT_STAT 0x98 +#define SE_L2SINT_EN 0x9c +#define SE_L2SINT_SET 0xa0 +#define SE_L2SINT_CL 0xa4 + +/* INT bit definition */ +#define SE_INT_SETUP BIT(0) +#define SE_INT_TPM BIT(5) + +#define SE_CMD_START 0x0 +#define SE_CMD_STOP 0x1 +#define SE_CMD_GETVER 0x2 +#define SE_CMD_SETBUF 0x3 +#define SE_CMD_SETMSG 0x4 + +#define SE_CMD_RNG 0x100 +#define SE_CMD_SM2_SIGN 0x200 +#define SE_CMD_SM2_VSIGN 0x201 +#define SE_CMD_SM3_DIGEST 0x300 +#define SE_CMD_SM3_UPDATE 0x301 +#define SE_CMD_SM3_FINISH 0x302 +#define SE_CMD_SM4_ECB_ENCRY 0x400 +#define SE_CMD_SM4_ECB_DECRY 0x401 +#define SE_CMD_SM4_CBC_ENCRY 0x402 +#define SE_CMD_SM4_CBC_DECRY 0x403 +#define SE_CMD_SM4_CTR 0x404 +#define SE_CMD_TPM 0x500 +#define SE_CMD_ZUC_INIT_READ 0x600 +#define SE_CMD_ZUC_READ 0x601 +#define SE_CMD_SDF 0x700 + +#define SE_CH_MAX 32 +#define SE_CH_RNG 1 +#define SE_CH_SM2 2 +#define SE_CH_SM3 3 +#define SE_CH_SM4 4 +#define SE_CH_TPM 5 +#define SE_CH_ZUC 6 +#define SE_CH_SDF 7 + +struct se_channel { + struct loongson_se *se; + void *priv; + u32 version; + u32 id; + u32 int_bit; + + void *smsg; + void *rmsg; + int msg_size; + + void *data_buffer; + int data_size; + u32 off; + + void (*complete)(struct se_channel *se_ch); +}; + +struct se_channel *se_init_ch(struct device *dev, int id, int data_size, int msg_size, + void *priv, void (*complete)(struct se_channel *se_ch)); +int se_send_ch_requeset(struct se_channel *ch); + +#endif -- 2.45.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v7 1/6] mfd: Add support for Loongson Security Module 2025-04-03 2:46 ` [PATCH v7 1/6] mfd: Add support for Loongson Security Module Qunqin Zhao @ 2025-04-04 16:06 ` Lee Jones 2025-04-07 7:53 ` Qunqin Zhao 0 siblings, 1 reply; 11+ messages in thread From: Lee Jones @ 2025-04-04 16:06 UTC (permalink / raw) To: Qunqin Zhao Cc: herbert, davem, peterhuewe, jarkko, linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Yinggang Gu, Huacai Chen On Thu, 03 Apr 2025, Qunqin Zhao wrote: > This driver supports Loongson Security Module, which provides the control > for it's hardware encryption acceleration child devices. > > Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> > Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> > Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> > Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> > --- > v7: Moved Kconfig entry between MFD_INTEL_M10_BMC_PMCI and MFD_QNAP_MCU. > > Renamed se_enable_int_locked() to se_enable_int(), then moved the > lock out of se_disable_int(). > > "se_send_genl_cmd" ---> "se_send_cmd". > "struct lsse_ch" ---> "struct se_channel". > > v6: Replace all "ls6000se" with "loongson" > v5: Registered "ls6000se-rng" device. > v3-v4: None > > v2: Removed "ls6000se-sdf" device, added "ls6000se-tpm" device. > Passed dmamem size to SE firmware in se_init_hw() function. > > drivers/mfd/Kconfig | 10 + > drivers/mfd/Makefile | 2 + > drivers/mfd/loongson-se.c | 374 ++++++++++++++++++++++++++++++++ > include/linux/mfd/loongson-se.h | 75 +++++++ > 4 files changed, 461 insertions(+) > create mode 100644 drivers/mfd/loongson-se.c > create mode 100644 include/linux/mfd/loongson-se.h > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > index 22b936310..66889f2a9 100644 > --- a/drivers/mfd/Kconfig > +++ b/drivers/mfd/Kconfig > @@ -2369,6 +2369,16 @@ config MFD_INTEL_M10_BMC_PMCI > additional drivers must be enabled in order to use the functionality > of the device. > > +config MFD_LOONGSON_SE > + tristate "Loongson Security Module Interface" > + depends on LOONGARCH && ACPI > + select MFD_CORE > + help > + The Loongson security module provides the control for hardware > + encryption acceleration devices. Each device uses at least one > + channel to interact with security module, and each channel may > + have its own buffer provided by security module. > + > config MFD_QNAP_MCU > tristate "QNAP microcontroller unit core driver" > depends on SERIAL_DEV_BUS > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile > index 948cbdf42..fc50601ca 100644 > --- a/drivers/mfd/Makefile > +++ b/drivers/mfd/Makefile > @@ -290,3 +290,5 @@ obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o > obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o > > obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o > + > +obj-$(CONFIG_MFD_LOONGSON_SE) += loongson-se.o > diff --git a/drivers/mfd/loongson-se.c b/drivers/mfd/loongson-se.c > new file mode 100644 > index 000000000..4f30695de > --- /dev/null > +++ b/drivers/mfd/loongson-se.c > @@ -0,0 +1,374 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* Copyright (C) 2025 Loongson Technology Corporation Limited */ > + > +#include <linux/acpi.h> > +#include <linux/delay.h> > +#include <linux/device.h> > +#include <linux/dma-mapping.h> > +#include <linux/errno.h> > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/iopoll.h> > +#include <linux/kernel.h> > +#include <linux/mfd/core.h> > +#include <linux/mfd/loongson-se.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > + > +/* > + * The Loongson Security Module provides the control for hardware > + * encryption acceleration child devices. The SE framework is > + * shown as follows: > + * > + * +------------+ > + * | CPU | > + * +------------+ > + * ^ ^ > + * DMA | | IRQ > + * v v > + * +-----------------------------------+ > + * | Loongson Security Module | > + * +-----------------------------------+ > + * ^ ^ > + * channel1 | channel2 | > + * v v > + * +-----------+ +----------+ > + * | sub-dev1 | | sub-dev2 | ..... Max sub-dev31 > + * +-----------+ +----------+ > + * > + * The CPU cannot directly communicate with SE's sub devices, > + * but sends commands to SE, which processes the commands and > + * sends them to the corresponding sub devices. > + */ > + > +struct loongson_se { > + void __iomem *base; > + u32 version; > + spinlock_t dev_lock; > + struct completion cmd_completion; > + > + /* dma memory */ > + void *mem_base; > + int mem_map_pages; > + unsigned long *mem_map; > + > + /* channel */ > + struct mutex ch_init_lock; > + struct se_channel chs[SE_CH_MAX]; > +}; > + > +union se_request { > + u32 info[8]; > + struct se_cmd { > + u32 cmd; > + u32 info[7]; > + } req; > + struct se_res { > + u32 cmd; > + u32 cmd_ret; > + u32 info[6]; > + } res; > +}; > + > +static inline u32 se_readl(struct loongson_se *se, u32 off) > +{ > + return readl(se->base + off); > +} > + > +static inline void se_writel(struct loongson_se *se, u32 val, u32 off) > +{ > + writel(val, se->base + off); > +} Why are these being abstracted? Just use readl/writel directly. > +static void se_enable_int(struct loongson_se *se, u32 int_bit) > +{ > + u32 tmp; > + > + tmp = se_readl(se, SE_S2LINT_EN); > + tmp |= int_bit; > + se_writel(se, tmp, SE_S2LINT_EN); > +} > + > +static void se_disable_int(struct loongson_se *se, u32 int_bit) > +{ > + u32 tmp; > + > + tmp = se_readl(se, SE_S2LINT_EN); > + tmp &= ~(int_bit); > + se_writel(se, tmp, SE_S2LINT_EN); > +} > + > +static int se_poll(struct loongson_se *se, u32 int_bit) > +{ > + u32 status; > + int err; > + > + spin_lock_irq(&se->dev_lock); > + > + se_enable_int(se, int_bit); > + se_writel(se, int_bit, SE_L2SINT_SET); > + err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, > + !(status & int_bit), 1, 10000); > + > + spin_unlock_irq(&se->dev_lock); > + > + return err; > +} > + > +static int se_send_requeset(struct loongson_se *se, union se_request *req) What's a requeset? > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(req->info); i++) > + se_writel(se, req->info[i], SE_DATA_S + i * 4); > + > + return se_poll(se, SE_INT_SETUP); > +} > + > +/* > + * Called by SE's child device driver. > + * Send a request to the corresponding device. > + */ > +int se_send_ch_requeset(struct se_channel *ch) > +{ > + return se_poll(ch->se, ch->int_bit); > +} More pointless abstraction. Just export se_poll()? > +EXPORT_SYMBOL_GPL(se_send_ch_requeset); > + > +static int se_get_res(struct loongson_se *se, u32 cmd, union se_request *res) What are we getting here? What is a 'res'? > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(res->info); i++) for (int i = 0; ... > + res->info[i] = se_readl(se, SE_DATA_L + i * 4); > + > + if (res->res.cmd != cmd) > + return -EFAULT; > + > + return 0; > +} > + > +static int se_send_cmd(struct loongson_se *se, union se_request *req) > +{ > + int err; > + > + err = se_send_requeset(se, req); > + if (err) > + return err; > + > + if (!wait_for_completion_timeout(&se->cmd_completion, HZ)) > + return -ETIME; -ETIMEDOUT > + > + return se_get_res(se, req->req.cmd, req); > +} > + > +static int se_set_msg(struct se_channel *ch) > +{ > + struct loongson_se *se = ch->se; > + union se_request req; > + > + req.req.cmd = SE_CMD_SETMSG; > + req.req.info[0] = ch->id; > + req.req.info[1] = ch->smsg - se->mem_base; > + req.req.info[2] = ch->msg_size; > + > + return se_send_cmd(se, &req); > +} > + > +static irqreturn_t se_irq(int irq, void *dev_id) se_irq_handler() > +{ > + struct loongson_se *se = (struct loongson_se *)dev_id; > + struct se_channel *ch; > + unsigned long flag; > + u32 int_status; > + int id; > + > + int_status = se_readl(se, SE_S2LINT_STAT); > + > + spin_lock_irqsave(&se->dev_lock, flag); > + se_disable_int(se, int_status); > + spin_unlock_irqrestore(&se->dev_lock, flag); > + > + if (int_status & SE_INT_SETUP) { > + complete(&se->cmd_completion); > + int_status &= ~SE_INT_SETUP; > + se_writel(se, SE_INT_SETUP, SE_S2LINT_CL); > + } > + > + while (int_status) { > + id = __ffs(int_status); > + > + ch = &se->chs[id]; > + if (ch->complete) > + ch->complete(ch); > + int_status &= ~BIT(id); > + se_writel(se, BIT(id), SE_S2LINT_CL); > + } > + > + return IRQ_HANDLED; > +} > + > +static int se_init_hw(struct loongson_se *se, dma_addr_t addr, int size) > +{ > + union se_request req; > + int err; > + > + /* Start engine */ > + req.req.cmd = SE_CMD_START; > + err = se_send_cmd(se, &req); > + if (err) > + return err; > + > + /* Get Version */ > + req.req.cmd = SE_CMD_GETVER; > + err = se_send_cmd(se, &req); > + if (err) > + return err; > + se->version = req.res.info[0]; > + > + /* Setup dma memory */ DMA > + req.req.cmd = SE_CMD_SETBUF; > + req.req.info[0] = addr & 0xffffffff; > + req.req.info[1] = addr >> 32; Define these magic numbers please. > + req.req.info[2] = size; > + > + return se_send_cmd(se, &req); > +} > + > +/* > + * se_init_ch() - Init the channel used by child device. > + * > + * Allocate dma memory as agreed upon with SE on SE probe, DMA, throughout please. > + * and register the callback function when the data processing > + * in this channel is completed. > + */ > +struct se_channel *se_init_ch(struct device *dev, int id, int data_size, int msg_size, What's a "ch"? > + void *priv, void (*complete)(struct se_channel *se_ch)) I'm not entirely sure what this device is or how it works, but this isn't really what MFD is for. MFD has no knowledge of channel initialisation or completion call-backs or the like. What you have here goes beyond scope. > +{ > + struct loongson_se *se = dev_get_drvdata(dev); > + struct se_channel *ch; > + int data_first, data_nr; > + int msg_first, msg_nr; > + > + mutex_lock(&se->ch_init_lock); > + > + ch = &se->chs[id]; > + ch->se = se; > + ch->id = id; > + ch->int_bit = BIT(id); This can be derived from ch->id, so you don't need to store it. Or you don't need 'id' - one of the two. > + > + data_nr = round_up(data_size, PAGE_SIZE) / PAGE_SIZE; > + data_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, > + 0, data_nr, 0); > + if (data_first >= se->mem_map_pages) { > + ch = NULL; > + goto out_unlock; > + } > + > + bitmap_set(se->mem_map, data_first, data_nr); > + ch->off = data_first * PAGE_SIZE; > + ch->data_buffer = se->mem_base + ch->off; > + ch->data_size = data_size; > + > + msg_nr = round_up(msg_size, PAGE_SIZE) / PAGE_SIZE; > + msg_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, > + 0, msg_nr, 0); > + if (msg_first >= se->mem_map_pages) { > + ch = NULL; > + goto out_unlock; > + } > + > + bitmap_set(se->mem_map, msg_first, msg_nr); > + ch->smsg = se->mem_base + msg_first * PAGE_SIZE; > + ch->rmsg = ch->smsg + msg_size / 2; > + ch->msg_size = msg_size; > + ch->complete = complete; > + ch->priv = priv; > + ch->version = se->version; > + > + if (se_set_msg(ch)) > + ch = NULL; > + > +out_unlock: > + mutex_unlock(&se->ch_init_lock); > + > + return ch; > +} > +EXPORT_SYMBOL_GPL(se_init_ch); > + > +static const struct mfd_cell se_devs[] = { > + { .name = "loongson-rng" }, > + { .name = "loongson-tpm" }, > +}; > + > +static int loongson_se_probe(struct platform_device *pdev) This function is totally unreadable. I'm not even going to try, sorry. > +{ > + struct loongson_se *se; > + struct device *dev = &pdev->dev; > + int nr_irq, irq, err, size; > + dma_addr_t paddr; > + > + se = devm_kmalloc(dev, sizeof(*se), GFP_KERNEL); > + if (!se) > + return -ENOMEM; > + dev_set_drvdata(dev, se); > + init_completion(&se->cmd_completion); > + spin_lock_init(&se->dev_lock); > + mutex_init(&se->ch_init_lock); > + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); > + if (device_property_read_u32(dev, "dmam_size", &size)) > + return -ENODEV; > + size = roundup_pow_of_two(size); > + se->mem_base = dmam_alloc_coherent(dev, size, &paddr, GFP_KERNEL); > + if (!se->mem_base) > + return -ENOMEM; > + se->mem_map_pages = size / PAGE_SIZE; > + se->mem_map = devm_bitmap_zalloc(dev, se->mem_map_pages, GFP_KERNEL); > + if (!se->mem_map) > + return -ENOMEM; > + > + se->base = devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(se->base)) > + return PTR_ERR(se->base); > + > + nr_irq = platform_irq_count(pdev); > + if (nr_irq <= 0) > + return -ENODEV; > + while (nr_irq) { > + irq = platform_get_irq(pdev, --nr_irq); > + /* Use the same interrupt handler address. > + * Determine which irq it is accroding > + * SE_S2LINT_STAT register. > + */ > + err = devm_request_irq(dev, irq, se_irq, 0, "loongson-se", se); > + if (err) > + dev_err(dev, "failed to request irq: %d\n", irq); > + } > + > + err = se_init_hw(se, paddr, size); > + if (err) > + return err; > + > + return devm_mfd_add_devices(dev, 0, se_devs, ARRAY_SIZE(se_devs), > + NULL, 0, NULL); > +} > + > +static const struct acpi_device_id loongson_se_acpi_match[] = { > + {"LOON0011", 0}, Spaces near the {}s > + {} > +}; > +MODULE_DEVICE_TABLE(acpi, loongson_se_acpi_match); > + > +static struct platform_driver loongson_se_driver = { > + .probe = loongson_se_probe, > + .driver = { > + .name = "loongson-se", > + .acpi_match_table = loongson_se_acpi_match, > + }, > +}; > +module_platform_driver(loongson_se_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>"); > +MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>"); > +MODULE_DESCRIPTION("Loongson Security Module driver"); > diff --git a/include/linux/mfd/loongson-se.h b/include/linux/mfd/loongson-se.h > new file mode 100644 > index 000000000..f209b7043 > --- /dev/null > +++ b/include/linux/mfd/loongson-se.h > @@ -0,0 +1,75 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* Copyright (C) 2025 Loongson Technology Corporation Limited */ > + > +#ifndef __LOONGSON_SE_H__ > +#define __LOONGSON_SE_H__ > + > +#define SE_DATA_S 0x0 > +#define SE_DATA_L 0x20 > +#define SE_S2LINT_STAT 0x88 > +#define SE_S2LINT_EN 0x8c > +#define SE_S2LINT_SET 0x90 > +#define SE_S2LINT_CL 0x94 > +#define SE_L2SINT_STAT 0x98 > +#define SE_L2SINT_EN 0x9c > +#define SE_L2SINT_SET 0xa0 > +#define SE_L2SINT_CL 0xa4 > + > +/* INT bit definition */ > +#define SE_INT_SETUP BIT(0) > +#define SE_INT_TPM BIT(5) > + > +#define SE_CMD_START 0x0 > +#define SE_CMD_STOP 0x1 > +#define SE_CMD_GETVER 0x2 > +#define SE_CMD_SETBUF 0x3 > +#define SE_CMD_SETMSG 0x4 > + > +#define SE_CMD_RNG 0x100 > +#define SE_CMD_SM2_SIGN 0x200 > +#define SE_CMD_SM2_VSIGN 0x201 > +#define SE_CMD_SM3_DIGEST 0x300 > +#define SE_CMD_SM3_UPDATE 0x301 > +#define SE_CMD_SM3_FINISH 0x302 > +#define SE_CMD_SM4_ECB_ENCRY 0x400 > +#define SE_CMD_SM4_ECB_DECRY 0x401 > +#define SE_CMD_SM4_CBC_ENCRY 0x402 > +#define SE_CMD_SM4_CBC_DECRY 0x403 > +#define SE_CMD_SM4_CTR 0x404 > +#define SE_CMD_TPM 0x500 > +#define SE_CMD_ZUC_INIT_READ 0x600 > +#define SE_CMD_ZUC_READ 0x601 > +#define SE_CMD_SDF 0x700 > + > +#define SE_CH_MAX 32 > +#define SE_CH_RNG 1 > +#define SE_CH_SM2 2 > +#define SE_CH_SM3 3 > +#define SE_CH_SM4 4 > +#define SE_CH_TPM 5 > +#define SE_CH_ZUC 6 > +#define SE_CH_SDF 7 > + > +struct se_channel { > + struct loongson_se *se; > + void *priv; > + u32 version; What do you do with this information? > + u32 id; > + u32 int_bit; > + > + void *smsg; > + void *rmsg; > + int msg_size; > + > + void *data_buffer; > + int data_size; > + u32 off; Most of these variables have terrible names. So either use proper nomenclature or document them. > + > + void (*complete)(struct se_channel *se_ch); Non-subsystem-level call-backs are generally evil. You'd need to provide a very good reason as to why nothing else works. > +}; > + > +struct se_channel *se_init_ch(struct device *dev, int id, int data_size, int msg_size, > + void *priv, void (*complete)(struct se_channel *se_ch)); > +int se_send_ch_requeset(struct se_channel *ch); > + > +#endif > -- > 2.45.2 > -- Lee Jones [李琼斯] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v7 1/6] mfd: Add support for Loongson Security Module 2025-04-04 16:06 ` Lee Jones @ 2025-04-07 7:53 ` Qunqin Zhao 0 siblings, 0 replies; 11+ messages in thread From: Qunqin Zhao @ 2025-04-07 7:53 UTC (permalink / raw) To: Lee Jones Cc: herbert, davem, peterhuewe, jarkko, linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Yinggang Gu, Huacai Chen Hi, Lee 在 2025/4/5 上午12:06, Lee Jones 写道: > On Thu, 03 Apr 2025, Qunqin Zhao wrote: > >> This driver supports Loongson Security Module, which provides the control >> for it's hardware encryption acceleration child devices. >> >> Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> >> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> >> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> >> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> >> --- >> v7: Moved Kconfig entry between MFD_INTEL_M10_BMC_PMCI and MFD_QNAP_MCU. >> >> Renamed se_enable_int_locked() to se_enable_int(), then moved the >> lock out of se_disable_int(). >> >> "se_send_genl_cmd" ---> "se_send_cmd". >> "struct lsse_ch" ---> "struct se_channel". >> >> v6: Replace all "ls6000se" with "loongson" >> v5: Registered "ls6000se-rng" device. >> v3-v4: None >> >> v2: Removed "ls6000se-sdf" device, added "ls6000se-tpm" device. >> Passed dmamem size to SE firmware in se_init_hw() function. >> >> drivers/mfd/Kconfig | 10 + >> drivers/mfd/Makefile | 2 + >> drivers/mfd/loongson-se.c | 374 ++++++++++++++++++++++++++++++++ >> include/linux/mfd/loongson-se.h | 75 +++++++ >> 4 files changed, 461 insertions(+) >> create mode 100644 drivers/mfd/loongson-se.c >> create mode 100644 include/linux/mfd/loongson-se.h >> ... >> diff --git a/drivers/mfd/loongson-se.c b/drivers/mfd/loongson-se.c >> new file mode 100644 >> index 000000000..4f30695de >> --- /dev/null >> +++ b/drivers/mfd/loongson-se.c >> @@ -0,0 +1,374 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* Copyright (C) 2025 Loongson Technology Corporation Limited */ >> + >> +#include <linux/acpi.h> >> +#include <linux/delay.h> >> +#include <linux/device.h> >> +#include <linux/dma-mapping.h> >> +#include <linux/errno.h> >> +#include <linux/init.h> >> +#include <linux/interrupt.h> >> +#include <linux/iopoll.h> >> +#include <linux/kernel.h> >> +#include <linux/mfd/core.h> >> +#include <linux/mfd/loongson-se.h> >> +#include <linux/module.h> >> +#include <linux/platform_device.h> >> + >> +/* >> + * The Loongson Security Module provides the control for hardware >> + * encryption acceleration child devices. The SE framework is >> + * shown as follows: >> + * >> + * +------------+ >> + * | CPU | >> + * +------------+ >> + * ^ ^ >> + * DMA | | IRQ >> + * v v >> + * +-----------------------------------+ >> + * | Loongson Security Module | >> + * +-----------------------------------+ >> + * ^ ^ >> + * channel1 | channel2 | >> + * v v >> + * +-----------+ +----------+ >> + * | sub-dev1 | | sub-dev2 | ..... Max sub-dev31 >> + * +-----------+ +----------+ >> + * >> + * The CPU cannot directly communicate with SE's sub devices, >> + * but sends commands to SE, which processes the commands and >> + * sends them to the corresponding sub devices. >> + */ >> + >> +struct loongson_se { >> + void __iomem *base; >> + u32 version; >> + spinlock_t dev_lock; >> + struct completion cmd_completion; >> + >> + /* dma memory */ >> + void *mem_base; >> + int mem_map_pages; >> + unsigned long *mem_map; >> + >> + /* channel */ >> + struct mutex ch_init_lock; >> + struct se_channel chs[SE_CH_MAX]; >> +}; >> + >> +union se_request { >> + u32 info[8]; >> + struct se_cmd { >> + u32 cmd; >> + u32 info[7]; >> + } req; >> + struct se_res { >> + u32 cmd; >> + u32 cmd_ret; >> + u32 info[6]; >> + } res; >> +}; >> + >> +static inline u32 se_readl(struct loongson_se *se, u32 off) >> +{ >> + return readl(se->base + off); >> +} >> + >> +static inline void se_writel(struct loongson_se *se, u32 val, u32 off) >> +{ >> + writel(val, se->base + off); >> +} > Why are these being abstracted? Just use readl/writel directly. Ok > >> +static void se_enable_int(struct loongson_se *se, u32 int_bit) >> +{ >> + u32 tmp; >> + >> + tmp = se_readl(se, SE_S2LINT_EN); >> + tmp |= int_bit; >> + se_writel(se, tmp, SE_S2LINT_EN); >> +} >> + >> +static void se_disable_int(struct loongson_se *se, u32 int_bit) >> +{ >> + u32 tmp; >> + >> + tmp = se_readl(se, SE_S2LINT_EN); >> + tmp &= ~(int_bit); >> + se_writel(se, tmp, SE_S2LINT_EN); >> +} >> + >> +static int se_poll(struct loongson_se *se, u32 int_bit) >> +{ >> + u32 status; >> + int err; >> + >> + spin_lock_irq(&se->dev_lock); >> + >> + se_enable_int(se, int_bit); >> + se_writel(se, int_bit, SE_L2SINT_SET); >> + err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, >> + !(status & int_bit), 1, 10000); >> + >> + spin_unlock_irq(&se->dev_lock); >> + >> + return err; >> +} >> + >> +static int se_send_requeset(struct loongson_se *se, union se_request *req) > What's a requeset? Request looks confusing, would it be better to call it a command package? >> +{ >> + int i; >> + >> + for (i = 0; i < ARRAY_SIZE(req->info); i++) >> + se_writel(se, req->info[i], SE_DATA_S + i * 4); >> + >> + return se_poll(se, SE_INT_SETUP); >> +} >> + >> +/* >> + * Called by SE's child device driver. >> + * Send a request to the corresponding device. >> + */ >> +int se_send_ch_requeset(struct se_channel *ch) >> +{ >> + return se_poll(ch->se, ch->int_bit); >> +} > More pointless abstraction. Just export se_poll()? Ok > >> +EXPORT_SYMBOL_GPL(se_send_ch_requeset); >> + >> +static int se_get_res(struct loongson_se *se, u32 cmd, union se_request *res) > What are we getting here? What is a 'res'? Response package from the device. >> +{ >> + int i; >> + >> + for (i = 0; i < ARRAY_SIZE(res->info); i++) > for (int i = 0; ... OK > >> + res->info[i] = se_readl(se, SE_DATA_L + i * 4); >> + >> + if (res->res.cmd != cmd) >> + return -EFAULT; >> + >> + return 0; >> +} >> + >> +static int se_send_cmd(struct loongson_se *se, union se_request *req) >> +{ >> + int err; >> + >> + err = se_send_requeset(se, req); >> + if (err) >> + return err; >> + >> + if (!wait_for_completion_timeout(&se->cmd_completion, HZ)) >> + return -ETIME; > -ETIMEDOUT OK > >> + >> + return se_get_res(se, req->req.cmd, req); >> +} >> + >> +static int se_set_msg(struct se_channel *ch) >> +{ >> + struct loongson_se *se = ch->se; >> + union se_request req; >> + >> + req.req.cmd = SE_CMD_SETMSG; >> + req.req.info[0] = ch->id; >> + req.req.info[1] = ch->smsg - se->mem_base; >> + req.req.info[2] = ch->msg_size; >> + >> + return se_send_cmd(se, &req); >> +} >> + >> +static irqreturn_t se_irq(int irq, void *dev_id) > se_irq_handler() OK > >> +{ >> + struct loongson_se *se = (struct loongson_se *)dev_id; >> + struct se_channel *ch; >> + unsigned long flag; >> + u32 int_status; >> + int id; >> + >> + int_status = se_readl(se, SE_S2LINT_STAT); >> + >> + spin_lock_irqsave(&se->dev_lock, flag); >> + se_disable_int(se, int_status); >> + spin_unlock_irqrestore(&se->dev_lock, flag); >> + >> + if (int_status & SE_INT_SETUP) { >> + complete(&se->cmd_completion); >> + int_status &= ~SE_INT_SETUP; >> + se_writel(se, SE_INT_SETUP, SE_S2LINT_CL); >> + } >> + >> + while (int_status) { >> + id = __ffs(int_status); >> + >> + ch = &se->chs[id]; >> + if (ch->complete) >> + ch->complete(ch); >> + int_status &= ~BIT(id); >> + se_writel(se, BIT(id), SE_S2LINT_CL); >> + } >> + >> + return IRQ_HANDLED; >> +} >> + >> +static int se_init_hw(struct loongson_se *se, dma_addr_t addr, int size) >> +{ >> + union se_request req; >> + int err; >> + >> + /* Start engine */ >> + req.req.cmd = SE_CMD_START; >> + err = se_send_cmd(se, &req); >> + if (err) >> + return err; >> + >> + /* Get Version */ >> + req.req.cmd = SE_CMD_GETVER; >> + err = se_send_cmd(se, &req); >> + if (err) >> + return err; >> + se->version = req.res.info[0]; >> + >> + /* Setup dma memory */ > DMA OK > >> + req.req.cmd = SE_CMD_SETBUF; >> + req.req.info[0] = addr & 0xffffffff; >> + req.req.info[1] = addr >> 32; > Define these magic numbers please. OK > >> + req.req.info[2] = size; >> + >> + return se_send_cmd(se, &req); >> +} >> + >> +/* >> + * se_init_ch() - Init the channel used by child device. >> + * >> + * Allocate dma memory as agreed upon with SE on SE probe, > DMA, throughout please. OK > >> + * and register the callback function when the data processing >> + * in this channel is completed. >> + */ >> +struct se_channel *se_init_ch(struct device *dev, int id, int data_size, int msg_size, > What's a "ch"? Channel. Sorry for this confusing abbreviation. > >> + void *priv, void (*complete)(struct se_channel *se_ch)) > I'm not entirely sure what this device is or how it works, but this > isn't really what MFD is for. MFD has no knowledge of channel > initialisation or completion call-backs or the like. What you have here > goes beyond scope. DMA memory used by different sub devices should better be contiguous in physical addresses, so a large block of DMA memory needs to be allocated first in probe function, and then each sub device allocates a small block from this large block of DMA memory during channel initialization. This is why i need a channel initialization function. >> +{ >> + struct loongson_se *se = dev_get_drvdata(dev); >> + struct se_channel *ch; >> + int data_first, data_nr; >> + int msg_first, msg_nr; >> + >> + mutex_lock(&se->ch_init_lock); >> + >> + ch = &se->chs[id]; >> + ch->se = se; >> + ch->id = id; >> + ch->int_bit = BIT(id); > This can be derived from ch->id, so you don't need to store it. > > Or you don't need 'id' - one of the two. Will fix. >> + >> + data_nr = round_up(data_size, PAGE_SIZE) / PAGE_SIZE; >> + data_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, >> + 0, data_nr, 0); >> + if (data_first >= se->mem_map_pages) { >> + ch = NULL; >> + goto out_unlock; >> + } >> + >> + bitmap_set(se->mem_map, data_first, data_nr); >> + ch->off = data_first * PAGE_SIZE; >> + ch->data_buffer = se->mem_base + ch->off; >> + ch->data_size = data_size; >> + >> + msg_nr = round_up(msg_size, PAGE_SIZE) / PAGE_SIZE; >> + msg_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, >> + 0, msg_nr, 0); >> + if (msg_first >= se->mem_map_pages) { >> + ch = NULL; >> + goto out_unlock; >> + } >> + >> + bitmap_set(se->mem_map, msg_first, msg_nr); >> + ch->smsg = se->mem_base + msg_first * PAGE_SIZE; >> + ch->rmsg = ch->smsg + msg_size / 2; >> + ch->msg_size = msg_size; >> + ch->complete = complete; >> + ch->priv = priv; >> + ch->version = se->version; >> + >> + if (se_set_msg(ch)) >> + ch = NULL; >> + >> +out_unlock: >> + mutex_unlock(&se->ch_init_lock); >> + >> + return ch; >> +} >> +EXPORT_SYMBOL_GPL(se_init_ch); >> + >> +static const struct mfd_cell se_devs[] = { >> + { .name = "loongson-rng" }, >> + { .name = "loongson-tpm" }, >> +}; >> + >> +static int loongson_se_probe(struct platform_device *pdev) > This function is totally unreadable. I'm not even going to try, sorry. > This function is mainly responsible for allocating a DMA memory for all sub devices and registering interrupt handling functions. >> +{ >> + struct loongson_se *se; >> + struct device *dev = &pdev->dev; >> + int nr_irq, irq, err, size; >> + dma_addr_t paddr; >> + >> + se = devm_kmalloc(dev, sizeof(*se), GFP_KERNEL); >> + if (!se) >> + return -ENOMEM; >> + dev_set_drvdata(dev, se); >> + init_completion(&se->cmd_completion); >> + spin_lock_init(&se->dev_lock); >> + mutex_init(&se->ch_init_lock); >> + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); >> + if (device_property_read_u32(dev, "dmam_size", &size)) >> + return -ENODEV; >> + size = roundup_pow_of_two(size); >> + se->mem_base = dmam_alloc_coherent(dev, size, &paddr, GFP_KERNEL); >> + if (!se->mem_base) >> + return -ENOMEM; >> + se->mem_map_pages = size / PAGE_SIZE; >> + se->mem_map = devm_bitmap_zalloc(dev, se->mem_map_pages, GFP_KERNEL); >> + if (!se->mem_map) >> + return -ENOMEM; >> + >> + se->base = devm_platform_ioremap_resource(pdev, 0); >> + if (IS_ERR(se->base)) >> + return PTR_ERR(se->base); >> + >> + nr_irq = platform_irq_count(pdev); >> + if (nr_irq <= 0) >> + return -ENODEV; >> + while (nr_irq) { >> + irq = platform_get_irq(pdev, --nr_irq); >> + /* Use the same interrupt handler address. >> + * Determine which irq it is accroding >> + * SE_S2LINT_STAT register. >> + */ >> + err = devm_request_irq(dev, irq, se_irq, 0, "loongson-se", se); >> + if (err) >> + dev_err(dev, "failed to request irq: %d\n", irq); >> + } >> + >> + err = se_init_hw(se, paddr, size); >> + if (err) >> + return err; >> + >> + return devm_mfd_add_devices(dev, 0, se_devs, ARRAY_SIZE(se_devs), >> + NULL, 0, NULL); >> +} >> + >> +static const struct acpi_device_id loongson_se_acpi_match[] = { >> + {"LOON0011", 0}, > Spaces near the {}s OK > >> + {} >> +}; >> +MODULE_DEVICE_TABLE(acpi, loongson_se_acpi_match); >> + >> +static struct platform_driver loongson_se_driver = { >> + .probe = loongson_se_probe, >> + .driver = { >> + .name = "loongson-se", >> + .acpi_match_table = loongson_se_acpi_match, >> + }, >> +}; >> +module_platform_driver(loongson_se_driver); >> + >> +MODULE_LICENSE("GPL"); >> +MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>"); >> +MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>"); >> +MODULE_DESCRIPTION("Loongson Security Module driver"); >> diff --git a/include/linux/mfd/loongson-se.h b/include/linux/mfd/loongson-se.h >> new file mode 100644 >> index 000000000..f209b7043 >> --- /dev/null >> +++ b/include/linux/mfd/loongson-se.h >> @@ -0,0 +1,75 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* Copyright (C) 2025 Loongson Technology Corporation Limited */ >> + >> +#ifndef __LOONGSON_SE_H__ >> +#define __LOONGSON_SE_H__ >> + >> +#define SE_DATA_S 0x0 >> +#define SE_DATA_L 0x20 >> +#define SE_S2LINT_STAT 0x88 >> +#define SE_S2LINT_EN 0x8c >> +#define SE_S2LINT_SET 0x90 >> +#define SE_S2LINT_CL 0x94 >> +#define SE_L2SINT_STAT 0x98 >> +#define SE_L2SINT_EN 0x9c >> +#define SE_L2SINT_SET 0xa0 >> +#define SE_L2SINT_CL 0xa4 >> + >> +/* INT bit definition */ >> +#define SE_INT_SETUP BIT(0) >> +#define SE_INT_TPM BIT(5) >> + >> +#define SE_CMD_START 0x0 >> +#define SE_CMD_STOP 0x1 >> +#define SE_CMD_GETVER 0x2 >> +#define SE_CMD_SETBUF 0x3 >> +#define SE_CMD_SETMSG 0x4 >> + >> +#define SE_CMD_RNG 0x100 >> +#define SE_CMD_SM2_SIGN 0x200 >> +#define SE_CMD_SM2_VSIGN 0x201 >> +#define SE_CMD_SM3_DIGEST 0x300 >> +#define SE_CMD_SM3_UPDATE 0x301 >> +#define SE_CMD_SM3_FINISH 0x302 >> +#define SE_CMD_SM4_ECB_ENCRY 0x400 >> +#define SE_CMD_SM4_ECB_DECRY 0x401 >> +#define SE_CMD_SM4_CBC_ENCRY 0x402 >> +#define SE_CMD_SM4_CBC_DECRY 0x403 >> +#define SE_CMD_SM4_CTR 0x404 >> +#define SE_CMD_TPM 0x500 >> +#define SE_CMD_ZUC_INIT_READ 0x600 >> +#define SE_CMD_ZUC_READ 0x601 >> +#define SE_CMD_SDF 0x700 >> + >> +#define SE_CH_MAX 32 >> +#define SE_CH_RNG 1 >> +#define SE_CH_SM2 2 >> +#define SE_CH_SM3 3 >> +#define SE_CH_SM4 4 >> +#define SE_CH_TPM 5 >> +#define SE_CH_ZUC 6 >> +#define SE_CH_SDF 7 >> + >> +struct se_channel { >> + struct loongson_se *se; >> + void *priv; >> + u32 version; > What do you do with this information? Will remove it. > >> + u32 id; >> + u32 int_bit; >> + >> + void *smsg; >> + void *rmsg; >> + int msg_size; >> + >> + void *data_buffer; >> + int data_size; >> + u32 off; > Most of these variables have terrible names. > > So either use proper nomenclature or document them. OK. > >> + >> + void (*complete)(struct se_channel *se_ch); > Non-subsystem-level call-backs are generally evil. > > You'd need to provide a very good reason as to why nothing else works. How about remove the callback, but define a "struct completion" in struct se_channel? Thanks for your comments. BR, Qunqin. > >> +}; >> + >> +struct se_channel *se_init_ch(struct device *dev, int id, int data_size, int msg_size, >> + void *priv, void (*complete)(struct se_channel *se_ch)); >> +int se_send_ch_requeset(struct se_channel *ch); >> + >> +#endif >> -- >> 2.45.2 >> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v7 2/6] MAINTAINERS: Add entry for Loongson Security Module driver 2025-04-03 2:46 [PATCH v7 0/6] Drivers for Loongson security engine Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 1/6] mfd: Add support for Loongson Security Module Qunqin Zhao @ 2025-04-03 2:46 ` Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 4/6] MAINTAINERS: Add entry for Loongson RNG driver Qunqin Zhao 3 siblings, 0 replies; 11+ messages in thread From: Qunqin Zhao @ 2025-04-03 2:46 UTC (permalink / raw) To: lee, herbert, davem, peterhuewe, jarkko Cc: linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Qunqin Zhao, Huacai Chen This patch adds an entry for Loongson Security Module driver in the list of maintainers. Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> --- v7: Added Huacai's tag v6: "ls6000se.c" --> "loongson_se.c" "ls6000se.h" --> "loongson_se.h" v5: None v4: Changed tile to "Add entry for ....". Lowcased "Maintainers" in commit message. MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e46b60ccf..d2d8ae6a6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13616,6 +13616,13 @@ S: Maintained F: Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml F: drivers/i2c/busses/i2c-ls2x.c +LOONGSON SECURITY MODULE DRIVER +M: Qunqin Zhao <zhaoqunqin@loongson.cn> +L: loongarch@lists.linux.dev +S: Maintained +F: drivers/mfd/loongson-se.c +F: include/linux/mfd/loongson-se.h + LOONGSON-2 SOC SERIES CLOCK DRIVER M: Yinbo Zhu <zhuyinbo@loongson.cn> L: linux-clk@vger.kernel.org -- 2.45.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support 2025-04-03 2:46 [PATCH v7 0/6] Drivers for Loongson security engine Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 1/6] mfd: Add support for Loongson Security Module Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 2/6] MAINTAINERS: Add entry for Loongson Security Module driver Qunqin Zhao @ 2025-04-03 2:46 ` Qunqin Zhao 2025-04-06 9:05 ` Huacai Chen 2025-04-07 4:04 ` Herbert Xu 2025-04-03 2:46 ` [PATCH v7 4/6] MAINTAINERS: Add entry for Loongson RNG driver Qunqin Zhao 3 siblings, 2 replies; 11+ messages in thread From: Qunqin Zhao @ 2025-04-03 2:46 UTC (permalink / raw) To: lee, herbert, davem, peterhuewe, jarkko Cc: linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Qunqin Zhao, Yinggang Gu, Huacai Chen Loongson's Random Number Generator is found inside Loongson security engine. Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> --- v7: Change the lsrng_ prefix to loongson_rng_ v6: Replace all "ls6000se" with "loongson" v2-v5: None drivers/crypto/Kconfig | 1 + drivers/crypto/Makefile | 1 + drivers/crypto/loongson/Kconfig | 6 + drivers/crypto/loongson/Makefile | 2 + drivers/crypto/loongson/loongson-rng.c | 190 +++++++++++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 drivers/crypto/loongson/Kconfig create mode 100644 drivers/crypto/loongson/Makefile create mode 100644 drivers/crypto/loongson/loongson-rng.c diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 19ab145f9..567ed81b0 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -855,5 +855,6 @@ config CRYPTO_DEV_SA2UL source "drivers/crypto/aspeed/Kconfig" source "drivers/crypto/starfive/Kconfig" +source "drivers/crypto/loongson/Kconfig" endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index fef18ffdb..643c3710b 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -50,3 +50,4 @@ obj-y += hisilicon/ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ obj-y += intel/ obj-y += starfive/ +obj-y += loongson/ diff --git a/drivers/crypto/loongson/Kconfig b/drivers/crypto/loongson/Kconfig new file mode 100644 index 000000000..4368701ad --- /dev/null +++ b/drivers/crypto/loongson/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +config CRYPTO_DEV_LOONGSON_RNG + tristate "Support for Loongson RNG Driver" + depends on MFD_LOONGSON_SE + help + Support for Loongson RNG Driver. diff --git a/drivers/crypto/loongson/Makefile b/drivers/crypto/loongson/Makefile new file mode 100644 index 000000000..b8b013c86 --- /dev/null +++ b/drivers/crypto/loongson/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o diff --git a/drivers/crypto/loongson/loongson-rng.c b/drivers/crypto/loongson/loongson-rng.c new file mode 100644 index 000000000..307014992 --- /dev/null +++ b/drivers/crypto/loongson/loongson-rng.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 HiSilicon Limited. */ +/* Copyright (c) 2025 Loongson Technology Corporation Limited. */ + +#include <linux/crypto.h> +#include <linux/err.h> +#include <linux/hw_random.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/mfd/loongson-se.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/random.h> +#include <crypto/internal/rng.h> + +struct loongson_rng_list { + struct mutex lock; + struct list_head list; + int is_init; +}; + +struct lsrng { + bool is_used; + struct se_channel *se_ch; + struct list_head list; + struct completion rng_completion; +}; + +struct loongson_rng_ctx { + struct lsrng *rng; +}; + +struct rng_msg { + u32 cmd; + union { + u32 len; + u32 ret; + } u; + u32 resved; + u32 out_off; + u32 pad[4]; +}; + +static atomic_t rng_active_devs; +static struct loongson_rng_list rng_devices; + +static void loongson_rng_complete(struct se_channel *ch) +{ + struct lsrng *rng = (struct lsrng *)ch->priv; + + complete(&rng->rng_completion); +} + +static int loongson_rng_generate(struct crypto_rng *tfm, const u8 *src, + unsigned int slen, u8 *dstn, unsigned int dlen) +{ + struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm); + struct lsrng *rng = ctx->rng; + struct rng_msg *msg; + int err, len; + + do { + len = min(dlen, PAGE_SIZE); + msg = rng->se_ch->smsg; + msg->u.len = len; + err = se_send_ch_requeset(rng->se_ch); + if (err) + return err; + + wait_for_completion_interruptible(&rng->rng_completion); + + msg = rng->se_ch->rmsg; + if (msg->u.ret) + return -EFAULT; + + memcpy(dstn, rng->se_ch->data_buffer, len); + dlen -= len; + dstn += len; + } while (dlen > 0); + + return 0; +} + +static int loongson_rng_init(struct crypto_tfm *tfm) +{ + struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); + struct lsrng *rng; + int ret = -EBUSY; + + mutex_lock(&rng_devices.lock); + list_for_each_entry(rng, &rng_devices.list, list) { + if (!rng->is_used) { + rng->is_used = true; + ctx->rng = rng; + ret = 0; + break; + } + } + mutex_unlock(&rng_devices.lock); + + return ret; +} + +static void loongson_rng_exit(struct crypto_tfm *tfm) +{ + struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); + + mutex_lock(&rng_devices.lock); + ctx->rng->is_used = false; + mutex_unlock(&rng_devices.lock); +} + +static int no_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) +{ + return 0; +} + +static struct rng_alg loongson_rng_alg = { + .generate = loongson_rng_generate, + .seed = no_seed, + .base = { + .cra_name = "stdrng", + .cra_driver_name = "loongson_stdrng", + .cra_priority = 300, + .cra_ctxsize = sizeof(struct loongson_rng_ctx), + .cra_module = THIS_MODULE, + .cra_init = loongson_rng_init, + .cra_exit = loongson_rng_exit, + }, +}; + +static void loongson_rng_add_to_list(struct lsrng *rng) +{ + mutex_lock(&rng_devices.lock); + list_add_tail(&rng->list, &rng_devices.list); + mutex_unlock(&rng_devices.lock); +} + +static int loongson_rng_probe(struct platform_device *pdev) +{ + struct rng_msg *msg; + struct lsrng *rng; + int ret; + + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); + if (!rng) + return -ENOMEM; + + init_completion(&rng->rng_completion); + rng->se_ch = se_init_ch(pdev->dev.parent, SE_CH_RNG, PAGE_SIZE, + sizeof(struct rng_msg) * 2, rng, loongson_rng_complete); + if (!rng->se_ch) + return -ENODEV; + msg = rng->se_ch->smsg; + msg->cmd = SE_CMD_RNG; + msg->out_off = rng->se_ch->off; + + if (!rng_devices.is_init) { + ret = crypto_register_rng(&loongson_rng_alg); + if (ret) { + dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret); + return ret; + } + INIT_LIST_HEAD(&rng_devices.list); + mutex_init(&rng_devices.lock); + rng_devices.is_init = true; + } + + loongson_rng_add_to_list(rng); + atomic_inc(&rng_active_devs); + + return 0; +} + +static struct platform_driver loongson_rng_driver = { + .probe = loongson_rng_probe, + .driver = { + .name = "loongson-rng", + }, +}; +module_platform_driver(loongson_rng_driver); + +MODULE_ALIAS("platform:loongson-rng"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>"); +MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>"); +MODULE_DESCRIPTION("Loongson random number generator driver"); -- 2.45.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support 2025-04-03 2:46 ` [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support Qunqin Zhao @ 2025-04-06 9:05 ` Huacai Chen 2025-04-08 12:07 ` Qunqin Zhao 2025-04-07 4:04 ` Herbert Xu 1 sibling, 1 reply; 11+ messages in thread From: Huacai Chen @ 2025-04-06 9:05 UTC (permalink / raw) To: Qunqin Zhao Cc: lee, herbert, davem, peterhuewe, jarkko, linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Yinggang Gu, Huacai Chen Hi, Qunqin, On Thu, Apr 3, 2025 at 10:46 AM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote: > > Loongson's Random Number Generator is found inside Loongson security > engine. > > Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> > Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> > Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> > Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> > --- > v7: Change the lsrng_ prefix to loongson_rng_ > v6: Replace all "ls6000se" with "loongson" > v2-v5: None > > drivers/crypto/Kconfig | 1 + > drivers/crypto/Makefile | 1 + > drivers/crypto/loongson/Kconfig | 6 + > drivers/crypto/loongson/Makefile | 2 + > drivers/crypto/loongson/loongson-rng.c | 190 +++++++++++++++++++++++++ > 5 files changed, 200 insertions(+) > create mode 100644 drivers/crypto/loongson/Kconfig > create mode 100644 drivers/crypto/loongson/Makefile > create mode 100644 drivers/crypto/loongson/loongson-rng.c > > diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig > index 19ab145f9..567ed81b0 100644 > --- a/drivers/crypto/Kconfig > +++ b/drivers/crypto/Kconfig > @@ -855,5 +855,6 @@ config CRYPTO_DEV_SA2UL > > source "drivers/crypto/aspeed/Kconfig" > source "drivers/crypto/starfive/Kconfig" > +source "drivers/crypto/loongson/Kconfig" > > endif # CRYPTO_HW > diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile > index fef18ffdb..643c3710b 100644 > --- a/drivers/crypto/Makefile > +++ b/drivers/crypto/Makefile > @@ -50,3 +50,4 @@ obj-y += hisilicon/ > obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ > obj-y += intel/ > obj-y += starfive/ > +obj-y += loongson/ > diff --git a/drivers/crypto/loongson/Kconfig b/drivers/crypto/loongson/Kconfig > new file mode 100644 > index 000000000..4368701ad > --- /dev/null > +++ b/drivers/crypto/loongson/Kconfig > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: GPL-2.0 > +config CRYPTO_DEV_LOONGSON_RNG > + tristate "Support for Loongson RNG Driver" > + depends on MFD_LOONGSON_SE > + help > + Support for Loongson RNG Driver. > diff --git a/drivers/crypto/loongson/Makefile b/drivers/crypto/loongson/Makefile > new file mode 100644 > index 000000000..b8b013c86 > --- /dev/null > +++ b/drivers/crypto/loongson/Makefile > @@ -0,0 +1,2 @@ > +# SPDX-License-Identifier: GPL-2.0 > +obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o > diff --git a/drivers/crypto/loongson/loongson-rng.c b/drivers/crypto/loongson/loongson-rng.c > new file mode 100644 > index 000000000..307014992 > --- /dev/null > +++ b/drivers/crypto/loongson/loongson-rng.c > @@ -0,0 +1,190 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2019 HiSilicon Limited. */ > +/* Copyright (c) 2025 Loongson Technology Corporation Limited. */ > + > +#include <linux/crypto.h> > +#include <linux/err.h> > +#include <linux/hw_random.h> > +#include <linux/io.h> > +#include <linux/iopoll.h> > +#include <linux/kernel.h> > +#include <linux/list.h> > +#include <linux/mfd/loongson-se.h> > +#include <linux/module.h> > +#include <linux/mutex.h> > +#include <linux/platform_device.h> > +#include <linux/random.h> > +#include <crypto/internal/rng.h> > + > +struct loongson_rng_list { > + struct mutex lock; > + struct list_head list; > + int is_init; > +}; > + > +struct lsrng { > + bool is_used; > + struct se_channel *se_ch; > + struct list_head list; > + struct completion rng_completion; > +}; Since there are other comments that should be addressed, you can rename lsrng to loongson_rng to keep consistency. Huacai > + > +struct loongson_rng_ctx { > + struct lsrng *rng; > +}; > + > +struct rng_msg { > + u32 cmd; > + union { > + u32 len; > + u32 ret; > + } u; > + u32 resved; > + u32 out_off; > + u32 pad[4]; > +}; > + > +static atomic_t rng_active_devs; > +static struct loongson_rng_list rng_devices; > + > +static void loongson_rng_complete(struct se_channel *ch) > +{ > + struct lsrng *rng = (struct lsrng *)ch->priv; > + > + complete(&rng->rng_completion); > +} > + > +static int loongson_rng_generate(struct crypto_rng *tfm, const u8 *src, > + unsigned int slen, u8 *dstn, unsigned int dlen) > +{ > + struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm); > + struct lsrng *rng = ctx->rng; > + struct rng_msg *msg; > + int err, len; > + > + do { > + len = min(dlen, PAGE_SIZE); > + msg = rng->se_ch->smsg; > + msg->u.len = len; > + err = se_send_ch_requeset(rng->se_ch); > + if (err) > + return err; > + > + wait_for_completion_interruptible(&rng->rng_completion); > + > + msg = rng->se_ch->rmsg; > + if (msg->u.ret) > + return -EFAULT; > + > + memcpy(dstn, rng->se_ch->data_buffer, len); > + dlen -= len; > + dstn += len; > + } while (dlen > 0); > + > + return 0; > +} > + > +static int loongson_rng_init(struct crypto_tfm *tfm) > +{ > + struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); > + struct lsrng *rng; > + int ret = -EBUSY; > + > + mutex_lock(&rng_devices.lock); > + list_for_each_entry(rng, &rng_devices.list, list) { > + if (!rng->is_used) { > + rng->is_used = true; > + ctx->rng = rng; > + ret = 0; > + break; > + } > + } > + mutex_unlock(&rng_devices.lock); > + > + return ret; > +} > + > +static void loongson_rng_exit(struct crypto_tfm *tfm) > +{ > + struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); > + > + mutex_lock(&rng_devices.lock); > + ctx->rng->is_used = false; > + mutex_unlock(&rng_devices.lock); > +} > + > +static int no_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) > +{ > + return 0; > +} > + > +static struct rng_alg loongson_rng_alg = { > + .generate = loongson_rng_generate, > + .seed = no_seed, > + .base = { > + .cra_name = "stdrng", > + .cra_driver_name = "loongson_stdrng", > + .cra_priority = 300, > + .cra_ctxsize = sizeof(struct loongson_rng_ctx), > + .cra_module = THIS_MODULE, > + .cra_init = loongson_rng_init, > + .cra_exit = loongson_rng_exit, > + }, > +}; > + > +static void loongson_rng_add_to_list(struct lsrng *rng) > +{ > + mutex_lock(&rng_devices.lock); > + list_add_tail(&rng->list, &rng_devices.list); > + mutex_unlock(&rng_devices.lock); > +} > + > +static int loongson_rng_probe(struct platform_device *pdev) > +{ > + struct rng_msg *msg; > + struct lsrng *rng; > + int ret; > + > + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); > + if (!rng) > + return -ENOMEM; > + > + init_completion(&rng->rng_completion); > + rng->se_ch = se_init_ch(pdev->dev.parent, SE_CH_RNG, PAGE_SIZE, > + sizeof(struct rng_msg) * 2, rng, loongson_rng_complete); > + if (!rng->se_ch) > + return -ENODEV; > + msg = rng->se_ch->smsg; > + msg->cmd = SE_CMD_RNG; > + msg->out_off = rng->se_ch->off; > + > + if (!rng_devices.is_init) { > + ret = crypto_register_rng(&loongson_rng_alg); > + if (ret) { > + dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret); > + return ret; > + } > + INIT_LIST_HEAD(&rng_devices.list); > + mutex_init(&rng_devices.lock); > + rng_devices.is_init = true; > + } > + > + loongson_rng_add_to_list(rng); > + atomic_inc(&rng_active_devs); > + > + return 0; > +} > + > +static struct platform_driver loongson_rng_driver = { > + .probe = loongson_rng_probe, > + .driver = { > + .name = "loongson-rng", > + }, > +}; > +module_platform_driver(loongson_rng_driver); > + > +MODULE_ALIAS("platform:loongson-rng"); > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>"); > +MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>"); > +MODULE_DESCRIPTION("Loongson random number generator driver"); > -- > 2.45.2 > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support 2025-04-06 9:05 ` Huacai Chen @ 2025-04-08 12:07 ` Qunqin Zhao 0 siblings, 0 replies; 11+ messages in thread From: Qunqin Zhao @ 2025-04-08 12:07 UTC (permalink / raw) To: Huacai Chen Cc: lee, herbert, davem, peterhuewe, jarkko, linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Yinggang Gu, Huacai Chen 在 2025/4/6 下午5:05, Huacai Chen 写道: > Hi, Qunqin, > > On Thu, Apr 3, 2025 at 10:46 AM Qunqin Zhao <zhaoqunqin@loongson.cn> wrote: >> Loongson's Random Number Generator is found inside Loongson security >> engine. >> >> Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> >> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> >> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> >> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> >> --- >> v7: Change the lsrng_ prefix to loongson_rng_ >> v6: Replace all "ls6000se" with "loongson" >> v2-v5: None >> >> drivers/crypto/Kconfig | 1 + >> drivers/crypto/Makefile | 1 + >> drivers/crypto/loongson/Kconfig | 6 + >> drivers/crypto/loongson/Makefile | 2 + >> drivers/crypto/loongson/loongson-rng.c | 190 +++++++++++++++++++++++++ >> 5 files changed, 200 insertions(+) >> create mode 100644 drivers/crypto/loongson/Kconfig >> create mode 100644 drivers/crypto/loongson/Makefile >> create mode 100644 drivers/crypto/loongson/loongson-rng.c >> >> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig >> index 19ab145f9..567ed81b0 100644 >> --- a/drivers/crypto/Kconfig >> +++ b/drivers/crypto/Kconfig >> @@ -855,5 +855,6 @@ config CRYPTO_DEV_SA2UL >> >> source "drivers/crypto/aspeed/Kconfig" >> source "drivers/crypto/starfive/Kconfig" >> +source "drivers/crypto/loongson/Kconfig" >> >> endif # CRYPTO_HW >> diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile >> index fef18ffdb..643c3710b 100644 >> --- a/drivers/crypto/Makefile >> +++ b/drivers/crypto/Makefile >> @@ -50,3 +50,4 @@ obj-y += hisilicon/ >> obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ >> obj-y += intel/ >> obj-y += starfive/ >> +obj-y += loongson/ >> diff --git a/drivers/crypto/loongson/Kconfig b/drivers/crypto/loongson/Kconfig >> new file mode 100644 >> index 000000000..4368701ad >> --- /dev/null >> +++ b/drivers/crypto/loongson/Kconfig >> @@ -0,0 +1,6 @@ >> +# SPDX-License-Identifier: GPL-2.0 >> +config CRYPTO_DEV_LOONGSON_RNG >> + tristate "Support for Loongson RNG Driver" >> + depends on MFD_LOONGSON_SE >> + help >> + Support for Loongson RNG Driver. >> diff --git a/drivers/crypto/loongson/Makefile b/drivers/crypto/loongson/Makefile >> new file mode 100644 >> index 000000000..b8b013c86 >> --- /dev/null >> +++ b/drivers/crypto/loongson/Makefile >> @@ -0,0 +1,2 @@ >> +# SPDX-License-Identifier: GPL-2.0 >> +obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o >> diff --git a/drivers/crypto/loongson/loongson-rng.c b/drivers/crypto/loongson/loongson-rng.c >> new file mode 100644 >> index 000000000..307014992 >> --- /dev/null >> +++ b/drivers/crypto/loongson/loongson-rng.c >> @@ -0,0 +1,190 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* Copyright (c) 2019 HiSilicon Limited. */ >> +/* Copyright (c) 2025 Loongson Technology Corporation Limited. */ >> + >> +#include <linux/crypto.h> >> +#include <linux/err.h> >> +#include <linux/hw_random.h> >> +#include <linux/io.h> >> +#include <linux/iopoll.h> >> +#include <linux/kernel.h> >> +#include <linux/list.h> >> +#include <linux/mfd/loongson-se.h> >> +#include <linux/module.h> >> +#include <linux/mutex.h> >> +#include <linux/platform_device.h> >> +#include <linux/random.h> >> +#include <crypto/internal/rng.h> >> + >> +struct loongson_rng_list { >> + struct mutex lock; >> + struct list_head list; >> + int is_init; >> +}; >> + >> +struct lsrng { >> + bool is_used; >> + struct se_channel *se_ch; >> + struct list_head list; >> + struct completion rng_completion; >> +}; > Since there are other comments that should be addressed, you can > rename lsrng to loongson_rng to keep consistency. OK, thanks Qunqin. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support 2025-04-03 2:46 ` [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support Qunqin Zhao 2025-04-06 9:05 ` Huacai Chen @ 2025-04-07 4:04 ` Herbert Xu 2025-04-08 12:06 ` Qunqin Zhao 1 sibling, 1 reply; 11+ messages in thread From: Herbert Xu @ 2025-04-07 4:04 UTC (permalink / raw) To: Qunqin Zhao Cc: lee, davem, peterhuewe, jarkko, linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Yinggang Gu, Huacai Chen On Thu, Apr 03, 2025 at 10:46:42AM +0800, Qunqin Zhao wrote: > Loongson's Random Number Generator is found inside Loongson security > engine. Is this a hardware RNG or a pseudo RNG? If it's pseudo, it should provide a means of reseeding. If it's a hardware RNG it should register with hwrng. Cheers, -- Email: Herbert Xu <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support 2025-04-07 4:04 ` Herbert Xu @ 2025-04-08 12:06 ` Qunqin Zhao 0 siblings, 0 replies; 11+ messages in thread From: Qunqin Zhao @ 2025-04-08 12:06 UTC (permalink / raw) To: Herbert Xu Cc: lee, davem, peterhuewe, jarkko, linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Yinggang Gu, Huacai Chen 在 2025/4/7 下午12:04, Herbert Xu 写道: > On Thu, Apr 03, 2025 at 10:46:42AM +0800, Qunqin Zhao wrote: >> Loongson's Random Number Generator is found inside Loongson security >> engine. > Is this a hardware RNG or a pseudo RNG? If it's pseudo, it should > provide a means of reseeding. Will provide a means of reseeding. Thanks for your comments. BR, Qunqin. > If it's a hardware RNG it should register with hwrng. > > Cheers, ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v7 4/6] MAINTAINERS: Add entry for Loongson RNG driver 2025-04-03 2:46 [PATCH v7 0/6] Drivers for Loongson security engine Qunqin Zhao ` (2 preceding siblings ...) 2025-04-03 2:46 ` [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support Qunqin Zhao @ 2025-04-03 2:46 ` Qunqin Zhao 3 siblings, 0 replies; 11+ messages in thread From: Qunqin Zhao @ 2025-04-03 2:46 UTC (permalink / raw) To: lee, herbert, davem, peterhuewe, jarkko Cc: linux-kernel, loongarch, linux-crypto, jgg, linux-integrity, pmenzel, Qunqin Zhao, Huacai Chen This patch adds an entry for Loongson RNG driver in the list of maintainers. Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> --- v7: Added Huacai's tag v5-v6: None v4: Changed tile to "Add entry for ...". Lowcased "Maintainers" in commit message. MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d2d8ae6a6..814205642 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13602,6 +13602,12 @@ S: Maintained F: Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml F: drivers/gpio/gpio-loongson-64bit.c +LOONGSON CRYPTO DRIVER +M: Qunqin Zhao <zhaoqunqin@loongson.com> +L: linux-crypto@vger.kernel.org +S: Maintained +F: drivers/crypto/loongson/ + LOONGSON-2 APB DMA DRIVER M: Binbin Zhou <zhoubinbin@loongson.cn> L: dmaengine@vger.kernel.org -- 2.45.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-04-08 12:08 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-04-03 2:46 [PATCH v7 0/6] Drivers for Loongson security engine Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 1/6] mfd: Add support for Loongson Security Module Qunqin Zhao 2025-04-04 16:06 ` Lee Jones 2025-04-07 7:53 ` Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 2/6] MAINTAINERS: Add entry for Loongson Security Module driver Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 3/6] crypto: loongson - add Loongson RNG driver support Qunqin Zhao 2025-04-06 9:05 ` Huacai Chen 2025-04-08 12:07 ` Qunqin Zhao 2025-04-07 4:04 ` Herbert Xu 2025-04-08 12:06 ` Qunqin Zhao 2025-04-03 2:46 ` [PATCH v7 4/6] MAINTAINERS: Add entry for Loongson RNG driver Qunqin Zhao
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).