Kernel
Threads by month
- ----- 2025 -----
- 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
- 53 participants
- 17720 discussions
Patch#1 Allocate VM table and save vpeid in it
Patch#2 avoid sending multi-SGIs in IPIV
Patch#3 Set base address of vm table and targe ITS when vpe schedule and deschedule
Patch#4 Register ipiv exception interrupt
Patch#5 Add interface KVM_CAP_ARM_IPIV_MODE
Patch#6 Probe and configure IPIV capacity on HIP12
Patch#7 Use KABI_EXTEND to perform kabi repair for IPIV
Jinqian Yang (2):
kvm: arm64: avoid sending multi-SGIs in IPIV
kabi: Use KABI_EXTEND to perform kabi repair for IPIV
Xiang Chen (5):
kvm: hisi_virt: Allocate VM table and save vpeid in it
irqchip: gicv3-its: Set base address of vm table and targe ITS when
vpe schedule and deschedule
kvm: hisi_virt: Register ipiv exception interrupt
kvm: arm64: Add interface KVM_CAP_ARM_IPIV_MODE
kvm: hisi_virt: Probe and configure IPIV capacity on HIP12
.../admin-guide/kernel-parameters.txt | 3 +
arch/arm64/include/asm/kvm_host.h | 1 +
arch/arm64/include/asm/sysreg.h | 3 +
arch/arm64/kvm/arm.c | 16 +++
arch/arm64/kvm/hisilicon/hisi_virt.c | 38 ++++++++
arch/arm64/kvm/hisilicon/hisi_virt.h | 11 +++
arch/arm64/kvm/sys_regs.c | 11 +++
arch/arm64/kvm/vgic/vgic-init.c | 44 ++++++++-
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 1 +
drivers/irqchip/irq-gic-v3-its.c | 97 ++++++++++++++++++-
drivers/irqchip/irq-gic-v3.c | 33 +++++++
include/linux/irqchip/arm-gic-v3.h | 24 +++++
include/linux/irqchip/arm-gic-v4.h | 2 +
include/uapi/linux/kvm.h | 2 +
14 files changed, 282 insertions(+), 4 deletions(-)
--
2.33.0
2
8

