Kernel
  Threads by month 
                
            - ----- 2025 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- 58 participants
- 20946 discussions
 
                        
                    
                        
                            
                                
                            
                            [openeuler:OLK-6.6 2121/2121] mm/kasan/shadow.c:90: undefined reference to `__memcpy_mc'
                        
                        
by kernel test robot 14 Apr '25
                    by kernel test robot 14 Apr '25
14 Apr '25
                    
                        tree:   https://gitee.com/openeuler/kernel.git OLK-6.6
head:   856215a06729654f070692189189edc4570084a0
commit: b991780c836ceb9a479c6c6e385e914b487e353a [2121/2121] arm64: introduce copy_mc_to_kernel() implementation
config: arm64-randconfig-003-20250414 (https://download.01.org/0day-ci/archive/20250414/202504142028.WisA9n7Q-lkp@…)
compiler: aarch64-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250414/202504142028.WisA9n7Q-lkp@…)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp(a)intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504142028.WisA9n7Q-lkp@intel.com/
All errors (new ones prefixed by >>):
   aarch64-linux-ld: Unexpected GOT/PLT entries detected!
   aarch64-linux-ld: Unexpected run-time procedure linkages detected!
   aarch64-linux-ld: mm/kasan/shadow.o: in function `memcpy_mc':
