Commit ed3ea64c authored by Zhao Qunqin's avatar Zhao Qunqin Committed by Hongchen Zhang
Browse files

drivers/char: add ACPI firmware support for Loongson SE driver

LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IBENRY


CVE: NA

--------------------------------

ACPI HID for Loongson SE is "LOONG0011", for Loongson SDF is
"LOON0012". And cleanned up coding style. Moved SE header
file form arch/loongarch/include/asm to include/soc/loongson.

Signed-off-by: default avatarZhao Qunqin <zhaoqunqin@loongson.cn>
Change-Id: Ie15d377ce0435643ac950b34dff48142f21f2d02
parent b94e805d
Loading
Loading
Loading
Loading
+181 −259
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2024 Loongson Technology Corporation Limited
 */

#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/iopoll.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/se.h>

static int se_mem_size = 0x800000;
module_param(se_mem_size, int, 0444);
MODULE_PARM_DESC(se_mem_size, "LOONGSON SE shared memory size");

static int se_mem_page = PAGE_SIZE;
module_param(se_mem_page, int, 0444);
MODULE_PARM_DESC(se_mem_page, "LOONGSON SE shared memory page size");

static struct loongson_se se_dev;

static int lsse_open(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t lsse_write(struct file *filp, const char __user *buf,
		size_t cnt, loff_t *offt)
{
	return 0;
}

static const struct file_operations lsse_fops = {
	.owner = THIS_MODULE,
	.open = lsse_open,
	.write = lsse_write,
};

static const struct miscdevice lsse_miscdev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "loongson-se",
	.fops = &lsse_fops,
};

static inline u32 se_readl(u64 addr)
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <soc/loongson/se.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      |
 *        +-----------------------------------+
 *             ^                ^
 *    chnnel0  |       channel1 |
 *             v                v
 *        +-----------+    +----------+
 *        | sub-dev0  |    | sub-dev1 |  ..... 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.
 */

static inline u32 se_readl(struct loongson_se *se, u32 off)
{
	return readl(se_dev.base + addr);
	return readl(se->base + off);
}

static inline void se_writel(u32 val, u64 addr)
static inline void se_writel(struct loongson_se *se, u32 val, u32 off)
{
	writel(val, se_dev.base + addr);
	writel(val, se->base + off);
}

static inline bool se_ch_status(struct loongson_se *se, u32 int_bit)
{
	return !!(se->ch_status & int_bit) == 1;
	return !!(se->ch_status & int_bit);
}

static void se_enable_int(struct loongson_se *se, u32 int_bit)
@@ -69,14 +63,11 @@ static void se_enable_int(struct loongson_se *se, u32 int_bit)
	unsigned long flag;
	u32 tmp;

	if (!int_bit)
		return;

	spin_lock_irqsave(&se->dev_lock, flag);

	tmp = se_readl(SE_S2LINT_EN);
	tmp = se_readl(se, SE_S2LINT_EN);
	tmp |= int_bit;
	se_writel(tmp, SE_S2LINT_EN);
	se_writel(se, tmp, SE_S2LINT_EN);

	spin_unlock_irqrestore(&se->dev_lock, flag);
}
@@ -86,40 +77,34 @@ static void se_disable_int(struct loongson_se *se, u32 int_bit)
	unsigned long flag;
	u32 tmp;

	if (!int_bit)
		return;

	spin_lock_irqsave(&se->dev_lock, flag);

	tmp = se_readl(SE_S2LINT_EN);
	tmp = se_readl(se, SE_S2LINT_EN);
	tmp &= ~(int_bit);
	se_writel(tmp, SE_S2LINT_EN);
	se_writel(se, tmp, SE_S2LINT_EN);

	spin_unlock_irqrestore(&se->dev_lock, flag);
}

static int se_send_requeset(struct loongson_se *se,
		struct se_mailbox_data *req)
