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
April 2025
- 53 participants
- 274 discussions
driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IC15TR
----------------------------------------------------------------------
This series adds support for HiSilicon SoC cache lockdown and cache
maintenance operations.
Cache lockdown feature prevents cache entries from being evicted from L3
cache. It can be enabled by calling mmap function to the file
(`/dev/hisi_soc_cache_mgmt`). This feature is implemented in the driver
hisi_soc_l3c.
Cache maintenance feature, following Arm64's CHI spec[1], enables users
to raise certain transactions to the memory residing in the cache. This
can be achieved by calling ioctl function to the same file as above.
This feature is implemented in the driver hisi_soc_hha.
L3 cache and L3 cache PMU share the same memory resource, which makes
one fails to probe while another is on board. Since both devices
rely on distinct information exported by ACPI, their probing functions
should be unrelated. Workaround the resource conflict check by
replacing devm_ioremap_resource() to devm_ioremap() instead.
[1] https://developer.arm.com/documentation/ihi0050/latest/
Yushan Wang (2):
soc cache: Add framework driver for HiSilicon SoC cache
soc cache: Support cache maintenance for HiSilicon SoC Hydra Home
Agent
drivers/soc/hisilicon/Kconfig | 22 +
drivers/soc/hisilicon/Makefile | 3 +
.../soc/hisilicon/hisi_soc_cache_framework.c | 381 ++++++++++++++++++
.../soc/hisilicon/hisi_soc_cache_framework.h | 77 ++++
drivers/soc/hisilicon/hisi_soc_hha.c | 188 +++++++++
.../uapi/misc/hisi_soc_cache/hisi_soc_cache.h | 35 ++
6 files changed, 706 insertions(+)
create mode 100644 drivers/soc/hisilicon/hisi_soc_cache_framework.c
create mode 100644 drivers/soc/hisilicon/hisi_soc_cache_framework.h
create mode 100644 drivers/soc/hisilicon/hisi_soc_hha.c
create mode 100644 include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h
--
2.33.0
1
2
From: Zhu Yanjun <yanjun.zhu(a)linux.dev>
mainline inclusion
from mainline-v6.13-rc6
commit 2ac5415022d16d63d912a39a06f32f1f51140261
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBID2B
CVE: CVE-2024-57795
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
-------------------------------------------------
The similar patch in siw is in the link:
https://git.kernel.org/rdma/rdma/c/16b87037b48889
This problem also occurred in RXE. The following analyze this problem.
In the following Call Traces:
"
BUG: KASAN: slab-use-after-free in dev_get_flags+0x188/0x1d0 net/core/dev.c:8782
Read of size 4 at addr ffff8880554640b0 by task kworker/1:4/5295
CPU: 1 UID: 0 PID: 5295 Comm: kworker/1:4 Not tainted
6.12.0-rc3-syzkaller-00399-g9197b73fd7bb #0
Hardware name: Google Compute Engine/Google Compute Engine,
BIOS Google 09/13/2024
Workqueue: infiniband ib_cache_event_task
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:377 [inline]
print_report+0x169/0x550 mm/kasan/report.c:488
kasan_report+0x143/0x180 mm/kasan/report.c:601
dev_get_flags+0x188/0x1d0 net/core/dev.c:8782
rxe_query_port+0x12d/0x260 drivers/infiniband/sw/rxe/rxe_verbs.c:60
__ib_query_port drivers/infiniband/core/device.c:2111 [inline]
ib_query_port+0x168/0x7d0 drivers/infiniband/core/device.c:2143
ib_cache_update+0x1a9/0xb80 drivers/infiniband/core/cache.c:1494
ib_cache_event_task+0xf3/0x1e0 drivers/infiniband/core/cache.c:1568
process_one_work kernel/workqueue.c:3229 [inline]
process_scheduled_works+0xa65/0x1850 kernel/workqueue.c:3310
worker_thread+0x870/0xd30 kernel/workqueue.c:3391
kthread+0x2f2/0x390 kernel/kthread.c:389
ret_from_fork+0x4d/0x80 arch/x86/kernel/process.c:147
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
</TASK>
"
1). In the link [1],
"
infiniband syz2: set down
"
This means that on 839.350575, the event ib_cache_event_task was sent andi
queued in ib_wq.
2). In the link [1],
"
team0 (unregistering): Port device team_slave_0 removed
"
It indicates that before 843.251853, the net device should be freed.
3). In the link [1],
"
BUG: KASAN: slab-use-after-free in dev_get_flags+0x188/0x1d0
"
This means that on 850.559070, this slab-use-after-free problem occurred.
In all, on 839.350575, the event ib_cache_event_task was sent and queued
in ib_wq,
before 843.251853, the net device veth was freed.
on 850.559070, this event was executed, and the mentioned freed net device
was called. Thus, the above call trace occurred.
[1] https://syzkaller.appspot.com/x/log.txt?x=12e7025f980000
Reported-by: syzbot+4b87489410b4efd181bf(a)syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4b87489410b4efd181bf
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Signed-off-by: Zhu Yanjun <yanjun.zhu(a)linux.dev>
Link: https://patch.msgid.link/20241220222325.2487767-1-yanjun.zhu@linux.dev
Signed-off-by: Leon Romanovsky <leon(a)kernel.org>
Conflicts:
drivers/infiniband/sw/rxe/rxe_net.c
[Did not backport af48f95492dc.]
Signed-off-by: Liu Jian <liujian56(a)huawei.com>
---
drivers/infiniband/sw/rxe/rxe.c | 23 +++++++++++++++++++----
drivers/infiniband/sw/rxe/rxe.h | 3 ++-
drivers/infiniband/sw/rxe/rxe_mcast.c | 22 ++++++++++++++++++++--
drivers/infiniband/sw/rxe/rxe_net.c | 25 ++++++++++++++++++++-----
drivers/infiniband/sw/rxe/rxe_verbs.c | 26 +++++++++++++++++++++-----
drivers/infiniband/sw/rxe/rxe_verbs.h | 11 ++++++++---
6 files changed, 90 insertions(+), 20 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c
index 0f8356cea293..1fb4fa4514bf 100644
--- a/drivers/infiniband/sw/rxe/rxe.c
+++ b/drivers/infiniband/sw/rxe/rxe.c
@@ -40,6 +40,8 @@ void rxe_dealloc(struct ib_device *ib_dev)
/* initialize rxe device parameters */
static void rxe_init_device_param(struct rxe_dev *rxe)
{
+ struct net_device *ndev;
+
rxe->max_inline_data = RXE_MAX_INLINE_DATA;
rxe->attr.vendor_id = RXE_VENDOR_ID;
@@ -71,8 +73,15 @@ static void rxe_init_device_param(struct rxe_dev *rxe)
rxe->attr.max_fast_reg_page_list_len = RXE_MAX_FMR_PAGE_LIST_LEN;
rxe->attr.max_pkeys = RXE_MAX_PKEYS;
rxe->attr.local_ca_ack_delay = RXE_LOCAL_CA_ACK_DELAY;
+
+ ndev = rxe_ib_device_get_netdev(&rxe->ib_dev);
+ if (!ndev)
+ return;
+
addrconf_addr_eui48((unsigned char *)&rxe->attr.sys_image_guid,
- rxe->ndev->dev_addr);
+ ndev->dev_addr);
+
+ dev_put(ndev);
rxe->max_ucontext = RXE_MAX_UCONTEXT;
}
@@ -109,10 +118,15 @@ static void rxe_init_port_param(struct rxe_port *port)
static void rxe_init_ports(struct rxe_dev *rxe)
{
struct rxe_port *port = &rxe->port;
+ struct net_device *ndev;
rxe_init_port_param(port);
+ ndev = rxe_ib_device_get_netdev(&rxe->ib_dev);
+ if (!ndev)
+ return;
addrconf_addr_eui48((unsigned char *)&port->port_guid,
- rxe->ndev->dev_addr);
+ ndev->dev_addr);
+ dev_put(ndev);
spin_lock_init(&port->port_lock);
}
@@ -169,12 +183,13 @@ void rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu)
/* called by ifc layer to create new rxe device.
* The caller should allocate memory for rxe by calling ib_alloc_device.
*/
-int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name)
+int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name,
+ struct net_device *ndev)
{
rxe_init(rxe);
rxe_set_mtu(rxe, mtu);
- return rxe_register_device(rxe, ibdev_name);
+ return rxe_register_device(rxe, ibdev_name, ndev);
}
static int rxe_newlink(const char *ibdev_name, struct net_device *ndev)
diff --git a/drivers/infiniband/sw/rxe/rxe.h b/drivers/infiniband/sw/rxe/rxe.h
index d8fb2c7af30a..fe7f97066732 100644
--- a/drivers/infiniband/sw/rxe/rxe.h
+++ b/drivers/infiniband/sw/rxe/rxe.h
@@ -139,7 +139,8 @@ enum resp_states {
void rxe_set_mtu(struct rxe_dev *rxe, unsigned int dev_mtu);
-int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name);
+int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name,
+ struct net_device *ndev);
void rxe_rcv(struct sk_buff *skb);
diff --git a/drivers/infiniband/sw/rxe/rxe_mcast.c b/drivers/infiniband/sw/rxe/rxe_mcast.c
index 86cc2e18a7fd..07ff47bae31d 100644
--- a/drivers/infiniband/sw/rxe/rxe_mcast.c
+++ b/drivers/infiniband/sw/rxe/rxe_mcast.c
@@ -31,10 +31,19 @@
static int rxe_mcast_add(struct rxe_dev *rxe, union ib_gid *mgid)
{
unsigned char ll_addr[ETH_ALEN];
+ struct net_device *ndev;
+ int ret;
+
+ ndev = rxe_ib_device_get_netdev(&rxe->ib_dev);
+ if (!ndev)
+ return -ENODEV;
ipv6_eth_mc_map((struct in6_addr *)mgid->raw, ll_addr);
- return dev_mc_add(rxe->ndev, ll_addr);
+ ret = dev_mc_add(ndev, ll_addr);
+ dev_put(ndev);
+
+ return ret;
}
/**
@@ -47,10 +56,19 @@ static int rxe_mcast_add(struct rxe_dev *rxe, union ib_gid *mgid)
static int rxe_mcast_del(struct rxe_dev *rxe, union ib_gid *mgid)
{
unsigned char ll_addr[ETH_ALEN];
+ struct net_device *ndev;
+ int ret;
+
+ ndev = rxe_ib_device_get_netdev(&rxe->ib_dev);
+ if (!ndev)
+ return -ENODEV;
ipv6_eth_mc_map((struct in6_addr *)mgid->raw, ll_addr);
- return dev_mc_del(rxe->ndev, ll_addr);
+ ret = dev_mc_del(ndev, ll_addr);
+ dev_put(ndev);
+
+ return ret;
}
/**
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c
index e5827064ab1e..e2859bbc9a71 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.c
+++ b/drivers/infiniband/sw/rxe/rxe_net.c
@@ -509,7 +509,16 @@ struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av,
*/
const char *rxe_parent_name(struct rxe_dev *rxe, unsigned int port_num)
{
- return rxe->ndev->name;
+ struct net_device *ndev;
+ char *ndev_name;
+
+ ndev = rxe_ib_device_get_netdev(&rxe->ib_dev);
+ if (!ndev)
+ return NULL;
+ ndev_name = ndev->name;
+ dev_put(ndev);
+
+ return ndev_name;
}
int rxe_net_add(const char *ibdev_name, struct net_device *ndev)
@@ -521,9 +530,7 @@ int rxe_net_add(const char *ibdev_name, struct net_device *ndev)
if (!rxe)
return -ENOMEM;
- rxe->ndev = ndev;
-
- err = rxe_add(rxe, ndev->mtu, ibdev_name);
+ err = rxe_add(rxe, ndev->mtu, ibdev_name, ndev);
if (err) {
ib_dealloc_device(&rxe->ib_dev);
return err;
@@ -571,10 +578,18 @@ void rxe_port_down(struct rxe_dev *rxe)
void rxe_set_port_state(struct rxe_dev *rxe)
{
- if (netif_running(rxe->ndev) && netif_carrier_ok(rxe->ndev))
+ struct net_device *ndev;
+
+ ndev = rxe_ib_device_get_netdev(&rxe->ib_dev);
+ if (!ndev)
+ return;
+
+ if (netif_running(ndev) && netif_carrier_ok(ndev))
rxe_port_up(rxe);
else
rxe_port_down(rxe);
+
+ dev_put(ndev);
}
static int rxe_notify(struct notifier_block *not_blk,
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index dbb9baa4ffd0..c4726f894fc2 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -41,6 +41,7 @@ static int rxe_query_port(struct ib_device *ibdev,
u32 port_num, struct ib_port_attr *attr)
{
struct rxe_dev *rxe = to_rdev(ibdev);
+ struct net_device *ndev;
int err, ret;
if (port_num != 1) {
@@ -49,6 +50,12 @@ static int rxe_query_port(struct ib_device *ibdev,
goto err_out;
}
+ ndev = rxe_ib_device_get_netdev(ibdev);
+ if (!ndev) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
memcpy(attr, &rxe->port.attr, sizeof(*attr));
mutex_lock(&rxe->usdev_lock);
@@ -57,13 +64,14 @@ static int rxe_query_port(struct ib_device *ibdev,
if (attr->state == IB_PORT_ACTIVE)
attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
- else if (dev_get_flags(rxe->ndev) & IFF_UP)
+ else if (dev_get_flags(ndev) & IFF_UP)
attr->phys_state = IB_PORT_PHYS_STATE_POLLING;
else
attr->phys_state = IB_PORT_PHYS_STATE_DISABLED;
mutex_unlock(&rxe->usdev_lock);
+ dev_put(ndev);
return ret;
err_out:
@@ -1428,9 +1436,16 @@ static const struct attribute_group rxe_attr_group = {
static int rxe_enable_driver(struct ib_device *ib_dev)
{
struct rxe_dev *rxe = container_of(ib_dev, struct rxe_dev, ib_dev);
+ struct net_device *ndev;
+
+ ndev = rxe_ib_device_get_netdev(ib_dev);
+ if (!ndev)
+ return -ENODEV;
rxe_set_port_state(rxe);
- dev_info(&rxe->ib_dev.dev, "added %s\n", netdev_name(rxe->ndev));
+ dev_info(&rxe->ib_dev.dev, "added %s\n", netdev_name(ndev));
+
+ dev_put(ndev);
return 0;
}
@@ -1498,7 +1513,8 @@ static const struct ib_device_ops rxe_dev_ops = {
INIT_RDMA_OBJ_SIZE(ib_mw, rxe_mw, ibmw),
};
-int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name)
+int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name,
+ struct net_device *ndev)
{
int err;
struct ib_device *dev = &rxe->ib_dev;
@@ -1510,13 +1526,13 @@ int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name)
dev->num_comp_vectors = num_possible_cpus();
dev->local_dma_lkey = 0;
addrconf_addr_eui48((unsigned char *)&dev->node_guid,
- rxe->ndev->dev_addr);
+ ndev->dev_addr);
dev->uverbs_cmd_mask |= BIT_ULL(IB_USER_VERBS_CMD_POST_SEND) |
BIT_ULL(IB_USER_VERBS_CMD_REQ_NOTIFY_CQ);
ib_set_device_ops(dev, &rxe_dev_ops);
- err = ib_device_set_netdev(&rxe->ib_dev, rxe->ndev, 1);
+ err = ib_device_set_netdev(&rxe->ib_dev, ndev, 1);
if (err)
return err;
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index ccb9d19ffe8a..4242b24a47da 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -369,6 +369,7 @@ struct rxe_port {
u32 qp_gsi_index;
};
+#define RXE_PORT 1
struct rxe_dev {
struct ib_device ib_dev;
struct ib_device_attr attr;
@@ -376,8 +377,6 @@ struct rxe_dev {
int max_inline_data;
struct mutex usdev_lock;
- struct net_device *ndev;
-
struct rxe_pool uc_pool;
struct rxe_pool pd_pool;
struct rxe_pool ah_pool;
@@ -405,6 +404,11 @@ struct rxe_dev {
struct crypto_shash *tfm;
};
+static inline struct net_device *rxe_ib_device_get_netdev(struct ib_device *dev)
+{
+ return ib_device_get_netdev(dev, RXE_PORT);
+}
+
static inline void rxe_counter_inc(struct rxe_dev *rxe, enum rxe_counters index)
{
atomic64_inc(&rxe->stats_counters[index]);
@@ -470,6 +474,7 @@ static inline struct rxe_pd *rxe_mw_pd(struct rxe_mw *mw)
return to_rpd(mw->ibmw.pd);
}
-int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name);
+int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name,
+ struct net_device *ndev);
#endif /* RXE_VERBS_H */
--
2.34.1
2
1

[openeuler:OLK-6.6 2123/2123] vmlinux.o: warning: objtool: kasan_report+0x10b: RET before UNTRAIN
by kernel test robot 15 Apr '25
by kernel test robot 15 Apr '25
15 Apr '25
tree: https://gitee.com/openeuler/kernel.git OLK-6.6
head: 8e04020e957c517ad3fb6bb3caa90e037dc3d5b8
commit: b73666e1e9554c77a69a647427cf77782e0bd9aa [2123/2123] x86/xen: don't do PV iret hypercall through hypercall page
config: x86_64-buildonly-randconfig-002-20250415 (https://download.01.org/0day-ci/archive/20250415/202504150515.bR3H6UHH-lkp@…)
compiler: gcc-11 (Debian 11.3.0-12) 11.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250415/202504150515.bR3H6UHH-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/202504150515.bR3H6UHH-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> vmlinux.o: warning: objtool: kasan_report+0x10b: RET before UNTRAIN
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
1
0

[openeuler:OLK-5.10 2861/2861] llvm-objcopy: error: 'arch/x86/entry/vdso/vdso64.so.dbg': No such file or directory
by kernel test robot 15 Apr '25
by kernel test robot 15 Apr '25
15 Apr '25
Hi Sean,
FYI, the error/warning still remains.
tree: https://gitee.com/openeuler/kernel.git OLK-5.10
head: 1afd05e282420aba2d2fc2132a8c2e52d4d9b253
commit: 5476cb89ef2297bd36f8b38e27b54617b6f63236 [2861/2861] x86/vdso: Implement a vDSO for Intel SGX enclave call
config: x86_64-buildonly-randconfig-003-20250414 (https://download.01.org/0day-ci/archive/20250415/202504150150.pd024mOU-lkp@…)
compiler: clang version 20.1.2 (https://github.com/llvm/llvm-project 58df0ef89dd64126512e4ee27b4ac3fd8ddf6247)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250415/202504150150.pd024mOU-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/202504150150.pd024mOU-lkp@intel.com/
All errors (new ones prefixed by >>):
>> llvm-objcopy: error: 'arch/x86/entry/vdso/vdso64.so.dbg': No such file or directory
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
1
0
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