[PATCH OLK-6.6] tpm: Add a driver for Loongson TPM device

From: Qunqin Zhao <zhaoqunqin@loongson.cn> LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICATLF CVE: NA -------------------------------- Loongson security engine supports random number generation, hash, symmetric encryption and asymmetric encryption. Based on these encryption functions, TPM2 have been implemented in the Loongson security engine firmware. This driver is responsible for copying data into the memory visible to the firmware and receiving data from the firmware. Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> Change-Id: I029740a822afd797d211a868b36e5ba8dd3b6b6a --- MAINTAINERS | 5 ++ drivers/char/Kconfig | 1 + drivers/char/loongson_se.c | 33 ++++++---- drivers/char/tpm/Kconfig | 9 +++ drivers/char/tpm/Makefile | 1 + drivers/char/tpm/tpm_loongson.c | 103 ++++++++++++++++++++++++++++++++ include/soc/loongson/se.h | 1 + 7 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 drivers/char/tpm/tpm_loongson.c diff --git a/MAINTAINERS b/MAINTAINERS index c6a3ac61989c..546459e25d4a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7337,6 +7337,11 @@ F: Documentation/networking/net_dim.rst F: include/linux/dim.h F: lib/dim/ +LOONGSON TPM DRIVER +M: Qunqin Zhao <zhaoqunqin@loongson.cn> +S: Maintained +F: drivers/char/tpm/tpm_loongson.c + DYNAMIC THERMAL POWER MANAGEMENT (DTPM) M: Daniel Lezcano <daniel.lezcano@kernel.org> L: linux-pm@vger.kernel.org diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ea7ace87a9df..1d2957bc100d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -394,6 +394,7 @@ config UV_MMTIMER config LOONGSON_SE tristate "LOONGSON SECURITY MODULE Interface" depends on LOONGARCH + select MFD_CORE default m help If you have LOONGSON security module (SE) support say Yes and it diff --git a/drivers/char/loongson_se.c b/drivers/char/loongson_se.c index 853f7e10cd41..c9bd51adc792 100644 --- a/drivers/char/loongson_se.c +++ b/drivers/char/loongson_se.c @@ -14,6 +14,7 @@ #include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mfd/core.h> #include <linux/platform_device.h> #include <soc/loongson/se.h> @@ -309,19 +310,25 @@ int se_send_ch_requeset(struct lsse_ch *ch) { struct loongson_se *se; u32 status, int_bit; + int err; se = ch->se; int_bit = ch->int_bit; + mutex_lock(&se->ch_init_lock); if ((se_readl(se, SE_L2SINT_STAT) & int_bit) || - !(se_readl(se, SE_L2SINT_EN) & int_bit)) + !(se_readl(se, SE_L2SINT_EN) & int_bit)) { + mutex_unlock(&se->ch_init_lock); return -EBUSY; + } se_enable_int(se, int_bit); se_writel(se, int_bit, SE_L2SINT_SET); - return readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, + err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, !(status & int_bit), 10, 10000); + mutex_unlock(&se->ch_init_lock); + return err; } EXPORT_SYMBOL_GPL(se_send_ch_requeset); @@ -337,10 +344,10 @@ struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_si { struct loongson_se *se = dev_get_drvdata(dev); struct lsse_ch *ch; - unsigned long flag; int data_first, data_nr; int msg_first, msg_nr; + mutex_lock(&se->ch_init_lock); if (!se) { pr_err("SE has bot been initialized\n"); return NULL; @@ -356,8 +363,6 @@ struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_si return NULL; } - spin_lock_irqsave(&se->dev_lock, flag); - ch = &se->chs[id]; ch->se = se; ch->id = id; @@ -369,7 +374,7 @@ struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_si 0, data_nr, 0); if (data_first >= se->mem_map_pages) { dev_err(se->dev, "Insufficient memory space\n"); - spin_unlock_irqrestore(&se->dev_lock, flag); + mutex_unlock(&se->ch_init_lock); return NULL; } @@ -384,7 +389,7 @@ struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_si if (msg_first >= se->mem_map_pages) { dev_err(se->dev, "Insufficient memory space\n"); bitmap_clear(se->mem_map, data_first, data_nr); - spin_unlock_irqrestore(&se->dev_lock, flag); + mutex_unlock(&se->ch_init_lock); return NULL; } @@ -396,14 +401,15 @@ struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_si ch->priv = priv; spin_lock_init(&ch->ch_lock); - spin_unlock_irqrestore(&se->dev_lock, flag); if (loongson_se_set_msg(ch)) { dev_err(se->dev, "Channel %d setup message address failed\n", id); + mutex_unlock(&se->ch_init_lock); return NULL; } se_enable_int(se, ch->int_bit); + mutex_unlock(&se->ch_init_lock); return ch; } @@ -448,6 +454,10 @@ void se_deinit_ch(struct lsse_ch *ch) } EXPORT_SYMBOL_GPL(se_deinit_ch); +static const struct mfd_cell engines[] = { + { .name = "loongson-tpm" }, +}; + static int loongson_se_probe(struct platform_device *pdev) { struct loongson_se *se; @@ -460,6 +470,7 @@ static int loongson_se_probe(struct platform_device *pdev) se->dev = dev; dev_set_drvdata(dev, se); init_completion(&se->cmd_completion); + mutex_init(&se->ch_init_lock); spin_lock_init(&se->cmd_lock); spin_lock_init(&se->dev_lock); /* Setup DMA buffer */ @@ -497,10 +508,12 @@ static int loongson_se_probe(struct platform_device *pdev) } err = se_init_hw(se, se->mem_addr, size); - if (err) + if (err) { se_disable_hw(se); + return err; + } - return err; + return devm_mfd_add_devices(dev, 0, engines, ARRAY_SIZE(engines), NULL, 0, NULL); } static const struct acpi_device_id loongson_se_acpi_match[] = { diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 301284e07603..3524b2e6086e 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -174,6 +174,15 @@ config TCG_IBMVTPM will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_ibmvtpm. +config TCG_LOONGSON + tristate "Loongson TPM Interface" + depends on LOONGSON_SE + help + If you want to make Loongson TPM support available, say Yes and + it will be accessible from within Linux. To compile this + driver as a module, choose M here; the module will be called + tpm_loongson. + config TCG_XEN tristate "XEN TPM Interface" depends on TCG_TPM && XEN diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 8f868c9b9ce7..ea2919ddbd6e 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_TCG_VTPM_PROXY) += tpm_vtpm_proxy.o obj-$(CONFIG_TCG_FTPM_TEE) += tpm_ftpm_tee.o obj-$(CONFIG_TCG_HYGON) += tpm_hygon.o obj-$(CONFIG_TCM_HYGON) += tcm_hygon.o +obj-$(CONFIG_TCG_LOONGSON) += tpm_loongson.o diff --git a/drivers/char/tpm/tpm_loongson.c b/drivers/char/tpm/tpm_loongson.c new file mode 100644 index 000000000000..3c27d86b77ba --- /dev/null +++ b/drivers/char/tpm/tpm_loongson.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025 Loongson Technology Corporation Limited. */ + +#include <linux/device.h> +#include <soc/loongson/se.h> +#include <linux/platform_device.h> +#include <linux/wait.h> + +#include "tpm.h" + +struct tpm_loongson_msg { + u32 cmd; + u32 data_off; + u32 data_len; + u32 info[5]; +}; + +struct tpm_loongson_dev { + struct lsse_ch *se_ch; + struct completion tpm_loongson_completion; +}; + +static void tpm_loongson_complete(struct lsse_ch *ch) +{ + struct tpm_loongson_dev *td = ch->priv; + + complete(&td->tpm_loongson_completion); +} + +static int tpm_loongson_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct tpm_loongson_dev *td = dev_get_drvdata(&chip->dev); + struct tpm_loongson_msg *rmsg; + int sig; + + sig = wait_for_completion_interruptible(&td->tpm_loongson_completion); + if (sig) + return sig; + + rmsg = td->se_ch->rmsg; + memcpy(buf, td->se_ch->data_buffer, rmsg->data_len); + + return rmsg->data_len; +} + +static int tpm_loongson_send(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct tpm_loongson_dev *td = dev_get_drvdata(&chip->dev); + struct tpm_loongson_msg *smsg = td->se_ch->smsg; + + memcpy(td->se_ch->data_buffer, buf, count); + smsg->data_len = count; + + return se_send_ch_requeset(td->se_ch); +} + +static const struct tpm_class_ops tpm_loongson_ops = { + .flags = TPM_OPS_AUTO_STARTUP, + .recv = tpm_loongson_recv, + .send = tpm_loongson_send, +}; + +static int tpm_loongson_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tpm_loongson_msg *smsg; + struct tpm_loongson_dev *td; + struct tpm_chip *chip; + + td = devm_kzalloc(dev, sizeof(struct tpm_loongson_dev), GFP_KERNEL); + if (!td) + return -ENOMEM; + + init_completion(&td->tpm_loongson_completion); + td->se_ch = se_init_ch(dev->parent, SE_CH_TPM, PAGE_SIZE, + 2 * sizeof(struct tpm_loongson_msg), td, + tpm_loongson_complete); + if (!td->se_ch) + return -ENODEV; + smsg = td->se_ch->smsg; + smsg->cmd = SE_CMD_TPM; + smsg->data_off = td->se_ch->data_buffer - td->se_ch->se->mem_base; + + chip = tpmm_chip_alloc(dev, &tpm_loongson_ops); + if (IS_ERR(chip)) + return PTR_ERR(chip); + chip->flags = TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_IRQ; + dev_set_drvdata(&chip->dev, td); + + return tpm_chip_register(chip); +} + +static struct platform_driver tpm_loongson_driver = { + .probe = tpm_loongson_probe, + .driver = { + .name = "loongson-tpm", + }, +}; +module_platform_driver(tpm_loongson_driver); + +MODULE_ALIAS("platform:loongson-tpm"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Loongson TPM driver"); diff --git a/include/soc/loongson/se.h b/include/soc/loongson/se.h index d9864e3f3b85..22872f7d1a19 100644 --- a/include/soc/loongson/se.h +++ b/include/soc/loongson/se.h @@ -109,6 +109,7 @@ struct loongson_se { void __iomem *base; u32 version; u32 ch_status; + struct mutex ch_init_lock; spinlock_t cmd_lock; spinlock_t dev_lock; -- 2.43.0

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/16465 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/BNY... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/16465 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/BNY...
participants (2)
-
Hongchen Zhang
-
patchwork bot