static int se_send_requeset(struct loongson_se *se, struct se_data *req)
{
	unsigned long flag;
	u32 status;
	int err = 0;
	int err;
	int i;

	if (!se || !req)
		return -EINVAL;

	if (se_readl(SE_L2SINT_STAT) ||
			!(se_readl(SE_L2SINT_EN) & req->int_bit))
	if (se_readl(se, SE_L2SINT_STAT) ||
	    !(se_readl(se, SE_L2SINT_EN) & req->int_bit))
		return -EBUSY;

	spin_lock_irqsave(&se->cmd_lock, flag);

	for (i = 0; i < ARRAY_SIZE(req->u.mailbox); i++)
		se_writel(req->u.mailbox[i], SE_MAILBOX_S + i * 4);

	se_writel(req->int_bit, SE_L2SINT_SET);

	for (i = 0; i < ARRAY_SIZE(req->u.data); i++)
		se_writel(se, req->u.data[i], SE_DATA_S + i * 4);
	se_writel(se, req->int_bit, SE_L2SINT_SET);
	err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status,
						!(status & req->int_bit), 10, 10000);

@@ -128,8 +113,7 @@ static int se_send_requeset(struct loongson_se *se,
	return err;
}

static int se_get_response(struct loongson_se *se,
		struct se_mailbox_data *res)