>> mm/kasan/shadow.c:90: undefined reference to `__memcpy_mc'
vim +90 mm/kasan/shadow.c
    81	
    82	#ifdef __HAVE_ARCH_MEMCPY_MC
    83	#undef memcpy_mc
    84	int memcpy_mc(void *dest, const void *src, size_t len)
    85	{
    86		if (!kasan_check_range(src, len, false, _RET_IP_) ||
    87		    !kasan_check_range(dest, len, true, _RET_IP_))
    88			return (int)len;
    89	
  > 90		return __memcpy_mc(dest, src, len);
    91	}
    92	#endif
    93	
-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        From: Qunqin Zhao <zhaoqunqin(a)loongson.cn>
LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IC1081
CVE: NA
--------------------------------
Add support for WST se chip support for LS*5000*.
Signed-off-by: Qunqin Zhao <zhaoqunqin(a)loongson.cn>
---
 arch/loongarch/configs/loongson3_defconfig    |    1 +
 drivers/crypto/Kconfig                        |    1 +
 drivers/crypto/Makefile                       |    1 +
 drivers/crypto/sedriver/Kconfig               |    8 +
 drivers/crypto/sedriver/Makefile              |    7 +
 drivers/crypto/sedriver/wst_se_common_type.h  |   98 ++
 drivers/crypto/sedriver/wst_se_define.h       |   27 +
 drivers/crypto/sedriver/wst_se_echip_driver.c | 1368 +++++++++++++++++
 drivers/crypto/sedriver/wst_se_echip_driver.h |  184 +++
 drivers/crypto/sedriver/wst_se_ktrans.h       |   17 +
 10 files changed, 1712 insertions(+)
 create mode 100644 drivers/crypto/sedriver/Kconfig
 create mode 100644 drivers/crypto/sedriver/Makefile
 create mode 100644 drivers/crypto/sedriver/wst_se_common_type.h
 create mode 100644 drivers/crypto/sedriver/wst_se_define.h
 create mode 100644 drivers/crypto/sedriver/wst_se_echip_driver.c
 create mode 100644 drivers/crypto/sedriver/wst_se_echip_driver.h
 create mode 100644 drivers/crypto/sedriver/wst_se_ktrans.h
diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig
index 980f5f2c99a1..cf359d1a2554 100644
--- a/arch/loongarch/configs/loongson3_defconfig
+++ b/arch/loongarch/configs/loongson3_defconfig
@@ -2177,6 +2177,7 @@ CONFIG_CRYPTO_CRC32_LOONGARCH=m
 CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
 CONFIG_CRYPTO_DEV_CHELSIO=m
 CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_SW_SE_CHIP=m
 CONFIG_SIGNED_PE_FILE_VERIFICATION=y
 CONFIG_SECONDARY_TRUSTED_KEYRING=y
 CONFIG_SYSTEM_BLACKLIST_KEYRING=y
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index b84a921d293f..efd6a855bca3 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -836,5 +836,6 @@ config CRYPTO_DEV_SA2UL
 source "drivers/crypto/aspeed/Kconfig"
 source "drivers/crypto/starfive/Kconfig"
 source "drivers/crypto/montage/Kconfig"
+source "drivers/crypto/sedriver/Kconfig"
 
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 5247d2bf09ce..6ad337bad109 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
 obj-y += intel/
 obj-y += starfive/
 obj-y += montage/
+obj-$(CONFIG_SW_SE_CHIP) += sedriver/
diff --git a/drivers/crypto/sedriver/Kconfig b/drivers/crypto/sedriver/Kconfig
new file mode 100644
index 000000000000..6a11bdf1e5fa
--- /dev/null
+++ b/drivers/crypto/sedriver/Kconfig
@@ -0,0 +1,8 @@
+#
+# se chip configuration
+#
+config SW_SE_CHIP
+	tristate "wst se chip driver"
+	depends on LOONGARCH
+	help
+		If unsure, say N.
diff --git a/drivers/crypto/sedriver/Makefile b/drivers/crypto/sedriver/Makefile
new file mode 100644
index 000000000000..0ee095d1a1d2
--- /dev/null
+++ b/drivers/crypto/sedriver/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for SE CHIP Driver
+#
+
+obj-$(CONFIG_SW_SE_CHIP) += sw_se_echip_drv.o
+sw_se_echip_drv-objs :=  wst_se_echip_driver.o
+
diff --git a/drivers/crypto/sedriver/wst_se_common_type.h b/drivers/crypto/sedriver/wst_se_common_type.h
new file mode 100644
index 000000000000..e29e9bccaa6d
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_common_type.h
@@ -0,0 +1,98 @@
+#ifndef _WST_SE_COMMON_TYPE_H
+#define _WST_SE_COMMON_TYPE_H
+
+#include <linux/kernel.h>	/* We're doing kernel work */
+#include <linux/module.h>	/* Specifically, a module */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/mman.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#define WST_GO_CHANNEL0			0x0002
+#define WST_GO_CHANNEL1		0x0000
+#define WST_GO_CHANNEL2		0x0001
+
+#define SE_OK 0
+
+struct loongson_sedriver_irq {
+	char  *pat;
+	int irq;
+};
+
+typedef struct tag_dma_buf_ctl {
+	struct list_head  list;
+	unsigned char *pDmaBuf;
+} dmabuf_ctl, *pdmabuf_ctl;
+
+typedef struct tag_Queue_container {
+	struct list_head     m_Head;
+	unsigned int qlen;
+	unsigned int max_qlen;
+} QUEUE_CONTAIN, *PQUEUE_CONTAIN;
+
+
+static inline int  wst_InitQueue(struct tag_Queue_container *pQueue, int count)
+{
+	INIT_LIST_HEAD(&pQueue->m_Head);
+	pQueue->qlen = 0;
+	pQueue->max_qlen = count;
+	return 0;
+}
+
+
+static inline struct list_head *wst_Popfront_Que(struct tag_Queue_container *pQueue)
+{
+	struct list_head *pNode = NULL;
+
+	if (list_empty(&pQueue->m_Head))
+		return NULL;
+
+	pQueue->qlen--;
+	pNode = pQueue->m_Head.next;
+	list_del(pNode);
+	return pNode;
+}
+
+
+static inline int  wst_Pushback_Que(struct tag_Queue_container *pQueue, void *pNode)
+{
+	if (unlikely(pQueue->qlen >= pQueue->max_qlen))
+		return -1;
+
+	pQueue->qlen++;
+	list_add_tail((struct list_head *)(pNode), &pQueue->m_Head);
+	return 0;
+}
+
+#define READUBUF  0
+#define WRITEUBUF 1
+
+static inline int wst_cpyusrbuf(unsigned char  *puserbuf,
+				unsigned char *pkbuf, size_t num, int orient)
+{
+	if (orient == READUBUF)
+		return copy_from_user(pkbuf, puserbuf, num);
+	else
+		return copy_to_user(puserbuf, pkbuf, num);
+}
+
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_define.h b/drivers/crypto/sedriver/wst_se_define.h
new file mode 100644
index 000000000000..7a29f1029afa
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_define.h
@@ -0,0 +1,27 @@
+#ifndef _WST_SE_DEFINE_H
+#define _WST_SE_DEFINE_H
+
+
+typedef void (*PSECallBackfn)(void *pParam);
+
+#define WST_SE_OK			0	//function syccess
+#define WST_SE_FAILURE			1
+#define WST_SE_ERROR_MALLOC		2
+#define WST_SE_ERROR_OPEN		3
+#define WST_SE_ERROR_ID			4
+#define WST_SE_ERROR_OPERTYPE		5
+#define WST_SE_ERROR_KEYID		6
+#define WST_SE_NOT_SUPPORT		7
+#define WST_SE_ERROR_FULL		8
+#define WST_SE_VERIFY_ERROR	0xb
+#define WST_SE_NOT_SUPPORT_VERIFY	0xd
+#define WST_SE_ERROR_LENGTH	0xc
+#define WST_SE_HAS_OPEN			0xd
+#define WST_COPY_MEM_ERROR		0xe
+#define WST_SE_PARAM_ERROR		0xf
+
+#define BASE_ERROR			0x1000
+#define WST_SE_ERROR_LICENSE		0x100b
+#define WST_SE_ERROR_NOT_SUPPORT_TYPE 0x100d
+
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_echip_driver.c b/drivers/crypto/sedriver/wst_se_echip_driver.c
new file mode 100644
index 000000000000..66e34549d209
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_echip_driver.c
@@ -0,0 +1,1368 @@
+#include <linux/semaphore.h>
+#include <linux/moduleparam.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/crypto.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/acpi.h>
+#include <asm/loongson.h>
+#include "wst_se_echip_driver.h"
+
+#define LS_CRYPTO_SE_ADDR1 TO_UNCACHE(LOONGSON_REG_BASE+0x0400)
+#define LS_CRYPTO_SE_ADDR2 TO_UNCACHE(0xc0010200000)
+#define DRIVER_VERSION "01.10.220111"
+DEFINE_SPINLOCK(g_reclistlock);
+DEFINE_SPINLOCK(g_sendlistlock);
+DEFINE_SPINLOCK(g_getdmabuflock);
+
+unsigned char *g_pCacheInBuf = NULL, *g_pCacheOutBuf = NULL;
+static struct class *g_psecclass;
+static struct device *g_psecdev;
+static SECHIPDRV_CTRL *g_psechipDrvCtrl;
+static int g_isechip_Major = -1;
+static struct semaphore g_lowsema, g_lowirqsema;
+static atomic_t g_sendtotallen;
+static struct tag_Queue_container g_RecQueueContainer;
+static struct tag_Queue_container g_SendQueueContainer;
+static int g_suspend;
+static struct semaphore g_dmabufsem;
+struct loongson_sedriver_irq se_irq[] = {
+	{
+		.pat = "se-irq",
+	},
+	{
+		.pat = "se-lirq",
+	},
+};
+static struct tag_Queue_container g_DmaBQueueContainer;
+static struct tag_dma_buf_ctl *g_pdmadatabuf;
+static int g_iDmaBufNum;
+static struct work_struct g_recwork, g_sendwork;
+static struct workqueue_struct *g_worksendqueue, *g_workrecqueue;
+static irqreturn_t se_interrupt(int irq, void *p);
+static irqreturn_t wst_low_channel_status(int irq, void *p);
+static void globalmem_do_send_op(struct work_struct *p);
+static void globalmem_do_rec_op(struct work_struct *p);
+static int g_iUseIntr = 1;
+module_param(g_iUseIntr, int, 0644);
+
+static int se_init_dma_buf(int idatasize, int idatanum)
+{
+	int i;
+	struct tag_dma_buf_ctl *pdmactl;
+
+	wst_InitQueue(&g_DmaBQueueContainer, idatanum);
+	g_pdmadatabuf = kmalloc((sizeof(struct tag_dma_buf_ctl)*idatanum), GFP_KERNEL);
+	if (!g_pdmadatabuf)
+		return -1;
+	for (i = 0; i < idatanum; i++) {
+		pdmactl = &g_pdmadatabuf[i];
+		pdmactl->pDmaBuf = (unsigned char *)__get_free_page(GFP_KERNEL|GFP_DMA);
+		if (!pdmactl->pDmaBuf) {
+			g_iDmaBufNum = i;
+			return SE_OK;
+		}
+		wst_Pushback_Que(&g_DmaBQueueContainer, pdmactl);
+	}
+	g_iDmaBufNum = i;
+	sema_init(&g_dmabufsem, 1);
+	return SE_OK;
+}
+
+static int se_del_dma_buf(void)
+{
+	int i;
+	struct tag_dma_buf_ctl *pdmactl;
+
+	for (i = 0; i < g_iDmaBufNum; i++) {
+		pdmactl = &g_pdmadatabuf[i];
+		if (pdmactl) {
+			free_page((unsigned long)pdmactl->pDmaBuf);
+			pdmactl->pDmaBuf = NULL;
+		}
+	}
+	kfree(g_pdmadatabuf);
+	g_pdmadatabuf = NULL;
+	return 0;
+}
+
+struct tag_dma_buf_ctl *se_get_dma_buf(int ikernel)
+{
+	struct tag_dma_buf_ctl *pbufctl = NULL;
+	unsigned long ultimeout = 0;
+
+	ultimeout = jiffies+20*HZ;
+	while (1) {
+		spin_lock(&g_getdmabuflock);
+		pbufctl = (struct tag_dma_buf_ctl *)wst_Popfront_Que(&g_DmaBQueueContainer);
+		spin_unlock(&g_getdmabuflock);
+		if (pbufctl)
+			return pbufctl;
+		if (down_timeout(&g_dmabufsem, ultimeout))
+			return NULL;
+	}
+	return pbufctl;
+}
+
+int se_free_dma_buf(struct tag_dma_buf_ctl *pdmabufctl)
+{
+	spin_lock(&g_getdmabuflock);
+	wst_Pushback_Que(&g_DmaBQueueContainer, pdmabufctl);
+	spin_unlock(&g_getdmabuflock);
+	if (g_dmabufsem.count <= 0)
+		up(&g_dmabufsem);
+
+	return 0;
+}
+
+static unsigned long  bytes_align(struct device *pdev, unsigned long ulVirAddr)
+{
+	unsigned char diff;
+	unsigned long ulPhyAddr = (unsigned long)__pa((void *)ulVirAddr);
+
+	if ((ulPhyAddr & 0x000000000000003f) == 0)
+		return ulVirAddr;
+	diff = ((long)ulPhyAddr & (~(0x000000000000003f))) + 64 - ulPhyAddr;
+	ulVirAddr += diff;
+
+	return ulVirAddr;
+}
+
+static unsigned long  descri_bytes_align(unsigned long ulVirAddr)
+{
+	unsigned char diff;
+	unsigned long ulPhyAddr = ulVirAddr;
+
+	if ((ulPhyAddr & (~0x00000000ffffffe0)) == 0)
+		return ulVirAddr;
+	diff = ((long)ulPhyAddr & 0x00000000ffffffe0) + 32 - ulPhyAddr;
+	ulVirAddr += diff;
+	return ulVirAddr;
+}
+
+int se_printk_hex(unsigned char *buff, int length)
+{
+	unsigned char *string_tmp = buff;
+	int i;
+	int count = 0;
+
+	for (i = 0; i < length; i++, count++) {
+		if (count < 16)
+			pr_info("%02x ", string_tmp[i]);
+		else {
+			count = 0;
+			pr_info("\n%02x ", string_tmp[i]);
+			continue;
+		}
+	}
+	pr_info("\n");
+	return 0;
+}
+
+static int se_ChipInit(SECHIPDRV_CTRL *pDrvCtrl)
+{
+	dma_addr_t ulBusAddr;
+	unsigned long ulVirAddr;
+	int i = 0, j = 0;
+	unsigned int dmaoldmask;
+
+	for (i = 0; i < SWCHANNELNUM; i++) {
+		ulVirAddr = (unsigned long)dma_alloc_coherent(
+			pDrvCtrl->pdev,
+			(SE_BDQUEUE_LEN * SE_BD_LENGTH+32),
+			&ulBusAddr, GFP_KERNEL
+			);
+		if (ulVirAddr == 0 || ulBusAddr == 0)
+			return -EFAULT;
+		memset((void *)ulVirAddr, 0, (SE_BDQUEUE_LEN*SE_BD_LENGTH));
+
+		pDrvCtrl->ulBDMemBasePhy[i]   = ulBusAddr;
+		pDrvCtrl->ulBDMemBase[i]      = ulVirAddr;
+		pDrvCtrl->ulCurrBdReadPtr[i]  = 0;
+		pDrvCtrl->ulCurrBdWritePtr[i] = 0;
+		pDrvCtrl->ulCurrReadPtr[i]  = 0;
+		pDrvCtrl->ulCurrWritePtr[i] = 0;
+	}
+	for (i = 0; i < SE_BDQUEUE_LEN; i++) {
+		for (j = 0; j < SWCHANNELNUM; j++)
+			(&((SE_BASIC_BD *)(pDrvCtrl->ulBDMemBase[j]))[i])->ucRetCode = 0x0f;
+	}
+	ulBusAddr = descri_bytes_align(pDrvCtrl->ulBDMemBasePhy[0]);
+	HandleWrite32(pDrvCtrl, SE_HREG_BQBA0, HIULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_LREG_BQBA0, LOULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_REG_BQS0,  SE_BDQUEUE_LEN - 1);
+	HandleWrite32(pDrvCtrl, SE_REG_RQRP0, pDrvCtrl->ulCurrBdReadPtr[0]);
+	HandleWrite32(pDrvCtrl, SE_REG_BQWP0, pDrvCtrl->ulCurrBdWritePtr[0]);
+
+	ulBusAddr = descri_bytes_align(pDrvCtrl->ulBDMemBasePhy[1]);
+	HandleWrite32(pDrvCtrl, SE_HREG_BQBA1, HIULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_LREG_BQBA1, LOULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_REG_BQS1,  SE_BDQUEUE_LEN - 1);
+	HandleWrite32(pDrvCtrl, SE_REG_RQRP1, pDrvCtrl->ulCurrBdReadPtr[1]);
+	HandleWrite32(pDrvCtrl, SE_REG_BQWP1, pDrvCtrl->ulCurrBdWritePtr[1]);
+	HandleRead32(pDrvCtrl, SE_REG_MSK, &dmaoldmask);
+	HandleWrite32(pDrvCtrl, SE_REG_MSK, (dmaoldmask | DMA0_CTRL_CHANNEL_ENABLE | DMA1_CTRL_CHANNEL_ENABLE));
+	if (g_iUseIntr != 0)
+		HandleWrite32(pDrvCtrl, SE_LOWREG_INQ, 1);
+	else
+		HandleWrite32(pDrvCtrl, SE_LOWREG_INQ, 0);
+	mdelay(1000);
+
+	return SE_OK;
+}
+
+static void  se_ChipRelease(SECHIPDRV_CTRL *pDrvCtrl)
+{
+	int i;
+
+	for (i = 0; i < SWCHANNELNUM; i++) {
+		if (pDrvCtrl->ulBDMemBase[i]) {
+			dma_free_coherent(
+				pDrvCtrl->pdev,
+				(SE_BDQUEUE_LEN * SE_BD_LENGTH),
+				(void *)pDrvCtrl->ulBDMemBase[i],
+				pDrvCtrl->ulBDMemBasePhy[i]
+				);
+			pDrvCtrl->ulBDMemBase[i] = 0;
+			pDrvCtrl->ulBDMemBasePhy[i] = 0;
+		}
+	}
+}
+
+static void SE_RESET(SECHIPDRV_CTRL *pdrvctl)
+{
+
+	unsigned int reg;
+	unsigned long   ulreg64, uladdr = LS_CRYPTO_SE_ADDR1;
+
+	HandleRead32(pdrvctl, SE_REG_RESET, ®);
+	HandleWrite32(pdrvctl, SE_REG_RESET, reg|SE_DMA_CONTROL_RESET);
+	mdelay(300);
+	HandleWrite32(pdrvctl, SE_REG_RESET, (reg&(~SE_DMA_CONTROL_RESET))|SE_DMA_CONTROL_SET);
+	mdelay(300);
+	ulreg64 = readq((volatile void __iomem *)uladdr);
+	if ((ulreg64 & 0xf0000000000000) != 0xf0000000000000)
+		writeq(ulreg64|0xf0000000000000, (volatile void __iomem *)uladdr);
+	HandleWrite32(pdrvctl, SE_INT_CLR, 0xf);
+}
+
+static int wst_init(void)
+{
+	int iRes = SE_OK;
+	static u64 wst_dma_mask = DMA_BIT_MASK(64);
+	char cName[256];
+	SECHIPDRV_CTRL *pdrvctl = NULL;
+
+	pdrvctl = kmalloc(sizeof(SECHIPDRV_CTRL), GFP_KERNEL);
+	if (pdrvctl == NULL)
+		return -ENOMEM;
+	memset(pdrvctl, 0, sizeof(SECHIPDRV_CTRL));
+	pdrvctl->ulMemBase = LS_CRYPTO_SE_ADDR2;
+	memset(cName, 0, 256);
+	sema_init(&(pdrvctl->sema), 0);
+	rwlock_init(&(pdrvctl->mr_lock));
+	rwlock_init(&(pdrvctl->mr_lowlock));
+	g_psechipDrvCtrl = pdrvctl;
+	g_psechipDrvCtrl->pdev = g_psecdev;
+	g_psechipDrvCtrl->pdev->dma_mask = &wst_dma_mask;
+	g_psechipDrvCtrl->pdev->coherent_dma_mask = (unsigned long long)&wst_dma_mask;
+	wst_InitQueue(&g_RecQueueContainer, 2000);
+	wst_InitQueue(&g_SendQueueContainer, 2000);
+	SE_RESET(pdrvctl);
+	pdrvctl->ilowIrq = 0;
+	pdrvctl->iIrq = se_irq[0].irq;
+	iRes = request_irq(pdrvctl->iIrq, &se_interrupt, IRQF_SHARED, "wst-se-hirq", pdrvctl);
+	if (iRes) {
+		pr_err("request_irq err\n");
+		pdrvctl->iIrq = 0;
+		goto err;
+	}
+	if (g_iUseIntr == 1) {
+		pdrvctl->ilowIrq = se_irq[1].irq;
+		iRes = request_irq(pdrvctl->ilowIrq, &wst_low_channel_status, IRQF_SHARED, "wst-se-lirq", pdrvctl);
+		if (iRes) {
+			pr_err("\nrequest_lowirq err, iRes=0x%x\n", iRes);
+			pdrvctl->ilowIrq = 0;
+			goto err;
+		}
+	}
+	if (se_ChipInit(pdrvctl) != SE_OK) {
+		iRes = -ENODEV;
+		goto err;
+	}
+	return SE_OK;
+err:
+	if (pdrvctl != NULL) {
+		if (pdrvctl->iIrq) {
+			free_irq(pdrvctl->iIrq, pdrvctl);
+			pdrvctl->iIrq = 0;
+		}
+		if (pdrvctl->ilowIrq) {
+			free_irq(pdrvctl->ilowIrq, pdrvctl);
+			pdrvctl->ilowIrq = 0;
+		}
+		se_ChipRelease(pdrvctl);
+		kfree(pdrvctl);
+		g_psechipDrvCtrl = NULL;
+	}
+	return iRes;
+}
+
+static void wst_clear(void)
+{
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+
+	pdrvctl = g_psechipDrvCtrl;
+	if (pdrvctl) {
+		if (pdrvctl->iIrq) {
+			free_irq(pdrvctl->iIrq, pdrvctl);
+			pdrvctl->iIrq = 0;
+		}
+		if (pdrvctl->ilowIrq) {
+			free_irq(pdrvctl->ilowIrq, pdrvctl);
+			pdrvctl->ilowIrq = 0;
+		}
+		se_ChipRelease(pdrvctl);
+		kfree(pdrvctl);
+		g_psechipDrvCtrl = NULL;
+	}
+}
+static void globalmem_do_send_op(struct work_struct *p)
+{
+	SE_BASIC_BD *pCurBD;
+	unsigned int ulCurrWritePtr, ulWritePtr;
+	unsigned short len = 0;
+	unsigned long ulCurrAddrInput = 0, ulCurrAddrOutput = 0;
+	SECHIPDRV_CTRL  *pdrvctl;
+	unsigned char *pInPtr;
+	unsigned short usInlen;
+	unsigned char *pOutPtr;
+	unsigned short *pusOutlen;
+	int iChannel;
+	unsigned char ucFlag;
+	unsigned char ucOpCode;
+	unsigned char *pucRetCode;
+	PSECallBackfn pcallback;
+	void *pParma;
+	int iKernel;
+	struct completion *mycomplete;
+	SEND_PACKAGE *psendpackage;
+	unsigned long ulflag;
+	unsigned long ultimeout;
+	int rv = 0;
+
+	while (1) {
+PROG:
+	spin_lock_irq(&g_sendlistlock);
+	psendpackage = (SEND_PACKAGE *)wst_Popfront_Que(&g_SendQueueContainer);
+	if (!psendpackage) {
+		spin_unlock_irq(&g_sendlistlock);
+		return;
+	}
+	spin_unlock_irq(&g_sendlistlock);
+	pdrvctl = psendpackage->pdrvctl;
+	pInPtr = psendpackage->pInPtr;
+	usInlen = psendpackage->usInlen;
+	pOutPtr = psendpackage->pOutPtr;
+	pusOutlen = psendpackage->pusOutlen;
+	iChannel = psendpackage->iChannel;
+	ucFlag = psendpackage->ucFlag;
+	ucOpCode = psendpackage->ucOpCode;
+	pucRetCode = psendpackage->pucRetCode;
+	pcallback = psendpackage->pcallback;
+	pParma = psendpackage->pParma;
+	iKernel = psendpackage->iKernel;
+	mycomplete = psendpackage->mycomplete;
+	ultimeout = psendpackage->ulendtime;
+	kfree(psendpackage);
+
+	if (iKernel == 0) {
+		while (time_before(jiffies, ultimeout)) {
+#ifdef CONFIG_MIPS
+			if ((pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+			|| ((atomic_read(&g_sendtotallen) + *pusOutlen + SE_FILL_LEN) > SE_MAX_SEND_LEN))
+#else
+			if (pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+#endif
+			{
+				down_timeout(&(pdrvctl->sema), 1*HZ);
+				rv = WST_SE_ERROR_FULL;
+			} else {
+				rv = 0;
+				break;
+			}
+		}
+		if (rv != 0x0) {
+			*pucRetCode = WST_SE_ERROR_FULL;
+			complete(mycomplete);
+			goto PROG;
+		}
+	} else {
+		ultimeout = jiffies+1*HZ;
+		while (time_before(jiffies, ultimeout)) {
+#ifdef CONFIG_MIPS
+			if ((pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+			|| ((atomic_read(&g_sendtotallen) + *pusOutlen + SE_FILL_LEN) > SE_MAX_SEND_LEN))
+#else
+			if (pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+#endif
+			{
+				rv = WST_SE_ERROR_FULL;
+			} else {
+				rv = 0;
+				break;
+			}
+		}
+		if (rv != 0x0) {
+			*pucRetCode = WST_SE_ERROR_FULL;
+			if (pcallback)
+				pcallback(pParma);
+			goto PROG;
+		}
+	}
+	ulCurrWritePtr = pdrvctl->ulCurrBdWritePtr[iChannel];
+	ulWritePtr = (ulCurrWritePtr + 1) & (SE_BDQUEUE_LEN-1);
+
+	pCurBD = &((SE_BASIC_BD *)(pdrvctl->ulBDMemBase[iChannel]))[ulCurrWritePtr];
+	memset(pCurBD, 0x0, sizeof(SE_BASIC_BD));
+	if (pcallback != NULL) {
+		(pdrvctl->pcallback)[iChannel][ulCurrWritePtr] = pcallback;
+		pdrvctl->pParma[iChannel][ulCurrWritePtr] = pParma;
+	} else {
+		(pdrvctl->pcallback)[iChannel][ulCurrWritePtr] = NULL;
+		pdrvctl->pParma[iChannel][ulCurrWritePtr] = NULL;
+	}
+
+	pdrvctl->ikernel[iChannel][ulCurrWritePtr] = iKernel;
+	pdrvctl->stsemphore[iChannel][ulCurrWritePtr] = mycomplete;
+
+	if (pInPtr == pOutPtr) {
+		if (pOutPtr) {
+			len = usInlen >= *pusOutlen ? usInlen : *pusOutlen;
+			if (len) {
+				ulCurrAddrOutput = dma_map_single(pdrvctl->pdev, pOutPtr, len, DMA_BIDIRECTIONAL);
+				if (ulCurrAddrOutput == 0) {
+					TRACEERR("map ulCurrAddrOutput error\n");
+					*pucRetCode = WST_SE_FAILURE;
+					if (iKernel == 0) {
+						complete(mycomplete);
+					} else {
+						*pucRetCode = WST_SE_FAILURE;
+						if (pcallback)
+							pcallback(pParma);
+					}
+					goto PROG;
+				}
+				pCurBD->ulOutputLPtr = LOULONG(ulCurrAddrOutput);
+				pCurBD->ulOutputHPtr = HIULONG(ulCurrAddrOutput);
+				pCurBD->ulInputLPtr = pCurBD->ulOutputLPtr;
+				pCurBD->ulInputHPtr = pCurBD->ulOutputHPtr;
+			}
+		}
+	} else {
+		if (pOutPtr && (*pusOutlen)) {
+			ulCurrAddrOutput = dma_map_single(pdrvctl->pdev, pOutPtr, *pusOutlen, DMA_FROM_DEVICE);
+			if (ulCurrAddrOutput == 0) {
+				TRACEERR("map ulCurrAddrOutput error\n");
+				*pucRetCode = WST_SE_FAILURE;
+				if (iKernel == 0) {
+					complete(mycomplete);
+				} else {
+					*pucRetCode = WST_SE_FAILURE;
+					if (pcallback)
+						pcallback(pParma);
+				}
+				goto PROG;
+			}
+			pCurBD->ulOutputLPtr = LOULONG(ulCurrAddrOutput);
+			pCurBD->ulOutputHPtr = HIULONG(ulCurrAddrOutput);
+		}
+		if (usInlen && pInPtr) {
+			ulCurrAddrInput = dma_map_single(pdrvctl->pdev, pInPtr, usInlen, DMA_TO_DEVICE);
+			if (ulCurrAddrInput == 0) {
+				if (ulCurrAddrOutput) {
+					dma_unmap_single(pdrvctl->pdev, ulCurrAddrOutput, *pusOutlen, DMA_FROM_DEVICE);
+					pCurBD->ulOutputLPtr = 0;
+					pCurBD->ulOutputHPtr = 0;
+				}
+				*pucRetCode = WST_SE_FAILURE;
+				if (iKernel == 0) {
+					complete(mycomplete);
+				} else {
+					*pucRetCode = WST_SE_FAILURE;
+					if (pcallback)
+						pcallback(pParma);
+				}
+				goto PROG;
+			}
+			pCurBD->ulInputLPtr = LOULONG(ulCurrAddrInput);
+			pCurBD->ulInputHPtr = HIULONG(ulCurrAddrInput);
+		}
+	}
+	pCurBD->ucOpCode = ucOpCode & 0x0f;
+	pCurBD->ucFlag = ucFlag & 0x7;
+	pCurBD->usInputLength = usInlen;
+	if (pusOutlen)
+		pCurBD->usOutputLength = *pusOutlen;
+
+	pCurBD->ucRetCode	= 0x0f;
+
+	pdrvctl->pusOutlen[iChannel][ulCurrWritePtr] = pusOutlen;
+	pdrvctl->usInlen[iChannel][ulCurrWritePtr] = usInlen&0xffff;
+	if (ulCurrAddrOutput)
+		pdrvctl->ulOutputPtr[iChannel][ulCurrWritePtr] = (unsigned long *)ulCurrAddrOutput;
+	else
+		pdrvctl->ulOutputPtr[iChannel][ulCurrWritePtr] = 0;
+	if (ulCurrAddrInput)
+		pdrvctl->ulInputPtr[iChannel][ulCurrWritePtr] = (unsigned long *)ulCurrAddrInput;
+	else
+		pdrvctl->ulInputPtr[iChannel][ulCurrWritePtr] = 0;
+	pdrvctl->pucRetCode[iChannel][ulCurrWritePtr] = pucRetCode;
+
+#ifdef CONFIG_MIPS
+	atomic_add((*(pdrvctl->pusOutlen[iChannel][ulCurrWritePtr]) + SE_FILL_LEN), &g_sendtotallen);
+#endif
+	write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	if (iChannel == 0)
+		HandleWrite32(pdrvctl, SE_REG_BQWP0, ulWritePtr);
+	else
+		HandleWrite32(pdrvctl, SE_REG_BQWP1, ulWritePtr);
+	write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+	pdrvctl->ulCurrBdWritePtr[iChannel] = ulWritePtr;
+	}
+}
+
+static int se_hardtrans(
+			SECHIPDRV_CTRL  *pdrvctl,
+			unsigned char *pInPtr,
+			unsigned short usInlen,
+			unsigned char *pOutPtr,
+			unsigned short *pusOutlen,
+			int iChannel,
+			unsigned char ucFlag,
+			unsigned char ucOpCode,
+			unsigned char *pucRetCode,
+			PSECallBackfn pcallback,
+			void *pParma,
+			int iKernel,
+			struct completion *mycomplete
+			)
+{
+	SEND_PACKAGE *psendpackage;
+	gfp_t gfp_flag;
+
+	if (in_interrupt())
+		gfp_flag = GFP_ATOMIC;
+	else
+		gfp_flag = GFP_KERNEL;
+	if (g_suspend == 1)
+		return WST_SE_FAILURE;
+	psendpackage = kmalloc(sizeof(SEND_PACKAGE), gfp_flag);
+	if (psendpackage == NULL)
+		return -1;
+
+	psendpackage->pdrvctl = pdrvctl;
+	psendpackage->pInPtr = pInPtr;
+	psendpackage->usInlen = usInlen;
+	psendpackage->pOutPtr = pOutPtr;
+	psendpackage->pusOutlen = pusOutlen;
+	psendpackage->iChannel = iChannel;
+	psendpackage->ucFlag = ucFlag;
+	psendpackage->ucOpCode = ucOpCode;
+	psendpackage->pucRetCode = pucRetCode;
+	psendpackage->pcallback = pcallback;
+	psendpackage->pParma = pParma;
+	psendpackage->iKernel = iKernel;
+	psendpackage->mycomplete = mycomplete;
+	psendpackage->ulendtime = jiffies+30*HZ;
+	spin_lock_irq(&g_sendlistlock);
+	if (wst_Pushback_Que(&g_SendQueueContainer, psendpackage) == -1) {
+		spin_unlock_irq(&g_sendlistlock);
+		kfree(psendpackage);
+		return WST_SE_ERROR_FULL;
+	}
+	spin_unlock_irq(&g_sendlistlock);
+	queue_work(g_worksendqueue, &g_sendwork);
+	return 0;
+}
+
+static irqreturn_t wst_low_channel_status(int irq, void *p)
+{
+	SECHIPDRV_CTRL *pdrvctl = (SECHIPDRV_CTRL *)p;
+	int64_t  ulIntStat = 0;
+	unsigned long ulflag;
+
+	read_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	HandleRead64(pdrvctl, SE_LOWREG_STS, &ulIntStat);
+	if (ulIntStat == 2) {
+		HandleWrite64(pdrvctl, SE_LOWINT_CLEAR, 2);
+		up(&g_lowirqsema);
+	}
+	read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+
+	return IRQ_HANDLED;
+}
+
+static int se_useropen(struct inode *inode, struct file *file)
+{
+	if (MINOR(inode->i_rdev) != 0)
+		return -ENODEV;
+
+	return SE_OK;
+}
+
+static ssize_t wst_low_channel_userwrite_op(
+					SECHIPDRV_CTRL  *pdrvctl,
+					SWCommuData *UserCommuData,
+					int iskernel
+					)
+{
+	unsigned long long addr = 0, outaddr = 0;
+	int ilen;
+	int count = SE_OK;
+	unsigned long long ulsendlen;
+	unsigned char *m_pCacheInBuf;
+	unsigned char *m_pCacheOutBuf;
+	unsigned long ulflag;
+
+	if ((g_pCacheInBuf == NULL) || (g_pCacheOutBuf == NULL))
+		return -EFAULT;
+
+	m_pCacheInBuf = (unsigned char *)bytes_align(0, (unsigned long)g_pCacheInBuf);
+	m_pCacheOutBuf = (unsigned char *)bytes_align(0, (unsigned long)g_pCacheOutBuf);
+	if (iskernel == 0) {
+		if (wst_cpyusrbuf((void   *)(UserCommuData->pucInbuf), (void *)m_pCacheInBuf, UserCommuData->usInputLen, READUBUF)) {
+			TRACEERR("copy user data error\n");
+			return -EFAULT;
+		}
+	} else
+
+		memcpy((void   *)m_pCacheInBuf, (void *)(UserCommuData->pucInbuf), UserCommuData->usInputLen);
+	ilen = UserCommuData->usInputLen >= UserCommuData->usOutputLen ? UserCommuData->usInputLen:UserCommuData->usOutputLen;
+	addr = dma_map_single(pdrvctl->pdev, m_pCacheInBuf, ilen, DMA_TO_DEVICE);
+	if (addr == 0) {
+		TRACEERR("transfer buffer is err\n");
+		return -EFAULT;
+	}
+	outaddr = dma_map_single(pdrvctl->pdev, m_pCacheOutBuf, ilen, DMA_FROM_DEVICE);
+	if (outaddr == 0) {
+		TRACEERR("transfer buffer is err\n");
+		dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+		return -EFAULT;
+	}
+	ulsendlen = (UserCommuData->usInputLen/8);
+	ulsendlen = (ulsendlen & 0x00000000ffffffff) << 32;
+	write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	HandleWrite64(pdrvctl, SE_WRITE_REG1, ulsendlen);
+	HandleWrite64(pdrvctl, SE_WRITE_REG2, addr);
+	HandleWrite64(pdrvctl, SE_WRITE_REG3, outaddr);
+	write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+	if (g_iUseIntr != 0) {
+		if (down_interruptible(&g_lowirqsema) == -EINTR) {
+			count = -EINTR;
+			goto EXIT;
+		}
+	} else {
+		unsigned long start_jiffies = 0, end_jiffies = 0;
+		int64_t  ulIntStat = 0;
+
+		start_jiffies = jiffies;
+		end_jiffies = jiffies;
+		while (1) {
+			write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+			HandleRead64(pdrvctl, SE_LOWREG_SR, &ulIntStat);
+			end_jiffies = jiffies;
+			if (ulIntStat == 1) {
+				HandleWrite64(pdrvctl, SE_LOWREG_SR, 0);
+				write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+				break;
+			}
+			write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+			if (jiffies_to_msecs(end_jiffies-start_jiffies)/1000 >= 90) {
+				count = -EFAULT;
+				goto EXIT;
+			}
+		}
+	}
+	dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+	dma_unmap_single(pdrvctl->pdev, outaddr, ilen, DMA_FROM_DEVICE);
+	if (UserCommuData->usOutputLen) {
+		if (iskernel == 0) {
+			if (wst_cpyusrbuf(UserCommuData->pucOutbuf, m_pCacheOutBuf, UserCommuData->usOutputLen, WRITEUBUF))
+				return -EFAULT;
+		} else
+			memcpy(UserCommuData->pucOutbuf, m_pCacheOutBuf, UserCommuData->usOutputLen);
+	}
+	return count;
+EXIT:
+	dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+	dma_unmap_single(pdrvctl->pdev, outaddr, ilen, DMA_FROM_DEVICE);
+	return count;
+}
+
+static ssize_t se_userwrite(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	unsigned char *pCacheBuf = NULL, *pCacheOutBuf = NULL, *pCacheBufalign = NULL, *pCacheOutBufalign = NULL;
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+	SWCommuData *pCommuData = NULL;
+	int iCommuDatalen = 0;
+	int pucRetCode = 0;
+	unsigned short iChannel = 0;
+	unsigned char ucFlag = 0, ucOpCode = 0;
+	int *ppucRetCode;
+	struct completion mycomplete;
+	struct tag_dma_buf_ctl *pbufinctl = NULL;
+	int iret = 0;
+
+	if (count == 0) {
+		TRACEERR("count=0\n");
+		return SE_OK;
+	}
+
+	if (MINOR(file->f_path.dentry->d_inode->i_rdev) != 0)
+		return -ENODEV;
+
+	iCommuDatalen = sizeof(SWCommuData);
+	if (count != iCommuDatalen)
+		return -EINVAL;
+
+	pdrvctl = g_psechipDrvCtrl;
+	pCommuData = kmalloc(iCommuDatalen, GFP_KERNEL);
+	if (!pCommuData) {
+		TRACEERR("pCommuData NULL\n");
+		return -ENOMEM;
+	}
+	if (wst_cpyusrbuf((void   *)buf, (void *)pCommuData, iCommuDatalen, READUBUF)) {
+		TRACEERR("copy user data error\n");
+		count = -EFAULT;
+		goto EXIT;
+	}
+	switch ((pCommuData->usFlags)&0x000f) {
+	case WST_GO_CHANNEL2:
+		if ((pCommuData->usInputLen > DMA_BUFSIZE) || (pCommuData->usOutputLen > DMA_BUFSIZE)) {
+			TRACEERR("len is error\n");
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (down_interruptible(&g_lowsema) == -EINTR) {
+			count = -EINTR;
+			goto EXIT;
+		}
+		count = wst_low_channel_userwrite_op(pdrvctl, pCommuData, 0);
+		up(&g_lowsema);
+		goto EXIT;
+	case WST_GO_CHANNEL0:
+		if (pCommuData->usInputLen == 0) {
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (pCommuData->usInputLen != 0) {
+			if (pCommuData->usInputLen > DMA_BUFSIZE) {
+				count = -EINVAL;
+				goto EXIT;
+			}
+			ucFlag = INPUT_VALID;
+			if (pCommuData->usOutputLen)
+				ucFlag |= OUTPUT_VALID;
+		}
+
+		iChannel = 0;
+		ucOpCode = 0x0;
+		break;
+	case WST_GO_CHANNEL1:
+		if (pCommuData->usInputLen == 0) {
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (pCommuData->usInputLen != 0) {
+			if (pCommuData->usInputLen > DMA_BUFSIZE) {
+				count = -EINVAL;
+				goto EXIT;
+			}
+			ucFlag = INPUT_VALID;
+			if (pCommuData->usOutputLen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 1;
+		ucOpCode = 0x0;
+		break;
+	default:
+		{
+			count = -EINVAL;
+			goto EXIT;
+		}
+	}
+	pbufinctl = se_get_dma_buf(0);
+	if (pbufinctl == NULL) {
+		TRACEERR("kmalloc pCacheBuf error\n");
+		count = -ENOMEM;
+		goto EXIT;
+	}
+	pCacheBuf = pbufinctl->pDmaBuf;
+	pCacheBufalign = pCacheBuf;
+
+	if (wst_cpyusrbuf((void   *)(pCommuData->pucInbuf), (void *)pCacheBufalign,
+				pCommuData->usInputLen, READUBUF)) {
+		TRACEERR("cpyuserbuf pCacheBufalign error\n");
+		count = -ENOMEM;
+		goto EXIT;
+	}
+
+	pCacheOutBuf = pbufinctl->pDmaBuf;
+	pCacheOutBufalign = pCacheOutBuf;
+
+	ppucRetCode = &pucRetCode;
+
+	count = SE_OK;
+	init_completion(&mycomplete);
+	iret = se_hardtrans(
+		pdrvctl,
+		pCacheBufalign,
+		pCommuData->usInputLen,
+		pCacheOutBufalign,
+		&(pCommuData->usOutputLen),
+		iChannel,
+		ucFlag,
+		ucOpCode,
+		(unsigned char *)ppucRetCode,
+		0,
+		0,
+		0,
+		&mycomplete
+		);
+	if (iret == -1) {
+		count = -EIO;
+		goto EXIT;
+	}
+	if (!wait_for_completion_timeout(&mycomplete, msecs_to_jiffies(60*1000))) {
+		count = -EFAULT;
+		goto EXIT;
+	}
+	if (pucRetCode != SE_OK) {
+		count = -(SE_BASEERR+pucRetCode);
+		goto EXIT;
+	}
+
+	if (pCommuData->pucOutbuf) {
+		if (wst_cpyusrbuf(pCommuData->pucOutbuf, pCacheOutBufalign,
+					pCommuData->usOutputLen, WRITEUBUF)) {
+			count = -EFAULT;
+			goto EXIT;
+		}
+	}
+EXIT:
+	if (pbufinctl)
+		se_free_dma_buf(pbufinctl);
+	kfree(pCommuData);
+	return count;
+}
+static void globalmem_do_rec_op(struct work_struct *p)
+{
+	INT_MESSAGE *intmessage;
+	unsigned long ulflags1;
+
+	while (1) {
+		spin_lock_irqsave(&g_reclistlock, ulflags1);
+		intmessage = (INT_MESSAGE *)wst_Popfront_Que(&g_RecQueueContainer);
+		spin_unlock_irqrestore(&g_reclistlock, ulflags1);
+		if (!intmessage)
+			return;
+		intmessage->pcallback(intmessage->pParma);
+		kfree(intmessage);
+	}
+}
+static irqreturn_t se_interrupt(int irq, void *p)
+{
+	SECHIPDRV_CTRL *pdrvctl;
+	SE_BASIC_BD *pCurBD;
+	unsigned int	ulCurrReadPtr, ulReadPtr;
+	int iChannel;
+	int len = 0;
+	int i;
+	unsigned char ucMyRetCode = 0;
+	unsigned long ulIntStat;
+	int istatus[2] = {1, 2};
+	unsigned long ulflags;
+
+	pdrvctl = (SECHIPDRV_CTRL *)p;
+	if (!pdrvctl)
+		return IRQ_HANDLED;
+
+	read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+	HandleRead32(pdrvctl, SE_REG_STS, &ulIntStat);
+	read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+	if ((!(ulIntStat & INT_STAT_DMA_MASK)) || (ulIntStat == 0xffffffff))
+		return IRQ_HANDLED;
+
+	for (i = 0; i <= 1; i++) {
+		if (ulIntStat & istatus[i]) {
+			if (i == 0) {
+				read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+				HandleWrite32(pdrvctl, SE_INT_CLR, 1);
+				HandleRead32(pdrvctl, SE_REG_RQRP0, &ulReadPtr);
+				read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+				iChannel = 0;
+			} else {
+				read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+				HandleWrite32(pdrvctl, SE_INT_CLR, 2);
+				HandleRead32(pdrvctl, SE_REG_RQRP1, &ulReadPtr);
+				read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+				iChannel = 1;
+			}
+		} else
+			continue;
+		ulCurrReadPtr = pdrvctl->ulCurrReadPtr[iChannel];
+		while (1) {
+			if (ulCurrReadPtr != ulReadPtr) {
+				pCurBD = &((SE_BASIC_BD *)(pdrvctl->ulBDMemBase[iChannel]))[ulCurrReadPtr];
+				if ((pCurBD->ucRetCode == 0x0f) || ((pCurBD->ucFlag & 0x8) != 0x8)) {
+					continue;
+				} else {
+					if (pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr] == pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+						if (pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+							len = (*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])) >= pdrvctl->usInlen[iChannel][ulCurrReadPtr] ?
+								(*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])):pdrvctl->usInlen[iChannel][ulCurrReadPtr];
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]),
+								len,
+								DMA_BIDIRECTIONAL
+								);
+							pCurBD->ulOutputLPtr = 0;
+							pCurBD->ulOutputHPtr = 0;
+							pCurBD->ulInputHPtr = 0;
+							pCurBD->ulInputLPtr = 0;
+							pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+					} else {
+						if (pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]),
+								*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr]), DMA_FROM_DEVICE
+								);
+							smp_wmb();
+							pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+						if (pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr]) {
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr]),
+								pdrvctl->usInlen[iChannel][ulCurrReadPtr],
+								DMA_TO_DEVICE
+								);
+							pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+					}
+					ucMyRetCode = pCurBD->ucRetCode;
+					memcpy(pdrvctl->pucRetCode[iChannel][ulCurrReadPtr], &ucMyRetCode, 1);
+					if (pCurBD->ucRetCode != SE_OK)
+						pr_info("\nstatus %x\n", pCurBD->ucRetCode);
+#ifdef CONFIG_MIPS
+					atomic_sub(((*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])) + SE_FILL_LEN), &g_sendtotallen);
+#endif
+					if ((pdrvctl->ikernel)[iChannel][ulCurrReadPtr] != 0) {
+						if (pdrvctl->pcallback[iChannel][ulCurrReadPtr]) {
+							INT_MESSAGE *intmessage = NULL;
+							unsigned long ulflags1;
+
+							intmessage = (INT_MESSAGE   *)kmalloc(sizeof(INT_MESSAGE), GFP_ATOMIC);
+							if (!intmessage)
+								return IRQ_HANDLED;
+							intmessage->pcallback = pdrvctl->pcallback[iChannel][ulCurrReadPtr];
+							intmessage->pParma = pdrvctl->pParma[iChannel][ulCurrReadPtr];
+							spin_lock_irqsave(&g_reclistlock, ulflags1);
+							wst_Pushback_Que(&g_RecQueueContainer, intmessage);
+							spin_unlock_irqrestore(&g_reclistlock, ulflags1);
+							queue_work(g_workrecqueue, &g_recwork);
+						}
+					} else {
+						complete(pdrvctl->stsemphore[iChannel][ulCurrReadPtr]);
+					}
+					ulCurrReadPtr = ((ulCurrReadPtr + 1)&(SE_BDQUEUE_LEN - 1));
+					pdrvctl->ulCurrReadPtr[iChannel] = ulCurrReadPtr;
+					pdrvctl->ulCurrBdReadPtr[iChannel] = ulCurrReadPtr;
+					if (pdrvctl->sema.count <= 0)
+						up(&(pdrvctl->sema));
+				}
+			} else
+
+				break;
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int se_userrelease(struct inode *inode, struct file *file)
+{
+	return SE_OK;
+}
+
+ssize_t se_kernelwrite(
+					   unsigned char *pInPtr,
+					   unsigned short usInlen,
+					   unsigned char *pOutPtr,
+					   unsigned short *pusOutlen,
+					   unsigned char ucFlag,
+					   unsigned char *pucRetCode,
+					   PSECallBackfn pcallback,
+					   void *pParma
+					   )
+{
+	int iret;
+	SECHIPDRV_CTRL  *pdrvctl;
+	int iChannel;
+	unsigned char ucOpCode;
+	SWCommuData CommuData;
+
+	pdrvctl = g_psechipDrvCtrl;
+
+	switch (ucFlag) {
+	case WST_GO_CHANNEL2:
+		{
+			CommuData.pucInbuf = pInPtr;
+			CommuData.pucOutbuf = pOutPtr;
+			CommuData.usFlags = 0;
+			CommuData.usInputLen = usInlen;
+			CommuData.usOutputLen = *pusOutlen;
+			CommuData.usReserve = 0;
+			if (down_interruptible(&g_lowsema) == -EINTR)
+				return -EINTR;
+			iret = wst_low_channel_userwrite_op(pdrvctl, &CommuData, 1);
+			up(&g_lowsema);
+			return iret;
+		}
+	case WST_GO_CHANNEL0:
+		if (pcallback == NULL)
+			return WST_SE_PARAM_ERROR;
+		if (usInlen == 0)
+			return -EINVAL;
+		ucFlag = 0;
+		if (usInlen != 0) {
+			if (usInlen > DMA_BUFSIZE)
+				return -EINVAL;
+			ucFlag = INPUT_VALID;
+			if (*pusOutlen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 0;
+		ucOpCode = 0x0;
+		break;
+	case WST_GO_CHANNEL1:
+		if (pcallback == NULL)
+			return WST_SE_PARAM_ERROR;
+		if (usInlen == 0) {
+			return -EINVAL;
+		}
+		ucFlag = 0;
+		if (usInlen != 0) {
+			if (usInlen > DMA_BUFSIZE)
+				return -EINVAL;
+			ucFlag = INPUT_VALID;
+			if (*pusOutlen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 1;
+		ucOpCode = 0x0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	iret = se_hardtrans(
+		pdrvctl,
+		pInPtr,
+		usInlen,
+		pOutPtr,
+		pusOutlen,
+		iChannel,
+		ucFlag,
+		ucOpCode,
+		pucRetCode,
+		pcallback,
+		pParma,
+		1,
+		NULL
+		);
+	if (iret == -1)
+		return -EIO;
+
+	return SE_OK;
+}
+EXPORT_SYMBOL(se_kernelwrite);
+
+static long se_userioctl(struct file *filp, u_int cmd, u_long arg)
+{
+	long iret = SE_OK;
+	SECHIPDRV_CTRL *pdrvctl = g_psechipDrvCtrl;
+	unsigned long ulvalue;
+
+	HandleRead64(pdrvctl, 0x120, &ulvalue);
+	pr_info("read reg value is 0x%lx in offset 120\n", ulvalue);
+	HandleRead64(pdrvctl, 0x118, &ulvalue);
+	pr_info("read reg value is 0x%lx in offset 118\n", ulvalue);
+
+	return iret;
+}
+
+
+static const struct file_operations SE_fops = {
+	.owner = THIS_MODULE,
+	.write = se_userwrite,
+	.open = se_useropen,
+	.release = se_userrelease,
+	.unlocked_ioctl = se_userioctl,
+	.compat_ioctl = se_userioctl
+};
+
+int  se_chip_load(void)
+{
+	int iRes = SE_OK;
+
+	if (g_isechip_Major >= 0)
+		return WST_SE_HAS_OPEN;
+	g_psechipDrvCtrl = NULL;
+	iRes = se_init_dma_buf(DMA_BUFSIZE, CTL_DMABUFNUM);
+	if (iRes != SE_OK)
+		return WST_SE_ERROR_MALLOC;
+	iRes = register_chrdev(0, CRYNAME, &SE_fops);
+	if (iRes < 0)
+		goto EXIT;
+
+	g_isechip_Major = iRes;
+	iRes = 0;
+	g_psecclass = class_create(CRYNAME);
+	if (IS_ERR(g_psecclass)) {
+		iRes = PTR_ERR(g_psecclass);
+		goto EXIT;
+	}
+	g_psecdev = device_create(g_psecclass, NULL, MKDEV(g_isechip_Major, 0), NULL, CRYNAME);
+	if (IS_ERR(g_psecdev)) {
+		iRes = PTR_ERR(g_psecdev);
+		goto EXIT;
+	}
+	iRes = wst_init();
+	if (iRes != SE_OK)
+		goto EXIT;
+
+	sema_init(&g_lowsema, 1);
+	sema_init(&g_lowirqsema, 0);
+	atomic_set(&g_sendtotallen, 0);
+	g_pCacheInBuf = (unsigned char *)__get_free_page(GFP_DMA);
+	if (IS_ERR(g_pCacheInBuf)) {
+		iRes = PTR_ERR(g_pCacheInBuf);
+		goto EXIT;
+	}
+	g_pCacheOutBuf = (unsigned char *)__get_free_page(GFP_DMA);
+	if (IS_ERR(g_pCacheOutBuf)) {
+		iRes = PTR_ERR(g_pCacheOutBuf);
+		goto EXIT;
+	}
+
+	g_worksendqueue = alloc_workqueue("seworksendqueue",
+					WQ_MEM_RECLAIM|__WQ_ORDERED|WQ_UNBOUND, 1);
+	if (IS_ERR(g_worksendqueue)) {
+		iRes = PTR_ERR(g_worksendqueue);
+		goto EXIT;
+	}
+	g_workrecqueue = alloc_workqueue("seworkrecqueue", WQ_MEM_RECLAIM|__WQ_ORDERED, 0);
+	if (IS_ERR(g_workrecqueue)) {
+		iRes = PTR_ERR(g_workrecqueue);
+		goto EXIT;
+	}
+	INIT_WORK(&g_recwork, globalmem_do_rec_op);
+	INIT_WORK(&g_sendwork, globalmem_do_send_op);
+	pr_info("this driver version is %s\n", DRIVER_VERSION);
+
+	return SE_OK;
+EXIT:
+	se_del_dma_buf();
+	if (g_pCacheInBuf) {
+
+		free_page((unsigned long)g_pCacheInBuf);
+		g_pCacheInBuf = NULL;
+	}
+	if (g_pCacheOutBuf) {
+
+		free_page((unsigned long)g_pCacheOutBuf);
+		g_pCacheOutBuf = NULL;
+	}
+	if (g_worksendqueue) {
+		destroy_workqueue(g_worksendqueue);
+		g_worksendqueue = NULL;
+	}
+	if (g_workrecqueue) {
+		destroy_workqueue(g_workrecqueue);
+		g_workrecqueue = NULL;
+	}
+	wst_clear();
+	if (g_psecdev) {
+		device_unregister(g_psecdev);
+		g_psecdev = NULL;
+	}
+	if (g_psecclass) {
+		class_destroy(g_psecclass);
+		g_psecclass = NULL;
+	}
+	if (g_isechip_Major >= 0) {
+		unregister_chrdev(g_isechip_Major, CRYNAME);
+		g_isechip_Major = -1;
+	}
+	return iRes;
+}
+
+void se_chip_unload(void)
+{
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+
+	pdrvctl = g_psechipDrvCtrl;
+
+	up(&pdrvctl->sema);
+	if (g_pCacheInBuf) {
+
+		free_page((unsigned long)g_pCacheInBuf);
+		g_pCacheInBuf = NULL;
+	}
+	if (g_pCacheOutBuf) {
+
+		free_page((unsigned long)g_pCacheOutBuf);
+		g_pCacheOutBuf = NULL;
+	}
+	if (g_worksendqueue) {
+		cancel_work_sync(&g_sendwork);
+		destroy_workqueue(g_worksendqueue);
+		g_worksendqueue = NULL;
+	}
+	if (g_workrecqueue) {
+		cancel_work_sync(&g_recwork);
+		destroy_workqueue(g_workrecqueue);
+		g_workrecqueue = NULL;
+	}
+	wst_clear();
+	if (g_psecdev) {
+		device_destroy(g_psecclass, MKDEV(g_isechip_Major, 0));
+		g_psecdev = NULL;
+	}
+	if (g_psecclass) {
+		class_destroy(g_psecclass);
+		g_psecclass = NULL;
+	}
+	if (g_isechip_Major >= 0) {
+		unregister_chrdev(g_isechip_Major, CRYNAME);
+		g_isechip_Major = -1;
+	}
+	se_del_dma_buf();
+}
+
+static int loongson_cryp_get_irq(struct platform_device *pdev, char *pat)
+{
+	int i;
+	struct resource *res = pdev->resource;
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		if (strcmp(res[i].name, pat) == 0)
+			return res[i].start;
+	}
+	return -1;
+
+}
+static int loongson_cryp_probe(struct platform_device *pdev)
+{
+	int i;
+
+	if (ACPI_COMPANION(&pdev->dev)) {
+		se_irq[0].irq = platform_get_irq(pdev, 1);
+		se_irq[1].irq = platform_get_irq(pdev, 0);
+	} else {
+		for (i = 0; i < pdev->num_resources; i++) {
+			se_irq[i].irq = loongson_cryp_get_irq(pdev,
+							se_irq[i].pat);
+			if (se_irq[i].irq < 0) {
+				pr_warn("ERROR:sedriver get irq failed\n");
+				return -1;
+			}
+		}
+	}
+
+	return se_chip_load();
+}
+static int loongson_cryp_remove(struct platform_device *pdev)
+{
+	se_chip_unload();
+	return 0;
+}
+static int loongson_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	g_suspend = 1;
+	cancel_work_sync(&g_recwork);
+	cancel_work_sync(&g_sendwork);
+	flush_work(&g_recwork);
+	flush_work(&g_sendwork);
+	se_chip_unload();
+	return 0;
+}
+
+static int loongson_cryp_resume(struct platform_device *pdev)
+{
+	int i;
+
+	g_suspend = 0;
+	g_worksendqueue = NULL;
+	g_workrecqueue = NULL;
+	g_isechip_Major = -1;
+	g_pCacheInBuf = NULL;
+	g_pCacheOutBuf = NULL;
+	g_iUseIntr = 1;
+	spin_lock_init(&g_reclistlock);
+	spin_lock_init(&g_sendlistlock);
+	spin_lock_init(&g_getdmabuflock);
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		se_irq[i].irq = loongson_cryp_get_irq(pdev, se_irq[i].pat);
+
+		if (se_irq[i].irq < 0) {
+			pr_warn("ERROR:sedriver get irq failed\n");
+			return -1;
+		}
+	}
+	se_chip_load();
+	return 0;
+}
+
+static const struct acpi_device_id loongson_cryp_acpi_match[] = {
+	{"LOON0003"},
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, loongson_cryp_acpi_match);
+
+static struct platform_driver loongson_cryp_driver = {
+	.probe		= loongson_cryp_probe,
+	.remove		= loongson_cryp_remove,
+	.suspend	= loongson_cryp_suspend,
+	.resume		= loongson_cryp_resume,
+	.driver		= {
+			.name = "loongson3_crypto",
+			.acpi_match_table = ACPI_PTR(loongson_cryp_acpi_match),
+	},
+};
+
+static int __init initmodule(void)
+{
+	return platform_driver_register(&loongson_cryp_driver);
+}
+
+static void __exit exitmodule(void)
+{
+	platform_driver_unregister(&loongson_cryp_driver);
+}
+
+module_init(initmodule);
+module_exit(exitmodule);
+
+MODULE_ALIAS("platform:loongson3_crypto");
+MODULE_AUTHOR("dcm");
+MODULE_DESCRIPTION("se encryption chip driver Co westone");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/sedriver/wst_se_echip_driver.h b/drivers/crypto/sedriver/wst_se_echip_driver.h
new file mode 100644
index 000000000000..3e562e55faac
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_echip_driver.h
@@ -0,0 +1,184 @@
+#ifndef _WST_SE_ECHIP_DRIVER_H
+#define _WST_SE_ECHIP_DRIVER_H
+#include "wst_se_ktrans.h"
+
+#define CRYNAME "wst-se"
+
+#define SWBUFNUM     512
+#define SWCHANNELNUM 2
+#define CTL_DMABUFNUM  512
+
+#define DMA_MASK 0xffffffff
+#define SE_DMA_CONTROL_RESET 0x80000000
+#define SE_DMA_CONTROL_SET   0x00000000
+
+#define SE_BASEERR 1000
+
+#define SE_MAX_SEND_LEN (3*2048)
+#define SE_FILL_LEN 48
+#define SE_BD_LENGTH sizeof(SE_BASIC_BD)
+#define SE_BDQUEUE_LEN  SWBUFNUM
+#define DMA0_CTRL_CHANNEL_ENABLE    1
+#define DMA0_CTRL_CHANNEL_DISABLE   0xfffffffe
+#define DMA1_CTRL_CHANNEL_ENABLE    2
+#define DMA1_CTRL_CHANNEL_DISABLE   0xfffffffd
+
+#define SE_REG_RESET			 0
+#define SE_REG_STS				0x08
+#define SE_INT_CTRL				0x10
+#define SE_REG_MSK				0x18
+#define SE_INT_CLR				0x20
+
+#define SE_LREG_BQBA0			0x100
+#define SE_HREG_BQBA0			0x108
+#define SE_REG_BQS0				0x110
+#define SE_REG_BQWP0			0x118
+#define SE_REG_RQRP0			0x120
+
+#define SE_LREG_BQBA1			0x128
+#define SE_HREG_BQBA1			0x130
+#define SE_REG_BQS1				0x138
+#define SE_REG_BQWP1			0x140
+#define SE_REG_RQRP1			0x148
+
+#define SE_WRITE_REG1			0x200
+#define SE_WRITE_REG2			0x208
+#define SE_WRITE_REG3			0x210
+#define SE_LOWREG_STS			0x240
+#define SE_LOWINT_CLEAR			0x248
+#define SE_LOWREG_INQ			0x1600
+#define SE_LOWREG_SR			0x1608
+#define INPUT_VALID				0x4
+#define OUTPUT_VALID			0x8
+#define SE_LOWINT_CLR			0x228
+#define INT_STAT_DMA0_PACK_DONE 1
+#define INT_STAT_DMA1_PACK_DONE 2
+#define INT_STAT_DMA_MASK		(INT_STAT_DMA0_PACK_DONE|INT_STAT_DMA1_PACK_DONE)
+
+typedef struct tagSEdrvctl {
+
+	unsigned long	ulMemBase;
+	struct device	*pdev;
+	struct device	dev;
+	unsigned int	ulCurrBdReadPtr[SWCHANNELNUM];
+	unsigned int	ulCurrBdWritePtr[SWCHANNELNUM];
+	unsigned int	ulCurrReadPtr[SWCHANNELNUM];
+	unsigned int	ulCurrWritePtr[SWCHANNELNUM];
+	PSECallBackfn	pcallback[SWCHANNELNUM][SWBUFNUM];
+	void *pParma[SWCHANNELNUM][SWBUFNUM];
+	struct completion	*stsemphore[SWCHANNELNUM][SWBUFNUM];
+	int		ikernel[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	ulBDMemBasePhy[SWCHANNELNUM];
+	unsigned long	ulBDMemBase[SWCHANNELNUM];
+	unsigned short	*pusOutlen[SWCHANNELNUM][SWBUFNUM];
+	unsigned short	usInlen[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	*ulOutputPtr[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	*ulInputPtr[SWCHANNELNUM][SWBUFNUM];
+	unsigned char	*pucRetCode[SWCHANNELNUM][SWBUFNUM];
+	rwlock_t mr_lock;
+	rwlock_t mr_lowlock;
+	spinlock_t readlock;
+	struct semaphore sema;
+	int iIrq;
+	int ilowIrq;
+} SECHIPDRV_CTRL;
+
+typedef struct tagSEBasicBD {
+
+	unsigned int  ucOpCode:4,
+		ucFlag:4,
+		ucRetCode:8,
+		ucInCtxLength:8,
+		ucOutCtxLength:8;
+	unsigned int	usInputLength:16,
+		usOutputLength:16;
+	unsigned int	ulCtxLPtr;
+	unsigned int	ulCtxHPtr;
+	unsigned int	ulInputLPtr;
+	unsigned int	ulInputHPtr;
+	unsigned int	ulOutputLPtr;
+	unsigned int	ulOutputHPtr;
+
+} SE_BASIC_BD;
+
+#define SW_CONT_BUF_SIZE		0x100
+#define DMA_BUFSIZE				0x1000
+
+#define PAGE_NUM (DMA_BUFSIZE/PAGE_SIZE+1)
+
+typedef struct _SW_GET_STAT {
+	unsigned long TXD;
+	unsigned long RXD;
+} SW_GET_STAT, *PSW_GET_STAT;
+
+DEFINE_SPINLOCK(g_writelock);
+
+#define HandleRead32(handle, addr, pData) \
+	do { \
+		smp_mb(); \
+		*(pData) = readl((void *)(handle->ulMemBase + addr));	\
+	} while (0)
+
+#define HandleWrite32(handle, addr, value)\
+	do { \
+		writel(value, (void *)(handle->ulMemBase + addr));	\
+		smp_mb(); \
+	} while (0)
+
+#define HandleRead64(handle, addr, pData) \
+	do { \
+		smp_mb(); \
+		*(pData) = readq((void *)(handle->ulMemBase + addr));	\
+	} while (0)
+
+#define HandleWrite64(handle, addr, value)\
+	do { \
+		writeq(value, (void *)(handle->ulMemBase + addr));	\
+		smp_mb(); \
+	} while (0)
+
+
+#define SPRINTF sprintf
+
+#define HIULONG(w)	((unsigned int)((((unsigned long long)w) >> 32) & 0x00000000ffffffff))
+#define LOULONG(w)	((unsigned int)((unsigned long long)w) & 0x00000000ffffffff)
+
+#ifdef DEBUG_DRIVER
+	#define TRACEMSG(fmt, args...) printk(KERN_DEBUG "msg: " fmt, ##args)
+#else
+	#define TRACEMSG(fmt, args...)
+#endif
+
+#ifdef DEBUG_DRIVER_ERROR
+	#define TRACEERR(fmt, args...) printk(KERN_DEBUG "err: " fmt, ##args)
+#else
+	#define TRACEERR(fmt, args...)
+#endif
+
+#define HIBYTE(w)		((unsigned char)(((unsigned short)(w) >> 8) & 0xFF))
+#define LOBYTE(w)		((unsigned char)(w))
+
+typedef struct ST_SEND_PACKAGE {
+	struct list_head  list;
+	SECHIPDRV_CTRL  *pdrvctl;
+	unsigned char *pInPtr;
+	unsigned short usInlen;
+	unsigned char *pOutPtr;
+	unsigned short *pusOutlen;
+	int iChannel;
+	unsigned char ucFlag;
+	unsigned char ucOpCode;
+	unsigned char *pucRetCode;
+	PSECallBackfn pcallback;
+	void *pParma;
+	int iKernel;
+	struct completion *mycomplete;
+	unsigned long ulendtime;
+} SEND_PACKAGE;
+
+typedef struct ST_INT_MESSAGE {
+	struct list_head  list;
+	PSECallBackfn pcallback;
+	void *pParma;
+} INT_MESSAGE;
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_ktrans.h b/drivers/crypto/sedriver/wst_se_ktrans.h
new file mode 100644
index 000000000000..da6c4b8f2824
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_ktrans.h
@@ -0,0 +1,17 @@
+#ifndef _WST_SE_KTRANS_H
+#define _WST_SE_KTRANS_H
+
+#include "wst_se_common_type.h"
+#include "wst_se_define.h"
+
+
+typedef struct tagSWCOMMUDATA {
+	unsigned short usFlags;
+	unsigned short usInputLen;
+	unsigned short usOutputLen;
+	unsigned short usReserve;
+	unsigned char *pucInbuf;
+	unsigned char *pucOutbuf;
+} SWCommuData;
+
+#endif
-- 
2.33.0
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                     
                        
                    14 Apr '25
                    
                        Ard Biesheuvel (1):
  objtool: Fix C jump table annotations for Clang
Gao Qihang (1):
  LoongArch: Preserve firmware configuration if ACPI requires.
Juxin Gao (1):
  LoongArch: configs: set CONFIG_UNWINDER_ORC=y
Ming Wang (1):
  LoongArch: configs: Disable CONFIG_RT_GROUP_SCHED to prevent cgroup2
    issues
Tiezhu Yang (3):
  LoongArch: Handle fp, lsx, lasx and lbt assembly symbols
  LoongArch: Make some signal and ptrace functions non-static
  LoongArch: Export some signal functions
 arch/loongarch/configs/loongson3_defconfig |  2 +-
 arch/loongarch/include/asm/fpu.h           |  6 ++++
 arch/loongarch/include/asm/lbt.h           |  4 +++
 arch/loongarch/kernel/Makefile             |  1 +
 arch/loongarch/kernel/extern.c             | 31 ++++++++++++++++++
 arch/loongarch/kernel/fpu.S                |  6 ++++
 arch/loongarch/kernel/lbt.S                |  4 +++
 arch/loongarch/kernel/ptrace.c             | 37 +++++++++++++++-------
 arch/loongarch/kernel/signal.c             | 28 +++-------------
 arch/loongarch/pci/acpi.c                  | 14 ++++++--
 include/linux/compiler.h                   |  2 +-
 tools/objtool/check.c                      |  7 ++--
 tools/objtool/include/objtool/special.h    |  2 +-
 13 files changed, 102 insertions(+), 42 deletions(-)
 create mode 100644 arch/loongarch/kernel/extern.c
-- 
2.33.0
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            8
                            
                          
                          
                            
    
                          
                        
                    
                    
                        From: Qunqin Zhao <zhaoqunqin(a)loongson.cn>
LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IC10DU
CVE: NA
--------------------------------
Add support for WST se chip support for LS*5000*.
Signed-off-by: Qunqin Zhao <zhaoqunqin(a)loongson.cn>
---
 arch/loongarch/configs/loongson3_defconfig    |    1 +
 drivers/crypto/Kconfig                        |    1 +
 drivers/crypto/Makefile                       |    1 +
 drivers/crypto/sedriver/Kconfig               |    8 +
 drivers/crypto/sedriver/Makefile              |    7 +
 drivers/crypto/sedriver/wst_se_common_type.h  |   98 ++
 drivers/crypto/sedriver/wst_se_define.h       |   27 +
 drivers/crypto/sedriver/wst_se_echip_driver.c | 1368 +++++++++++++++++
 drivers/crypto/sedriver/wst_se_echip_driver.h |  184 +++
 drivers/crypto/sedriver/wst_se_ktrans.h       |   17 +
 10 files changed, 1712 insertions(+)
 create mode 100644 drivers/crypto/sedriver/Kconfig
 create mode 100644 drivers/crypto/sedriver/Makefile
 create mode 100644 drivers/crypto/sedriver/wst_se_common_type.h
 create mode 100644 drivers/crypto/sedriver/wst_se_define.h
 create mode 100644 drivers/crypto/sedriver/wst_se_echip_driver.c
 create mode 100644 drivers/crypto/sedriver/wst_se_echip_driver.h
 create mode 100644 drivers/crypto/sedriver/wst_se_ktrans.h
diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig
index 980f5f2c99a1..cf359d1a2554 100644
--- a/arch/loongarch/configs/loongson3_defconfig
+++ b/arch/loongarch/configs/loongson3_defconfig
@@ -2177,6 +2177,7 @@ CONFIG_CRYPTO_CRC32_LOONGARCH=m
 CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
 CONFIG_CRYPTO_DEV_CHELSIO=m
 CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_SW_SE_CHIP=m
 CONFIG_SIGNED_PE_FILE_VERIFICATION=y
 CONFIG_SECONDARY_TRUSTED_KEYRING=y
 CONFIG_SYSTEM_BLACKLIST_KEYRING=y
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index b84a921d293f..efd6a855bca3 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -836,5 +836,6 @@ config CRYPTO_DEV_SA2UL
 source "drivers/crypto/aspeed/Kconfig"
 source "drivers/crypto/starfive/Kconfig"
 source "drivers/crypto/montage/Kconfig"
+source "drivers/crypto/sedriver/Kconfig"
 
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 5247d2bf09ce..6ad337bad109 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
 obj-y += intel/
 obj-y += starfive/
 obj-y += montage/
+obj-$(CONFIG_SW_SE_CHIP) += sedriver/
diff --git a/drivers/crypto/sedriver/Kconfig b/drivers/crypto/sedriver/Kconfig
new file mode 100644
index 000000000000..6a11bdf1e5fa
--- /dev/null
+++ b/drivers/crypto/sedriver/Kconfig
@@ -0,0 +1,8 @@
+#
+# se chip configuration
+#
+config SW_SE_CHIP
+	tristate "wst se chip driver"
+	depends on LOONGARCH
+	help
+		If unsure, say N.
diff --git a/drivers/crypto/sedriver/Makefile b/drivers/crypto/sedriver/Makefile
new file mode 100644
index 000000000000..0ee095d1a1d2
--- /dev/null
+++ b/drivers/crypto/sedriver/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for SE CHIP Driver
+#
+
+obj-$(CONFIG_SW_SE_CHIP) += sw_se_echip_drv.o
+sw_se_echip_drv-objs :=  wst_se_echip_driver.o
+
diff --git a/drivers/crypto/sedriver/wst_se_common_type.h b/drivers/crypto/sedriver/wst_se_common_type.h
new file mode 100644
index 000000000000..e29e9bccaa6d
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_common_type.h
@@ -0,0 +1,98 @@
+#ifndef _WST_SE_COMMON_TYPE_H
+#define _WST_SE_COMMON_TYPE_H
+
+#include <linux/kernel.h>	/* We're doing kernel work */
+#include <linux/module.h>	/* Specifically, a module */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/mman.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#define WST_GO_CHANNEL0			0x0002
+#define WST_GO_CHANNEL1		0x0000
+#define WST_GO_CHANNEL2		0x0001
+
+#define SE_OK 0
+
+struct loongson_sedriver_irq {
+	char  *pat;
+	int irq;
+};
+
+typedef struct tag_dma_buf_ctl {
+	struct list_head  list;
+	unsigned char *pDmaBuf;
+} dmabuf_ctl, *pdmabuf_ctl;
+
+typedef struct tag_Queue_container {
+	struct list_head     m_Head;
+	unsigned int qlen;
+	unsigned int max_qlen;
+} QUEUE_CONTAIN, *PQUEUE_CONTAIN;
+
+
+static inline int  wst_InitQueue(struct tag_Queue_container *pQueue, int count)
+{
+	INIT_LIST_HEAD(&pQueue->m_Head);
+	pQueue->qlen = 0;
+	pQueue->max_qlen = count;
+	return 0;
+}
+
+
+static inline struct list_head *wst_Popfront_Que(struct tag_Queue_container *pQueue)
+{
+	struct list_head *pNode = NULL;
+
+	if (list_empty(&pQueue->m_Head))
+		return NULL;
+
+	pQueue->qlen--;
+	pNode = pQueue->m_Head.next;
+	list_del(pNode);
+	return pNode;
+}
+
+
+static inline int  wst_Pushback_Que(struct tag_Queue_container *pQueue, void *pNode)
+{
+	if (unlikely(pQueue->qlen >= pQueue->max_qlen))
+		return -1;
+
+	pQueue->qlen++;
+	list_add_tail((struct list_head *)(pNode), &pQueue->m_Head);
+	return 0;
+}
+
+#define READUBUF  0
+#define WRITEUBUF 1
+
+static inline int wst_cpyusrbuf(unsigned char  *puserbuf,
+				unsigned char *pkbuf, size_t num, int orient)
+{
+	if (orient == READUBUF)
+		return copy_from_user(pkbuf, puserbuf, num);
+	else
+		return copy_to_user(puserbuf, pkbuf, num);
+}
+
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_define.h b/drivers/crypto/sedriver/wst_se_define.h
new file mode 100644
index 000000000000..7a29f1029afa
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_define.h
@@ -0,0 +1,27 @@
+#ifndef _WST_SE_DEFINE_H
+#define _WST_SE_DEFINE_H
+
+
+typedef void (*PSECallBackfn)(void *pParam);
+
+#define WST_SE_OK			0	//function syccess
+#define WST_SE_FAILURE			1
+#define WST_SE_ERROR_MALLOC		2
+#define WST_SE_ERROR_OPEN		3
+#define WST_SE_ERROR_ID			4
+#define WST_SE_ERROR_OPERTYPE		5
+#define WST_SE_ERROR_KEYID		6
+#define WST_SE_NOT_SUPPORT		7
+#define WST_SE_ERROR_FULL		8
+#define WST_SE_VERIFY_ERROR	0xb
+#define WST_SE_NOT_SUPPORT_VERIFY	0xd
+#define WST_SE_ERROR_LENGTH	0xc
+#define WST_SE_HAS_OPEN			0xd
+#define WST_COPY_MEM_ERROR		0xe
+#define WST_SE_PARAM_ERROR		0xf
+
+#define BASE_ERROR			0x1000
+#define WST_SE_ERROR_LICENSE		0x100b
+#define WST_SE_ERROR_NOT_SUPPORT_TYPE 0x100d
+
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_echip_driver.c b/drivers/crypto/sedriver/wst_se_echip_driver.c
new file mode 100644
index 000000000000..66e34549d209
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_echip_driver.c
@@ -0,0 +1,1368 @@
+#include <linux/semaphore.h>
+#include <linux/moduleparam.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/crypto.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/acpi.h>
+#include <asm/loongson.h>
+#include "wst_se_echip_driver.h"
+
+#define LS_CRYPTO_SE_ADDR1 TO_UNCACHE(LOONGSON_REG_BASE+0x0400)
+#define LS_CRYPTO_SE_ADDR2 TO_UNCACHE(0xc0010200000)
+#define DRIVER_VERSION "01.10.220111"
+DEFINE_SPINLOCK(g_reclistlock);
+DEFINE_SPINLOCK(g_sendlistlock);
+DEFINE_SPINLOCK(g_getdmabuflock);
+
+unsigned char *g_pCacheInBuf = NULL, *g_pCacheOutBuf = NULL;
+static struct class *g_psecclass;
+static struct device *g_psecdev;
+static SECHIPDRV_CTRL *g_psechipDrvCtrl;
+static int g_isechip_Major = -1;
+static struct semaphore g_lowsema, g_lowirqsema;
+static atomic_t g_sendtotallen;
+static struct tag_Queue_container g_RecQueueContainer;
+static struct tag_Queue_container g_SendQueueContainer;
+static int g_suspend;
+static struct semaphore g_dmabufsem;
+struct loongson_sedriver_irq se_irq[] = {
+	{
+		.pat = "se-irq",
+	},
+	{
+		.pat = "se-lirq",
+	},
+};
+static struct tag_Queue_container g_DmaBQueueContainer;
+static struct tag_dma_buf_ctl *g_pdmadatabuf;
+static int g_iDmaBufNum;
+static struct work_struct g_recwork, g_sendwork;
+static struct workqueue_struct *g_worksendqueue, *g_workrecqueue;
+static irqreturn_t se_interrupt(int irq, void *p);
+static irqreturn_t wst_low_channel_status(int irq, void *p);
+static void globalmem_do_send_op(struct work_struct *p);
+static void globalmem_do_rec_op(struct work_struct *p);
+static int g_iUseIntr = 1;
+module_param(g_iUseIntr, int, 0644);
+
+static int se_init_dma_buf(int idatasize, int idatanum)
+{
+	int i;
+	struct tag_dma_buf_ctl *pdmactl;
+
+	wst_InitQueue(&g_DmaBQueueContainer, idatanum);
+	g_pdmadatabuf = kmalloc((sizeof(struct tag_dma_buf_ctl)*idatanum), GFP_KERNEL);
+	if (!g_pdmadatabuf)
+		return -1;
+	for (i = 0; i < idatanum; i++) {
+		pdmactl = &g_pdmadatabuf[i];
+		pdmactl->pDmaBuf = (unsigned char *)__get_free_page(GFP_KERNEL|GFP_DMA);
+		if (!pdmactl->pDmaBuf) {
+			g_iDmaBufNum = i;
+			return SE_OK;
+		}
+		wst_Pushback_Que(&g_DmaBQueueContainer, pdmactl);
+	}
+	g_iDmaBufNum = i;
+	sema_init(&g_dmabufsem, 1);
+	return SE_OK;
+}
+
+static int se_del_dma_buf(void)
+{
+	int i;
+	struct tag_dma_buf_ctl *pdmactl;
+
+	for (i = 0; i < g_iDmaBufNum; i++) {
+		pdmactl = &g_pdmadatabuf[i];
+		if (pdmactl) {
+			free_page((unsigned long)pdmactl->pDmaBuf);
+			pdmactl->pDmaBuf = NULL;
+		}
+	}
+	kfree(g_pdmadatabuf);
+	g_pdmadatabuf = NULL;
+	return 0;
+}
+
+struct tag_dma_buf_ctl *se_get_dma_buf(int ikernel)
+{
+	struct tag_dma_buf_ctl *pbufctl = NULL;
+	unsigned long ultimeout = 0;
+
+	ultimeout = jiffies+20*HZ;
+	while (1) {
+		spin_lock(&g_getdmabuflock);
+		pbufctl = (struct tag_dma_buf_ctl *)wst_Popfront_Que(&g_DmaBQueueContainer);
+		spin_unlock(&g_getdmabuflock);
+		if (pbufctl)
+			return pbufctl;
+		if (down_timeout(&g_dmabufsem, ultimeout))
+			return NULL;
+	}
+	return pbufctl;
+}
+
+int se_free_dma_buf(struct tag_dma_buf_ctl *pdmabufctl)
+{
+	spin_lock(&g_getdmabuflock);
+	wst_Pushback_Que(&g_DmaBQueueContainer, pdmabufctl);
+	spin_unlock(&g_getdmabuflock);
+	if (g_dmabufsem.count <= 0)
+		up(&g_dmabufsem);
+
+	return 0;
+}
+
+static unsigned long  bytes_align(struct device *pdev, unsigned long ulVirAddr)
+{
+	unsigned char diff;
+	unsigned long ulPhyAddr = (unsigned long)__pa((void *)ulVirAddr);
+
+	if ((ulPhyAddr & 0x000000000000003f) == 0)
+		return ulVirAddr;
+	diff = ((long)ulPhyAddr & (~(0x000000000000003f))) + 64 - ulPhyAddr;
+	ulVirAddr += diff;
+
+	return ulVirAddr;
+}
+
+static unsigned long  descri_bytes_align(unsigned long ulVirAddr)
+{
+	unsigned char diff;
+	unsigned long ulPhyAddr = ulVirAddr;
+
+	if ((ulPhyAddr & (~0x00000000ffffffe0)) == 0)
+		return ulVirAddr;
+	diff = ((long)ulPhyAddr & 0x00000000ffffffe0) + 32 - ulPhyAddr;
+	ulVirAddr += diff;
+	return ulVirAddr;
+}
+
+int se_printk_hex(unsigned char *buff, int length)
+{
+	unsigned char *string_tmp = buff;
+	int i;
+	int count = 0;
+
+	for (i = 0; i < length; i++, count++) {
+		if (count < 16)
+			pr_info("%02x ", string_tmp[i]);
+		else {
+			count = 0;
+			pr_info("\n%02x ", string_tmp[i]);
+			continue;
+		}
+	}
+	pr_info("\n");
+	return 0;
+}
+
+static int se_ChipInit(SECHIPDRV_CTRL *pDrvCtrl)
+{
+	dma_addr_t ulBusAddr;
+	unsigned long ulVirAddr;
+	int i = 0, j = 0;
+	unsigned int dmaoldmask;
+
+	for (i = 0; i < SWCHANNELNUM; i++) {
+		ulVirAddr = (unsigned long)dma_alloc_coherent(
+			pDrvCtrl->pdev,
+			(SE_BDQUEUE_LEN * SE_BD_LENGTH+32),
+			&ulBusAddr, GFP_KERNEL
+			);
+		if (ulVirAddr == 0 || ulBusAddr == 0)
+			return -EFAULT;
+		memset((void *)ulVirAddr, 0, (SE_BDQUEUE_LEN*SE_BD_LENGTH));
+
+		pDrvCtrl->ulBDMemBasePhy[i]   = ulBusAddr;
+		pDrvCtrl->ulBDMemBase[i]      = ulVirAddr;
+		pDrvCtrl->ulCurrBdReadPtr[i]  = 0;
+		pDrvCtrl->ulCurrBdWritePtr[i] = 0;
+		pDrvCtrl->ulCurrReadPtr[i]  = 0;
+		pDrvCtrl->ulCurrWritePtr[i] = 0;
+	}
+	for (i = 0; i < SE_BDQUEUE_LEN; i++) {
+		for (j = 0; j < SWCHANNELNUM; j++)
+			(&((SE_BASIC_BD *)(pDrvCtrl->ulBDMemBase[j]))[i])->ucRetCode = 0x0f;
+	}
+	ulBusAddr = descri_bytes_align(pDrvCtrl->ulBDMemBasePhy[0]);
+	HandleWrite32(pDrvCtrl, SE_HREG_BQBA0, HIULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_LREG_BQBA0, LOULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_REG_BQS0,  SE_BDQUEUE_LEN - 1);
+	HandleWrite32(pDrvCtrl, SE_REG_RQRP0, pDrvCtrl->ulCurrBdReadPtr[0]);
+	HandleWrite32(pDrvCtrl, SE_REG_BQWP0, pDrvCtrl->ulCurrBdWritePtr[0]);
+
+	ulBusAddr = descri_bytes_align(pDrvCtrl->ulBDMemBasePhy[1]);
+	HandleWrite32(pDrvCtrl, SE_HREG_BQBA1, HIULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_LREG_BQBA1, LOULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_REG_BQS1,  SE_BDQUEUE_LEN - 1);
+	HandleWrite32(pDrvCtrl, SE_REG_RQRP1, pDrvCtrl->ulCurrBdReadPtr[1]);
+	HandleWrite32(pDrvCtrl, SE_REG_BQWP1, pDrvCtrl->ulCurrBdWritePtr[1]);
+	HandleRead32(pDrvCtrl, SE_REG_MSK, &dmaoldmask);
+	HandleWrite32(pDrvCtrl, SE_REG_MSK, (dmaoldmask | DMA0_CTRL_CHANNEL_ENABLE | DMA1_CTRL_CHANNEL_ENABLE));
+	if (g_iUseIntr != 0)
+		HandleWrite32(pDrvCtrl, SE_LOWREG_INQ, 1);
+	else
+		HandleWrite32(pDrvCtrl, SE_LOWREG_INQ, 0);
+	mdelay(1000);
+
+	return SE_OK;
+}
+
+static void  se_ChipRelease(SECHIPDRV_CTRL *pDrvCtrl)
+{
+	int i;
+
+	for (i = 0; i < SWCHANNELNUM; i++) {
+		if (pDrvCtrl->ulBDMemBase[i]) {
+			dma_free_coherent(
+				pDrvCtrl->pdev,
+				(SE_BDQUEUE_LEN * SE_BD_LENGTH),
+				(void *)pDrvCtrl->ulBDMemBase[i],
+				pDrvCtrl->ulBDMemBasePhy[i]
+				);
+			pDrvCtrl->ulBDMemBase[i] = 0;
+			pDrvCtrl->ulBDMemBasePhy[i] = 0;
+		}
+	}
+}
+
+static void SE_RESET(SECHIPDRV_CTRL *pdrvctl)
+{
+
+	unsigned int reg;
+	unsigned long   ulreg64, uladdr = LS_CRYPTO_SE_ADDR1;
+
+	HandleRead32(pdrvctl, SE_REG_RESET, ®);
+	HandleWrite32(pdrvctl, SE_REG_RESET, reg|SE_DMA_CONTROL_RESET);
+	mdelay(300);
+	HandleWrite32(pdrvctl, SE_REG_RESET, (reg&(~SE_DMA_CONTROL_RESET))|SE_DMA_CONTROL_SET);
+	mdelay(300);
+	ulreg64 = readq((volatile void __iomem *)uladdr);
+	if ((ulreg64 & 0xf0000000000000) != 0xf0000000000000)
+		writeq(ulreg64|0xf0000000000000, (volatile void __iomem *)uladdr);
+	HandleWrite32(pdrvctl, SE_INT_CLR, 0xf);
+}
+
+static int wst_init(void)
+{
+	int iRes = SE_OK;
+	static u64 wst_dma_mask = DMA_BIT_MASK(64);
+	char cName[256];
+	SECHIPDRV_CTRL *pdrvctl = NULL;
+
+	pdrvctl = kmalloc(sizeof(SECHIPDRV_CTRL), GFP_KERNEL);
+	if (pdrvctl == NULL)
+		return -ENOMEM;
+	memset(pdrvctl, 0, sizeof(SECHIPDRV_CTRL));
+	pdrvctl->ulMemBase = LS_CRYPTO_SE_ADDR2;
+	memset(cName, 0, 256);
+	sema_init(&(pdrvctl->sema), 0);
+	rwlock_init(&(pdrvctl->mr_lock));
+	rwlock_init(&(pdrvctl->mr_lowlock));
+	g_psechipDrvCtrl = pdrvctl;
+	g_psechipDrvCtrl->pdev = g_psecdev;
+	g_psechipDrvCtrl->pdev->dma_mask = &wst_dma_mask;
+	g_psechipDrvCtrl->pdev->coherent_dma_mask = (unsigned long long)&wst_dma_mask;
+	wst_InitQueue(&g_RecQueueContainer, 2000);
+	wst_InitQueue(&g_SendQueueContainer, 2000);
+	SE_RESET(pdrvctl);
+	pdrvctl->ilowIrq = 0;
+	pdrvctl->iIrq = se_irq[0].irq;
+	iRes = request_irq(pdrvctl->iIrq, &se_interrupt, IRQF_SHARED, "wst-se-hirq", pdrvctl);
+	if (iRes) {
+		pr_err("request_irq err\n");
+		pdrvctl->iIrq = 0;
+		goto err;
+	}
+	if (g_iUseIntr == 1) {
+		pdrvctl->ilowIrq = se_irq[1].irq;
+		iRes = request_irq(pdrvctl->ilowIrq, &wst_low_channel_status, IRQF_SHARED, "wst-se-lirq", pdrvctl);
+		if (iRes) {
+			pr_err("\nrequest_lowirq err, iRes=0x%x\n", iRes);
+			pdrvctl->ilowIrq = 0;
+			goto err;
+		}
+	}
+	if (se_ChipInit(pdrvctl) != SE_OK) {
+		iRes = -ENODEV;
+		goto err;
+	}
+	return SE_OK;
+err:
+	if (pdrvctl != NULL) {
+		if (pdrvctl->iIrq) {
+			free_irq(pdrvctl->iIrq, pdrvctl);
+			pdrvctl->iIrq = 0;
+		}
+		if (pdrvctl->ilowIrq) {
+			free_irq(pdrvctl->ilowIrq, pdrvctl);
+			pdrvctl->ilowIrq = 0;
+		}
+		se_ChipRelease(pdrvctl);
+		kfree(pdrvctl);
+		g_psechipDrvCtrl = NULL;
+	}
+	return iRes;
+}
+
+static void wst_clear(void)
+{
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+
+	pdrvctl = g_psechipDrvCtrl;
+	if (pdrvctl) {
+		if (pdrvctl->iIrq) {
+			free_irq(pdrvctl->iIrq, pdrvctl);
+			pdrvctl->iIrq = 0;
+		}
+		if (pdrvctl->ilowIrq) {
+			free_irq(pdrvctl->ilowIrq, pdrvctl);
+			pdrvctl->ilowIrq = 0;
+		}
+		se_ChipRelease(pdrvctl);
+		kfree(pdrvctl);
+		g_psechipDrvCtrl = NULL;
+	}
+}
+static void globalmem_do_send_op(struct work_struct *p)
+{
+	SE_BASIC_BD *pCurBD;
+	unsigned int ulCurrWritePtr, ulWritePtr;
+	unsigned short len = 0;
+	unsigned long ulCurrAddrInput = 0, ulCurrAddrOutput = 0;
+	SECHIPDRV_CTRL  *pdrvctl;
+	unsigned char *pInPtr;
+	unsigned short usInlen;
+	unsigned char *pOutPtr;
+	unsigned short *pusOutlen;
+	int iChannel;
+	unsigned char ucFlag;
+	unsigned char ucOpCode;
+	unsigned char *pucRetCode;
+	PSECallBackfn pcallback;
+	void *pParma;
+	int iKernel;
+	struct completion *mycomplete;
+	SEND_PACKAGE *psendpackage;
+	unsigned long ulflag;
+	unsigned long ultimeout;
+	int rv = 0;
+
+	while (1) {
+PROG:
+	spin_lock_irq(&g_sendlistlock);
+	psendpackage = (SEND_PACKAGE *)wst_Popfront_Que(&g_SendQueueContainer);
+	if (!psendpackage) {
+		spin_unlock_irq(&g_sendlistlock);
+		return;
+	}
+	spin_unlock_irq(&g_sendlistlock);
+	pdrvctl = psendpackage->pdrvctl;
+	pInPtr = psendpackage->pInPtr;
+	usInlen = psendpackage->usInlen;
+	pOutPtr = psendpackage->pOutPtr;
+	pusOutlen = psendpackage->pusOutlen;
+	iChannel = psendpackage->iChannel;
+	ucFlag = psendpackage->ucFlag;
+	ucOpCode = psendpackage->ucOpCode;
+	pucRetCode = psendpackage->pucRetCode;
+	pcallback = psendpackage->pcallback;
+	pParma = psendpackage->pParma;
+	iKernel = psendpackage->iKernel;
+	mycomplete = psendpackage->mycomplete;
+	ultimeout = psendpackage->ulendtime;
+	kfree(psendpackage);
+
+	if (iKernel == 0) {
+		while (time_before(jiffies, ultimeout)) {
+#ifdef CONFIG_MIPS
+			if ((pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+			|| ((atomic_read(&g_sendtotallen) + *pusOutlen + SE_FILL_LEN) > SE_MAX_SEND_LEN))
+#else
+			if (pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+#endif
+			{
+				down_timeout(&(pdrvctl->sema), 1*HZ);
+				rv = WST_SE_ERROR_FULL;
+			} else {
+				rv = 0;
+				break;
+			}
+		}
+		if (rv != 0x0) {
+			*pucRetCode = WST_SE_ERROR_FULL;
+			complete(mycomplete);
+			goto PROG;
+		}
+	} else {
+		ultimeout = jiffies+1*HZ;
+		while (time_before(jiffies, ultimeout)) {
+#ifdef CONFIG_MIPS
+			if ((pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+			|| ((atomic_read(&g_sendtotallen) + *pusOutlen + SE_FILL_LEN) > SE_MAX_SEND_LEN))
+#else
+			if (pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+#endif
+			{
+				rv = WST_SE_ERROR_FULL;
+			} else {
+				rv = 0;
+				break;
+			}
+		}
+		if (rv != 0x0) {
+			*pucRetCode = WST_SE_ERROR_FULL;
+			if (pcallback)
+				pcallback(pParma);
+			goto PROG;
+		}
+	}
+	ulCurrWritePtr = pdrvctl->ulCurrBdWritePtr[iChannel];
+	ulWritePtr = (ulCurrWritePtr + 1) & (SE_BDQUEUE_LEN-1);
+
+	pCurBD = &((SE_BASIC_BD *)(pdrvctl->ulBDMemBase[iChannel]))[ulCurrWritePtr];
+	memset(pCurBD, 0x0, sizeof(SE_BASIC_BD));
+	if (pcallback != NULL) {
+		(pdrvctl->pcallback)[iChannel][ulCurrWritePtr] = pcallback;
+		pdrvctl->pParma[iChannel][ulCurrWritePtr] = pParma;
+	} else {
+		(pdrvctl->pcallback)[iChannel][ulCurrWritePtr] = NULL;
+		pdrvctl->pParma[iChannel][ulCurrWritePtr] = NULL;
+	}
+
+	pdrvctl->ikernel[iChannel][ulCurrWritePtr] = iKernel;
+	pdrvctl->stsemphore[iChannel][ulCurrWritePtr] = mycomplete;
+
+	if (pInPtr == pOutPtr) {
+		if (pOutPtr) {
+			len = usInlen >= *pusOutlen ? usInlen : *pusOutlen;
+			if (len) {
+				ulCurrAddrOutput = dma_map_single(pdrvctl->pdev, pOutPtr, len, DMA_BIDIRECTIONAL);
+				if (ulCurrAddrOutput == 0) {
+					TRACEERR("map ulCurrAddrOutput error\n");
+					*pucRetCode = WST_SE_FAILURE;
+					if (iKernel == 0) {
+						complete(mycomplete);
+					} else {
+						*pucRetCode = WST_SE_FAILURE;
+						if (pcallback)
+							pcallback(pParma);
+					}
+					goto PROG;
+				}
+				pCurBD->ulOutputLPtr = LOULONG(ulCurrAddrOutput);
+				pCurBD->ulOutputHPtr = HIULONG(ulCurrAddrOutput);
+				pCurBD->ulInputLPtr = pCurBD->ulOutputLPtr;
+				pCurBD->ulInputHPtr = pCurBD->ulOutputHPtr;
+			}
+		}
+	} else {
+		if (pOutPtr && (*pusOutlen)) {
+			ulCurrAddrOutput = dma_map_single(pdrvctl->pdev, pOutPtr, *pusOutlen, DMA_FROM_DEVICE);
+			if (ulCurrAddrOutput == 0) {
+				TRACEERR("map ulCurrAddrOutput error\n");
+				*pucRetCode = WST_SE_FAILURE;
+				if (iKernel == 0) {
+					complete(mycomplete);
+				} else {
+					*pucRetCode = WST_SE_FAILURE;
+					if (pcallback)
+						pcallback(pParma);
+				}
+				goto PROG;
+			}
+			pCurBD->ulOutputLPtr = LOULONG(ulCurrAddrOutput);
+			pCurBD->ulOutputHPtr = HIULONG(ulCurrAddrOutput);
+		}
+		if (usInlen && pInPtr) {
+			ulCurrAddrInput = dma_map_single(pdrvctl->pdev, pInPtr, usInlen, DMA_TO_DEVICE);
+			if (ulCurrAddrInput == 0) {
+				if (ulCurrAddrOutput) {
+					dma_unmap_single(pdrvctl->pdev, ulCurrAddrOutput, *pusOutlen, DMA_FROM_DEVICE);
+					pCurBD->ulOutputLPtr = 0;
+					pCurBD->ulOutputHPtr = 0;
+				}
+				*pucRetCode = WST_SE_FAILURE;
+				if (iKernel == 0) {
+					complete(mycomplete);
+				} else {
+					*pucRetCode = WST_SE_FAILURE;
+					if (pcallback)
+						pcallback(pParma);
+				}
+				goto PROG;
+			}
+			pCurBD->ulInputLPtr = LOULONG(ulCurrAddrInput);
+			pCurBD->ulInputHPtr = HIULONG(ulCurrAddrInput);
+		}
+	}
+	pCurBD->ucOpCode = ucOpCode & 0x0f;
+	pCurBD->ucFlag = ucFlag & 0x7;
+	pCurBD->usInputLength = usInlen;
+	if (pusOutlen)
+		pCurBD->usOutputLength = *pusOutlen;
+
+	pCurBD->ucRetCode	= 0x0f;
+
+	pdrvctl->pusOutlen[iChannel][ulCurrWritePtr] = pusOutlen;
+	pdrvctl->usInlen[iChannel][ulCurrWritePtr] = usInlen&0xffff;
+	if (ulCurrAddrOutput)
+		pdrvctl->ulOutputPtr[iChannel][ulCurrWritePtr] = (unsigned long *)ulCurrAddrOutput;
+	else
+		pdrvctl->ulOutputPtr[iChannel][ulCurrWritePtr] = 0;
+	if (ulCurrAddrInput)
+		pdrvctl->ulInputPtr[iChannel][ulCurrWritePtr] = (unsigned long *)ulCurrAddrInput;
+	else
+		pdrvctl->ulInputPtr[iChannel][ulCurrWritePtr] = 0;
+	pdrvctl->pucRetCode[iChannel][ulCurrWritePtr] = pucRetCode;
+
+#ifdef CONFIG_MIPS
+	atomic_add((*(pdrvctl->pusOutlen[iChannel][ulCurrWritePtr]) + SE_FILL_LEN), &g_sendtotallen);
+#endif
+	write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	if (iChannel == 0)
+		HandleWrite32(pdrvctl, SE_REG_BQWP0, ulWritePtr);
+	else
+		HandleWrite32(pdrvctl, SE_REG_BQWP1, ulWritePtr);
+	write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+	pdrvctl->ulCurrBdWritePtr[iChannel] = ulWritePtr;
+	}
+}
+
+static int se_hardtrans(
+			SECHIPDRV_CTRL  *pdrvctl,
+			unsigned char *pInPtr,
+			unsigned short usInlen,
+			unsigned char *pOutPtr,
+			unsigned short *pusOutlen,
+			int iChannel,
+			unsigned char ucFlag,
+			unsigned char ucOpCode,
+			unsigned char *pucRetCode,
+			PSECallBackfn pcallback,
+			void *pParma,
+			int iKernel,
+			struct completion *mycomplete
+			)
+{
+	SEND_PACKAGE *psendpackage;
+	gfp_t gfp_flag;
+
+	if (in_interrupt())
+		gfp_flag = GFP_ATOMIC;
+	else
+		gfp_flag = GFP_KERNEL;
+	if (g_suspend == 1)
+		return WST_SE_FAILURE;
+	psendpackage = kmalloc(sizeof(SEND_PACKAGE), gfp_flag);
+	if (psendpackage == NULL)
+		return -1;
+
+	psendpackage->pdrvctl = pdrvctl;
+	psendpackage->pInPtr = pInPtr;
+	psendpackage->usInlen = usInlen;
+	psendpackage->pOutPtr = pOutPtr;
+	psendpackage->pusOutlen = pusOutlen;
+	psendpackage->iChannel = iChannel;
+	psendpackage->ucFlag = ucFlag;
+	psendpackage->ucOpCode = ucOpCode;
+	psendpackage->pucRetCode = pucRetCode;
+	psendpackage->pcallback = pcallback;
+	psendpackage->pParma = pParma;
+	psendpackage->iKernel = iKernel;
+	psendpackage->mycomplete = mycomplete;
+	psendpackage->ulendtime = jiffies+30*HZ;
+	spin_lock_irq(&g_sendlistlock);
+	if (wst_Pushback_Que(&g_SendQueueContainer, psendpackage) == -1) {
+		spin_unlock_irq(&g_sendlistlock);
+		kfree(psendpackage);
+		return WST_SE_ERROR_FULL;
+	}
+	spin_unlock_irq(&g_sendlistlock);
+	queue_work(g_worksendqueue, &g_sendwork);
+	return 0;
+}
+
+static irqreturn_t wst_low_channel_status(int irq, void *p)
+{
+	SECHIPDRV_CTRL *pdrvctl = (SECHIPDRV_CTRL *)p;
+	int64_t  ulIntStat = 0;
+	unsigned long ulflag;
+
+	read_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	HandleRead64(pdrvctl, SE_LOWREG_STS, &ulIntStat);
+	if (ulIntStat == 2) {
+		HandleWrite64(pdrvctl, SE_LOWINT_CLEAR, 2);
+		up(&g_lowirqsema);
+	}
+	read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+
+	return IRQ_HANDLED;
+}
+
+static int se_useropen(struct inode *inode, struct file *file)
+{
+	if (MINOR(inode->i_rdev) != 0)
+		return -ENODEV;
+
+	return SE_OK;
+}
+
+static ssize_t wst_low_channel_userwrite_op(
+					SECHIPDRV_CTRL  *pdrvctl,
+					SWCommuData *UserCommuData,
+					int iskernel
+					)
+{
+	unsigned long long addr = 0, outaddr = 0;
+	int ilen;
+	int count = SE_OK;
+	unsigned long long ulsendlen;
+	unsigned char *m_pCacheInBuf;
+	unsigned char *m_pCacheOutBuf;
+	unsigned long ulflag;
+
+	if ((g_pCacheInBuf == NULL) || (g_pCacheOutBuf == NULL))
+		return -EFAULT;
+
+	m_pCacheInBuf = (unsigned char *)bytes_align(0, (unsigned long)g_pCacheInBuf);
+	m_pCacheOutBuf = (unsigned char *)bytes_align(0, (unsigned long)g_pCacheOutBuf);
+	if (iskernel == 0) {
+		if (wst_cpyusrbuf((void   *)(UserCommuData->pucInbuf), (void *)m_pCacheInBuf, UserCommuData->usInputLen, READUBUF)) {
+			TRACEERR("copy user data error\n");
+			return -EFAULT;
+		}
+	} else
+
+		memcpy((void   *)m_pCacheInBuf, (void *)(UserCommuData->pucInbuf), UserCommuData->usInputLen);
+	ilen = UserCommuData->usInputLen >= UserCommuData->usOutputLen ? UserCommuData->usInputLen:UserCommuData->usOutputLen;
+	addr = dma_map_single(pdrvctl->pdev, m_pCacheInBuf, ilen, DMA_TO_DEVICE);
+	if (addr == 0) {
+		TRACEERR("transfer buffer is err\n");
+		return -EFAULT;
+	}
+	outaddr = dma_map_single(pdrvctl->pdev, m_pCacheOutBuf, ilen, DMA_FROM_DEVICE);
+	if (outaddr == 0) {
+		TRACEERR("transfer buffer is err\n");
+		dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+		return -EFAULT;
+	}
+	ulsendlen = (UserCommuData->usInputLen/8);
+	ulsendlen = (ulsendlen & 0x00000000ffffffff) << 32;
+	write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	HandleWrite64(pdrvctl, SE_WRITE_REG1, ulsendlen);
+	HandleWrite64(pdrvctl, SE_WRITE_REG2, addr);
+	HandleWrite64(pdrvctl, SE_WRITE_REG3, outaddr);
+	write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+	if (g_iUseIntr != 0) {
+		if (down_interruptible(&g_lowirqsema) == -EINTR) {
+			count = -EINTR;
+			goto EXIT;
+		}
+	} else {
+		unsigned long start_jiffies = 0, end_jiffies = 0;
+		int64_t  ulIntStat = 0;
+
+		start_jiffies = jiffies;
+		end_jiffies = jiffies;
+		while (1) {
+			write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+			HandleRead64(pdrvctl, SE_LOWREG_SR, &ulIntStat);
+			end_jiffies = jiffies;
+			if (ulIntStat == 1) {
+				HandleWrite64(pdrvctl, SE_LOWREG_SR, 0);
+				write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+				break;
+			}
+			write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+			if (jiffies_to_msecs(end_jiffies-start_jiffies)/1000 >= 90) {
+				count = -EFAULT;
+				goto EXIT;
+			}
+		}
+	}
+	dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+	dma_unmap_single(pdrvctl->pdev, outaddr, ilen, DMA_FROM_DEVICE);
+	if (UserCommuData->usOutputLen) {
+		if (iskernel == 0) {
+			if (wst_cpyusrbuf(UserCommuData->pucOutbuf, m_pCacheOutBuf, UserCommuData->usOutputLen, WRITEUBUF))
+				return -EFAULT;
+		} else
+			memcpy(UserCommuData->pucOutbuf, m_pCacheOutBuf, UserCommuData->usOutputLen);
+	}
+	return count;
+EXIT:
+	dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+	dma_unmap_single(pdrvctl->pdev, outaddr, ilen, DMA_FROM_DEVICE);
+	return count;
+}
+
+static ssize_t se_userwrite(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	unsigned char *pCacheBuf = NULL, *pCacheOutBuf = NULL, *pCacheBufalign = NULL, *pCacheOutBufalign = NULL;
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+	SWCommuData *pCommuData = NULL;
+	int iCommuDatalen = 0;
+	int pucRetCode = 0;
+	unsigned short iChannel = 0;
+	unsigned char ucFlag = 0, ucOpCode = 0;
+	int *ppucRetCode;
+	struct completion mycomplete;
+	struct tag_dma_buf_ctl *pbufinctl = NULL;
+	int iret = 0;
+
+	if (count == 0) {
+		TRACEERR("count=0\n");
+		return SE_OK;
+	}
+
+	if (MINOR(file->f_path.dentry->d_inode->i_rdev) != 0)
+		return -ENODEV;
+
+	iCommuDatalen = sizeof(SWCommuData);
+	if (count != iCommuDatalen)
+		return -EINVAL;
+
+	pdrvctl = g_psechipDrvCtrl;
+	pCommuData = kmalloc(iCommuDatalen, GFP_KERNEL);
+	if (!pCommuData) {
+		TRACEERR("pCommuData NULL\n");
+		return -ENOMEM;
+	}
+	if (wst_cpyusrbuf((void   *)buf, (void *)pCommuData, iCommuDatalen, READUBUF)) {
+		TRACEERR("copy user data error\n");
+		count = -EFAULT;
+		goto EXIT;
+	}
+	switch ((pCommuData->usFlags)&0x000f) {
+	case WST_GO_CHANNEL2:
+		if ((pCommuData->usInputLen > DMA_BUFSIZE) || (pCommuData->usOutputLen > DMA_BUFSIZE)) {
+			TRACEERR("len is error\n");
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (down_interruptible(&g_lowsema) == -EINTR) {
+			count = -EINTR;
+			goto EXIT;
+		}
+		count = wst_low_channel_userwrite_op(pdrvctl, pCommuData, 0);
+		up(&g_lowsema);
+		goto EXIT;
+	case WST_GO_CHANNEL0:
+		if (pCommuData->usInputLen == 0) {
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (pCommuData->usInputLen != 0) {
+			if (pCommuData->usInputLen > DMA_BUFSIZE) {
+				count = -EINVAL;
+				goto EXIT;
+			}
+			ucFlag = INPUT_VALID;
+			if (pCommuData->usOutputLen)
+				ucFlag |= OUTPUT_VALID;
+		}
+
+		iChannel = 0;
+		ucOpCode = 0x0;
+		break;
+	case WST_GO_CHANNEL1:
+		if (pCommuData->usInputLen == 0) {
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (pCommuData->usInputLen != 0) {
+			if (pCommuData->usInputLen > DMA_BUFSIZE) {
+				count = -EINVAL;
+				goto EXIT;
+			}
+			ucFlag = INPUT_VALID;
+			if (pCommuData->usOutputLen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 1;
+		ucOpCode = 0x0;
+		break;
+	default:
+		{
+			count = -EINVAL;
+			goto EXIT;
+		}
+	}
+	pbufinctl = se_get_dma_buf(0);
+	if (pbufinctl == NULL) {
+		TRACEERR("kmalloc pCacheBuf error\n");
+		count = -ENOMEM;
+		goto EXIT;
+	}
+	pCacheBuf = pbufinctl->pDmaBuf;
+	pCacheBufalign = pCacheBuf;
+
+	if (wst_cpyusrbuf((void   *)(pCommuData->pucInbuf), (void *)pCacheBufalign,
+				pCommuData->usInputLen, READUBUF)) {
+		TRACEERR("cpyuserbuf pCacheBufalign error\n");
+		count = -ENOMEM;
+		goto EXIT;
+	}
+
+	pCacheOutBuf = pbufinctl->pDmaBuf;
+	pCacheOutBufalign = pCacheOutBuf;
+
+	ppucRetCode = &pucRetCode;
+
+	count = SE_OK;
+	init_completion(&mycomplete);
+	iret = se_hardtrans(
+		pdrvctl,
+		pCacheBufalign,
+		pCommuData->usInputLen,
+		pCacheOutBufalign,
+		&(pCommuData->usOutputLen),
+		iChannel,
+		ucFlag,
+		ucOpCode,
+		(unsigned char *)ppucRetCode,
+		0,
+		0,
+		0,
+		&mycomplete
+		);
+	if (iret == -1) {
+		count = -EIO;
+		goto EXIT;
+	}
+	if (!wait_for_completion_timeout(&mycomplete, msecs_to_jiffies(60*1000))) {
+		count = -EFAULT;
+		goto EXIT;
+	}
+	if (pucRetCode != SE_OK) {
+		count = -(SE_BASEERR+pucRetCode);
+		goto EXIT;
+	}
+
+	if (pCommuData->pucOutbuf) {
+		if (wst_cpyusrbuf(pCommuData->pucOutbuf, pCacheOutBufalign,
+					pCommuData->usOutputLen, WRITEUBUF)) {
+			count = -EFAULT;
+			goto EXIT;
+		}
+	}
+EXIT:
+	if (pbufinctl)
+		se_free_dma_buf(pbufinctl);
+	kfree(pCommuData);
+	return count;
+}
+static void globalmem_do_rec_op(struct work_struct *p)
+{
+	INT_MESSAGE *intmessage;
+	unsigned long ulflags1;
+
+	while (1) {
+		spin_lock_irqsave(&g_reclistlock, ulflags1);
+		intmessage = (INT_MESSAGE *)wst_Popfront_Que(&g_RecQueueContainer);
+		spin_unlock_irqrestore(&g_reclistlock, ulflags1);
+		if (!intmessage)
+			return;
+		intmessage->pcallback(intmessage->pParma);
+		kfree(intmessage);
+	}
+}
+static irqreturn_t se_interrupt(int irq, void *p)
+{
+	SECHIPDRV_CTRL *pdrvctl;
+	SE_BASIC_BD *pCurBD;
+	unsigned int	ulCurrReadPtr, ulReadPtr;
+	int iChannel;
+	int len = 0;
+	int i;
+	unsigned char ucMyRetCode = 0;
+	unsigned long ulIntStat;
+	int istatus[2] = {1, 2};
+	unsigned long ulflags;
+
+	pdrvctl = (SECHIPDRV_CTRL *)p;
+	if (!pdrvctl)
+		return IRQ_HANDLED;
+
+	read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+	HandleRead32(pdrvctl, SE_REG_STS, &ulIntStat);
+	read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+	if ((!(ulIntStat & INT_STAT_DMA_MASK)) || (ulIntStat == 0xffffffff))
+		return IRQ_HANDLED;
+
+	for (i = 0; i <= 1; i++) {
+		if (ulIntStat & istatus[i]) {
+			if (i == 0) {
+				read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+				HandleWrite32(pdrvctl, SE_INT_CLR, 1);
+				HandleRead32(pdrvctl, SE_REG_RQRP0, &ulReadPtr);
+				read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+				iChannel = 0;
+			} else {
+				read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+				HandleWrite32(pdrvctl, SE_INT_CLR, 2);
+				HandleRead32(pdrvctl, SE_REG_RQRP1, &ulReadPtr);
+				read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+				iChannel = 1;
+			}
+		} else
+			continue;
+		ulCurrReadPtr = pdrvctl->ulCurrReadPtr[iChannel];
+		while (1) {
+			if (ulCurrReadPtr != ulReadPtr) {
+				pCurBD = &((SE_BASIC_BD *)(pdrvctl->ulBDMemBase[iChannel]))[ulCurrReadPtr];
+				if ((pCurBD->ucRetCode == 0x0f) || ((pCurBD->ucFlag & 0x8) != 0x8)) {
+					continue;
+				} else {
+					if (pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr] == pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+						if (pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+							len = (*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])) >= pdrvctl->usInlen[iChannel][ulCurrReadPtr] ?
+								(*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])):pdrvctl->usInlen[iChannel][ulCurrReadPtr];
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]),
+								len,
+								DMA_BIDIRECTIONAL
+								);
+							pCurBD->ulOutputLPtr = 0;
+							pCurBD->ulOutputHPtr = 0;
+							pCurBD->ulInputHPtr = 0;
+							pCurBD->ulInputLPtr = 0;
+							pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+					} else {
+						if (pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]),
+								*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr]), DMA_FROM_DEVICE
+								);
+							smp_wmb();
+							pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+						if (pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr]) {
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr]),
+								pdrvctl->usInlen[iChannel][ulCurrReadPtr],
+								DMA_TO_DEVICE
+								);
+							pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+					}
+					ucMyRetCode = pCurBD->ucRetCode;
+					memcpy(pdrvctl->pucRetCode[iChannel][ulCurrReadPtr], &ucMyRetCode, 1);
+					if (pCurBD->ucRetCode != SE_OK)
+						pr_info("\nstatus %x\n", pCurBD->ucRetCode);
+#ifdef CONFIG_MIPS
+					atomic_sub(((*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])) + SE_FILL_LEN), &g_sendtotallen);
+#endif
+					if ((pdrvctl->ikernel)[iChannel][ulCurrReadPtr] != 0) {
+						if (pdrvctl->pcallback[iChannel][ulCurrReadPtr]) {
+							INT_MESSAGE *intmessage = NULL;
+							unsigned long ulflags1;
+
+							intmessage = (INT_MESSAGE   *)kmalloc(sizeof(INT_MESSAGE), GFP_ATOMIC);
+							if (!intmessage)
+								return IRQ_HANDLED;
+							intmessage->pcallback = pdrvctl->pcallback[iChannel][ulCurrReadPtr];
+							intmessage->pParma = pdrvctl->pParma[iChannel][ulCurrReadPtr];
+							spin_lock_irqsave(&g_reclistlock, ulflags1);
+							wst_Pushback_Que(&g_RecQueueContainer, intmessage);
+							spin_unlock_irqrestore(&g_reclistlock, ulflags1);
+							queue_work(g_workrecqueue, &g_recwork);
+						}
+					} else {
+						complete(pdrvctl->stsemphore[iChannel][ulCurrReadPtr]);
+					}
+					ulCurrReadPtr = ((ulCurrReadPtr + 1)&(SE_BDQUEUE_LEN - 1));
+					pdrvctl->ulCurrReadPtr[iChannel] = ulCurrReadPtr;
+					pdrvctl->ulCurrBdReadPtr[iChannel] = ulCurrReadPtr;
+					if (pdrvctl->sema.count <= 0)
+						up(&(pdrvctl->sema));
+				}
+			} else
+
+				break;
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int se_userrelease(struct inode *inode, struct file *file)
+{
+	return SE_OK;
+}
+
+ssize_t se_kernelwrite(
+					   unsigned char *pInPtr,
+					   unsigned short usInlen,
+					   unsigned char *pOutPtr,
+					   unsigned short *pusOutlen,
+					   unsigned char ucFlag,
+					   unsigned char *pucRetCode,
+					   PSECallBackfn pcallback,
+					   void *pParma
+					   )
+{
+	int iret;
+	SECHIPDRV_CTRL  *pdrvctl;
+	int iChannel;
+	unsigned char ucOpCode;
+	SWCommuData CommuData;
+
+	pdrvctl = g_psechipDrvCtrl;
+
+	switch (ucFlag) {
+	case WST_GO_CHANNEL2:
+		{
+			CommuData.pucInbuf = pInPtr;
+			CommuData.pucOutbuf = pOutPtr;
+			CommuData.usFlags = 0;
+			CommuData.usInputLen = usInlen;
+			CommuData.usOutputLen = *pusOutlen;
+			CommuData.usReserve = 0;
+			if (down_interruptible(&g_lowsema) == -EINTR)
+				return -EINTR;
+			iret = wst_low_channel_userwrite_op(pdrvctl, &CommuData, 1);
+			up(&g_lowsema);
+			return iret;
+		}
+	case WST_GO_CHANNEL0:
+		if (pcallback == NULL)
+			return WST_SE_PARAM_ERROR;
+		if (usInlen == 0)
+			return -EINVAL;
+		ucFlag = 0;
+		if (usInlen != 0) {
+			if (usInlen > DMA_BUFSIZE)
+				return -EINVAL;
+			ucFlag = INPUT_VALID;
+			if (*pusOutlen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 0;
+		ucOpCode = 0x0;
+		break;
+	case WST_GO_CHANNEL1:
+		if (pcallback == NULL)
+			return WST_SE_PARAM_ERROR;
+		if (usInlen == 0) {
+			return -EINVAL;
+		}
+		ucFlag = 0;
+		if (usInlen != 0) {
+			if (usInlen > DMA_BUFSIZE)
+				return -EINVAL;
+			ucFlag = INPUT_VALID;
+			if (*pusOutlen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 1;
+		ucOpCode = 0x0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	iret = se_hardtrans(
+		pdrvctl,
+		pInPtr,
+		usInlen,
+		pOutPtr,
+		pusOutlen,
+		iChannel,
+		ucFlag,
+		ucOpCode,
+		pucRetCode,
+		pcallback,
+		pParma,
+		1,
+		NULL
+		);
+	if (iret == -1)
+		return -EIO;
+
+	return SE_OK;
+}
+EXPORT_SYMBOL(se_kernelwrite);
+
+static long se_userioctl(struct file *filp, u_int cmd, u_long arg)
+{
+	long iret = SE_OK;
+	SECHIPDRV_CTRL *pdrvctl = g_psechipDrvCtrl;
+	unsigned long ulvalue;
+
+	HandleRead64(pdrvctl, 0x120, &ulvalue);
+	pr_info("read reg value is 0x%lx in offset 120\n", ulvalue);
+	HandleRead64(pdrvctl, 0x118, &ulvalue);
+	pr_info("read reg value is 0x%lx in offset 118\n", ulvalue);
+
+	return iret;
+}
+
+
+static const struct file_operations SE_fops = {
+	.owner = THIS_MODULE,
+	.write = se_userwrite,
+	.open = se_useropen,
+	.release = se_userrelease,
+	.unlocked_ioctl = se_userioctl,
+	.compat_ioctl = se_userioctl
+};
+
+int  se_chip_load(void)
+{
+	int iRes = SE_OK;
+
+	if (g_isechip_Major >= 0)
+		return WST_SE_HAS_OPEN;
+	g_psechipDrvCtrl = NULL;
+	iRes = se_init_dma_buf(DMA_BUFSIZE, CTL_DMABUFNUM);
+	if (iRes != SE_OK)
+		return WST_SE_ERROR_MALLOC;
+	iRes = register_chrdev(0, CRYNAME, &SE_fops);
+	if (iRes < 0)
+		goto EXIT;
+
+	g_isechip_Major = iRes;
+	iRes = 0;
+	g_psecclass = class_create(CRYNAME);
+	if (IS_ERR(g_psecclass)) {
+		iRes = PTR_ERR(g_psecclass);
+		goto EXIT;
+	}
+	g_psecdev = device_create(g_psecclass, NULL, MKDEV(g_isechip_Major, 0), NULL, CRYNAME);
+	if (IS_ERR(g_psecdev)) {
+		iRes = PTR_ERR(g_psecdev);
+		goto EXIT;
+	}
+	iRes = wst_init();
+	if (iRes != SE_OK)
+		goto EXIT;
+
+	sema_init(&g_lowsema, 1);
+	sema_init(&g_lowirqsema, 0);
+	atomic_set(&g_sendtotallen, 0);
+	g_pCacheInBuf = (unsigned char *)__get_free_page(GFP_DMA);
+	if (IS_ERR(g_pCacheInBuf)) {
+		iRes = PTR_ERR(g_pCacheInBuf);
+		goto EXIT;
+	}
+	g_pCacheOutBuf = (unsigned char *)__get_free_page(GFP_DMA);
+	if (IS_ERR(g_pCacheOutBuf)) {
+		iRes = PTR_ERR(g_pCacheOutBuf);
+		goto EXIT;
+	}
+
+	g_worksendqueue = alloc_workqueue("seworksendqueue",
+					WQ_MEM_RECLAIM|__WQ_ORDERED|WQ_UNBOUND, 1);
+	if (IS_ERR(g_worksendqueue)) {
+		iRes = PTR_ERR(g_worksendqueue);
+		goto EXIT;
+	}
+	g_workrecqueue = alloc_workqueue("seworkrecqueue", WQ_MEM_RECLAIM|__WQ_ORDERED, 0);
+	if (IS_ERR(g_workrecqueue)) {
+		iRes = PTR_ERR(g_workrecqueue);
+		goto EXIT;
+	}
+	INIT_WORK(&g_recwork, globalmem_do_rec_op);
+	INIT_WORK(&g_sendwork, globalmem_do_send_op);
+	pr_info("this driver version is %s\n", DRIVER_VERSION);
+
+	return SE_OK;
+EXIT:
+	se_del_dma_buf();
+	if (g_pCacheInBuf) {
+
+		free_page((unsigned long)g_pCacheInBuf);
+		g_pCacheInBuf = NULL;
+	}
+	if (g_pCacheOutBuf) {
+
+		free_page((unsigned long)g_pCacheOutBuf);
+		g_pCacheOutBuf = NULL;
+	}
+	if (g_worksendqueue) {
+		destroy_workqueue(g_worksendqueue);
+		g_worksendqueue = NULL;
+	}
+	if (g_workrecqueue) {
+		destroy_workqueue(g_workrecqueue);
+		g_workrecqueue = NULL;
+	}
+	wst_clear();
+	if (g_psecdev) {
+		device_unregister(g_psecdev);
+		g_psecdev = NULL;
+	}
+	if (g_psecclass) {
+		class_destroy(g_psecclass);
+		g_psecclass = NULL;
+	}
+	if (g_isechip_Major >= 0) {
+		unregister_chrdev(g_isechip_Major, CRYNAME);
+		g_isechip_Major = -1;
+	}
+	return iRes;
+}
+
+void se_chip_unload(void)
+{
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+
+	pdrvctl = g_psechipDrvCtrl;
+
+	up(&pdrvctl->sema);
+	if (g_pCacheInBuf) {
+
+		free_page((unsigned long)g_pCacheInBuf);
+		g_pCacheInBuf = NULL;
+	}
+	if (g_pCacheOutBuf) {
+
+		free_page((unsigned long)g_pCacheOutBuf);
+		g_pCacheOutBuf = NULL;
+	}
+	if (g_worksendqueue) {
+		cancel_work_sync(&g_sendwork);
+		destroy_workqueue(g_worksendqueue);
+		g_worksendqueue = NULL;
+	}
+	if (g_workrecqueue) {
+		cancel_work_sync(&g_recwork);
+		destroy_workqueue(g_workrecqueue);
+		g_workrecqueue = NULL;
+	}
+	wst_clear();
+	if (g_psecdev) {
+		device_destroy(g_psecclass, MKDEV(g_isechip_Major, 0));
+		g_psecdev = NULL;
+	}
+	if (g_psecclass) {
+		class_destroy(g_psecclass);
+		g_psecclass = NULL;
+	}
+	if (g_isechip_Major >= 0) {
+		unregister_chrdev(g_isechip_Major, CRYNAME);
+		g_isechip_Major = -1;
+	}
+	se_del_dma_buf();
+}
+
+static int loongson_cryp_get_irq(struct platform_device *pdev, char *pat)
+{
+	int i;
+	struct resource *res = pdev->resource;
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		if (strcmp(res[i].name, pat) == 0)
+			return res[i].start;
+	}
+	return -1;
+
+}
+static int loongson_cryp_probe(struct platform_device *pdev)
+{
+	int i;
+
+	if (ACPI_COMPANION(&pdev->dev)) {
+		se_irq[0].irq = platform_get_irq(pdev, 1);
+		se_irq[1].irq = platform_get_irq(pdev, 0);
+	} else {
+		for (i = 0; i < pdev->num_resources; i++) {
+			se_irq[i].irq = loongson_cryp_get_irq(pdev,
+							se_irq[i].pat);
+			if (se_irq[i].irq < 0) {
+				pr_warn("ERROR:sedriver get irq failed\n");
+				return -1;
+			}
+		}
+	}
+
+	return se_chip_load();
+}
+static int loongson_cryp_remove(struct platform_device *pdev)
+{
+	se_chip_unload();
+	return 0;
+}
+static int loongson_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	g_suspend = 1;
+	cancel_work_sync(&g_recwork);
+	cancel_work_sync(&g_sendwork);
+	flush_work(&g_recwork);
+	flush_work(&g_sendwork);
+	se_chip_unload();
+	return 0;
+}
+
+static int loongson_cryp_resume(struct platform_device *pdev)
+{
+	int i;
+
+	g_suspend = 0;
+	g_worksendqueue = NULL;
+	g_workrecqueue = NULL;
+	g_isechip_Major = -1;
+	g_pCacheInBuf = NULL;
+	g_pCacheOutBuf = NULL;
+	g_iUseIntr = 1;
+	spin_lock_init(&g_reclistlock);
+	spin_lock_init(&g_sendlistlock);
+	spin_lock_init(&g_getdmabuflock);
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		se_irq[i].irq = loongson_cryp_get_irq(pdev, se_irq[i].pat);
+
+		if (se_irq[i].irq < 0) {
+			pr_warn("ERROR:sedriver get irq failed\n");
+			return -1;
+		}
+	}
+	se_chip_load();
+	return 0;
+}
+
+static const struct acpi_device_id loongson_cryp_acpi_match[] = {
+	{"LOON0003"},
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, loongson_cryp_acpi_match);
+
+static struct platform_driver loongson_cryp_driver = {
+	.probe		= loongson_cryp_probe,
+	.remove		= loongson_cryp_remove,
+	.suspend	= loongson_cryp_suspend,
+	.resume		= loongson_cryp_resume,
+	.driver		= {
+			.name = "loongson3_crypto",
+			.acpi_match_table = ACPI_PTR(loongson_cryp_acpi_match),
+	},
+};
+
+static int __init initmodule(void)
+{
+	return platform_driver_register(&loongson_cryp_driver);
+}
+
+static void __exit exitmodule(void)
+{
+	platform_driver_unregister(&loongson_cryp_driver);
+}
+
+module_init(initmodule);
+module_exit(exitmodule);
+
+MODULE_ALIAS("platform:loongson3_crypto");
+MODULE_AUTHOR("dcm");
+MODULE_DESCRIPTION("se encryption chip driver Co westone");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/sedriver/wst_se_echip_driver.h b/drivers/crypto/sedriver/wst_se_echip_driver.h
new file mode 100644
index 000000000000..3e562e55faac
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_echip_driver.h
@@ -0,0 +1,184 @@
+#ifndef _WST_SE_ECHIP_DRIVER_H
+#define _WST_SE_ECHIP_DRIVER_H
+#include "wst_se_ktrans.h"
+
+#define CRYNAME "wst-se"
+
+#define SWBUFNUM     512
+#define SWCHANNELNUM 2
+#define CTL_DMABUFNUM  512
+
+#define DMA_MASK 0xffffffff
+#define SE_DMA_CONTROL_RESET 0x80000000
+#define SE_DMA_CONTROL_SET   0x00000000
+
+#define SE_BASEERR 1000
+
+#define SE_MAX_SEND_LEN (3*2048)
+#define SE_FILL_LEN 48
+#define SE_BD_LENGTH sizeof(SE_BASIC_BD)
+#define SE_BDQUEUE_LEN  SWBUFNUM
+#define DMA0_CTRL_CHANNEL_ENABLE    1
+#define DMA0_CTRL_CHANNEL_DISABLE   0xfffffffe
+#define DMA1_CTRL_CHANNEL_ENABLE    2
+#define DMA1_CTRL_CHANNEL_DISABLE   0xfffffffd
+
+#define SE_REG_RESET			 0
+#define SE_REG_STS				0x08
+#define SE_INT_CTRL				0x10
+#define SE_REG_MSK				0x18
+#define SE_INT_CLR				0x20
+
+#define SE_LREG_BQBA0			0x100
+#define SE_HREG_BQBA0			0x108
+#define SE_REG_BQS0				0x110
+#define SE_REG_BQWP0			0x118
+#define SE_REG_RQRP0			0x120
+
+#define SE_LREG_BQBA1			0x128
+#define SE_HREG_BQBA1			0x130
+#define SE_REG_BQS1				0x138
+#define SE_REG_BQWP1			0x140
+#define SE_REG_RQRP1			0x148
+
+#define SE_WRITE_REG1			0x200
+#define SE_WRITE_REG2			0x208
+#define SE_WRITE_REG3			0x210
+#define SE_LOWREG_STS			0x240
+#define SE_LOWINT_CLEAR			0x248
+#define SE_LOWREG_INQ			0x1600
+#define SE_LOWREG_SR			0x1608
+#define INPUT_VALID				0x4
+#define OUTPUT_VALID			0x8
+#define SE_LOWINT_CLR			0x228
+#define INT_STAT_DMA0_PACK_DONE 1
+#define INT_STAT_DMA1_PACK_DONE 2
+#define INT_STAT_DMA_MASK		(INT_STAT_DMA0_PACK_DONE|INT_STAT_DMA1_PACK_DONE)
+
+typedef struct tagSEdrvctl {
+
+	unsigned long	ulMemBase;
+	struct device	*pdev;
+	struct device	dev;
+	unsigned int	ulCurrBdReadPtr[SWCHANNELNUM];
+	unsigned int	ulCurrBdWritePtr[SWCHANNELNUM];
+	unsigned int	ulCurrReadPtr[SWCHANNELNUM];
+	unsigned int	ulCurrWritePtr[SWCHANNELNUM];
+	PSECallBackfn	pcallback[SWCHANNELNUM][SWBUFNUM];
+	void *pParma[SWCHANNELNUM][SWBUFNUM];
+	struct completion	*stsemphore[SWCHANNELNUM][SWBUFNUM];
+	int		ikernel[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	ulBDMemBasePhy[SWCHANNELNUM];
+	unsigned long	ulBDMemBase[SWCHANNELNUM];
+	unsigned short	*pusOutlen[SWCHANNELNUM][SWBUFNUM];
+	unsigned short	usInlen[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	*ulOutputPtr[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	*ulInputPtr[SWCHANNELNUM][SWBUFNUM];
+	unsigned char	*pucRetCode[SWCHANNELNUM][SWBUFNUM];
+	rwlock_t mr_lock;
+	rwlock_t mr_lowlock;
+	spinlock_t readlock;
+	struct semaphore sema;
+	int iIrq;
+	int ilowIrq;
+} SECHIPDRV_CTRL;
+
+typedef struct tagSEBasicBD {
+
+	unsigned int  ucOpCode:4,
+		ucFlag:4,
+		ucRetCode:8,
+		ucInCtxLength:8,
+		ucOutCtxLength:8;
+	unsigned int	usInputLength:16,
+		usOutputLength:16;
+	unsigned int	ulCtxLPtr;
+	unsigned int	ulCtxHPtr;
+	unsigned int	ulInputLPtr;
+	unsigned int	ulInputHPtr;
+	unsigned int	ulOutputLPtr;
+	unsigned int	ulOutputHPtr;
+
+} SE_BASIC_BD;
+
+#define SW_CONT_BUF_SIZE		0x100
+#define DMA_BUFSIZE				0x1000
+
+#define PAGE_NUM (DMA_BUFSIZE/PAGE_SIZE+1)
+
+typedef struct _SW_GET_STAT {
+	unsigned long TXD;
+	unsigned long RXD;
+} SW_GET_STAT, *PSW_GET_STAT;
+
+DEFINE_SPINLOCK(g_writelock);
+
+#define HandleRead32(handle, addr, pData) \
+	do { \
+		smp_mb(); \
+		*(pData) = readl((void *)(handle->ulMemBase + addr));	\
+	} while (0)
+
+#define HandleWrite32(handle, addr, value)\
+	do { \
+		writel(value, (void *)(handle->ulMemBase + addr));	\
+		smp_mb(); \
+	} while (0)
+
+#define HandleRead64(handle, addr, pData) \
+	do { \
+		smp_mb(); \
+		*(pData) = readq((void *)(handle->ulMemBase + addr));	\
+	} while (0)
+
+#define HandleWrite64(handle, addr, value)\
+	do { \
+		writeq(value, (void *)(handle->ulMemBase + addr));	\
+		smp_mb(); \
+	} while (0)
+
+
+#define SPRINTF sprintf
+
+#define HIULONG(w)	((unsigned int)((((unsigned long long)w) >> 32) & 0x00000000ffffffff))
+#define LOULONG(w)	((unsigned int)((unsigned long long)w) & 0x00000000ffffffff)
+
+#ifdef DEBUG_DRIVER
+	#define TRACEMSG(fmt, args...) printk(KERN_DEBUG "msg: " fmt, ##args)
+#else
+	#define TRACEMSG(fmt, args...)
+#endif
+
+#ifdef DEBUG_DRIVER_ERROR
+	#define TRACEERR(fmt, args...) printk(KERN_DEBUG "err: " fmt, ##args)
+#else
+	#define TRACEERR(fmt, args...)
+#endif
+
+#define HIBYTE(w)		((unsigned char)(((unsigned short)(w) >> 8) & 0xFF))
+#define LOBYTE(w)		((unsigned char)(w))
+
+typedef struct ST_SEND_PACKAGE {
+	struct list_head  list;
+	SECHIPDRV_CTRL  *pdrvctl;
+	unsigned char *pInPtr;
+	unsigned short usInlen;
+	unsigned char *pOutPtr;
+	unsigned short *pusOutlen;
+	int iChannel;
+	unsigned char ucFlag;
+	unsigned char ucOpCode;
+	unsigned char *pucRetCode;
+	PSECallBackfn pcallback;
+	void *pParma;
+	int iKernel;
+	struct completion *mycomplete;
+	unsigned long ulendtime;
+} SEND_PACKAGE;
+
+typedef struct ST_INT_MESSAGE {
+	struct list_head  list;
+	PSECallBackfn pcallback;
+	void *pParma;
+} INT_MESSAGE;
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_ktrans.h b/drivers/crypto/sedriver/wst_se_ktrans.h
new file mode 100644
index 000000000000..da6c4b8f2824
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_ktrans.h
@@ -0,0 +1,17 @@
+#ifndef _WST_SE_KTRANS_H
+#define _WST_SE_KTRANS_H
+
+#include "wst_se_common_type.h"
+#include "wst_se_define.h"
+
+
+typedef struct tagSWCOMMUDATA {
+	unsigned short usFlags;
+	unsigned short usInputLen;
+	unsigned short usOutputLen;
+	unsigned short usReserve;
+	unsigned char *pucInbuf;
+	unsigned char *pucOutbuf;
+} SWCommuData;
+
+#endif
-- 
2.33.0
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                     
                        
                    
                        
                            
                                
                            
                            [PATCH OLK-6.6] KVM: arm64: Unconditionally save+flush host FPSIMD/SVE/SME state
                        
                        
by Huang Xiaojia 14 Apr '25
                    by Huang Xiaojia 14 Apr '25
14 Apr '25
                    
                        From: Mark Rutland <mark.rutland(a)arm.com>
stable inclusion
from stable-v6.12.21
commit 79e140bba70bcacc5fe15bf8c0b958793fd7d56f
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBZH7N
CVE: CVE-2025-22013
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit fbc7e61195e23f744814e78524b73b59faa54ab4 ]
There are several problems with the way hyp code lazily saves the host's
FPSIMD/SVE state, including:
* Host SVE being discarded unexpectedly due to inconsistent
  configuration of TIF_SVE and CPACR_ELx.ZEN. This has been seen to
  result in QEMU crashes where SVE is used by memmove(), as reported by
  Eric Auger:
  https://issues.redhat.com/browse/RHEL-68997
* Host SVE state is discarded *after* modification by ptrace, which was an
  unintentional ptrace ABI change introduced with lazy discarding of SVE state.
* The host FPMR value can be discarded when running a non-protected VM,
  where FPMR support is not exposed to a VM, and that VM uses
  FPSIMD/SVE. In these cases the hyp code does not save the host's FPMR
  before unbinding the host's FPSIMD/SVE/SME state, leaving a stale
  value in memory.
Avoid these by eagerly saving and "flushing" the host's FPSIMD/SVE/SME
state when loading a vCPU such that KVM does not need to save any of the
host's FPSIMD/SVE/SME state. For clarity, fpsimd_kvm_prepare() is
removed and the necessary call to fpsimd_save_and_flush_cpu_state() is
placed in kvm_arch_vcpu_load_fp(). As 'fpsimd_state' and 'fpmr_ptr'
should not be used, they are set to NULL; all uses of these will be
removed in subsequent patches.
Historical problems go back at least as far as v5.17, e.g. erroneous
assumptions about TIF_SVE being clear in commit:
  8383741ab2e773a9 ("KVM: arm64: Get rid of host SVE tracking/saving")
... and so this eager save+flush probably needs to be backported to ALL
stable trees.
Fixes: 93ae6b01bafee8fa ("KVM: arm64: Discard any SVE state when entering KVM guests")
Fixes: 8c845e2731041f0f ("arm64/sve: Leave SVE enabled on syscall if we don't context switch")
Fixes: ef3be86021c3bdf3 ("KVM: arm64: Add save/restore support for FPMR")
Reported-by: Eric Auger <eauger(a)redhat.com>
Reported-by: Wilco Dijkstra <wilco.dijkstra(a)arm.com>
Reviewed-by: Mark Brown <broonie(a)kernel.org>
Tested-by: Mark Brown <broonie(a)kernel.org>
Tested-by: Eric Auger <eric.auger(a)redhat.com>
Acked-by: Will Deacon <will(a)kernel.org>
Cc: Catalin Marinas <catalin.marinas(a)arm.com>
Cc: Florian Weimer <fweimer(a)redhat.com>
Cc: Fuad Tabba <tabba(a)google.com>
Cc: Jeremy Linton <jeremy.linton(a)arm.com>
Cc: Marc Zyngier <maz(a)kernel.org>
Cc: Oliver Upton <oliver.upton(a)linux.dev>
Cc: Paolo Bonzini <pbonzini(a)redhat.com>
Signed-off-by: Mark Rutland <mark.rutland(a)arm.com>
Reviewed-by: Oliver Upton <oliver.upton(a)linux.dev>
Link: https://lore.kernel.org/r/20250210195226.1215254-2-mark.rutland@arm.com
Signed-off-by: Marc Zyngier <maz(a)kernel.org>
[ Mark: Handle vcpu/host flag conflict ]
Signed-off-by: Mark Rutland <mark.rutland(a)arm.com>
Signed-off-by: Mark Brown <broonie(a)kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Conflicts:
	arch/arm64/kvm/fpsimd.c
[Lack of commit ef3be86021c3bdf384c36d9d4aa1ee9fe65b95af]
Signed-off-by: Huang Xiaojia <huangxiaojia2(a)huawei.com>
---
 arch/arm64/kernel/fpsimd.c | 25 -------------------------
 arch/arm64/kvm/fpsimd.c    | 33 +++++++++------------------------
 2 files changed, 9 insertions(+), 49 deletions(-)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 0137d987631e..bd4f6c6ee0f3 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1707,31 +1707,6 @@ void fpsimd_signal_preserve_current_state(void)
 		sve_to_fpsimd(current);
 }
 
-/*
- * Called by KVM when entering the guest.
- */
-void fpsimd_kvm_prepare(void)
-{
-	if (!system_supports_sve())
-		return;
-
-	/*
-	 * KVM does not save host SVE state since we can only enter
-	 * the guest from a syscall so the ABI means that only the
-	 * non-saved SVE state needs to be saved.  If we have left
-	 * SVE enabled for performance reasons then update the task
-	 * state to be FPSIMD only.
-	 */
-	get_cpu_fpsimd_context();
-
-	if (test_and_clear_thread_flag(TIF_SVE)) {
-		sve_to_fpsimd(current);
-		current->thread.fp_type = FP_STATE_FPSIMD;
-	}
-
-	put_cpu_fpsimd_context();
-}
-
 /*
  * Associate current's FPSIMD context with this cpu
  * The caller must have ownership of the cpu FPSIMD context before calling
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 4f51293db173..9c444a277a17 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -77,15 +77,17 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
 	if (!system_supports_fpsimd())
 		return;
 
-	fpsimd_kvm_prepare();
-
 	/*
-	 * We will check TIF_FOREIGN_FPSTATE just before entering the
-	 * guest in kvm_arch_vcpu_ctxflush_fp() and override this to
-	 * FP_STATE_FREE if the flag set.
+	 * Ensure that any host FPSIMD/SVE/SME state is saved and unbound such
+	 * that the host kernel is responsible for restoring this state upon
+	 * return to userspace, and the hyp code doesn't need to save anything.
+	 *
+	 * When the host may use SME, fpsimd_save_and_flush_cpu_state() ensures
+	 * that PSTATE.{SM,ZA} == {0,0}.
 	 */
-	*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
-	*host_data_ptr(fpsimd_state) = kern_hyp_va(¤t->thread.uw.fpsimd_state);
+	fpsimd_save_and_flush_cpu_state();
+	*host_data_ptr(fp_owner) = FP_STATE_FREE;
+	*host_data_ptr(fpsimd_state) = NULL;
 
 	vcpu_clear_flag(vcpu, HOST_SVE_ENABLED);
 	if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN)
@@ -95,23 +97,6 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
 		vcpu_clear_flag(vcpu, HOST_SME_ENABLED);
 		if (read_sysreg(cpacr_el1) & CPACR_EL1_SMEN_EL0EN)
 			vcpu_set_flag(vcpu, HOST_SME_ENABLED);
-
-		/*
-		 * If PSTATE.SM is enabled then save any pending FP
-		 * state and disable PSTATE.SM. If we leave PSTATE.SM
-		 * enabled and the guest does not enable SME via
-		 * CPACR_EL1.SMEN then operations that should be valid
-		 * may generate SME traps from EL1 to EL1 which we
-		 * can't intercept and which would confuse the guest.
-		 *
-		 * Do the same for PSTATE.ZA in the case where there
-		 * is state in the registers which has not already
-		 * been saved, this is very unlikely to happen.
-		 */
-		if (read_sysreg_s(SYS_SVCR) & (SVCR_SM_MASK | SVCR_ZA_MASK)) {
-			*host_data_ptr(fp_owner) = FP_STATE_FREE;
-			fpsimd_save_and_flush_cpu_state();
-		}
 	}
 }
 
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    
                    
                        From: Qunqin Zhao <zhaoqunqin(a)loongson.cn>
LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IC10DU
CVE: NA
--------------------------------
Add support for WST se chip support for LS*5000*.
Signed-off-by: Qunqin Zhao <zhaoqunqin(a)loongson.cn>
---
 arch/loongarch/configs/loongson3_defconfig    |    1 +
 drivers/crypto/Kconfig                        |    1 +
 drivers/crypto/Makefile                       |    1 +
 drivers/crypto/sedriver/Kconfig               |    8 +
 drivers/crypto/sedriver/Makefile              |    7 +
 drivers/crypto/sedriver/wst_se_common_type.h  |   98 ++
 drivers/crypto/sedriver/wst_se_define.h       |   27 +
 drivers/crypto/sedriver/wst_se_echip_driver.c | 1368 +++++++++++++++++
 drivers/crypto/sedriver/wst_se_echip_driver.h |  184 +++
 drivers/crypto/sedriver/wst_se_ktrans.h       |   17 +
 10 files changed, 1712 insertions(+)
 create mode 100644 drivers/crypto/sedriver/Kconfig
 create mode 100644 drivers/crypto/sedriver/Makefile
 create mode 100644 drivers/crypto/sedriver/wst_se_common_type.h
 create mode 100644 drivers/crypto/sedriver/wst_se_define.h
 create mode 100644 drivers/crypto/sedriver/wst_se_echip_driver.c
 create mode 100644 drivers/crypto/sedriver/wst_se_echip_driver.h
 create mode 100644 drivers/crypto/sedriver/wst_se_ktrans.h
diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig
index 980f5f2c99a1..cf359d1a2554 100644
--- a/arch/loongarch/configs/loongson3_defconfig
+++ b/arch/loongarch/configs/loongson3_defconfig
@@ -2177,6 +2177,7 @@ CONFIG_CRYPTO_CRC32_LOONGARCH=m
 CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
 CONFIG_CRYPTO_DEV_CHELSIO=m
 CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_SW_SE_CHIP=m
 CONFIG_SIGNED_PE_FILE_VERIFICATION=y
 CONFIG_SECONDARY_TRUSTED_KEYRING=y
 CONFIG_SYSTEM_BLACKLIST_KEYRING=y
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index b84a921d293f..efd6a855bca3 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -836,5 +836,6 @@ config CRYPTO_DEV_SA2UL
 source "drivers/crypto/aspeed/Kconfig"
 source "drivers/crypto/starfive/Kconfig"
 source "drivers/crypto/montage/Kconfig"
+source "drivers/crypto/sedriver/Kconfig"
 
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 5247d2bf09ce..6ad337bad109 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
 obj-y += intel/
 obj-y += starfive/
 obj-y += montage/
+obj-$(CONFIG_SW_SE_CHIP) += sedriver/
diff --git a/drivers/crypto/sedriver/Kconfig b/drivers/crypto/sedriver/Kconfig
new file mode 100644
index 000000000000..6a11bdf1e5fa
--- /dev/null
+++ b/drivers/crypto/sedriver/Kconfig
@@ -0,0 +1,8 @@
+#
+# se chip configuration
+#
+config SW_SE_CHIP
+	tristate "wst se chip driver"
+	depends on LOONGARCH
+	help
+		If unsure, say N.
diff --git a/drivers/crypto/sedriver/Makefile b/drivers/crypto/sedriver/Makefile
new file mode 100644
index 000000000000..0ee095d1a1d2
--- /dev/null
+++ b/drivers/crypto/sedriver/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for SE CHIP Driver
+#
+
+obj-$(CONFIG_SW_SE_CHIP) += sw_se_echip_drv.o
+sw_se_echip_drv-objs :=  wst_se_echip_driver.o
+
diff --git a/drivers/crypto/sedriver/wst_se_common_type.h b/drivers/crypto/sedriver/wst_se_common_type.h
new file mode 100644
index 000000000000..e29e9bccaa6d
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_common_type.h
@@ -0,0 +1,98 @@
+#ifndef _WST_SE_COMMON_TYPE_H
+#define _WST_SE_COMMON_TYPE_H
+
+#include <linux/kernel.h>	/* We're doing kernel work */
+#include <linux/module.h>	/* Specifically, a module */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/mman.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#define WST_GO_CHANNEL0			0x0002
+#define WST_GO_CHANNEL1		0x0000
+#define WST_GO_CHANNEL2		0x0001
+
+#define SE_OK 0
+
+struct loongson_sedriver_irq {
+	char  *pat;
+	int irq;
+};
+
+typedef struct tag_dma_buf_ctl {
+	struct list_head  list;
+	unsigned char *pDmaBuf;
+} dmabuf_ctl, *pdmabuf_ctl;
+
+typedef struct tag_Queue_container {
+	struct list_head     m_Head;
+	unsigned int qlen;
+	unsigned int max_qlen;
+} QUEUE_CONTAIN, *PQUEUE_CONTAIN;
+
+
+static inline int  wst_InitQueue(struct tag_Queue_container *pQueue, int count)
+{
+	INIT_LIST_HEAD(&pQueue->m_Head);
+	pQueue->qlen = 0;
+	pQueue->max_qlen = count;
+	return 0;
+}
+
+
+static inline struct list_head *wst_Popfront_Que(struct tag_Queue_container *pQueue)
+{
+	struct list_head *pNode = NULL;
+
+	if (list_empty(&pQueue->m_Head))
+		return NULL;
+
+	pQueue->qlen--;
+	pNode = pQueue->m_Head.next;
+	list_del(pNode);
+	return pNode;
+}
+
+
+static inline int  wst_Pushback_Que(struct tag_Queue_container *pQueue, void *pNode)
+{
+	if (unlikely(pQueue->qlen >= pQueue->max_qlen))
+		return -1;
+
+	pQueue->qlen++;
+	list_add_tail((struct list_head *)(pNode), &pQueue->m_Head);
+	return 0;
+}
+
+#define READUBUF  0
+#define WRITEUBUF 1
+
+static inline int wst_cpyusrbuf(unsigned char  *puserbuf,
+				unsigned char *pkbuf, size_t num, int orient)
+{
+	if (orient == READUBUF)
+		return copy_from_user(pkbuf, puserbuf, num);
+	else
+		return copy_to_user(puserbuf, pkbuf, num);
+}
+
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_define.h b/drivers/crypto/sedriver/wst_se_define.h
new file mode 100644
index 000000000000..7a29f1029afa
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_define.h
@@ -0,0 +1,27 @@
+#ifndef _WST_SE_DEFINE_H
+#define _WST_SE_DEFINE_H
+
+
+typedef void (*PSECallBackfn)(void *pParam);
+
+#define WST_SE_OK			0	//function syccess
+#define WST_SE_FAILURE			1
+#define WST_SE_ERROR_MALLOC		2
+#define WST_SE_ERROR_OPEN		3
+#define WST_SE_ERROR_ID			4
+#define WST_SE_ERROR_OPERTYPE		5
+#define WST_SE_ERROR_KEYID		6
+#define WST_SE_NOT_SUPPORT		7
+#define WST_SE_ERROR_FULL		8
+#define WST_SE_VERIFY_ERROR	0xb
+#define WST_SE_NOT_SUPPORT_VERIFY	0xd
+#define WST_SE_ERROR_LENGTH	0xc
+#define WST_SE_HAS_OPEN			0xd
+#define WST_COPY_MEM_ERROR		0xe
+#define WST_SE_PARAM_ERROR		0xf
+
+#define BASE_ERROR			0x1000
+#define WST_SE_ERROR_LICENSE		0x100b
+#define WST_SE_ERROR_NOT_SUPPORT_TYPE 0x100d
+
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_echip_driver.c b/drivers/crypto/sedriver/wst_se_echip_driver.c
new file mode 100644
index 000000000000..66e34549d209
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_echip_driver.c
@@ -0,0 +1,1368 @@
+#include <linux/semaphore.h>
+#include <linux/moduleparam.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/crypto.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/acpi.h>
+#include <asm/loongson.h>
+#include "wst_se_echip_driver.h"
+
+#define LS_CRYPTO_SE_ADDR1 TO_UNCACHE(LOONGSON_REG_BASE+0x0400)
+#define LS_CRYPTO_SE_ADDR2 TO_UNCACHE(0xc0010200000)
+#define DRIVER_VERSION "01.10.220111"
+DEFINE_SPINLOCK(g_reclistlock);
+DEFINE_SPINLOCK(g_sendlistlock);
+DEFINE_SPINLOCK(g_getdmabuflock);
+
+unsigned char *g_pCacheInBuf = NULL, *g_pCacheOutBuf = NULL;
+static struct class *g_psecclass;
+static struct device *g_psecdev;
+static SECHIPDRV_CTRL *g_psechipDrvCtrl;
+static int g_isechip_Major = -1;
+static struct semaphore g_lowsema, g_lowirqsema;
+static atomic_t g_sendtotallen;
+static struct tag_Queue_container g_RecQueueContainer;
+static struct tag_Queue_container g_SendQueueContainer;
+static int g_suspend;
+static struct semaphore g_dmabufsem;
+struct loongson_sedriver_irq se_irq[] = {
+	{
+		.pat = "se-irq",
+	},
+	{
+		.pat = "se-lirq",
+	},
+};
+static struct tag_Queue_container g_DmaBQueueContainer;
+static struct tag_dma_buf_ctl *g_pdmadatabuf;
+static int g_iDmaBufNum;
+static struct work_struct g_recwork, g_sendwork;
+static struct workqueue_struct *g_worksendqueue, *g_workrecqueue;
+static irqreturn_t se_interrupt(int irq, void *p);
+static irqreturn_t wst_low_channel_status(int irq, void *p);
+static void globalmem_do_send_op(struct work_struct *p);
+static void globalmem_do_rec_op(struct work_struct *p);
+static int g_iUseIntr = 1;
+module_param(g_iUseIntr, int, 0644);
+
+static int se_init_dma_buf(int idatasize, int idatanum)
+{
+	int i;
+	struct tag_dma_buf_ctl *pdmactl;
+
+	wst_InitQueue(&g_DmaBQueueContainer, idatanum);
+	g_pdmadatabuf = kmalloc((sizeof(struct tag_dma_buf_ctl)*idatanum), GFP_KERNEL);
+	if (!g_pdmadatabuf)
+		return -1;
+	for (i = 0; i < idatanum; i++) {
+		pdmactl = &g_pdmadatabuf[i];
+		pdmactl->pDmaBuf = (unsigned char *)__get_free_page(GFP_KERNEL|GFP_DMA);
+		if (!pdmactl->pDmaBuf) {
+			g_iDmaBufNum = i;
+			return SE_OK;
+		}
+		wst_Pushback_Que(&g_DmaBQueueContainer, pdmactl);
+	}
+	g_iDmaBufNum = i;
+	sema_init(&g_dmabufsem, 1);
+	return SE_OK;
+}
+
+static int se_del_dma_buf(void)
+{
+	int i;
+	struct tag_dma_buf_ctl *pdmactl;
+
+	for (i = 0; i < g_iDmaBufNum; i++) {
+		pdmactl = &g_pdmadatabuf[i];
+		if (pdmactl) {
+			free_page((unsigned long)pdmactl->pDmaBuf);
+			pdmactl->pDmaBuf = NULL;
+		}
+	}
+	kfree(g_pdmadatabuf);
+	g_pdmadatabuf = NULL;
+	return 0;
+}
+
+struct tag_dma_buf_ctl *se_get_dma_buf(int ikernel)
+{
+	struct tag_dma_buf_ctl *pbufctl = NULL;
+	unsigned long ultimeout = 0;
+
+	ultimeout = jiffies+20*HZ;
+	while (1) {
+		spin_lock(&g_getdmabuflock);
+		pbufctl = (struct tag_dma_buf_ctl *)wst_Popfront_Que(&g_DmaBQueueContainer);
+		spin_unlock(&g_getdmabuflock);
+		if (pbufctl)
+			return pbufctl;
+		if (down_timeout(&g_dmabufsem, ultimeout))
+			return NULL;
+	}
+	return pbufctl;
+}
+
+int se_free_dma_buf(struct tag_dma_buf_ctl *pdmabufctl)
+{
+	spin_lock(&g_getdmabuflock);
+	wst_Pushback_Que(&g_DmaBQueueContainer, pdmabufctl);
+	spin_unlock(&g_getdmabuflock);
+	if (g_dmabufsem.count <= 0)
+		up(&g_dmabufsem);
+
+	return 0;
+}
+
+static unsigned long  bytes_align(struct device *pdev, unsigned long ulVirAddr)
+{
+	unsigned char diff;
+	unsigned long ulPhyAddr = (unsigned long)__pa((void *)ulVirAddr);
+
+	if ((ulPhyAddr & 0x000000000000003f) == 0)
+		return ulVirAddr;
+	diff = ((long)ulPhyAddr & (~(0x000000000000003f))) + 64 - ulPhyAddr;
+	ulVirAddr += diff;
+
+	return ulVirAddr;
+}
+
+static unsigned long  descri_bytes_align(unsigned long ulVirAddr)
+{
+	unsigned char diff;
+	unsigned long ulPhyAddr = ulVirAddr;
+
+	if ((ulPhyAddr & (~0x00000000ffffffe0)) == 0)
+		return ulVirAddr;
+	diff = ((long)ulPhyAddr & 0x00000000ffffffe0) + 32 - ulPhyAddr;
+	ulVirAddr += diff;
+	return ulVirAddr;
+}
+
+int se_printk_hex(unsigned char *buff, int length)
+{
+	unsigned char *string_tmp = buff;
+	int i;
+	int count = 0;
+
+	for (i = 0; i < length; i++, count++) {
+		if (count < 16)
+			pr_info("%02x ", string_tmp[i]);
+		else {
+			count = 0;
+			pr_info("\n%02x ", string_tmp[i]);
+			continue;
+		}
+	}
+	pr_info("\n");
+	return 0;
+}
+
+static int se_ChipInit(SECHIPDRV_CTRL *pDrvCtrl)
+{
+	dma_addr_t ulBusAddr;
+	unsigned long ulVirAddr;
+	int i = 0, j = 0;
+	unsigned int dmaoldmask;
+
+	for (i = 0; i < SWCHANNELNUM; i++) {
+		ulVirAddr = (unsigned long)dma_alloc_coherent(
+			pDrvCtrl->pdev,
+			(SE_BDQUEUE_LEN * SE_BD_LENGTH+32),
+			&ulBusAddr, GFP_KERNEL
+			);
+		if (ulVirAddr == 0 || ulBusAddr == 0)
+			return -EFAULT;
+		memset((void *)ulVirAddr, 0, (SE_BDQUEUE_LEN*SE_BD_LENGTH));
+
+		pDrvCtrl->ulBDMemBasePhy[i]   = ulBusAddr;
+		pDrvCtrl->ulBDMemBase[i]      = ulVirAddr;
+		pDrvCtrl->ulCurrBdReadPtr[i]  = 0;
+		pDrvCtrl->ulCurrBdWritePtr[i] = 0;
+		pDrvCtrl->ulCurrReadPtr[i]  = 0;
+		pDrvCtrl->ulCurrWritePtr[i] = 0;
+	}
+	for (i = 0; i < SE_BDQUEUE_LEN; i++) {
+		for (j = 0; j < SWCHANNELNUM; j++)
+			(&((SE_BASIC_BD *)(pDrvCtrl->ulBDMemBase[j]))[i])->ucRetCode = 0x0f;
+	}
+	ulBusAddr = descri_bytes_align(pDrvCtrl->ulBDMemBasePhy[0]);
+	HandleWrite32(pDrvCtrl, SE_HREG_BQBA0, HIULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_LREG_BQBA0, LOULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_REG_BQS0,  SE_BDQUEUE_LEN - 1);
+	HandleWrite32(pDrvCtrl, SE_REG_RQRP0, pDrvCtrl->ulCurrBdReadPtr[0]);
+	HandleWrite32(pDrvCtrl, SE_REG_BQWP0, pDrvCtrl->ulCurrBdWritePtr[0]);
+
+	ulBusAddr = descri_bytes_align(pDrvCtrl->ulBDMemBasePhy[1]);
+	HandleWrite32(pDrvCtrl, SE_HREG_BQBA1, HIULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_LREG_BQBA1, LOULONG(ulBusAddr));
+	HandleWrite32(pDrvCtrl, SE_REG_BQS1,  SE_BDQUEUE_LEN - 1);
+	HandleWrite32(pDrvCtrl, SE_REG_RQRP1, pDrvCtrl->ulCurrBdReadPtr[1]);
+	HandleWrite32(pDrvCtrl, SE_REG_BQWP1, pDrvCtrl->ulCurrBdWritePtr[1]);
+	HandleRead32(pDrvCtrl, SE_REG_MSK, &dmaoldmask);
+	HandleWrite32(pDrvCtrl, SE_REG_MSK, (dmaoldmask | DMA0_CTRL_CHANNEL_ENABLE | DMA1_CTRL_CHANNEL_ENABLE));
+	if (g_iUseIntr != 0)
+		HandleWrite32(pDrvCtrl, SE_LOWREG_INQ, 1);
+	else
+		HandleWrite32(pDrvCtrl, SE_LOWREG_INQ, 0);
+	mdelay(1000);
+
+	return SE_OK;
+}
+
+static void  se_ChipRelease(SECHIPDRV_CTRL *pDrvCtrl)
+{
+	int i;
+
+	for (i = 0; i < SWCHANNELNUM; i++) {
+		if (pDrvCtrl->ulBDMemBase[i]) {
+			dma_free_coherent(
+				pDrvCtrl->pdev,
+				(SE_BDQUEUE_LEN * SE_BD_LENGTH),
+				(void *)pDrvCtrl->ulBDMemBase[i],
+				pDrvCtrl->ulBDMemBasePhy[i]
+				);
+			pDrvCtrl->ulBDMemBase[i] = 0;
+			pDrvCtrl->ulBDMemBasePhy[i] = 0;
+		}
+	}
+}
+
+static void SE_RESET(SECHIPDRV_CTRL *pdrvctl)
+{
+
+	unsigned int reg;
+	unsigned long   ulreg64, uladdr = LS_CRYPTO_SE_ADDR1;
+
+	HandleRead32(pdrvctl, SE_REG_RESET, ®);
+	HandleWrite32(pdrvctl, SE_REG_RESET, reg|SE_DMA_CONTROL_RESET);
+	mdelay(300);
+	HandleWrite32(pdrvctl, SE_REG_RESET, (reg&(~SE_DMA_CONTROL_RESET))|SE_DMA_CONTROL_SET);
+	mdelay(300);
+	ulreg64 = readq((volatile void __iomem *)uladdr);
+	if ((ulreg64 & 0xf0000000000000) != 0xf0000000000000)
+		writeq(ulreg64|0xf0000000000000, (volatile void __iomem *)uladdr);
+	HandleWrite32(pdrvctl, SE_INT_CLR, 0xf);
+}
+
+static int wst_init(void)
+{
+	int iRes = SE_OK;
+	static u64 wst_dma_mask = DMA_BIT_MASK(64);
+	char cName[256];
+	SECHIPDRV_CTRL *pdrvctl = NULL;
+
+	pdrvctl = kmalloc(sizeof(SECHIPDRV_CTRL), GFP_KERNEL);
+	if (pdrvctl == NULL)
+		return -ENOMEM;
+	memset(pdrvctl, 0, sizeof(SECHIPDRV_CTRL));
+	pdrvctl->ulMemBase = LS_CRYPTO_SE_ADDR2;
+	memset(cName, 0, 256);
+	sema_init(&(pdrvctl->sema), 0);
+	rwlock_init(&(pdrvctl->mr_lock));
+	rwlock_init(&(pdrvctl->mr_lowlock));
+	g_psechipDrvCtrl = pdrvctl;
+	g_psechipDrvCtrl->pdev = g_psecdev;
+	g_psechipDrvCtrl->pdev->dma_mask = &wst_dma_mask;
+	g_psechipDrvCtrl->pdev->coherent_dma_mask = (unsigned long long)&wst_dma_mask;
+	wst_InitQueue(&g_RecQueueContainer, 2000);
+	wst_InitQueue(&g_SendQueueContainer, 2000);
+	SE_RESET(pdrvctl);
+	pdrvctl->ilowIrq = 0;
+	pdrvctl->iIrq = se_irq[0].irq;
+	iRes = request_irq(pdrvctl->iIrq, &se_interrupt, IRQF_SHARED, "wst-se-hirq", pdrvctl);
+	if (iRes) {
+		pr_err("request_irq err\n");
+		pdrvctl->iIrq = 0;
+		goto err;
+	}
+	if (g_iUseIntr == 1) {
+		pdrvctl->ilowIrq = se_irq[1].irq;
+		iRes = request_irq(pdrvctl->ilowIrq, &wst_low_channel_status, IRQF_SHARED, "wst-se-lirq", pdrvctl);
+		if (iRes) {
+			pr_err("\nrequest_lowirq err, iRes=0x%x\n", iRes);
+			pdrvctl->ilowIrq = 0;
+			goto err;
+		}
+	}
+	if (se_ChipInit(pdrvctl) != SE_OK) {
+		iRes = -ENODEV;
+		goto err;
+	}
+	return SE_OK;
+err:
+	if (pdrvctl != NULL) {
+		if (pdrvctl->iIrq) {
+			free_irq(pdrvctl->iIrq, pdrvctl);
+			pdrvctl->iIrq = 0;
+		}
+		if (pdrvctl->ilowIrq) {
+			free_irq(pdrvctl->ilowIrq, pdrvctl);
+			pdrvctl->ilowIrq = 0;
+		}
+		se_ChipRelease(pdrvctl);
+		kfree(pdrvctl);
+		g_psechipDrvCtrl = NULL;
+	}
+	return iRes;
+}
+
+static void wst_clear(void)
+{
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+
+	pdrvctl = g_psechipDrvCtrl;
+	if (pdrvctl) {
+		if (pdrvctl->iIrq) {
+			free_irq(pdrvctl->iIrq, pdrvctl);
+			pdrvctl->iIrq = 0;
+		}
+		if (pdrvctl->ilowIrq) {
+			free_irq(pdrvctl->ilowIrq, pdrvctl);
+			pdrvctl->ilowIrq = 0;
+		}
+		se_ChipRelease(pdrvctl);
+		kfree(pdrvctl);
+		g_psechipDrvCtrl = NULL;
+	}
+}
+static void globalmem_do_send_op(struct work_struct *p)
+{
+	SE_BASIC_BD *pCurBD;
+	unsigned int ulCurrWritePtr, ulWritePtr;
+	unsigned short len = 0;
+	unsigned long ulCurrAddrInput = 0, ulCurrAddrOutput = 0;
+	SECHIPDRV_CTRL  *pdrvctl;
+	unsigned char *pInPtr;
+	unsigned short usInlen;
+	unsigned char *pOutPtr;
+	unsigned short *pusOutlen;
+	int iChannel;
+	unsigned char ucFlag;
+	unsigned char ucOpCode;
+	unsigned char *pucRetCode;
+	PSECallBackfn pcallback;
+	void *pParma;
+	int iKernel;
+	struct completion *mycomplete;
+	SEND_PACKAGE *psendpackage;
+	unsigned long ulflag;
+	unsigned long ultimeout;
+	int rv = 0;
+
+	while (1) {
+PROG:
+	spin_lock_irq(&g_sendlistlock);
+	psendpackage = (SEND_PACKAGE *)wst_Popfront_Que(&g_SendQueueContainer);
+	if (!psendpackage) {
+		spin_unlock_irq(&g_sendlistlock);
+		return;
+	}
+	spin_unlock_irq(&g_sendlistlock);
+	pdrvctl = psendpackage->pdrvctl;
+	pInPtr = psendpackage->pInPtr;
+	usInlen = psendpackage->usInlen;
+	pOutPtr = psendpackage->pOutPtr;
+	pusOutlen = psendpackage->pusOutlen;
+	iChannel = psendpackage->iChannel;
+	ucFlag = psendpackage->ucFlag;
+	ucOpCode = psendpackage->ucOpCode;
+	pucRetCode = psendpackage->pucRetCode;
+	pcallback = psendpackage->pcallback;
+	pParma = psendpackage->pParma;
+	iKernel = psendpackage->iKernel;
+	mycomplete = psendpackage->mycomplete;
+	ultimeout = psendpackage->ulendtime;
+	kfree(psendpackage);
+
+	if (iKernel == 0) {
+		while (time_before(jiffies, ultimeout)) {
+#ifdef CONFIG_MIPS
+			if ((pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+			|| ((atomic_read(&g_sendtotallen) + *pusOutlen + SE_FILL_LEN) > SE_MAX_SEND_LEN))
+#else
+			if (pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+#endif
+			{
+				down_timeout(&(pdrvctl->sema), 1*HZ);
+				rv = WST_SE_ERROR_FULL;
+			} else {
+				rv = 0;
+				break;
+			}
+		}
+		if (rv != 0x0) {
+			*pucRetCode = WST_SE_ERROR_FULL;
+			complete(mycomplete);
+			goto PROG;
+		}
+	} else {
+		ultimeout = jiffies+1*HZ;
+		while (time_before(jiffies, ultimeout)) {
+#ifdef CONFIG_MIPS
+			if ((pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+			|| ((atomic_read(&g_sendtotallen) + *pusOutlen + SE_FILL_LEN) > SE_MAX_SEND_LEN))
+#else
+			if (pdrvctl->ulCurrBdReadPtr[iChannel] == ((pdrvctl->ulCurrBdWritePtr[iChannel] + 1) & (SE_BDQUEUE_LEN-1)))
+#endif
+			{
+				rv = WST_SE_ERROR_FULL;
+			} else {
+				rv = 0;
+				break;
+			}
+		}
+		if (rv != 0x0) {
+			*pucRetCode = WST_SE_ERROR_FULL;
+			if (pcallback)
+				pcallback(pParma);
+			goto PROG;
+		}
+	}
+	ulCurrWritePtr = pdrvctl->ulCurrBdWritePtr[iChannel];
+	ulWritePtr = (ulCurrWritePtr + 1) & (SE_BDQUEUE_LEN-1);
+
+	pCurBD = &((SE_BASIC_BD *)(pdrvctl->ulBDMemBase[iChannel]))[ulCurrWritePtr];
+	memset(pCurBD, 0x0, sizeof(SE_BASIC_BD));
+	if (pcallback != NULL) {
+		(pdrvctl->pcallback)[iChannel][ulCurrWritePtr] = pcallback;
+		pdrvctl->pParma[iChannel][ulCurrWritePtr] = pParma;
+	} else {
+		(pdrvctl->pcallback)[iChannel][ulCurrWritePtr] = NULL;
+		pdrvctl->pParma[iChannel][ulCurrWritePtr] = NULL;
+	}
+
+	pdrvctl->ikernel[iChannel][ulCurrWritePtr] = iKernel;
+	pdrvctl->stsemphore[iChannel][ulCurrWritePtr] = mycomplete;
+
+	if (pInPtr == pOutPtr) {
+		if (pOutPtr) {
+			len = usInlen >= *pusOutlen ? usInlen : *pusOutlen;
+			if (len) {
+				ulCurrAddrOutput = dma_map_single(pdrvctl->pdev, pOutPtr, len, DMA_BIDIRECTIONAL);
+				if (ulCurrAddrOutput == 0) {
+					TRACEERR("map ulCurrAddrOutput error\n");
+					*pucRetCode = WST_SE_FAILURE;
+					if (iKernel == 0) {
+						complete(mycomplete);
+					} else {
+						*pucRetCode = WST_SE_FAILURE;
+						if (pcallback)
+							pcallback(pParma);
+					}
+					goto PROG;
+				}
+				pCurBD->ulOutputLPtr = LOULONG(ulCurrAddrOutput);
+				pCurBD->ulOutputHPtr = HIULONG(ulCurrAddrOutput);
+				pCurBD->ulInputLPtr = pCurBD->ulOutputLPtr;
+				pCurBD->ulInputHPtr = pCurBD->ulOutputHPtr;
+			}
+		}
+	} else {
+		if (pOutPtr && (*pusOutlen)) {
+			ulCurrAddrOutput = dma_map_single(pdrvctl->pdev, pOutPtr, *pusOutlen, DMA_FROM_DEVICE);
+			if (ulCurrAddrOutput == 0) {
+				TRACEERR("map ulCurrAddrOutput error\n");
+				*pucRetCode = WST_SE_FAILURE;
+				if (iKernel == 0) {
+					complete(mycomplete);
+				} else {
+					*pucRetCode = WST_SE_FAILURE;
+					if (pcallback)
+						pcallback(pParma);
+				}
+				goto PROG;
+			}
+			pCurBD->ulOutputLPtr = LOULONG(ulCurrAddrOutput);
+			pCurBD->ulOutputHPtr = HIULONG(ulCurrAddrOutput);
+		}
+		if (usInlen && pInPtr) {
+			ulCurrAddrInput = dma_map_single(pdrvctl->pdev, pInPtr, usInlen, DMA_TO_DEVICE);
+			if (ulCurrAddrInput == 0) {
+				if (ulCurrAddrOutput) {
+					dma_unmap_single(pdrvctl->pdev, ulCurrAddrOutput, *pusOutlen, DMA_FROM_DEVICE);
+					pCurBD->ulOutputLPtr = 0;
+					pCurBD->ulOutputHPtr = 0;
+				}
+				*pucRetCode = WST_SE_FAILURE;
+				if (iKernel == 0) {
+					complete(mycomplete);
+				} else {
+					*pucRetCode = WST_SE_FAILURE;
+					if (pcallback)
+						pcallback(pParma);
+				}
+				goto PROG;
+			}
+			pCurBD->ulInputLPtr = LOULONG(ulCurrAddrInput);
+			pCurBD->ulInputHPtr = HIULONG(ulCurrAddrInput);
+		}
+	}
+	pCurBD->ucOpCode = ucOpCode & 0x0f;
+	pCurBD->ucFlag = ucFlag & 0x7;
+	pCurBD->usInputLength = usInlen;
+	if (pusOutlen)
+		pCurBD->usOutputLength = *pusOutlen;
+
+	pCurBD->ucRetCode	= 0x0f;
+
+	pdrvctl->pusOutlen[iChannel][ulCurrWritePtr] = pusOutlen;
+	pdrvctl->usInlen[iChannel][ulCurrWritePtr] = usInlen&0xffff;
+	if (ulCurrAddrOutput)
+		pdrvctl->ulOutputPtr[iChannel][ulCurrWritePtr] = (unsigned long *)ulCurrAddrOutput;
+	else
+		pdrvctl->ulOutputPtr[iChannel][ulCurrWritePtr] = 0;
+	if (ulCurrAddrInput)
+		pdrvctl->ulInputPtr[iChannel][ulCurrWritePtr] = (unsigned long *)ulCurrAddrInput;
+	else
+		pdrvctl->ulInputPtr[iChannel][ulCurrWritePtr] = 0;
+	pdrvctl->pucRetCode[iChannel][ulCurrWritePtr] = pucRetCode;
+
+#ifdef CONFIG_MIPS
+	atomic_add((*(pdrvctl->pusOutlen[iChannel][ulCurrWritePtr]) + SE_FILL_LEN), &g_sendtotallen);
+#endif
+	write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	if (iChannel == 0)
+		HandleWrite32(pdrvctl, SE_REG_BQWP0, ulWritePtr);
+	else
+		HandleWrite32(pdrvctl, SE_REG_BQWP1, ulWritePtr);
+	write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+	pdrvctl->ulCurrBdWritePtr[iChannel] = ulWritePtr;
+	}
+}
+
+static int se_hardtrans(
+			SECHIPDRV_CTRL  *pdrvctl,
+			unsigned char *pInPtr,
+			unsigned short usInlen,
+			unsigned char *pOutPtr,
+			unsigned short *pusOutlen,
+			int iChannel,
+			unsigned char ucFlag,
+			unsigned char ucOpCode,
+			unsigned char *pucRetCode,
+			PSECallBackfn pcallback,
+			void *pParma,
+			int iKernel,
+			struct completion *mycomplete
+			)
+{
+	SEND_PACKAGE *psendpackage;
+	gfp_t gfp_flag;
+
+	if (in_interrupt())
+		gfp_flag = GFP_ATOMIC;
+	else
+		gfp_flag = GFP_KERNEL;
+	if (g_suspend == 1)
+		return WST_SE_FAILURE;
+	psendpackage = kmalloc(sizeof(SEND_PACKAGE), gfp_flag);
+	if (psendpackage == NULL)
+		return -1;
+
+	psendpackage->pdrvctl = pdrvctl;
+	psendpackage->pInPtr = pInPtr;
+	psendpackage->usInlen = usInlen;
+	psendpackage->pOutPtr = pOutPtr;
+	psendpackage->pusOutlen = pusOutlen;
+	psendpackage->iChannel = iChannel;
+	psendpackage->ucFlag = ucFlag;
+	psendpackage->ucOpCode = ucOpCode;
+	psendpackage->pucRetCode = pucRetCode;
+	psendpackage->pcallback = pcallback;
+	psendpackage->pParma = pParma;
+	psendpackage->iKernel = iKernel;
+	psendpackage->mycomplete = mycomplete;
+	psendpackage->ulendtime = jiffies+30*HZ;
+	spin_lock_irq(&g_sendlistlock);
+	if (wst_Pushback_Que(&g_SendQueueContainer, psendpackage) == -1) {
+		spin_unlock_irq(&g_sendlistlock);
+		kfree(psendpackage);
+		return WST_SE_ERROR_FULL;
+	}
+	spin_unlock_irq(&g_sendlistlock);
+	queue_work(g_worksendqueue, &g_sendwork);
+	return 0;
+}
+
+static irqreturn_t wst_low_channel_status(int irq, void *p)
+{
+	SECHIPDRV_CTRL *pdrvctl = (SECHIPDRV_CTRL *)p;
+	int64_t  ulIntStat = 0;
+	unsigned long ulflag;
+
+	read_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	HandleRead64(pdrvctl, SE_LOWREG_STS, &ulIntStat);
+	if (ulIntStat == 2) {
+		HandleWrite64(pdrvctl, SE_LOWINT_CLEAR, 2);
+		up(&g_lowirqsema);
+	}
+	read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+
+	return IRQ_HANDLED;
+}
+
+static int se_useropen(struct inode *inode, struct file *file)
+{
+	if (MINOR(inode->i_rdev) != 0)
+		return -ENODEV;
+
+	return SE_OK;
+}
+
+static ssize_t wst_low_channel_userwrite_op(
+					SECHIPDRV_CTRL  *pdrvctl,
+					SWCommuData *UserCommuData,
+					int iskernel
+					)
+{
+	unsigned long long addr = 0, outaddr = 0;
+	int ilen;
+	int count = SE_OK;
+	unsigned long long ulsendlen;
+	unsigned char *m_pCacheInBuf;
+	unsigned char *m_pCacheOutBuf;
+	unsigned long ulflag;
+
+	if ((g_pCacheInBuf == NULL) || (g_pCacheOutBuf == NULL))
+		return -EFAULT;
+
+	m_pCacheInBuf = (unsigned char *)bytes_align(0, (unsigned long)g_pCacheInBuf);
+	m_pCacheOutBuf = (unsigned char *)bytes_align(0, (unsigned long)g_pCacheOutBuf);
+	if (iskernel == 0) {
+		if (wst_cpyusrbuf((void   *)(UserCommuData->pucInbuf), (void *)m_pCacheInBuf, UserCommuData->usInputLen, READUBUF)) {
+			TRACEERR("copy user data error\n");
+			return -EFAULT;
+		}
+	} else
+
+		memcpy((void   *)m_pCacheInBuf, (void *)(UserCommuData->pucInbuf), UserCommuData->usInputLen);
+	ilen = UserCommuData->usInputLen >= UserCommuData->usOutputLen ? UserCommuData->usInputLen:UserCommuData->usOutputLen;
+	addr = dma_map_single(pdrvctl->pdev, m_pCacheInBuf, ilen, DMA_TO_DEVICE);
+	if (addr == 0) {
+		TRACEERR("transfer buffer is err\n");
+		return -EFAULT;
+	}
+	outaddr = dma_map_single(pdrvctl->pdev, m_pCacheOutBuf, ilen, DMA_FROM_DEVICE);
+	if (outaddr == 0) {
+		TRACEERR("transfer buffer is err\n");
+		dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+		return -EFAULT;
+	}
+	ulsendlen = (UserCommuData->usInputLen/8);
+	ulsendlen = (ulsendlen & 0x00000000ffffffff) << 32;
+	write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+	HandleWrite64(pdrvctl, SE_WRITE_REG1, ulsendlen);
+	HandleWrite64(pdrvctl, SE_WRITE_REG2, addr);
+	HandleWrite64(pdrvctl, SE_WRITE_REG3, outaddr);
+	write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+	if (g_iUseIntr != 0) {
+		if (down_interruptible(&g_lowirqsema) == -EINTR) {
+			count = -EINTR;
+			goto EXIT;
+		}
+	} else {
+		unsigned long start_jiffies = 0, end_jiffies = 0;
+		int64_t  ulIntStat = 0;
+
+		start_jiffies = jiffies;
+		end_jiffies = jiffies;
+		while (1) {
+			write_lock_irqsave(&(pdrvctl->mr_lock), ulflag);
+			HandleRead64(pdrvctl, SE_LOWREG_SR, &ulIntStat);
+			end_jiffies = jiffies;
+			if (ulIntStat == 1) {
+				HandleWrite64(pdrvctl, SE_LOWREG_SR, 0);
+				write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+				break;
+			}
+			write_unlock_irqrestore(&(pdrvctl->mr_lock), ulflag);
+			if (jiffies_to_msecs(end_jiffies-start_jiffies)/1000 >= 90) {
+				count = -EFAULT;
+				goto EXIT;
+			}
+		}
+	}
+	dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+	dma_unmap_single(pdrvctl->pdev, outaddr, ilen, DMA_FROM_DEVICE);
+	if (UserCommuData->usOutputLen) {
+		if (iskernel == 0) {
+			if (wst_cpyusrbuf(UserCommuData->pucOutbuf, m_pCacheOutBuf, UserCommuData->usOutputLen, WRITEUBUF))
+				return -EFAULT;
+		} else
+			memcpy(UserCommuData->pucOutbuf, m_pCacheOutBuf, UserCommuData->usOutputLen);
+	}
+	return count;
+EXIT:
+	dma_unmap_single(pdrvctl->pdev, addr, ilen, DMA_TO_DEVICE);
+	dma_unmap_single(pdrvctl->pdev, outaddr, ilen, DMA_FROM_DEVICE);
+	return count;
+}
+
+static ssize_t se_userwrite(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	unsigned char *pCacheBuf = NULL, *pCacheOutBuf = NULL, *pCacheBufalign = NULL, *pCacheOutBufalign = NULL;
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+	SWCommuData *pCommuData = NULL;
+	int iCommuDatalen = 0;
+	int pucRetCode = 0;
+	unsigned short iChannel = 0;
+	unsigned char ucFlag = 0, ucOpCode = 0;
+	int *ppucRetCode;
+	struct completion mycomplete;
+	struct tag_dma_buf_ctl *pbufinctl = NULL;
+	int iret = 0;
+
+	if (count == 0) {
+		TRACEERR("count=0\n");
+		return SE_OK;
+	}
+
+	if (MINOR(file->f_path.dentry->d_inode->i_rdev) != 0)
+		return -ENODEV;
+
+	iCommuDatalen = sizeof(SWCommuData);
+	if (count != iCommuDatalen)
+		return -EINVAL;
+
+	pdrvctl = g_psechipDrvCtrl;
+	pCommuData = kmalloc(iCommuDatalen, GFP_KERNEL);
+	if (!pCommuData) {
+		TRACEERR("pCommuData NULL\n");
+		return -ENOMEM;
+	}
+	if (wst_cpyusrbuf((void   *)buf, (void *)pCommuData, iCommuDatalen, READUBUF)) {
+		TRACEERR("copy user data error\n");
+		count = -EFAULT;
+		goto EXIT;
+	}
+	switch ((pCommuData->usFlags)&0x000f) {
+	case WST_GO_CHANNEL2:
+		if ((pCommuData->usInputLen > DMA_BUFSIZE) || (pCommuData->usOutputLen > DMA_BUFSIZE)) {
+			TRACEERR("len is error\n");
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (down_interruptible(&g_lowsema) == -EINTR) {
+			count = -EINTR;
+			goto EXIT;
+		}
+		count = wst_low_channel_userwrite_op(pdrvctl, pCommuData, 0);
+		up(&g_lowsema);
+		goto EXIT;
+	case WST_GO_CHANNEL0:
+		if (pCommuData->usInputLen == 0) {
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (pCommuData->usInputLen != 0) {
+			if (pCommuData->usInputLen > DMA_BUFSIZE) {
+				count = -EINVAL;
+				goto EXIT;
+			}
+			ucFlag = INPUT_VALID;
+			if (pCommuData->usOutputLen)
+				ucFlag |= OUTPUT_VALID;
+		}
+
+		iChannel = 0;
+		ucOpCode = 0x0;
+		break;
+	case WST_GO_CHANNEL1:
+		if (pCommuData->usInputLen == 0) {
+			count = -EINVAL;
+			goto EXIT;
+		}
+		if (pCommuData->usInputLen != 0) {
+			if (pCommuData->usInputLen > DMA_BUFSIZE) {
+				count = -EINVAL;
+				goto EXIT;
+			}
+			ucFlag = INPUT_VALID;
+			if (pCommuData->usOutputLen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 1;
+		ucOpCode = 0x0;
+		break;
+	default:
+		{
+			count = -EINVAL;
+			goto EXIT;
+		}
+	}
+	pbufinctl = se_get_dma_buf(0);
+	if (pbufinctl == NULL) {
+		TRACEERR("kmalloc pCacheBuf error\n");
+		count = -ENOMEM;
+		goto EXIT;
+	}
+	pCacheBuf = pbufinctl->pDmaBuf;
+	pCacheBufalign = pCacheBuf;
+
+	if (wst_cpyusrbuf((void   *)(pCommuData->pucInbuf), (void *)pCacheBufalign,
+				pCommuData->usInputLen, READUBUF)) {
+		TRACEERR("cpyuserbuf pCacheBufalign error\n");
+		count = -ENOMEM;
+		goto EXIT;
+	}
+
+	pCacheOutBuf = pbufinctl->pDmaBuf;
+	pCacheOutBufalign = pCacheOutBuf;
+
+	ppucRetCode = &pucRetCode;
+
+	count = SE_OK;
+	init_completion(&mycomplete);
+	iret = se_hardtrans(
+		pdrvctl,
+		pCacheBufalign,
+		pCommuData->usInputLen,
+		pCacheOutBufalign,
+		&(pCommuData->usOutputLen),
+		iChannel,
+		ucFlag,
+		ucOpCode,
+		(unsigned char *)ppucRetCode,
+		0,
+		0,
+		0,
+		&mycomplete
+		);
+	if (iret == -1) {
+		count = -EIO;
+		goto EXIT;
+	}
+	if (!wait_for_completion_timeout(&mycomplete, msecs_to_jiffies(60*1000))) {
+		count = -EFAULT;
+		goto EXIT;
+	}
+	if (pucRetCode != SE_OK) {
+		count = -(SE_BASEERR+pucRetCode);
+		goto EXIT;
+	}
+
+	if (pCommuData->pucOutbuf) {
+		if (wst_cpyusrbuf(pCommuData->pucOutbuf, pCacheOutBufalign,
+					pCommuData->usOutputLen, WRITEUBUF)) {
+			count = -EFAULT;
+			goto EXIT;
+		}
+	}
+EXIT:
+	if (pbufinctl)
+		se_free_dma_buf(pbufinctl);
+	kfree(pCommuData);
+	return count;
+}
+static void globalmem_do_rec_op(struct work_struct *p)
+{
+	INT_MESSAGE *intmessage;
+	unsigned long ulflags1;
+
+	while (1) {
+		spin_lock_irqsave(&g_reclistlock, ulflags1);
+		intmessage = (INT_MESSAGE *)wst_Popfront_Que(&g_RecQueueContainer);
+		spin_unlock_irqrestore(&g_reclistlock, ulflags1);
+		if (!intmessage)
+			return;
+		intmessage->pcallback(intmessage->pParma);
+		kfree(intmessage);
+	}
+}
+static irqreturn_t se_interrupt(int irq, void *p)
+{
+	SECHIPDRV_CTRL *pdrvctl;
+	SE_BASIC_BD *pCurBD;
+	unsigned int	ulCurrReadPtr, ulReadPtr;
+	int iChannel;
+	int len = 0;
+	int i;
+	unsigned char ucMyRetCode = 0;
+	unsigned long ulIntStat;
+	int istatus[2] = {1, 2};
+	unsigned long ulflags;
+
+	pdrvctl = (SECHIPDRV_CTRL *)p;
+	if (!pdrvctl)
+		return IRQ_HANDLED;
+
+	read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+	HandleRead32(pdrvctl, SE_REG_STS, &ulIntStat);
+	read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+	if ((!(ulIntStat & INT_STAT_DMA_MASK)) || (ulIntStat == 0xffffffff))
+		return IRQ_HANDLED;
+
+	for (i = 0; i <= 1; i++) {
+		if (ulIntStat & istatus[i]) {
+			if (i == 0) {
+				read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+				HandleWrite32(pdrvctl, SE_INT_CLR, 1);
+				HandleRead32(pdrvctl, SE_REG_RQRP0, &ulReadPtr);
+				read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+				iChannel = 0;
+			} else {
+				read_lock_irqsave(&(pdrvctl->mr_lock), ulflags);
+				HandleWrite32(pdrvctl, SE_INT_CLR, 2);
+				HandleRead32(pdrvctl, SE_REG_RQRP1, &ulReadPtr);
+				read_unlock_irqrestore(&(pdrvctl->mr_lock), ulflags);
+				iChannel = 1;
+			}
+		} else
+			continue;
+		ulCurrReadPtr = pdrvctl->ulCurrReadPtr[iChannel];
+		while (1) {
+			if (ulCurrReadPtr != ulReadPtr) {
+				pCurBD = &((SE_BASIC_BD *)(pdrvctl->ulBDMemBase[iChannel]))[ulCurrReadPtr];
+				if ((pCurBD->ucRetCode == 0x0f) || ((pCurBD->ucFlag & 0x8) != 0x8)) {
+					continue;
+				} else {
+					if (pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr] == pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+						if (pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+							len = (*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])) >= pdrvctl->usInlen[iChannel][ulCurrReadPtr] ?
+								(*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])):pdrvctl->usInlen[iChannel][ulCurrReadPtr];
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]),
+								len,
+								DMA_BIDIRECTIONAL
+								);
+							pCurBD->ulOutputLPtr = 0;
+							pCurBD->ulOutputHPtr = 0;
+							pCurBD->ulInputHPtr = 0;
+							pCurBD->ulInputLPtr = 0;
+							pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+					} else {
+						if (pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]) {
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr]),
+								*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr]), DMA_FROM_DEVICE
+								);
+							smp_wmb();
+							pdrvctl->ulOutputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+						if (pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr]) {
+							dma_unmap_single(
+								pdrvctl->pdev,
+								(unsigned long)(pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr]),
+								pdrvctl->usInlen[iChannel][ulCurrReadPtr],
+								DMA_TO_DEVICE
+								);
+							pdrvctl->ulInputPtr[iChannel][ulCurrReadPtr] = 0;
+						}
+					}
+					ucMyRetCode = pCurBD->ucRetCode;
+					memcpy(pdrvctl->pucRetCode[iChannel][ulCurrReadPtr], &ucMyRetCode, 1);
+					if (pCurBD->ucRetCode != SE_OK)
+						pr_info("\nstatus %x\n", pCurBD->ucRetCode);
+#ifdef CONFIG_MIPS
+					atomic_sub(((*(pdrvctl->pusOutlen[iChannel][ulCurrReadPtr])) + SE_FILL_LEN), &g_sendtotallen);
+#endif
+					if ((pdrvctl->ikernel)[iChannel][ulCurrReadPtr] != 0) {
+						if (pdrvctl->pcallback[iChannel][ulCurrReadPtr]) {
+							INT_MESSAGE *intmessage = NULL;
+							unsigned long ulflags1;
+
+							intmessage = (INT_MESSAGE   *)kmalloc(sizeof(INT_MESSAGE), GFP_ATOMIC);
+							if (!intmessage)
+								return IRQ_HANDLED;
+							intmessage->pcallback = pdrvctl->pcallback[iChannel][ulCurrReadPtr];
+							intmessage->pParma = pdrvctl->pParma[iChannel][ulCurrReadPtr];
+							spin_lock_irqsave(&g_reclistlock, ulflags1);
+							wst_Pushback_Que(&g_RecQueueContainer, intmessage);
+							spin_unlock_irqrestore(&g_reclistlock, ulflags1);
+							queue_work(g_workrecqueue, &g_recwork);
+						}
+					} else {
+						complete(pdrvctl->stsemphore[iChannel][ulCurrReadPtr]);
+					}
+					ulCurrReadPtr = ((ulCurrReadPtr + 1)&(SE_BDQUEUE_LEN - 1));
+					pdrvctl->ulCurrReadPtr[iChannel] = ulCurrReadPtr;
+					pdrvctl->ulCurrBdReadPtr[iChannel] = ulCurrReadPtr;
+					if (pdrvctl->sema.count <= 0)
+						up(&(pdrvctl->sema));
+				}
+			} else
+
+				break;
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int se_userrelease(struct inode *inode, struct file *file)
+{
+	return SE_OK;
+}
+
+ssize_t se_kernelwrite(
+					   unsigned char *pInPtr,
+					   unsigned short usInlen,
+					   unsigned char *pOutPtr,
+					   unsigned short *pusOutlen,
+					   unsigned char ucFlag,
+					   unsigned char *pucRetCode,
+					   PSECallBackfn pcallback,
+					   void *pParma
+					   )
+{
+	int iret;
+	SECHIPDRV_CTRL  *pdrvctl;
+	int iChannel;
+	unsigned char ucOpCode;
+	SWCommuData CommuData;
+
+	pdrvctl = g_psechipDrvCtrl;
+
+	switch (ucFlag) {
+	case WST_GO_CHANNEL2:
+		{
+			CommuData.pucInbuf = pInPtr;
+			CommuData.pucOutbuf = pOutPtr;
+			CommuData.usFlags = 0;
+			CommuData.usInputLen = usInlen;
+			CommuData.usOutputLen = *pusOutlen;
+			CommuData.usReserve = 0;
+			if (down_interruptible(&g_lowsema) == -EINTR)
+				return -EINTR;
+			iret = wst_low_channel_userwrite_op(pdrvctl, &CommuData, 1);
+			up(&g_lowsema);
+			return iret;
+		}
+	case WST_GO_CHANNEL0:
+		if (pcallback == NULL)
+			return WST_SE_PARAM_ERROR;
+		if (usInlen == 0)
+			return -EINVAL;
+		ucFlag = 0;
+		if (usInlen != 0) {
+			if (usInlen > DMA_BUFSIZE)
+				return -EINVAL;
+			ucFlag = INPUT_VALID;
+			if (*pusOutlen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 0;
+		ucOpCode = 0x0;
+		break;
+	case WST_GO_CHANNEL1:
+		if (pcallback == NULL)
+			return WST_SE_PARAM_ERROR;
+		if (usInlen == 0) {
+			return -EINVAL;
+		}
+		ucFlag = 0;
+		if (usInlen != 0) {
+			if (usInlen > DMA_BUFSIZE)
+				return -EINVAL;
+			ucFlag = INPUT_VALID;
+			if (*pusOutlen)
+				ucFlag |= OUTPUT_VALID;
+		}
+		iChannel = 1;
+		ucOpCode = 0x0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	iret = se_hardtrans(
+		pdrvctl,
+		pInPtr,
+		usInlen,
+		pOutPtr,
+		pusOutlen,
+		iChannel,
+		ucFlag,
+		ucOpCode,
+		pucRetCode,
+		pcallback,
+		pParma,
+		1,
+		NULL
+		);
+	if (iret == -1)
+		return -EIO;
+
+	return SE_OK;
+}
+EXPORT_SYMBOL(se_kernelwrite);
+
+static long se_userioctl(struct file *filp, u_int cmd, u_long arg)
+{
+	long iret = SE_OK;
+	SECHIPDRV_CTRL *pdrvctl = g_psechipDrvCtrl;
+	unsigned long ulvalue;
+
+	HandleRead64(pdrvctl, 0x120, &ulvalue);
+	pr_info("read reg value is 0x%lx in offset 120\n", ulvalue);
+	HandleRead64(pdrvctl, 0x118, &ulvalue);
+	pr_info("read reg value is 0x%lx in offset 118\n", ulvalue);
+
+	return iret;
+}
+
+
+static const struct file_operations SE_fops = {
+	.owner = THIS_MODULE,
+	.write = se_userwrite,
+	.open = se_useropen,
+	.release = se_userrelease,
+	.unlocked_ioctl = se_userioctl,
+	.compat_ioctl = se_userioctl
+};
+
+int  se_chip_load(void)
+{
+	int iRes = SE_OK;
+
+	if (g_isechip_Major >= 0)
+		return WST_SE_HAS_OPEN;
+	g_psechipDrvCtrl = NULL;
+	iRes = se_init_dma_buf(DMA_BUFSIZE, CTL_DMABUFNUM);
+	if (iRes != SE_OK)
+		return WST_SE_ERROR_MALLOC;
+	iRes = register_chrdev(0, CRYNAME, &SE_fops);
+	if (iRes < 0)
+		goto EXIT;
+
+	g_isechip_Major = iRes;
+	iRes = 0;
+	g_psecclass = class_create(CRYNAME);
+	if (IS_ERR(g_psecclass)) {
+		iRes = PTR_ERR(g_psecclass);
+		goto EXIT;
+	}
+	g_psecdev = device_create(g_psecclass, NULL, MKDEV(g_isechip_Major, 0), NULL, CRYNAME);
+	if (IS_ERR(g_psecdev)) {
+		iRes = PTR_ERR(g_psecdev);
+		goto EXIT;
+	}
+	iRes = wst_init();
+	if (iRes != SE_OK)
+		goto EXIT;
+
+	sema_init(&g_lowsema, 1);
+	sema_init(&g_lowirqsema, 0);
+	atomic_set(&g_sendtotallen, 0);
+	g_pCacheInBuf = (unsigned char *)__get_free_page(GFP_DMA);
+	if (IS_ERR(g_pCacheInBuf)) {
+		iRes = PTR_ERR(g_pCacheInBuf);
+		goto EXIT;
+	}
+	g_pCacheOutBuf = (unsigned char *)__get_free_page(GFP_DMA);
+	if (IS_ERR(g_pCacheOutBuf)) {
+		iRes = PTR_ERR(g_pCacheOutBuf);
+		goto EXIT;
+	}
+
+	g_worksendqueue = alloc_workqueue("seworksendqueue",
+					WQ_MEM_RECLAIM|__WQ_ORDERED|WQ_UNBOUND, 1);
+	if (IS_ERR(g_worksendqueue)) {
+		iRes = PTR_ERR(g_worksendqueue);
+		goto EXIT;
+	}
+	g_workrecqueue = alloc_workqueue("seworkrecqueue", WQ_MEM_RECLAIM|__WQ_ORDERED, 0);
+	if (IS_ERR(g_workrecqueue)) {
+		iRes = PTR_ERR(g_workrecqueue);
+		goto EXIT;
+	}
+	INIT_WORK(&g_recwork, globalmem_do_rec_op);
+	INIT_WORK(&g_sendwork, globalmem_do_send_op);
+	pr_info("this driver version is %s\n", DRIVER_VERSION);
+
+	return SE_OK;
+EXIT:
+	se_del_dma_buf();
+	if (g_pCacheInBuf) {
+
+		free_page((unsigned long)g_pCacheInBuf);
+		g_pCacheInBuf = NULL;
+	}
+	if (g_pCacheOutBuf) {
+
+		free_page((unsigned long)g_pCacheOutBuf);
+		g_pCacheOutBuf = NULL;
+	}
+	if (g_worksendqueue) {
+		destroy_workqueue(g_worksendqueue);
+		g_worksendqueue = NULL;
+	}
+	if (g_workrecqueue) {
+		destroy_workqueue(g_workrecqueue);
+		g_workrecqueue = NULL;
+	}
+	wst_clear();
+	if (g_psecdev) {
+		device_unregister(g_psecdev);
+		g_psecdev = NULL;
+	}
+	if (g_psecclass) {
+		class_destroy(g_psecclass);
+		g_psecclass = NULL;
+	}
+	if (g_isechip_Major >= 0) {
+		unregister_chrdev(g_isechip_Major, CRYNAME);
+		g_isechip_Major = -1;
+	}
+	return iRes;
+}
+
+void se_chip_unload(void)
+{
+	SECHIPDRV_CTRL  *pdrvctl = NULL;
+
+	pdrvctl = g_psechipDrvCtrl;
+
+	up(&pdrvctl->sema);
+	if (g_pCacheInBuf) {
+
+		free_page((unsigned long)g_pCacheInBuf);
+		g_pCacheInBuf = NULL;
+	}
+	if (g_pCacheOutBuf) {
+
+		free_page((unsigned long)g_pCacheOutBuf);
+		g_pCacheOutBuf = NULL;
+	}
+	if (g_worksendqueue) {
+		cancel_work_sync(&g_sendwork);
+		destroy_workqueue(g_worksendqueue);
+		g_worksendqueue = NULL;
+	}
+	if (g_workrecqueue) {
+		cancel_work_sync(&g_recwork);
+		destroy_workqueue(g_workrecqueue);
+		g_workrecqueue = NULL;
+	}
+	wst_clear();
+	if (g_psecdev) {
+		device_destroy(g_psecclass, MKDEV(g_isechip_Major, 0));
+		g_psecdev = NULL;
+	}
+	if (g_psecclass) {
+		class_destroy(g_psecclass);
+		g_psecclass = NULL;
+	}
+	if (g_isechip_Major >= 0) {
+		unregister_chrdev(g_isechip_Major, CRYNAME);
+		g_isechip_Major = -1;
+	}
+	se_del_dma_buf();
+}
+
+static int loongson_cryp_get_irq(struct platform_device *pdev, char *pat)
+{
+	int i;
+	struct resource *res = pdev->resource;
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		if (strcmp(res[i].name, pat) == 0)
+			return res[i].start;
+	}
+	return -1;
+
+}
+static int loongson_cryp_probe(struct platform_device *pdev)
+{
+	int i;
+
+	if (ACPI_COMPANION(&pdev->dev)) {
+		se_irq[0].irq = platform_get_irq(pdev, 1);
+		se_irq[1].irq = platform_get_irq(pdev, 0);
+	} else {
+		for (i = 0; i < pdev->num_resources; i++) {
+			se_irq[i].irq = loongson_cryp_get_irq(pdev,
+							se_irq[i].pat);
+			if (se_irq[i].irq < 0) {
+				pr_warn("ERROR:sedriver get irq failed\n");
+				return -1;
+			}
+		}
+	}
+
+	return se_chip_load();
+}
+static int loongson_cryp_remove(struct platform_device *pdev)
+{
+	se_chip_unload();
+	return 0;
+}
+static int loongson_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	g_suspend = 1;
+	cancel_work_sync(&g_recwork);
+	cancel_work_sync(&g_sendwork);
+	flush_work(&g_recwork);
+	flush_work(&g_sendwork);
+	se_chip_unload();
+	return 0;
+}
+
+static int loongson_cryp_resume(struct platform_device *pdev)
+{
+	int i;
+
+	g_suspend = 0;
+	g_worksendqueue = NULL;
+	g_workrecqueue = NULL;
+	g_isechip_Major = -1;
+	g_pCacheInBuf = NULL;
+	g_pCacheOutBuf = NULL;
+	g_iUseIntr = 1;
+	spin_lock_init(&g_reclistlock);
+	spin_lock_init(&g_sendlistlock);
+	spin_lock_init(&g_getdmabuflock);
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		se_irq[i].irq = loongson_cryp_get_irq(pdev, se_irq[i].pat);
+
+		if (se_irq[i].irq < 0) {
+			pr_warn("ERROR:sedriver get irq failed\n");
+			return -1;
+		}
+	}
+	se_chip_load();
+	return 0;
+}
+
+static const struct acpi_device_id loongson_cryp_acpi_match[] = {
+	{"LOON0003"},
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, loongson_cryp_acpi_match);
+
+static struct platform_driver loongson_cryp_driver = {
+	.probe		= loongson_cryp_probe,
+	.remove		= loongson_cryp_remove,
+	.suspend	= loongson_cryp_suspend,
+	.resume		= loongson_cryp_resume,
+	.driver		= {
+			.name = "loongson3_crypto",
+			.acpi_match_table = ACPI_PTR(loongson_cryp_acpi_match),
+	},
+};
+
+static int __init initmodule(void)
+{
+	return platform_driver_register(&loongson_cryp_driver);
+}
+
+static void __exit exitmodule(void)
+{
+	platform_driver_unregister(&loongson_cryp_driver);
+}
+
+module_init(initmodule);
+module_exit(exitmodule);
+
+MODULE_ALIAS("platform:loongson3_crypto");
+MODULE_AUTHOR("dcm");
+MODULE_DESCRIPTION("se encryption chip driver Co westone");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/sedriver/wst_se_echip_driver.h b/drivers/crypto/sedriver/wst_se_echip_driver.h
new file mode 100644
index 000000000000..3e562e55faac
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_echip_driver.h
@@ -0,0 +1,184 @@
+#ifndef _WST_SE_ECHIP_DRIVER_H
+#define _WST_SE_ECHIP_DRIVER_H
+#include "wst_se_ktrans.h"
+
+#define CRYNAME "wst-se"
+
+#define SWBUFNUM     512
+#define SWCHANNELNUM 2
+#define CTL_DMABUFNUM  512
+
+#define DMA_MASK 0xffffffff
+#define SE_DMA_CONTROL_RESET 0x80000000
+#define SE_DMA_CONTROL_SET   0x00000000
+
+#define SE_BASEERR 1000
+
+#define SE_MAX_SEND_LEN (3*2048)
+#define SE_FILL_LEN 48
+#define SE_BD_LENGTH sizeof(SE_BASIC_BD)
+#define SE_BDQUEUE_LEN  SWBUFNUM
+#define DMA0_CTRL_CHANNEL_ENABLE    1
+#define DMA0_CTRL_CHANNEL_DISABLE   0xfffffffe
+#define DMA1_CTRL_CHANNEL_ENABLE    2
+#define DMA1_CTRL_CHANNEL_DISABLE   0xfffffffd
+
+#define SE_REG_RESET			 0
+#define SE_REG_STS				0x08
+#define SE_INT_CTRL				0x10
+#define SE_REG_MSK				0x18
+#define SE_INT_CLR				0x20
+
+#define SE_LREG_BQBA0			0x100
+#define SE_HREG_BQBA0			0x108
+#define SE_REG_BQS0				0x110
+#define SE_REG_BQWP0			0x118
+#define SE_REG_RQRP0			0x120
+
+#define SE_LREG_BQBA1			0x128
+#define SE_HREG_BQBA1			0x130
+#define SE_REG_BQS1				0x138
+#define SE_REG_BQWP1			0x140
+#define SE_REG_RQRP1			0x148
+
+#define SE_WRITE_REG1			0x200
+#define SE_WRITE_REG2			0x208
+#define SE_WRITE_REG3			0x210
+#define SE_LOWREG_STS			0x240
+#define SE_LOWINT_CLEAR			0x248
+#define SE_LOWREG_INQ			0x1600
+#define SE_LOWREG_SR			0x1608
+#define INPUT_VALID				0x4
+#define OUTPUT_VALID			0x8
+#define SE_LOWINT_CLR			0x228
+#define INT_STAT_DMA0_PACK_DONE 1
+#define INT_STAT_DMA1_PACK_DONE 2
+#define INT_STAT_DMA_MASK		(INT_STAT_DMA0_PACK_DONE|INT_STAT_DMA1_PACK_DONE)
+
+typedef struct tagSEdrvctl {
+
+	unsigned long	ulMemBase;
+	struct device	*pdev;
+	struct device	dev;
+	unsigned int	ulCurrBdReadPtr[SWCHANNELNUM];
+	unsigned int	ulCurrBdWritePtr[SWCHANNELNUM];
+	unsigned int	ulCurrReadPtr[SWCHANNELNUM];
+	unsigned int	ulCurrWritePtr[SWCHANNELNUM];
+	PSECallBackfn	pcallback[SWCHANNELNUM][SWBUFNUM];
+	void *pParma[SWCHANNELNUM][SWBUFNUM];
+	struct completion	*stsemphore[SWCHANNELNUM][SWBUFNUM];
+	int		ikernel[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	ulBDMemBasePhy[SWCHANNELNUM];
+	unsigned long	ulBDMemBase[SWCHANNELNUM];
+	unsigned short	*pusOutlen[SWCHANNELNUM][SWBUFNUM];
+	unsigned short	usInlen[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	*ulOutputPtr[SWCHANNELNUM][SWBUFNUM];
+	unsigned long	*ulInputPtr[SWCHANNELNUM][SWBUFNUM];
+	unsigned char	*pucRetCode[SWCHANNELNUM][SWBUFNUM];
+	rwlock_t mr_lock;
+	rwlock_t mr_lowlock;
+	spinlock_t readlock;
+	struct semaphore sema;
+	int iIrq;
+	int ilowIrq;
+} SECHIPDRV_CTRL;
+
+typedef struct tagSEBasicBD {
+
+	unsigned int  ucOpCode:4,
+		ucFlag:4,
+		ucRetCode:8,
+		ucInCtxLength:8,
+		ucOutCtxLength:8;
+	unsigned int	usInputLength:16,
+		usOutputLength:16;
+	unsigned int	ulCtxLPtr;
+	unsigned int	ulCtxHPtr;
+	unsigned int	ulInputLPtr;
+	unsigned int	ulInputHPtr;
+	unsigned int	ulOutputLPtr;
+	unsigned int	ulOutputHPtr;
+
+} SE_BASIC_BD;
+
+#define SW_CONT_BUF_SIZE		0x100
+#define DMA_BUFSIZE				0x1000
+
+#define PAGE_NUM (DMA_BUFSIZE/PAGE_SIZE+1)
+
+typedef struct _SW_GET_STAT {
+	unsigned long TXD;
+	unsigned long RXD;
+} SW_GET_STAT, *PSW_GET_STAT;
+
+DEFINE_SPINLOCK(g_writelock);
+
+#define HandleRead32(handle, addr, pData) \
+	do { \
+		smp_mb(); \
+		*(pData) = readl((void *)(handle->ulMemBase + addr));	\
+	} while (0)
+
+#define HandleWrite32(handle, addr, value)\
+	do { \
+		writel(value, (void *)(handle->ulMemBase + addr));	\
+		smp_mb(); \
+	} while (0)
+
+#define HandleRead64(handle, addr, pData) \
+	do { \
+		smp_mb(); \
+		*(pData) = readq((void *)(handle->ulMemBase + addr));	\
+	} while (0)
+
+#define HandleWrite64(handle, addr, value)\
+	do { \
+		writeq(value, (void *)(handle->ulMemBase + addr));	\
+		smp_mb(); \
+	} while (0)
+
+
+#define SPRINTF sprintf
+
+#define HIULONG(w)	((unsigned int)((((unsigned long long)w) >> 32) & 0x00000000ffffffff))
+#define LOULONG(w)	((unsigned int)((unsigned long long)w) & 0x00000000ffffffff)
+
+#ifdef DEBUG_DRIVER
+	#define TRACEMSG(fmt, args...) printk(KERN_DEBUG "msg: " fmt, ##args)
+#else
+	#define TRACEMSG(fmt, args...)
+#endif
+
+#ifdef DEBUG_DRIVER_ERROR
+	#define TRACEERR(fmt, args...) printk(KERN_DEBUG "err: " fmt, ##args)
+#else
+	#define TRACEERR(fmt, args...)
+#endif
+
+#define HIBYTE(w)		((unsigned char)(((unsigned short)(w) >> 8) & 0xFF))
+#define LOBYTE(w)		((unsigned char)(w))
+
+typedef struct ST_SEND_PACKAGE {
+	struct list_head  list;
+	SECHIPDRV_CTRL  *pdrvctl;
+	unsigned char *pInPtr;
+	unsigned short usInlen;
+	unsigned char *pOutPtr;
+	unsigned short *pusOutlen;
+	int iChannel;
+	unsigned char ucFlag;
+	unsigned char ucOpCode;
+	unsigned char *pucRetCode;
+	PSECallBackfn pcallback;
+	void *pParma;
+	int iKernel;
+	struct completion *mycomplete;
+	unsigned long ulendtime;
+} SEND_PACKAGE;
+
+typedef struct ST_INT_MESSAGE {
+	struct list_head  list;
+	PSECallBackfn pcallback;
+	void *pParma;
+} INT_MESSAGE;
+#endif
diff --git a/drivers/crypto/sedriver/wst_se_ktrans.h b/drivers/crypto/sedriver/wst_se_ktrans.h
new file mode 100644
index 000000000000..da6c4b8f2824
--- /dev/null
+++ b/drivers/crypto/sedriver/wst_se_ktrans.h
@@ -0,0 +1,17 @@
+#ifndef _WST_SE_KTRANS_H
+#define _WST_SE_KTRANS_H
+
+#include "wst_se_common_type.h"
+#include "wst_se_define.h"
+
+
+typedef struct tagSWCOMMUDATA {
+	unsigned short usFlags;
+	unsigned short usInputLen;
+	unsigned short usOutputLen;
+	unsigned short usReserve;
+	unsigned char *pucInbuf;
+	unsigned char *pucOutbuf;
+} SWCommuData;
+
+#endif
-- 
2.33.0
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    
                    
                        From: JiangShui Yang <yangjiangshui(a)h-partners.com>
Longfang Liu (9):
  hisi_acc_vfio_pci: fix XQE dma address error
  hisi_acc_vfio_pci: add eq and aeq interruption restore
  hisi_acc_vfio_pci: bugfix cache write-back issue
  hisi_acc_vfio_pci: bugfix the problem of uninstalling driver
  hisi_acc_vfio_pci: bugfix live migration function without VF device
    driver
  hisi_acc_vfio_pci: update function return values.
  migration: update BAR space size
  migration: qm updates BAR configuration
  migration: adapt to new migration configuration
 drivers/crypto/hisilicon/qm.c                 |  29 ++
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 312 +++++++++++++-----
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |  21 +-
 3 files changed, 272 insertions(+), 90 deletions(-)
-- 
2.43.0
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            9
                            
                          
                          
                            
    
                          
                        
                     
                        
                    
                        
                            
                                
                            
                            [PATCH OLK-6.6] regulator: check that dummy regulator has been probed before using it
                        
                        
by Huang Xiaojia 14 Apr '25
                    by Huang Xiaojia 14 Apr '25
14 Apr '25
                    
                        From: Christian Eggers <ceggers(a)arri.de>
stable inclusion
from stable-v6.6.85
commit 998b1aae22dca87da392ea35f089406cbef6032d
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBZH67
CVE: CVE-2025-22008
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit 2c7a50bec4958f1d1c84d19cde518d0e96a676fd upstream.
Due to asynchronous driver probing there is a chance that the dummy
regulator hasn't already been probed when first accessing it.
Cc: stable(a)vger.kernel.org
Signed-off-by: Christian Eggers <ceggers(a)arri.de>
Link: https://patch.msgid.link/20250313103051.32430-3-ceggers@arri.de
Signed-off-by: Mark Brown <broonie(a)kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Huang Xiaojia <huangxiaojia2(a)huawei.com>
---
 drivers/regulator/core.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c96bf095695f..9e435a332057 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2084,6 +2084,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
 
 		if (have_full_constraints()) {
 			r = dummy_regulator_rdev;
+			if (!r) {
+				ret = -EPROBE_DEFER;
+				goto out;
+			}
 			get_device(&r->dev);
 		} else {
 			dev_err(dev, "Failed to resolve %s-supply for %s\n",
@@ -2101,6 +2105,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
 			goto out;
 		}
 		r = dummy_regulator_rdev;
+		if (!r) {
+			ret = -EPROBE_DEFER;
+			goto out;
+		}
 		get_device(&r->dev);
 	}
 
@@ -2209,8 +2217,10 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
 			 * enabled, even if it isn't hooked up, and just
 			 * provide a dummy.
 			 */
-			dev_warn(dev, "supply %s not found, using dummy regulator\n", id);
 			rdev = dummy_regulator_rdev;
+			if (!rdev)
+				return ERR_PTR(-EPROBE_DEFER);
+			dev_warn(dev, "supply %s not found, using dummy regulator\n", id);
 			get_device(&rdev->dev);
 			break;
 
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                     
                        
                    
                        
                            
                                
                            
                            [PATCH OLK-6.6] KVM: arm64: Unconditionally save+flush host FPSIMD/SVE/SME state
                        
                        
by Huang Xiaojia 14 Apr '25
                    by Huang Xiaojia 14 Apr '25
14 Apr '25
                    
                        From: Mark Rutland <mark.rutland(a)arm.com>
stable inclusion
from stable-v6.12.21
commit 79e140bba70bcacc5fe15bf8c0b958793fd7d56f
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBZH7N
CVE: CVE-2025-22013
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit fbc7e61195e23f744814e78524b73b59faa54ab4 ]
There are several problems with the way hyp code lazily saves the host's
FPSIMD/SVE state, including:
* Host SVE being discarded unexpectedly due to inconsistent
  configuration of TIF_SVE and CPACR_ELx.ZEN. This has been seen to
  result in QEMU crashes where SVE is used by memmove(), as reported by
  Eric Auger:
  https://issues.redhat.com/browse/RHEL-68997
* Host SVE state is discarded *after* modification by ptrace, which was an
  unintentional ptrace ABI change introduced with lazy discarding of SVE state.
* The host FPMR value can be discarded when running a non-protected VM,
  where FPMR support is not exposed to a VM, and that VM uses
  FPSIMD/SVE. In these cases the hyp code does not save the host's FPMR
  before unbinding the host's FPSIMD/SVE/SME state, leaving a stale
  value in memory.
Avoid these by eagerly saving and "flushing" the host's FPSIMD/SVE/SME
state when loading a vCPU such that KVM does not need to save any of the
host's FPSIMD/SVE/SME state. For clarity, fpsimd_kvm_prepare() is
removed and the necessary call to fpsimd_save_and_flush_cpu_state() is
placed in kvm_arch_vcpu_load_fp(). As 'fpsimd_state' and 'fpmr_ptr'
should not be used, they are set to NULL; all uses of these will be
removed in subsequent patches.
Historical problems go back at least as far as v5.17, e.g. erroneous
assumptions about TIF_SVE being clear in commit:
  8383741ab2e773a9 ("KVM: arm64: Get rid of host SVE tracking/saving")
... and so this eager save+flush probably needs to be backported to ALL
stable trees.
Fixes: 93ae6b01bafee8fa ("KVM: arm64: Discard any SVE state when entering KVM guests")
Fixes: 8c845e2731041f0f ("arm64/sve: Leave SVE enabled on syscall if we don't context switch")
Fixes: ef3be86021c3bdf3 ("KVM: arm64: Add save/restore support for FPMR")
Reported-by: Eric Auger <eauger(a)redhat.com>
Reported-by: Wilco Dijkstra <wilco.dijkstra(a)arm.com>
Reviewed-by: Mark Brown <broonie(a)kernel.org>
Tested-by: Mark Brown <broonie(a)kernel.org>
Tested-by: Eric Auger <eric.auger(a)redhat.com>
Acked-by: Will Deacon <will(a)kernel.org>
Cc: Catalin Marinas <catalin.marinas(a)arm.com>
Cc: Florian Weimer <fweimer(a)redhat.com>
Cc: Fuad Tabba <tabba(a)google.com>
Cc: Jeremy Linton <jeremy.linton(a)arm.com>
Cc: Marc Zyngier <maz(a)kernel.org>
Cc: Oliver Upton <oliver.upton(a)linux.dev>
Cc: Paolo Bonzini <pbonzini(a)redhat.com>
Signed-off-by: Mark Rutland <mark.rutland(a)arm.com>
Reviewed-by: Oliver Upton <oliver.upton(a)linux.dev>
Link: https://lore.kernel.org/r/20250210195226.1215254-2-mark.rutland@arm.com
Signed-off-by: Marc Zyngier <maz(a)kernel.org>
[ Mark: Handle vcpu/host flag conflict ]
Signed-off-by: Mark Rutland <mark.rutland(a)arm.com>
Signed-off-by: Mark Brown <broonie(a)kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Huang Xiaojia <huangxiaojia2(a)huawei.com>
---
 arch/arm64/kernel/fpsimd.c | 25 -------------------------
 arch/arm64/kvm/fpsimd.c    | 33 +++++++++------------------------
 2 files changed, 9 insertions(+), 49 deletions(-)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 0137d987631e..bd4f6c6ee0f3 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1707,31 +1707,6 @@ void fpsimd_signal_preserve_current_state(void)
 		sve_to_fpsimd(current);
 }
 
-/*
- * Called by KVM when entering the guest.
- */
-void fpsimd_kvm_prepare(void)
-{
-	if (!system_supports_sve())
-		return;
-
-	/*
-	 * KVM does not save host SVE state since we can only enter
-	 * the guest from a syscall so the ABI means that only the
-	 * non-saved SVE state needs to be saved.  If we have left
-	 * SVE enabled for performance reasons then update the task
-	 * state to be FPSIMD only.
-	 */
-	get_cpu_fpsimd_context();
-
-	if (test_and_clear_thread_flag(TIF_SVE)) {
-		sve_to_fpsimd(current);
-		current->thread.fp_type = FP_STATE_FPSIMD;
-	}
-
-	put_cpu_fpsimd_context();
-}
-
 /*
  * Associate current's FPSIMD context with this cpu
  * The caller must have ownership of the cpu FPSIMD context before calling
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 4f51293db173..9c444a277a17 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -77,15 +77,17 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
 	if (!system_supports_fpsimd())
 		return;
 
-	fpsimd_kvm_prepare();
-
 	/*
-	 * We will check TIF_FOREIGN_FPSTATE just before entering the
-	 * guest in kvm_arch_vcpu_ctxflush_fp() and override this to
-	 * FP_STATE_FREE if the flag set.
+	 * Ensure that any host FPSIMD/SVE/SME state is saved and unbound such
+	 * that the host kernel is responsible for restoring this state upon
+	 * return to userspace, and the hyp code doesn't need to save anything.
+	 *
+	 * When the host may use SME, fpsimd_save_and_flush_cpu_state() ensures
+	 * that PSTATE.{SM,ZA} == {0,0}.
 	 */
-	*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
-	*host_data_ptr(fpsimd_state) = kern_hyp_va(¤t->thread.uw.fpsimd_state);
+	fpsimd_save_and_flush_cpu_state();
+	*host_data_ptr(fp_owner) = FP_STATE_FREE;
+	*host_data_ptr(fpsimd_state) = NULL;
 
 	vcpu_clear_flag(vcpu, HOST_SVE_ENABLED);
 	if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN)
@@ -95,23 +97,6 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
 		vcpu_clear_flag(vcpu, HOST_SME_ENABLED);
 		if (read_sysreg(cpacr_el1) & CPACR_EL1_SMEN_EL0EN)
 			vcpu_set_flag(vcpu, HOST_SME_ENABLED);
-
-		/*
-		 * If PSTATE.SM is enabled then save any pending FP
-		 * state and disable PSTATE.SM. If we leave PSTATE.SM
-		 * enabled and the guest does not enable SME via
-		 * CPACR_EL1.SMEN then operations that should be valid
-		 * may generate SME traps from EL1 to EL1 which we
-		 * can't intercept and which would confuse the guest.
-		 *
-		 * Do the same for PSTATE.ZA in the case where there
-		 * is state in the registers which has not already
-		 * been saved, this is very unlikely to happen.
-		 */
-		if (read_sysreg_s(SYS_SVCR) & (SVCR_SM_MASK | SVCR_ZA_MASK)) {
-			*host_data_ptr(fp_owner) = FP_STATE_FREE;
-			fpsimd_save_and_flush_cpu_state();
-		}
 	}
 }
 
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                     
                        
                    
                        
                            
                                
                            
                            [PATCH openEuler-1.0-LTS] tty: synclink_gt: Fix null-pointer-dereference in slgt_clean()
                        
                        
by Cui GaoSheng 14 Apr '25
                    by Cui GaoSheng 14 Apr '25
14 Apr '25
                    
                        From: Zheyu Ma <zheyuma97(a)gmail.com>
stable inclusion
from stable-v4.19.247
commit ba08cbc5b53e151d0acf1930fb526fc65b7f3e65
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBP74I
CVE: CVE-2022-49307
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit 689ca31c542687709ba21ec2195c1fbce34fd029 ]
When the driver fails at alloc_hdlcdev(), and then we remove the driver
module, we will get the following splat:
[   25.065966] general protection fault, probably for non-canonical address 0xdffffc0000000182: 0000 [#1] PREEMPT SMP KASAN PTI
[   25.066914] KASAN: null-ptr-deref in range [0x0000000000000c10-0x0000000000000c17]
[   25.069262] RIP: 0010:detach_hdlc_protocol+0x2a/0x3e0
[   25.077709] Call Trace:
[   25.077924]  <TASK>
[   25.078108]  unregister_hdlc_device+0x16/0x30
[   25.078481]  slgt_cleanup+0x157/0x9f0 [synclink_gt]
Fix this by checking whether the 'info->netdev' is a null pointer first.
Reviewed-by: Jiri Slaby <jirislaby(a)kernel.org>
Signed-off-by: Zheyu Ma <zheyuma97(a)gmail.com>
Link: https://lore.kernel.org/r/20220410114814.3920474-1-zheyuma97@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Cui GaoSheng <cuigaosheng1(a)huawei.com>
---
 drivers/tty/synclink_gt.c | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index b88ecf102764..5d971ae3f5e5 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -1808,6 +1808,8 @@ static int hdlcdev_init(struct slgt_info *info)
  */
 static void hdlcdev_exit(struct slgt_info *info)
 {
+	if (!info->netdev)
+		return;
 	unregister_hdlc_device(info->netdev);
 	free_netdev(info->netdev);
 	info->netdev = NULL;
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    