[PATCH OLK-6.6] perf arm-spe: Add support for SPE Data Source packet on HiSilicon HIP12
by Yushan Wang 14 Apr '25
by Yushan Wang 14 Apr '25
14 Apr '25
From: Yicong Yang <yangyicong(a)hisilicon.com>
driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IC07S9
----------------------------------------------------------------------
Add data source encoding for HiSilicon HIP12 and coresponding mapping
to the perf's memory data source. This will help to synthesize the data
and support upper layer tools like perf-mem and perf-c2c.
Signed-off-by: Yicong Yang <yangyicong(a)hisilicon.com>
Signed-off-by: Yushan Wang <wangyushan12(a)huawei.com>
Signed-off-by: Qizhi Zhang <zhangqizhi3(a)h-partners.com>
---
arch/arm64/include/asm/cputype.h | 2 +
tools/arch/arm64/include/asm/cputype.h | 2 +
.../util/arm-spe-decoder/arm-spe-decoder.h | 17 +++
tools/perf/util/arm-spe.c | 103 ++++++++++++++++++
4 files changed, 124 insertions(+)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 5c1cadeb032d..ae983d335456 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -137,6 +137,7 @@
#define HISI_CPU_PART_TSV110 0xD01
#define HISI_CPU_PART_LINXICORE9100 0xD02
+#define HISI_CPU_PART_HIP12 0xD06
#define APPLE_CPU_PART_M1_ICESTORM 0x022
#define APPLE_CPU_PART_M1_FIRESTORM 0x023
@@ -217,6 +218,7 @@
#define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
#define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
#define MIDR_HISI_LINXICORE9100 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_LINXICORE9100)
+#define MIDR_HISI_HIP12 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP12)
#define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM)
#define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM)
#define MIDR_APPLE_M1_ICESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO)
diff --git a/tools/arch/arm64/include/asm/cputype.h b/tools/arch/arm64/include/asm/cputype.h
index 329d41f8c923..8ade4dc85fcb 100644
--- a/tools/arch/arm64/include/asm/cputype.h
+++ b/tools/arch/arm64/include/asm/cputype.h
@@ -120,6 +120,7 @@
#define FUJITSU_CPU_PART_A64FX 0x001
#define HISI_CPU_PART_TSV110 0xD01
+#define HISI_CPU_PART_HIP12 0xD06
#define APPLE_CPU_PART_M1_ICESTORM 0x022
#define APPLE_CPU_PART_M1_FIRESTORM 0x023
@@ -183,6 +184,7 @@
#define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
#define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
#define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
+#define MIDR_HISI_HIP12 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP12)
#define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM)
#define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM)
#define MIDR_APPLE_M1_ICESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h
index 1443c28545a9..713d778a4fad 100644
--- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h
+++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h
@@ -67,6 +67,23 @@ enum arm_spe_neoverse_data_source {
ARM_SPE_NV_DRAM = 0xe,
};
+enum arm_spe_hisi_hip_data_source {
+ ARM_SPE_HISI_HIP_PEER_CPU = 0,
+ ARM_SPE_HISI_HIP_PEER_CPU_HITM = 1,
+ ARM_SPE_HISI_HIP_L3 = 2,
+ ARM_SPE_HISI_HIP_L3_HITM = 3,
+ ARM_SPE_HISI_HIP_PEER_CLUSTER = 4,
+ ARM_SPE_HISI_HIP_PEER_CLUSTER_HITM = 5,
+ ARM_SPE_HISI_HIP_REMOTE_SOCKET = 6,
+ ARM_SPE_HISI_HIP_REMOTE_SOCKET_HITM = 7,
+ ARM_SPE_HISI_HIP_LOCAL = 8,
+ ARM_SPE_HISI_HIP_REMOTE = 9,
+ ARM_SPE_HISI_HIP_NC_DEV = 13,
+ ARM_SPE_HISI_HIP_L2 = 16,
+ ARM_SPE_HISI_HIP_L2_HITM = 17,
+ ARM_SPE_HISI_HIP_L1 = 18,
+};
+
struct arm_spe_record {
enum arm_spe_sample_type type;
int err;
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
index afbd5869f6bf..dbc437532fb7 100644
--- a/tools/perf/util/arm-spe.c
+++ b/tools/perf/util/arm-spe.c
@@ -416,6 +416,11 @@ static const struct midr_range neoverse_spe[] = {
{},
};
+static const struct midr_range hisi_hip_ds_encoding_cpus[] = {
+ MIDR_ALL_VERSIONS(MIDR_HISI_HIP12),
+ {},
+};
+
static void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *record,
union perf_mem_data_src *data_src)
{
@@ -515,10 +520,106 @@ static void arm_spe__synth_data_source_generic(const struct arm_spe_record *reco
data_src->mem_lvl |= PERF_MEM_LVL_REM_CCE1;
}
+static void arm_spe__synth_data_source_hisi_hip(const struct arm_spe_record *record,
+ union perf_mem_data_src *data_src)
+{
+ /* Use common synthesis method to handle store operations */
+ if (record->op & ARM_SPE_OP_ST) {
+ arm_spe__synth_data_source_generic(record, data_src);
+ return;
+ }
+
+ switch (record->source) {
+ case ARM_SPE_HISI_HIP_PEER_CPU:
+ data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_PEER_CPU_HITM:
+ data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
+ data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_L3:
+ data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ break;
+ case ARM_SPE_HISI_HIP_L3_HITM:
+ data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
+ data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_PEER_CLUSTER:
+ data_src->mem_lvl = PERF_MEM_LVL_REM_CCE1 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_PEER_CLUSTER_HITM:
+ data_src->mem_lvl = PERF_MEM_LVL_REM_CCE1 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
+ data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_REMOTE_SOCKET:
+ data_src->mem_lvl = PERF_MEM_LVL_REM_CCE2;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_ANY_CACHE;
+ data_src->mem_remote = PERF_MEM_REMOTE_REMOTE;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_REMOTE_SOCKET_HITM:
+ data_src->mem_lvl = PERF_MEM_LVL_REM_CCE2;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_ANY_CACHE;
+ data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
+ data_src->mem_remote = PERF_MEM_REMOTE_REMOTE;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_LOCAL:
+ data_src->mem_lvl = PERF_MEM_LVL_LOC_RAM | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_RAM;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ break;
+ case ARM_SPE_HISI_HIP_REMOTE:
+ data_src->mem_lvl = PERF_MEM_LVL_REM_RAM1 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_RAM;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ data_src->mem_remote = PERF_MEM_REMOTE_REMOTE;
+ break;
+ case ARM_SPE_HISI_HIP_NC_DEV:
+ data_src->mem_lvl = PERF_MEM_LVL_IO | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_IO;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ break;
+ case ARM_SPE_HISI_HIP_L2:
+ data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ break;
+ case ARM_SPE_HISI_HIP_L2_HITM:
+ data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2;
+ data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
+ data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
+ break;
+ case ARM_SPE_HISI_HIP_L1:
+ data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
+ data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1;
+ data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
+ break;
+ default:
+ break;
+ }
+}
+
static u64 arm_spe__synth_data_source(const struct arm_spe_record *record, u64 midr)
{
union perf_mem_data_src data_src = { .mem_op = PERF_MEM_OP_NA };
bool is_neoverse = is_midr_in_range_list(midr, neoverse_spe);
+ bool is_hisilicon = is_midr_in_range_list(midr, hisi_hip_ds_encoding_cpus);
if (record->op & ARM_SPE_OP_LD)
data_src.mem_op = PERF_MEM_OP_LOAD;
@@ -529,6 +630,8 @@ static u64 arm_spe__synth_data_source(const struct arm_spe_record *record, u64 m
if (is_neoverse)
arm_spe__synth_data_source_neoverse(record, &data_src);
+ else if (is_hisilicon)
+ arm_spe__synth_data_source_hisi_hip(record, &data_src);
else
arm_spe__synth_data_source_generic(record, &data_src);
--
2.33.0
2
1
From: Qinxin Xia <xiaqinxin(a)huawei.com>
driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IC0ZB4
----------------------------------------------------------------------
This patch introduce optprobe for ARM64. In optprobe, probed
instruction is replaced by a branch instruction to trampoline.
Performance of optprobe on Hip08 platform is test using kprobe
example module to analyze the latency of a kernel function,
and here is the result:
common kprobe:
[280709.846380] do_empty returned 0 and took 1530 ns to execute
[280709.852057] do_empty returned 0 and took 550 ns to execute
[280709.857631] do_empty returned 0 and took 440 ns to execute
[280709.863215] do_empty returned 0 and took 380 ns to execute
[280709.868787] do_empty returned 0 and took 360 ns to execute
[280709.874362] do_empty returned 0 and took 340 ns to execute
[280709.879936] do_empty returned 0 and took 320 ns to execute
[280709.885505] do_empty returned 0 and took 300 ns to execute
[280709.891075] do_empty returned 0 and took 280 ns to execute
[280709.896646] do_empty returned 0 and took 290 ns to execute
optprobe:
[ 2965.964572] do_empty returned 0 and took 90 ns to execute
[ 2965.969952] do_empty returned 0 and took 80 ns to execute
[ 2965.975332] do_empty returned 0 and took 70 ns to execute
[ 2965.980714] do_empty returned 0 and took 60 ns to execute
[ 2965.986128] do_empty returned 0 and took 80 ns to execute
[ 2965.991507] do_empty returned 0 and took 70 ns to execute
[ 2965.996884] do_empty returned 0 and took 70 ns to execute
[ 2966.002262] do_empty returned 0 and took 80 ns to execute
[ 2966.007642] do_empty returned 0 and took 70 ns to execute
[ 2966.013020] do_empty returned 0 and took 70 ns to execute
[ 2966.018400] do_empty returned 0 and took 70 ns to execute
As the result shows, optprobe can greatly reduce the latency. Big
latency of common kprobe will significantly impact the real result
while doing performance analysis or debugging performance issues
in lab, so optprobe is useful in this scenario.
The trampoline design is illustrated in the following diagram.
Some commands will be replaced in arch_prepare_optimized_kprobe.
+------------------optprobe_template_entry---------------------+
|- Saving stacks and registers |
|- Loading params for callback |
+------------------optprobe_template_common--------------------+
|- nop |
|(replaced to the branch jump to optprobe_common) |
|- Restore stacks and registers |
+-------------optprobe_template_restore_orig_insn--------------+
|- nop |
|(replaced to the kprobe->opcode) |
+----------------optprobe_template_restore_end-----------------+
|- nop |
|(replaced to next address of the probe point) |
+------------------optprobe_template_val-----------------------+
|- 0 (two 32-bit words) |
|(replaced to params for optprobe_optimized_callback) |
+-----------------optprobe_template_orig_addr------------------+
|- 0 (two 32-bit words) |
|(replaced to origin probe point address) |
+-------------------optprobe_template_end----------------------+
|- nop |
+--------------------------------------------------------------+
Co-developed-by: Qi Liu <liuqi115(a)huawei.com>
Signed-off-by: Qi Liu <liuqi115(a)huawei.com>
Signed-off-by: Qinxin Xia <xiaqinxin(a)huawei.com>
Signed-off-by: Qizhi Zhang <zhangqizhi3(a)h-partners.com>
Signed-off-by: Yushan Wang <wangyushan12(a)huawei.com>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/kprobes.h | 22 ++
arch/arm64/kernel/probes/Makefile | 2 +
arch/arm64/kernel/probes/opt_arm64.c | 243 ++++++++++++++++++
.../arm64/kernel/probes/optprobe_trampoline.S | 113 ++++++++
5 files changed, 381 insertions(+)
create mode 100644 arch/arm64/kernel/probes/opt_arm64.c
create mode 100644 arch/arm64/kernel/probes/optprobe_trampoline.S
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9da9d58f1c02..194051628457 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -240,6 +240,7 @@ config ARM64
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_KPROBES
select HAVE_KRETPROBES
+ select HAVE_OPTPROBES
select HAVE_GENERIC_VDSO
select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
select HOTPLUG_SMT if (SMP && HOTPLUG_CPU)
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
index 05cd82eeca13..e4972645a381 100644
--- a/arch/arm64/include/asm/kprobes.h
+++ b/arch/arm64/include/asm/kprobes.h
@@ -39,6 +39,28 @@ void arch_remove_kprobe(struct kprobe *);
int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
+
+struct arch_optimized_insn {
+ kprobe_opcode_t orig_insn[1];
+ kprobe_opcode_t *trampoline;
+};
+
+#define MAX_OPTIMIZED_LENGTH sizeof(kprobe_opcode_t)
+#define MAX_OPTINSN_SIZE \
+ ((unsigned long)optprobe_template_end - (unsigned long)optprobe_template_entry)
+
+extern __visible kprobe_opcode_t optprobe_template_entry[];
+extern __visible kprobe_opcode_t optprobe_template_val[];
+extern __visible kprobe_opcode_t optprobe_template_orig_addr[];
+extern __visible kprobe_opcode_t optprobe_template_common[];
+extern __visible kprobe_opcode_t optprobe_template_end[];
+extern __visible kprobe_opcode_t optprobe_template_restore_begin[];
+extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn[];
+extern __visible kprobe_opcode_t optprobe_template_restore_end[];
+extern __visible kprobe_opcode_t optinsn_slot[];
+
+void optprobe_common(void);
+
void __kretprobe_trampoline(void);
void __kprobes *trampoline_probe_handler(struct pt_regs *regs);
diff --git a/arch/arm64/kernel/probes/Makefile b/arch/arm64/kernel/probes/Makefile
index 8e4be92e25b1..7b2885b23ff6 100644
--- a/arch/arm64/kernel/probes/Makefile
+++ b/arch/arm64/kernel/probes/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o \
simulate-insn.o
obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o \
simulate-insn.o
+obj-$(CONFIG_OPTPROBES) += opt_arm64.o \
+ optprobe_trampoline.o
diff --git a/arch/arm64/kernel/probes/opt_arm64.c b/arch/arm64/kernel/probes/opt_arm64.c
new file mode 100644
index 000000000000..976ab264350d
--- /dev/null
+++ b/arch/arm64/kernel/probes/opt_arm64.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Code for Kernel probes Jump optimization.
+ *
+ * Copyright (C) 2025 HiSilicon Limited
+ */
+
+#include <linux/jump_label.h>
+#include <linux/kprobes.h>
+
+#include <asm/cacheflush.h>
+#include <asm/compiler.h>
+#include <asm/insn.h>
+#include <asm/kprobes.h>
+#include <asm/patching.h>
+
+#define OPTPROBE_BATCH_SIZE 64
+
+#define TMPL_VAL_IDX \
+ (optprobe_template_val - optprobe_template_entry)
+#define TMPL_ORIGN_ADDR \
+ (optprobe_template_orig_addr - optprobe_template_entry)
+#define TMPL_CALL_COMMON \
+ (optprobe_template_common - optprobe_template_entry)
+#define TMPL_RESTORE_ORIGN_INSN \
+ (optprobe_template_restore_orig_insn - optprobe_template_entry)
+#define TMPL_RESTORE_END \
+ (optprobe_template_restore_end - optprobe_template_entry)
+
+#define OPT_SLOT_SIZE 65536
+#define OPT_INSN_PAGES (OPT_SLOT_SIZE / PAGE_SIZE)
+
+static bool insn_page_in_use[OPT_INSN_PAGES];
+
+void *alloc_optinsn_page(void)
+{
+ int i;
+
+ for (i = 0; i < OPT_INSN_PAGES; i++) {
+ if (!insn_page_in_use[i]) {
+ insn_page_in_use[i] = true;
+ return (void *)((unsigned long)optinsn_slot + PAGE_SIZE * i);
+ }
+ }
+
+ return NULL;
+}
+
+void free_optinsn_page(void *page)
+{
+ unsigned long idx = (unsigned long)page - (unsigned long)optinsn_slot;
+
+ WARN_ONCE(idx & (PAGE_SIZE - 1), "Invalid idx with wrong align\n");
+ idx >>= PAGE_SHIFT;
+ if (WARN_ONCE(idx >= OPT_INSN_PAGES, "Invalid idx with wrong size\n"))
+ return;
+ insn_page_in_use[idx] = false;
+}
+
+/*
+ * In ARM ISA, kprobe opt always replace one instruction (4 bytes
+ * aligned and 4 bytes long). It is impossible to encounter another
+ * kprobe in the address range. So always return 0.
+ */
+int arch_check_optimized_kprobe(struct optimized_kprobe *op)
+{
+ return 0;
+}
+
+int arch_prepared_optinsn(struct arch_optimized_insn *optinsn)
+{
+ return optinsn->trampoline != NULL;
+}
+
+int arch_within_optimized_kprobe(struct optimized_kprobe *op, kprobe_opcode_t *addr)
+{
+ return op->kp.addr == addr;
+}
+
+static int optprobe_check_branch_limit(unsigned long pc, unsigned long addr)
+{
+ long offset;
+
+ if ((pc & 0x3) || (addr & 0x3))
+ return -ERANGE;
+
+ offset = (long)addr - (long)pc;
+ if (offset < -SZ_128M || offset >= SZ_128M)
+ return -ERANGE;
+
+ return 0;
+}
+
+int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig)
+{
+ kprobe_opcode_t *code, *buf;
+ int ret = -ENOMEM;
+ u32 insn;
+ int i;
+
+ buf = kzalloc(MAX_OPTINSN_SIZE, GFP_KERNEL);
+ if (!buf)
+ return ret;
+
+ code = get_optinsn_slot();
+ if (!code)
+ goto out;
+
+ if (optprobe_check_branch_limit((unsigned long)code, (unsigned long)orig->addr + 8)) {
+ ret = -ERANGE;
+ goto error;
+ }
+
+ memcpy(buf, optprobe_template_entry, MAX_OPTINSN_SIZE);
+
+ insn = aarch64_insn_gen_branch_imm((unsigned long)&code[TMPL_CALL_COMMON],
+ (unsigned long)&optprobe_common,
+ AARCH64_INSN_BRANCH_LINK);
+ if (insn == AARCH64_BREAK_FAULT) {
+ ret = -ERANGE;
+ goto error;
+ }
+
+ buf[TMPL_CALL_COMMON] = insn;
+
+ insn = aarch64_insn_gen_branch_imm((unsigned long)&code[TMPL_RESTORE_END],
+ (unsigned long)(op->kp.addr + 1),
+ AARCH64_INSN_BRANCH_NOLINK);
+ if (insn == AARCH64_BREAK_FAULT) {
+ ret = -ERANGE;
+ goto error;
+ }
+
+ buf[TMPL_RESTORE_END] = insn;
+
+ buf[TMPL_VAL_IDX] = cpu_to_le32(lower_32_bits((unsigned long)op));
+ buf[TMPL_VAL_IDX + 1] = cpu_to_le32(upper_32_bits((unsigned long)op));
+ buf[TMPL_ORIGN_ADDR] = cpu_to_le32(lower_32_bits((unsigned long)orig->addr));
+ buf[TMPL_ORIGN_ADDR + 1] = cpu_to_le32(upper_32_bits((unsigned long)orig->addr));
+
+ buf[TMPL_RESTORE_ORIGN_INSN] = orig->opcode;
+
+ /* Setup template */
+ for (i = 0; i < MAX_OPTINSN_SIZE / MAX_OPTIMIZED_LENGTH; i++)
+ aarch64_insn_patch_text_nosync(code + i, buf[i]);
+
+ flush_icache_range((unsigned long)code, (unsigned long)(&code[TMPL_VAL_IDX]));
+ /* Set op->optinsn.trampoline means prepared. */
+ op->optinsn.trampoline = code;
+
+ return 0;
+error:
+ free_optinsn_slot(code, 0);
+
+out:
+ kfree(buf);
+ return ret;
+}
+
+void arch_optimize_kprobes(struct list_head *oplist)
+{
+ struct optimized_kprobe *op, *tmp;
+ kprobe_opcode_t insns[OPTPROBE_BATCH_SIZE];
+ void *addrs[OPTPROBE_BATCH_SIZE];
+ int i = 0;
+
+ list_for_each_entry_safe(op, tmp, oplist, list) {
+ WARN_ON(kprobe_disabled(&op->kp));
+
+ /*
+ * Backup instructions which will be replaced
+ * by jump address
+ */
+ memcpy(op->optinsn.orig_insn, op->kp.addr, AARCH64_INSN_SIZE);
+
+ addrs[i] = op->kp.addr;
+ insns[i] = aarch64_insn_gen_branch_imm((unsigned long)op->kp.addr,
+ (unsigned long)op->optinsn.trampoline,
+ AARCH64_INSN_BRANCH_NOLINK);
+
+ list_del_init(&op->list);
+ if (++i == OPTPROBE_BATCH_SIZE)
+ break;
+ }
+
+ aarch64_insn_patch_text(addrs, insns, i);
+}
+
+void arch_unoptimize_kprobe(struct optimized_kprobe *op)
+{
+ arch_arm_kprobe(&op->kp);
+}
+
+/*
+ * Recover original instructions and breakpoints from relative jumps.
+ * Caller must call with locking kprobe_mutex.
+ */
+void arch_unoptimize_kprobes(struct list_head *oplist,
+ struct list_head *done_list)
+{
+ struct optimized_kprobe *op, *tmp;
+ kprobe_opcode_t insns[OPTPROBE_BATCH_SIZE];
+ void *addrs[OPTPROBE_BATCH_SIZE];
+ int i = 0;
+
+ list_for_each_entry_safe(op, tmp, oplist, list) {
+ addrs[i] = op->kp.addr;
+ insns[i] = BRK64_OPCODE_KPROBES;
+ list_move(&op->list, done_list);
+
+ if (++i == OPTPROBE_BATCH_SIZE)
+ break;
+ }
+
+ aarch64_insn_patch_text(addrs, insns, i);
+}
+
+void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
+{
+ if (op->optinsn.trampoline) {
+ free_optinsn_slot(op->optinsn.trampoline, 1);
+ op->optinsn.trampoline = NULL;
+ }
+
+}
+
+void optprobe_optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
+{
+ if (kprobe_disabled(&op->kp))
+ return;
+
+ guard(preempt)();
+
+ if (kprobe_running()) {
+ kprobes_inc_nmissed_count(&op->kp);
+ } else {
+ __this_cpu_write(current_kprobe, &op->kp);
+ get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
+ opt_pre_handler(&op->kp, regs);
+ __this_cpu_write(current_kprobe, NULL);
+ }
+}
+NOKPROBE_SYMBOL(optprobe_optimized_callback)
diff --git a/arch/arm64/kernel/probes/optprobe_trampoline.S b/arch/arm64/kernel/probes/optprobe_trampoline.S
new file mode 100644
index 000000000000..d08f39c5d8c5
--- /dev/null
+++ b/arch/arm64/kernel/probes/optprobe_trampoline.S
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * trampoline entry and return code for optprobes.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/assembler.h>
+
+#define OPT_SLOT_SIZE 65536
+
+ .global optinsn_slot
+optinsn_slot:
+ .space OPT_SLOT_SIZE
+
+SYM_CODE_START(optprobe_common)
+ stp x2, x3, [sp, #S_X2]
+ stp x4, x5, [sp, #S_X4]
+ stp x6, x7, [sp, #S_X6]
+ stp x8, x9, [sp, #S_X8]
+ stp x10, x11, [sp, #S_X10]
+ stp x12, x13, [sp, #S_X12]
+ stp x14, x15, [sp, #S_X14]
+ stp x16, x17, [sp, #S_X16]
+ stp x18, x19, [sp, #S_X18]
+ stp x20, x21, [sp, #S_X20]
+ stp x22, x23, [sp, #S_X22]
+ stp x24, x25, [sp, #S_X24]
+ stp x26, x27, [sp, #S_X26]
+ stp x28, x29, [sp, #S_X28]
+ add x2, sp, #PT_REGS_SIZE
+ str x2, [sp, #S_SP]
+ /* Construct a useful saved PSTATE */
+ mrs x2, nzcv
+ mrs x3, daif
+ orr x2, x2, x3
+ mrs x3, CurrentEL
+ orr x2, x2, x3
+ mrs x3, SPSel
+ orr x2, x2, x3
+ stp x1, x2, [sp, #S_PC]
+
+ /* set the pt_regs address to x1 */
+ mov x1, sp
+ /* store lr of optprobe_common temporary */
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ bl optprobe_optimized_callback
+
+ ldp x29, x30, [sp], #16
+
+ ldr x0, [sp, #S_PSTATE]
+ and x0, x0, #(PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT)
+ msr nzcv, x0
+
+ ldp x0, x1, [sp, #S_X0]
+ ldp x2, x3, [sp, #S_X2]
+ ldp x4, x5, [sp, #S_X4]
+ ldp x6, x7, [sp, #S_X6]
+ ldp x8, x9, [sp, #S_X8]
+ ldp x10, x11, [sp, #S_X10]
+ ldp x12, x13, [sp, #S_X12]
+ ldp x14, x15, [sp, #S_X14]
+ ldp x16, x17, [sp, #S_X16]
+ ldp x18, x19, [sp, #S_X18]
+ ldp x20, x21, [sp, #S_X20]
+ ldp x22, x23, [sp, #S_X22]
+ ldp x24, x25, [sp, #S_X24]
+ ldp x26, x27, [sp, #S_X26]
+ ldp x28, x29, [sp, #S_X28]
+ ret
+SYM_CODE_END(optprobe_common)
+
+ .global optprobe_template_entry
+optprobe_template_entry:
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+ ldr x30, 2f
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+ sub sp, sp, #PT_REGS_SIZE
+ str lr, [sp, #S_LR]
+ stp x0, x1, [sp, #S_X0]
+ /* Get parameters to optimized_callback() */
+ ldr x0, 1f
+ ldr x1, 2f
+ .global optprobe_template_common
+optprobe_template_common:
+ nop
+ ldr lr, [sp, #S_LR]
+ add sp, sp, #PT_REGS_SIZE
+ ldp x29, x30, [sp], #16
+ ldp x29, x30, [sp], #16
+ .global optprobe_template_restore_orig_insn
+optprobe_template_restore_orig_insn:
+ nop
+ .global optprobe_template_restore_end
+optprobe_template_restore_end:
+ nop
+ .balign
+ .global optprobe_template_val
+optprobe_template_val:
+ 1: .long 0
+ .long 0
+ .balign
+ .global optprobe_template_orig_addr
+optprobe_template_orig_addr:
+ 2: .long 0
+ .long 0
+ .global optprobe_template_end
+optprobe_template_end:
+ nop
--
2.33.0
2
1
*** BLURB HERE ***
Mark Rutland (1):
KVM: arm64: Unconditionally save+flush host FPSIMD/SVE/SME state
Yue Haibing (1):
arm64/fpsimd: Remove unused declaration fpsimd_kvm_prepare()
arch/arm64/include/asm/fpsimd.h | 1 -
arch/arm64/kernel/fpsimd.c | 25 -------------------------
arch/arm64/kvm/fpsimd.c | 33 +++++++++------------------------
3 files changed, 9 insertions(+), 50 deletions(-)
--
2.34.1
2
3

[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