Unverified Commit 82151bac authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!14738 LoongArch: fix some dwmac/pci/SE/i2c/interrupt issues

Merge Pull Request from: @ci-robot 
 
PR sync from: Hongchen Zhang <zhanghongchen@loongson.cn>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/X6HFPB6KJQMQ5TJHIWUZMKWXSXP6FWMK/ 
Zhao Qunqin (3):
  pci/quirks: LS7A2000: fix pm transition of devices under pcie port
  net: stmmac: dwmac-loongson: fix Mac DMA reset
  drivers/char: add ACPI firmware support for Loongson SE driver

wanghongliang (3):
  LoongArch: fix i2c related issues
  LoongArch: eiointc: fix ext irq route error
  LoongArch: adjust the calc method of number of packages.

 rename {arch/loongarch/include/asm => include/soc/loongson}/se.h (68%)

-- 
2.33.0
 
https://gitee.com/openeuler/kernel/issues/IBENRY 
 
Link:https://gitee.com/openeuler/kernel/pulls/14738

 

Reviewed-by: default avatarJuxin Gao <gaojuxin@loongson.cn>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents c329afbe 3185ec7c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1673,6 +1673,8 @@ CONFIG_HID_ALPS=m
CONFIG_HID_PID=y
CONFIG_USB_HIDDEV=y
CONFIG_I2C_HID=m
CONFIG_I2C_HID_ACPI=m
CONFIG_I2C_HID_OF=m
CONFIG_USB_LED_TRIG=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+4 −0
Original line number Diff line number Diff line
@@ -29,10 +29,14 @@ void numa_set_distance(int from, int to, int distance);
#endif

#ifdef CONFIG_SMP
extern unsigned int __max_packages;
#define topology_max_packages()                 (__max_packages)
#define topology_physical_package_id(cpu)	(cpu_data[cpu].package)
#define topology_core_id(cpu)			(cpu_data[cpu].core)
#define topology_core_cpumask(cpu)		(&cpu_core_map[cpu])
#define topology_sibling_cpumask(cpu)		(&cpu_sibling_map[cpu])
#else
#define topology_max_packages()                 (1)
#endif

#include <asm-generic/topology.h>
+1 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ static void __init parse_cpu_table(const struct dmi_header *dm)

	loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]);
	loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET);
	__max_packages++;

	pr_info("CpuClock = %llu\n", cpu_clock_freq);
}
+3 −0
Original line number Diff line number Diff line
@@ -74,6 +74,9 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
	[IPI_CLEAR_VECTOR] = "Clear vector interrupts",
};

unsigned int __max_packages __read_mostly;
EXPORT_SYMBOL(__max_packages);

void show_ipi_list(struct seq_file *p, int prec)
{
	unsigned int cpu, i;
+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");
Loading