static int se_get_response(struct loongson_se *se, struct se_data *res)
{
	unsigned long flag;
	int i;
@@ -137,15 +121,14 @@ static int se_get_response(struct loongson_se *se,
	if (!se || !res)
		return -EINVAL;

	if ((se_readl(SE_S2LINT_STAT) & res->int_bit) == 0)
	if ((se_readl(se, SE_S2LINT_STAT) & res->int_bit) == 0)
		return -EBUSY;

	spin_lock_irqsave(&se->cmd_lock, flag);

	for (i = 0; i < ARRAY_SIZE(res->u.mailbox); i++)
		res->u.mailbox[i] = se_readl(SE_MAILBOX_L + i * 4);

	se_writel(res->int_bit, SE_S2LINT_CL);
	for (i = 0; i < ARRAY_SIZE(res->u.data); i++)
		res->u.data[i] = se_readl(se, SE_DATA_L + i * 4);
	se_writel(se, res->int_bit, SE_S2LINT_CL);

	spin_unlock_irqrestore(&se->cmd_lock, flag);

@@ -153,10 +136,8 @@ static int se_get_response(struct loongson_se *se,
}

static int loongson_se_get_res(struct loongson_se *se, u32 int_bit, u32 cmd,
		struct se_mailbox_data *res)
			       struct se_data *res)
{
	int err = 0;

	res->int_bit = int_bit;

	if (se_get_response(se, res)) {
@@ -165,21 +146,19 @@ static int loongson_se_get_res(struct loongson_se *se, u32 int_bit, u32 cmd,
	}

	/* Check response */
	if (res->u.res.cmd == cmd)
		err = 0;
	else {
	if (res->u.res.cmd != cmd) {
		dev_err(se->dev, "Response cmd is 0x%x, not expect cmd 0x%x.\n",
			res->u.res.cmd, cmd);
		err = -EFAULT;
		return -EFAULT;
	}

	return err;
	return 0;
}

static int se_send_genl_cmd(struct loongson_se *se, struct se_mailbox_data *req,
		struct se_mailbox_data *res, int retry)
static int se_send_genl_cmd(struct loongson_se *se, struct se_data *req,
			    struct se_data *res, int retry)
{
	int err = 0, cnt = 0;
	int err, cnt = 0;

try_again:
	if (cnt++ >= retry) {
@@ -193,12 +172,10 @@ static int se_send_genl_cmd(struct loongson_se *se, struct se_mailbox_data *req,
	if (err)
		goto try_again;

	if (!wait_for_completion_timeout(&se->cmd_completion,
			msecs_to_jiffies(0x1000))) {
	if (!wait_for_completion_timeout(&se->cmd_completion, HZ)) {
		se_enable_int(se, req->int_bit);
		goto try_again;
	}

	err = loongson_se_get_res(se, req->int_bit, req->u.gcmd.cmd, res);
	if (err || res->u.res.cmd_ret) {
		se_enable_int(se, req->int_bit);
@@ -214,8 +191,8 @@ static int se_send_genl_cmd(struct loongson_se *se, struct se_mailbox_data *req,
static int loongson_se_set_msg(struct lsse_ch *ch)
{
	struct loongson_se *se = ch->se;
	struct se_mailbox_data req = {0};
	struct se_mailbox_data res = {0};
	struct se_data req = {0};
	struct se_data res = {0};
	int err;

	req.int_bit = SE_INT_SETUP;
@@ -225,8 +202,8 @@ static int loongson_se_set_msg(struct lsse_ch *ch)
	req.u.gcmd.info[1] = ch->smsg - se->mem_base;
	req.u.gcmd.info[2] = ch->msg_size;

	dev_dbg(se->dev, "Set Channel %d msg off 0x%x, msg size %d\n", ch->id,
			req.u.gcmd.info[1], req.u.gcmd.info[2]);
	dev_dbg(se->dev, "Set Channel %d msg off 0x%x, msg size %d\n",
		ch->id, req.u.gcmd.info[1], req.u.gcmd.info[2]);

	err = se_send_genl_cmd(se, &req, &res, 5);
	if (res.u.res.cmd_ret)
@@ -235,13 +212,13 @@ static int loongson_se_set_msg(struct lsse_ch *ch)
	return err;
}

static irqreturn_t loongson_se_irq(int irq, void *dev_id)
static irqreturn_t se_irq(int irq, void *dev_id)
{
	struct loongson_se *se = (struct loongson_se *)dev_id;
	struct lsse_ch *ch;
	u32 int_status;

	int_status = se_readl(SE_S2LINT_STAT);
	int_status = se_readl(se, SE_S2LINT_STAT);

	dev_dbg(se->dev, "%s int status is 0x%x\n", __func__, int_status);

@@ -259,32 +236,23 @@ static irqreturn_t loongson_se_irq(int irq, void *dev_id)
		if (ch->complete)
			ch->complete(ch);
		int_status &= ~BIT(id);
		se_writel(BIT(id), SE_S2LINT_CL);
		se_writel(se, BIT(id), SE_S2LINT_CL);
	}

	return IRQ_HANDLED;
}

static int se_init_hw(struct loongson_se *se)
static int se_init_hw(struct loongson_se *se, dma_addr_t addr, int size)
{
	struct se_mailbox_data req = {0};
	struct se_mailbox_data res = {0};
	struct device *dev = se->dev;
	struct se_data req;
	struct se_data res;
	int err, retry = 5;
	u64 size;

	size = se_mem_size;

	if (size & (size - 1)) {
		size = roundup_pow_of_two(size);
		se_mem_size = size;
	}

	se_enable_int(se, SE_INT_SETUP);

	/* Start engine */
	memset(&req, 0, sizeof(struct se_mailbox_data));
	memset(&res, 0, sizeof(struct se_mailbox_data));
	memset(&req, 0, sizeof(struct se_data));
	memset(&res, 0, sizeof(struct se_data));
	req.int_bit = SE_INT_SETUP;
	req.u.gcmd.cmd = SE_CMD_START;
	err = se_send_genl_cmd(se, &req, &res, retry);
@@ -292,99 +260,82 @@ static int se_init_hw(struct loongson_se *se)
		return err;

	/* Get Version */
	memset(&req, 0, sizeof(struct se_mailbox_data));
	memset(&res, 0, sizeof(struct se_mailbox_data));
	memset(&req, 0, sizeof(struct se_data));
	memset(&res, 0, sizeof(struct se_data));
	req.int_bit = SE_INT_SETUP;
	req.u.gcmd.cmd = SE_CMD_GETVER;
	err = se_send_genl_cmd(se, &req, &res, retry);
	if (err)
		return err;

	se->version = res.u.res.info[0];

	/* Setup data buffer */
	se->mem_base = dmam_alloc_coherent(dev, size,
			&se->mem_addr, GFP_KERNEL);
	if (!se->mem_base)
		return -ENOMEM;

	memset(se->mem_base, 0, size);

	memset(&req, 0, sizeof(struct se_mailbox_data));
	memset(&res, 0, sizeof(struct se_mailbox_data));
	/* Set shared mem */
	memset(&req, 0, sizeof(struct se_data));
	memset(&res, 0, sizeof(struct se_data));
	req.int_bit = SE_INT_SETUP;
	req.u.gcmd.cmd = SE_CMD_SETBUF;
	/* MMAP */
	req.u.gcmd.info[0] = (se->mem_addr & 0xffffffff) | 0x80;
	req.u.gcmd.info[1] = se->mem_addr >> 32;
	req.u.gcmd.info[0] = addr & 0xffffffff;
	req.u.gcmd.info[1] = addr >> 32;
	/* MASK */
	req.u.gcmd.info[2] = ~(size - 1);
	req.u.gcmd.info[3] = 0xffffffff;

	pr_debug("Set win mmap 0x%llx, mask 0x%llx\n",
			((u64)req.u.gcmd.info[1] << 32) | req.u.gcmd.info[0],
			((u64)req.u.gcmd.info[3] << 32) | req.u.gcmd.info[2]);

	err = se_send_genl_cmd(se, &req, &res, retry);
	if (err)
		return err;

	se->mem_map_size = size / se_mem_page;
	se->mem_map = bitmap_zalloc(se->mem_map_size, GFP_KERNEL);
	if (!se->mem_map)
		return -ENOMEM;

	dev_info(se->dev, "SE module setup down, shared memory size is 0x%x bytes, memory page size is 0x%x bytes\n",
					se_mem_size, se_mem_page);
	pr_debug("Set win mmap 0x%llx, mask 0x%llx\n",
		 ((u64)req.u.gcmd.info[1] << 32) | req.u.gcmd.info[0],
		 ((u64)req.u.gcmd.info[3] << 32) | req.u.gcmd.info[2]);

	return err;
}

static void loongson_se_disable_hw(struct loongson_se *se)
static void se_disable_hw(struct loongson_se *se)
{
	struct se_mailbox_data req = {0};
	struct se_mailbox_data res = {0};
	int retry = 5;
	struct se_data req = {0};
	struct se_data res = {0};

	/* Stop engine */
	req.int_bit = SE_INT_SETUP;
	req.u.gcmd.cmd = SE_CMD_STOP;
	se_send_genl_cmd(se, &req, &res, retry);

	se_send_genl_cmd(se, &req, &res, 5);
	se_disable_int(se, SE_INT_ALL);
	kfree(se->mem_map);
}

/*
 * Called by SE's child device driver.
 */
int se_send_ch_requeset(struct lsse_ch *ch)
{
	struct loongson_se *se;
	u32 status, int_bit;
	int err = 0;

	if (!ch)
		return -EINVAL;

	se = ch->se;
	int_bit = ch->int_bit;

	if ((se_readl(SE_L2SINT_STAT) & int_bit) ||
			!(se_readl(SE_L2SINT_EN) & int_bit))
	if ((se_readl(se, SE_L2SINT_STAT) & int_bit) ||
	    !(se_readl(se, SE_L2SINT_EN) & int_bit))
		return -EBUSY;

	se_enable_int(se, int_bit);
	se_writel(int_bit, SE_L2SINT_SET);
	se_writel(se, int_bit, SE_L2SINT_SET);

	err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status,
	return readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status,
						 !(status & int_bit), 10, 10000);

	return err;
}
EXPORT_SYMBOL_GPL(se_send_ch_requeset);

struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv,
		void (*complete)(struct lsse_ch *se_ch))
/*
 * se_init_ch() - Init the channel used by child device.
 *
 * Allocate the shared memory agreed upon with SE on SE probe,
 * and register the callback function when the data processing
 * in this channel is completed.
 */
struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_size,
			   void *priv, void (*complete)(struct lsse_ch *se_ch))
{
	struct loongson_se *se = &se_dev;
	struct loongson_se *se = dev_get_drvdata(dev);
	struct lsse_ch *ch;
	unsigned long flag;
	int data_first, data_nr;
@@ -395,7 +346,7 @@ struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv,
		return NULL;
	}

	if (id == 0 || id > SE_CH_MAX) {
	if (id > SE_CH_MAX) {
		dev_err(se->dev, "Channel number %d is invalid\n", id);
		return NULL;
	}
@@ -407,30 +358,30 @@ struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv,

	spin_lock_irqsave(&se->dev_lock, flag);

	ch = &se_dev.chs[id];
	ch = &se->chs[id];
	ch->se = se;
	ch->id = id;
	ch->int_bit = BIT(id);
	se->ch_status |= BIT(id);

	data_nr = round_up(data_size, se_mem_page) / se_mem_page;
	data_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_size,
	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_size) {
	if (data_first >= se->mem_map_pages) {
		dev_err(se->dev, "Insufficient memory space\n");
		spin_unlock_irqrestore(&se->dev_lock, flag);
		return NULL;
	}

	bitmap_set(se->mem_map, data_first, data_nr);
	ch->data_buffer = se->mem_base + data_first * se_mem_page;
	ch->data_addr = se->mem_addr + data_first * se_mem_page;
	ch->data_buffer = se->mem_base + data_first * PAGE_SIZE;
	ch->data_addr = se->mem_addr + data_first * PAGE_SIZE;
	ch->data_size = data_size;

	msg_nr = round_up(msg_size, se_mem_page) / se_mem_page;
	msg_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_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_size) {
	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);
@@ -438,13 +389,11 @@ struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv,
	}

	bitmap_set(se->mem_map, msg_first, msg_nr);
	ch->smsg = se->mem_base + msg_first * se_mem_page;
	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;

	spin_lock_init(&ch->ch_lock);

	spin_unlock_irqrestore(&se->dev_lock, flag);
@@ -462,7 +411,7 @@ EXPORT_SYMBOL_GPL(se_init_ch);

void se_deinit_ch(struct lsse_ch *ch)
{
	struct loongson_se *se = &se_dev;
	struct loongson_se *se = ch->se;
	unsigned long flag;
	int first, nr;
	int id = ch->id;
@@ -472,7 +421,7 @@ void se_deinit_ch(struct lsse_ch *ch)
		return;
	}

	if (id == 0 || id > SE_CH_MAX) {
	if (id > SE_CH_MAX) {
		dev_err(se->dev, "Channel number %d is invalid\n", id);
		return;
	}
@@ -483,119 +432,92 @@ void se_deinit_ch(struct lsse_ch *ch)
	}

	spin_lock_irqsave(&se->dev_lock, flag);

	se->ch_status &= ~BIT(ch->id);

	first = (ch->data_buffer - se->mem_base) / se_mem_page;
	nr = round_up(ch->data_size, se_mem_page) / se_mem_page;
	first = (ch->data_buffer - se->mem_base) / PAGE_SIZE;
	nr = round_up(ch->data_size, PAGE_SIZE) / PAGE_SIZE;
	bitmap_clear(se->mem_map, first, nr);

	first = (ch->smsg - se->mem_base) / se_mem_page;
	nr = round_up(ch->msg_size, se_mem_page) / se_mem_page;
	first = (ch->smsg - se->mem_base) / PAGE_SIZE;
	nr = round_up(ch->msg_size, PAGE_SIZE) / PAGE_SIZE;
	bitmap_clear(se->mem_map, first, nr);

	se_disable_int(se, ch->int_bit);
	spin_unlock_irqrestore(&se->dev_lock, flag);

	se_disable_int(se, ch->int_bit);
}
EXPORT_SYMBOL_GPL(se_deinit_ch);

static struct platform_device lsse_sdf_pdev = {
	.name	= "loongson-sdf",
	.id	= -1,
};

static const struct of_device_id loongson_se_of_match[] = {
	{ .compatible = "loongson,ls3c6000se", },
	{}
};
MODULE_DEVICE_TABLE(of, loongson_se_of_match);

static int loongson_se_probe(struct platform_device *pdev)
{
	struct loongson_se *se = &se_dev;
	struct resource *res;
	struct loongson_se *se;
	struct device *dev = &pdev->dev;
	int nr_irq, err, i;
	int irq[8];
	int nr_irq, irq, err, size;

	nr_irq = platform_irq_count(pdev);
	if (nr_irq < 0)
		return -ENODEV;

	for (i = 0; i < nr_irq; i++) {
		irq[i] = platform_get_irq(pdev, i);
		if (irq[i] < 0)
			return -ENODEV;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
	se = devm_kmalloc(dev, sizeof(*se), GFP_KERNEL);
	if (!se)
		return -ENOMEM;
	se->dev = dev;
	dev_set_drvdata(dev, se);
	init_completion(&se->cmd_completion);
	spin_lock_init(&se->cmd_lock);
	spin_lock_init(&se->dev_lock);
	/* Setup DMA buffer */
	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, &se->mem_addr, 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_ioremap_resource(dev, res);
	se->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(se->base))
		return PTR_ERR(se->base);

	se->dev = &pdev->dev;
	platform_set_drvdata(pdev, se);
	dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
	init_completion(&se->cmd_completion);
	spin_lock_init(&se->cmd_lock);
	spin_lock_init(&se->dev_lock);

	for (i = 0; i < nr_irq; i++) {
		err = devm_request_irq(dev, irq[i], loongson_se_irq, 0,
	nr_irq = platform_irq_count(pdev);
	if (nr_irq <= 0)
		return -ENODEV;
	while (nr_irq) {
		irq = platform_get_irq(pdev, --nr_irq);
		if (irq < 0)
			return -ENODEV;
		/* 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)
			goto out;
			dev_err(dev, "failed to request irq: %d\n", err);
	}

	err = se_init_hw(se);
	if (err)
		goto disable_hw;

	err = misc_register(&lsse_miscdev);
	if (err)
		goto disable_hw;

	err = platform_device_register(&lsse_sdf_pdev);
	err = se_init_hw(se, se->mem_addr, size);
	if (err)
		pr_err("register sdf device failed\n");

	return 0;

disable_hw:
	loongson_se_disable_hw(se);
out:
	for ( ; i >= 0; i--)
		devm_free_irq(dev, irq[i], se);
		se_disable_hw(se);

	return err;
}

static int loongson_se_remove(struct platform_device *pdev)
{
	struct loongson_se *se = platform_get_drvdata(pdev);

	misc_deregister(&lsse_miscdev);
	loongson_se_disable_hw(se);
	platform_device_unregister(&lsse_sdf_pdev);

	return 0;
}
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,
	.remove  = loongson_se_remove,
	.driver  = {
		.name  = "loongson-se",
		.of_match_table = loongson_se_of_match,
		.acpi_match_table = loongson_se_acpi_match,
	},
};

module_platform_driver(loongson_se_driver);

MODULE_AUTHOR("Yinggang Gu");
MODULE_DESCRIPTION("Loongson SE driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Loongson Technology Corporation");
MODULE_DESCRIPTION("Loongson Security Module driver");
+154 −156

File changed.

Preview size limit exceeded, changes collapsed.

+20 −32
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2012 IBM Corporation
 *
 * Copyright 2023 Loongson Technology, Inc.
 * Yinggang Gu <guyinggang@loongson.cn>
 *
 * Device driver for Loongson SE module.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2 of the
 * License.
 *
 */
/* Copyright (C) 2024 Loongson Technology Corporation Limited */

#ifndef __LOONGSON_SE_H__
#define __LOONGSON_SE_H__

#define SE_MAILBOX_S			0x0
#define SE_MAILBOX_L			0x20
#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
@@ -91,10 +79,10 @@ struct se_res {
	u32 info[6];
};

struct se_mailbox_data {
struct se_data {
	u32 int_bit;
	union {
		u32 mailbox[8];
		u32 data[8];
		struct se_cmd gcmd;
		struct se_res res;
	} u;
@@ -128,19 +116,19 @@ struct loongson_se {
	void *mem_base;
	dma_addr_t mem_addr;
	unsigned long *mem_map;
	int mem_map_size;
	int mem_map_pages;
	void *smsg;
	void *rmsg;

	/* Synchronous CMD */
	struct completion cmd_completion;

	/* Virtual Channel */
	/* Channel */
	struct lsse_ch chs[SE_CH_MAX];
};

struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv,
		void (*complete)(struct lsse_ch *se_ch));
struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_size,
			   void *priv, void (*complete)(struct lsse_ch *se_ch));
void se_deinit_ch(struct lsse_ch *ch);
int se_send_ch_requeset(struct lsse_ch *ch);