From 0a57f68454a9ec3649e0cf1a0e624fb69218e1c1 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Thu, 17 Apr 2025 21:49:29 +0800 Subject: [PATCH 01/21] soc cache: Add framework driver for HiSilicon SoC cache ANBZ: #45460 commit e6ecc3b028b8c3151c7ca3f4bd53e6385db72f93 openEuler. HiSilicon SoC cache is comprised of multiple hardware devices, a driver in this patch is used to provide common utilities for other drivers to avoid redundancy. The driver will create a file of `/dev/hisi_soc_cache_mgmt`, mmap operations to it will be taken as applying cache lock for a memory region, ioctl operations will be taken as cache maintenance. The address is aligned up to return to user and the arena's starting address is stored for future release. Unused pages produced during above process are released to allow minimum arena. Co-developed-by: Yicong Yang Signed-off-by: Yicong Yang Co-developed-by: Yushan Wang Signed-off-by: Yushan Wang Signed-off-by: Jie Wang Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/Kconfig | 11 + drivers/soc/hisilicon/Makefile | 2 + .../soc/hisilicon/hisi_soc_cache_framework.c | 378 ++++++++++++++++++ .../soc/hisilicon/hisi_soc_cache_framework.h | 77 ++++ .../uapi/misc/hisi_soc_cache/hisi_soc_cache.h | 35 ++ 5 files changed, 503 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 include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 0ab688af308f..a85dbe8ac60c 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -18,4 +18,15 @@ config KUNPENG_HCCS Say M here if you want to include support for querying the health status and port information of HCCS on Kunpeng SoC. +config HISI_SOC_CACHE + tristate "HiSilicon Cache driver for Kunpeng SoC" + depends on ARCH_HISI + help + This driver provides the basic utilities for drivers of + different part of Kunpeng SoC cache, including L3 cache and + Hydra Home Agent etc. + + If either HiSilicon L3 cache driver or HiSilicon Hydra Home + Agent driver is needed, say yes. + endmenu diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile index 226e747e70d6..7d96f366404b 100644 --- a/drivers/soc/hisilicon/Makefile +++ b/drivers/soc/hisilicon/Makefile @@ -1,2 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_KUNPENG_HCCS) += kunpeng_hccs.o + +obj-$(CONFIG_HISI_SOC_CACHE) += hisi_soc_cache_framework.o diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c new file mode 100644 index 000000000000..1782e6a44668 --- /dev/null +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Framework for HiSilicon SoC cache, manages HiSilicon SoC cache drivers. + * + * Copyright (c) 2024 HiSilicon Technologies Co., Ltd. + * Author: Jie Wang + * Author: Yicong Yang + * Author: Yushan Wang + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hisi_soc_cache_framework.h" + +struct hisi_soc_comp_inst { + struct list_head node; + struct hisi_soc_comp *comp; +}; + +struct hisi_soc_comp_list { + struct list_head node; + /* protects list of HiSilicon SoC cache components */ + spinlock_t lock; + u32 inst_num; +}; + +static struct hisi_soc_comp_list soc_cache_devs[SOC_COMP_TYPE_MAX]; + +int hisi_soc_cache_maintain(phys_addr_t addr, size_t size, + enum hisi_soc_cache_maint_type mnt_type) +{ + struct hisi_soc_comp_inst *inst; + struct list_head *head; + int ret = -EOPNOTSUPP; + + if (mnt_type >= HISI_CACHE_MAINT_MAX) + return -EINVAL; + + guard(spinlock)(&soc_cache_devs[HISI_SOC_HHA].lock); + + head = &soc_cache_devs[HISI_SOC_HHA].node; + list_for_each_entry(inst, head, node) { + ret = inst->comp->ops->do_maintain(inst->comp, addr, size, + mnt_type); + if (ret) + return ret; + } + + list_for_each_entry(inst, head, node) { + ret = inst->comp->ops->poll_maintain_done(inst->comp, addr, + size, mnt_type); + if (ret) + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(hisi_soc_cache_maintain); + +static int hisi_soc_cache_maint_pte_entry(pte_t *pte, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ +#ifdef HISI_SOC_CACHE_LLT + unsigned int mnt_type = *((unsigned int *)walk->priv); +#else + unsigned int mnt_type = *((unsigned int *)walk->private); +#endif + size_t size = next - addr; + phys_addr_t paddr; + + if (!pte_present(ptep_get(pte))) + return -EINVAL; + + paddr = PFN_PHYS(pte_pfn(*pte)) + offset_in_page(addr); + + return hisi_soc_cache_maintain(paddr, size, mnt_type); +} + +static const struct mm_walk_ops hisi_soc_cache_maint_walk = { + .pte_entry = hisi_soc_cache_maint_pte_entry, + .walk_lock = PGWALK_RDLOCK, +}; + +static int hisi_soc_cache_inst_check(const struct hisi_soc_comp *comp, + enum hisi_soc_comp_type comp_type) +{ + /* Different types of component could have different ops. */ + switch (comp_type) { + case HISI_SOC_HHA: + if (!comp->ops->do_maintain || !comp->ops->poll_maintain_done) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int hisi_soc_cache_inst_add(struct hisi_soc_comp *comp, + enum hisi_soc_comp_type comp_type) +{ + struct hisi_soc_comp_inst *comp_inst; + int ret; + + ret = hisi_soc_cache_inst_check(comp, comp_type); + if (ret) + return ret; + + comp_inst = kzalloc(sizeof(*comp_inst), GFP_KERNEL); + if (!comp_inst) + return -ENOMEM; + + comp_inst->comp = comp; + + scoped_guard(spinlock, &soc_cache_devs[comp_type].lock) { + list_add_tail(&comp_inst->node, + &soc_cache_devs[comp_type].node); + soc_cache_devs[comp_type].inst_num++; + } + + return 0; +} + +/* + * When @comp is NULL, it means to delete all instances of @comp_type. + */ +static void hisi_soc_cache_inst_del(struct hisi_soc_comp *comp, + enum hisi_soc_comp_type comp_type) +{ + struct hisi_soc_comp_inst *inst, *tmp; + + guard(spinlock)(&soc_cache_devs[comp_type].lock); + list_for_each_entry_safe(inst, tmp, &soc_cache_devs[comp_type].node, + node) { + if (comp && comp != inst->comp) + continue; + + if (soc_cache_devs[comp_type].inst_num > 0) + soc_cache_devs[comp_type].inst_num--; + + list_del(&inst->node); + kfree(inst); + + /* Stop the loop if we have already deleted @comp. */ + if (comp) + break; + } +} + +int hisi_soc_comp_inst_add(struct hisi_soc_comp *comp) +{ + int ret, i = 0; + + if (!comp || !comp->ops || comp->comp_type == 0) + return -EINVAL; + + for_each_set_bit_from(i, &comp->comp_type, SOC_COMP_TYPE_MAX) { + ret = hisi_soc_cache_inst_add(comp, i); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_soc_comp_inst_add); + +int hisi_soc_comp_inst_del(struct hisi_soc_comp *comp) +{ + int i; + + if (!comp) + return -EINVAL; + + for_each_set_bit(i, &comp->comp_type, SOC_COMP_TYPE_MAX) + hisi_soc_cache_inst_del(comp, i); + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_soc_comp_inst_del); + +static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, + enum hisi_soc_cache_maint_type mnt_type) +{ + unsigned long start = untagged_addr(vaddr); + struct vm_area_struct *vma; + int ret = 0; + + mmap_read_lock_killable(current->mm); + + vma = vma_lookup(current->mm, vaddr); + if (!vma || vaddr + size > vma->vm_end || !size) { + ret = -EINVAL; + goto out; + } + + /* User should have the write permission of target memory */ + if (!(vma->vm_flags & VM_WRITE)) { + ret = -EINVAL; + goto out; + } + + ret = walk_page_range(current->mm, start, start + size, + &hisi_soc_cache_maint_walk, &mnt_type); + +out: + mmap_read_unlock(current->mm); + return ret; +} + +static long hisi_soc_cache_mgmt_ioctl(struct file *file, u32 cmd, unsigned long arg) +{ + struct hisi_soc_cache_ioctl_param *param = + kzalloc(sizeof(struct hisi_soc_cache_ioctl_param), GFP_KERNEL); + long ret; + + if (!param) { + ret = -ENOMEM; + goto out; + } + + if (copy_from_user(param, (void __user *)arg, sizeof(*param))) { + ret = -EFAULT; + goto out; + } + + switch (cmd) { + case HISI_CACHE_MAINTAIN: + ret = __hisi_soc_cache_maintain(param->addr, param->size, + param->op_type); + break; + default: + ret = -EINVAL; + break; + } +out: + kfree(param); + return ret; +} + +static const struct file_operations soc_cache_dev_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = hisi_soc_cache_mgmt_ioctl, +}; + +static struct miscdevice soc_cache_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "hisi_soc_cache_mgmt", + .fops = &soc_cache_dev_fops, + .mode = 0600, +}; + +static void hisi_soc_cache_inst_uninit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(soc_cache_devs); ++i) + hisi_soc_cache_inst_del(NULL, i); +} + +static void hisi_soc_cache_framework_data_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(soc_cache_devs); ++i) { + spin_lock_init(&soc_cache_devs[i].lock); + INIT_LIST_HEAD(&soc_cache_devs[i].node); + } +} + +static const char *const hisi_soc_cache_item_str[SOC_COMP_TYPE_MAX] = { + "hha" +}; + +/* + * Print cache instance number debug information for debug FS. + */ +static ssize_t hisi_soc_cache_dbg_get_inst_num(struct file *file, + char __user *buff, + size_t cnt, + loff_t *ppos) +{ +#define HISI_SOC_CACHE_DBGFS_REG_LEN 100 + char *read_buff; + int len, i, pos = 0; + int ret = 0; + + if (!access_ok(buff, cnt)) + return -EFAULT; + if (*ppos < 0) + return -EINVAL; + if (cnt == 0) + return 0; + + read_buff = kzalloc(HISI_SOC_CACHE_DBGFS_REG_LEN, GFP_KERNEL); + if (!read_buff) + return -ENOMEM; + + len = HISI_SOC_CACHE_DBGFS_REG_LEN; + + for (i = 0; i < ARRAY_SIZE(soc_cache_devs); i++) { + guard(spinlock)(&soc_cache_devs[i].lock); + pos += scnprintf(read_buff + pos, len - pos, + "%s inst num: %u\n", + hisi_soc_cache_item_str[i], + soc_cache_devs[i].inst_num); + } + + ret = simple_read_from_buffer(buff, cnt, ppos, read_buff, + strlen(read_buff)); + kfree(read_buff); + return ret; +} + +static struct dentry *hisi_cache_dbgfs_root; +static const struct file_operations hisi_cache_dbgfs_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = hisi_soc_cache_dbg_get_inst_num, +}; + +static void hisi_soc_cache_dbgfs_init(void) +{ + hisi_cache_dbgfs_root = debugfs_create_dir("hisi_soc_cache_frm", NULL); + debugfs_create_file("instance", 0400, hisi_cache_dbgfs_root, NULL, + &hisi_cache_dbgfs_ops); +} + +static void hisi_soc_cache_dbgfs_uninit(void) +{ + debugfs_remove_recursive(hisi_cache_dbgfs_root); + hisi_cache_dbgfs_root = NULL; +} + +static int __init hisi_soc_cache_framework_init(void) +{ + int ret; + + hisi_soc_cache_framework_data_init(); + + ret = misc_register(&soc_cache_miscdev); + if (ret) { + hisi_soc_cache_inst_uninit(); + return ret; + } + + hisi_soc_cache_dbgfs_init(); + + return 0; +} +module_init(hisi_soc_cache_framework_init); + +static void __exit hisi_soc_cache_framework_exit(void) +{ + hisi_soc_cache_dbgfs_uninit(); + misc_deregister(&soc_cache_miscdev); + hisi_soc_cache_inst_uninit(); +} +module_exit(hisi_soc_cache_framework_exit); + +MODULE_DESCRIPTION("HiSilicon SoC Cache Framework Driver"); +MODULE_AUTHOR("Jie Wang "); +MODULE_AUTHOR("Yushan Wang "); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.h b/drivers/soc/hisilicon/hisi_soc_cache_framework.h new file mode 100644 index 000000000000..9b3de4e50161 --- /dev/null +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file of framework for HiSilicon SoC cache. + * + * Copyright (c) 2024 HiSilicon Technologies Co., Ltd. + * Author: Jie Wang + * Author: Yicong Yang + * Author: Yushan Wang + */ + +#ifndef HISI_CACHE_FRAMEWORK_H +#define HISI_CACHE_FRAMEWORK_H + +#include +#include + +#include + +enum hisi_soc_comp_type { + HISI_SOC_HHA, + SOC_COMP_TYPE_MAX +}; + +struct hisi_soc_comp; + +/** + * struct hisi_soc_comp_ops - Callbacks for SoC cache drivers to handle + * operation requests. + * @maintain_enable: perform certain cache maintain operation on HHA. + * @poll_maintain_done: check if the HHA maintain operation has succeeded. + * + * Operations are decoupled into two phases so that framework does not have + * to wait for one operation to finish before calling the next when multiple + * hardwares onboard. + * + * Implementers must implement the functions in pairs. Implementation should + * return -EBUSY when: + * - insufficient resources are available to perform the operation. + * - previously raised operation is not finished. + * - new operations (do_lock(), do_unlock() etc.) to the same address + * before corresponding done functions being called. + */ +struct hisi_soc_comp_ops { + int (*do_maintain)(struct hisi_soc_comp *comp, + phys_addr_t addr, size_t size, + enum hisi_soc_cache_maint_type mnt_type); + int (*poll_maintain_done)(struct hisi_soc_comp *comp, + phys_addr_t addr, size_t size, + enum hisi_soc_cache_maint_type mnt_type); +}; + +/** + * struct hisi_soc_comp - Struct of HiSilicon SoC cache components. + * @ops: possible operations a component may perform. + * @affinity_mask: cpus that associate with this component. + * @comp_type: bitmap declaring the type of the component. + * + * A component may have multiple types (e.g. a piece of multi-function device). + * If so, set the bit of @comp_type according to its supporting type in struct + * hisi_soc_comp_type. + */ +struct hisi_soc_comp { + struct hisi_soc_comp_ops *ops; + cpumask_t affinity_mask; + /* + * Setting bit x to 1 means this instance supports feature of x-th + * entry in enum hisi_soc_comp_type. + */ + unsigned long comp_type; +}; + +int hisi_soc_comp_inst_add(struct hisi_soc_comp *comp); +int hisi_soc_comp_inst_del(struct hisi_soc_comp *comp); +int hisi_soc_cache_maintain(phys_addr_t addr, size_t size, + enum hisi_soc_cache_maint_type mnt_type); + +#endif diff --git a/include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h b/include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h new file mode 100644 index 000000000000..5441f6f75b81 --- /dev/null +++ b/include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* Copyright (c) 2024-2024 HiSilicon Limited. */ +#ifndef _UAPI_HISI_SOC_CACHE_H +#define _UAPI_HISI_SOC_CACHE_H + +#include + +/* HISI_CACHE_MAINTAIN: cache maintain operation for HiSilicon SoC */ +#define HISI_CACHE_MAINTAIN _IOW('C', 1, unsigned long) + +/* + * Further information of these operations can be found at: + * https://developer.arm.com/documentation/ihi0050/latest/ + */ +enum hisi_soc_cache_maint_type { + HISI_CACHE_MAINT_CLEANSHARED, + HISI_CACHE_MAINT_CLEANINVALID, + HISI_CACHE_MAINT_MAKEINVALID, + + HISI_CACHE_MAINT_MAX +}; + +/** + * struct hisi_soc_cache_ioctl_param - User data for hisi cache operates. + * @op_type: cache maintain type + * @addr: cache maintain address + * @size: cache maintain size + */ +struct hisi_soc_cache_ioctl_param { + enum hisi_soc_cache_maint_type op_type; + unsigned long addr; + unsigned long size; +}; + +#endif -- Gitee From 97774c82aae6c604c6461ebc27e58988ae2726d9 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Thu, 17 Apr 2025 21:49:30 +0800 Subject: [PATCH 02/21] soc cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent ANBZ: #45460 commit 84d2eab3f180350469bf01b351bba6610c22c932 openEuler Hydra Home Agent is a device used for maintain cache coherency, add support of cache maintenance operations for it. Same as HiSilicon L3 cache and L3 cache PMU, memory resource of HHA conflicts with that of HHA PMU. Same workaround is implemented here to workaround resource conflict check. Signed-off-by: Yicong Yang Co-developed-by: Yushan Wang Signed-off-by: Yushan Wang Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- .../L1-RECOMMEND/arm64/CONFIG_HISI_SOC_HHA | 1 + drivers/soc/hisilicon/Kconfig | 11 + drivers/soc/hisilicon/Makefile | 1 + drivers/soc/hisilicon/hisi_soc_hha.c | 189 ++++++++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_HHA create mode 100644 drivers/soc/hisilicon/hisi_soc_hha.c diff --git a/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_HHA b/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_HHA new file mode 100644 index 000000000000..489346ed5871 --- /dev/null +++ b/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_HHA @@ -0,0 +1 @@ +CONFIG_HISI_SOC_HHA=m \ No newline at end of file diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index a85dbe8ac60c..49ccc25a0d13 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -29,4 +29,15 @@ config HISI_SOC_CACHE If either HiSilicon L3 cache driver or HiSilicon Hydra Home Agent driver is needed, say yes. +config HISI_SOC_HHA + tristate "HiSilicon Hydra Home Agent (HHA) device driver" + depends on ARM64 && ACPI || COMPILE_TEST + depends on HISI_SOC_CACHE + help + The Hydra Home Agent (HHA) is responsible of cache coherency + on SoC. This drivers provides cache maintenance functions of HHA. + + This driver can be built as a module. If so, the module will be + called hisi_soc_hha. + endmenu diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile index 7d96f366404b..0d3bcdbec6b8 100644 --- a/drivers/soc/hisilicon/Makefile +++ b/drivers/soc/hisilicon/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_KUNPENG_HCCS) += kunpeng_hccs.o obj-$(CONFIG_HISI_SOC_CACHE) += hisi_soc_cache_framework.o +obj-$(CONFIG_HISI_SOC_HHA) += hisi_soc_hha.o diff --git a/drivers/soc/hisilicon/hisi_soc_hha.c b/drivers/soc/hisilicon/hisi_soc_hha.c new file mode 100644 index 000000000000..2b6ded47d4fe --- /dev/null +++ b/drivers/soc/hisilicon/hisi_soc_hha.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for HiSilicon Hydra Home Agent (HHA). + * + * Copyright (c) 2024 HiSilicon Technologies Co., Ltd. + * Author: Yicong Yang + * Yushan Wang + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hisi_soc_cache_framework.h" + +#define HISI_HHA_CTRL 0x5004 +#define HISI_HHA_CTRL_EN BIT(0) +#define HISI_HHA_CTRL_RANGE BIT(1) +#define HISI_HHA_CTRL_TYPE GENMASK(3, 2) +#define HISI_HHA_START_L 0x5008 +#define HISI_HHA_START_H 0x500c +#define HISI_HHA_LEN_L 0x5010 +#define HISI_HHA_LEN_H 0x5014 + +/* The maintain operation performs in a 128 Byte granularity */ +#define HISI_HHA_MAINT_ALIGN 128 + +#define HISI_HHA_POLL_GAP_US 10 + +struct hisi_soc_hha { + struct hisi_soc_comp comp; + /* Locks HHA instance to forbid overlapping access. */ + spinlock_t lock; + struct device *dev; + void __iomem *base; +}; + +static bool hisi_hha_cache_maintain_wait_finished(struct hisi_soc_hha *soc_hha) +{ + u32 val; + + return !readl_poll_timeout_atomic(soc_hha->base + HISI_HHA_CTRL, val, + !(val & HISI_HHA_CTRL_EN), + HISI_HHA_POLL_GAP_US, + jiffies_to_usecs(HZ)); +} + +static int hisi_hha_cache_do_maintain(struct hisi_soc_comp *comp, + phys_addr_t addr, size_t size, + enum hisi_soc_cache_maint_type mnt_type) +{ + struct hisi_soc_hha *soc_hha = container_of(comp, struct hisi_soc_hha, + comp); + int ret = 0; + u32 reg; + + if (!size) + return -EINVAL; + + if (mnt_type < 0) + return -EOPNOTSUPP; + + /* + * Hardware will search for addresses ranging [addr, addr + size -1], + * last byte included, and perform maintain in 128 byte granule + * on those which contain the addresses. + */ + size -= 1; + + guard(spinlock)(&soc_hha->lock); + + if (!hisi_hha_cache_maintain_wait_finished(soc_hha)) + return -EBUSY; + + writel(lower_32_bits(addr), soc_hha->base + HISI_HHA_START_L); + writel(upper_32_bits(addr), soc_hha->base + HISI_HHA_START_H); + writel(lower_32_bits(size), soc_hha->base + HISI_HHA_LEN_L); + writel(upper_32_bits(size), soc_hha->base + HISI_HHA_LEN_H); + + reg = FIELD_PREP(HISI_HHA_CTRL_TYPE, mnt_type); + reg |= HISI_HHA_CTRL_RANGE | HISI_HHA_CTRL_EN; + writel(reg, soc_hha->base + HISI_HHA_CTRL); + + return ret; +} + +static int hisi_hha_cache_poll_maintain_done(struct hisi_soc_comp *comp, + phys_addr_t addr, size_t size, + enum hisi_soc_cache_maint_type mnt_type) +{ + struct hisi_soc_hha *soc_hha = container_of(comp, struct hisi_soc_hha, + comp); + + guard(spinlock)(&soc_hha->lock); + + if (!hisi_hha_cache_maintain_wait_finished(soc_hha)) + return -ETIMEDOUT; + + return 0; +} + +static struct hisi_soc_comp_ops hisi_soc_hha_comp_ops = { + .do_maintain = hisi_hha_cache_do_maintain, + .poll_maintain_done = hisi_hha_cache_poll_maintain_done, +}; + +static void hisi_hha_comp_inst_del(void *priv) +{ + struct hisi_soc_hha *soc_hha = priv; + + hisi_soc_comp_inst_del(&soc_hha->comp); +} + +static int hisi_soc_hha_probe(struct platform_device *pdev) +{ + struct hisi_soc_hha *soc_hha; + struct resource *mem; + int ret; + + soc_hha = devm_kzalloc(&pdev->dev, sizeof(*soc_hha), GFP_KERNEL); + if (!soc_hha) + return -ENOMEM; + + platform_set_drvdata(pdev, soc_hha); + soc_hha->dev = &pdev->dev; + + spin_lock_init(&soc_hha->lock); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENODEV; + + /* + * HHA cache driver share the same register region with HHA uncore PMU + * driver in hardware's perspective, none of them should reserve the + * resource to itself only. Here exclusive access verification is + * avoided by calling devm_ioremap instead of devm_ioremap_resource to + * allow both drivers to exist at the same time. + */ + soc_hha->base = devm_ioremap(&pdev->dev, mem->start, + resource_size(mem)); + if (IS_ERR_OR_NULL(soc_hha->base)) { + return dev_err_probe(&pdev->dev, PTR_ERR(soc_hha->base), + "failed to remap io memory"); + } + + soc_hha->comp.ops = &hisi_soc_hha_comp_ops; + soc_hha->comp.comp_type = BIT(HISI_SOC_HHA); + cpumask_copy(&soc_hha->comp.affinity_mask, cpu_possible_mask); + + ret = hisi_soc_comp_inst_add(&soc_hha->comp); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to register maintain inst"); + + return devm_add_action_or_reset(&pdev->dev, hisi_hha_comp_inst_del, + soc_hha); +} + +static const struct acpi_device_id hisi_soc_hha_ids[] = { + { "HISI0511", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, hisi_soc_hha_ids); + +static struct platform_driver hisi_soc_hha_driver = { + .driver = { + .name = "hisi_soc_hha", + .acpi_match_table = hisi_soc_hha_ids, + }, + .probe = hisi_soc_hha_probe, +}; + +module_platform_driver(hisi_soc_hha_driver); + +MODULE_DESCRIPTION("Hisilicon Hydra Home Agent driver supporting cache maintenance"); +MODULE_AUTHOR("Yicong Yang "); +MODULE_AUTHOR("Yushan Wang "); +MODULE_LICENSE("GPL"); -- Gitee From 7979084714f3150a3da05a041adea85991c77c83 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 26 Aug 2025 10:02:24 +0800 Subject: [PATCH 03/21] soc cache: Enforce maintain type check ANBZ: #45460 commit ea6777a90d70f56dbf730fafbe936dbc0ee784ad openEuler Make Invalid may cause data loss, which is too dangereous to be exposed to userspace, so invalidate it then. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 4 ++++ drivers/soc/hisilicon/hisi_soc_hha.c | 7 ++++++- include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 1782e6a44668..6e3b128df4e7 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -200,6 +200,10 @@ static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, struct vm_area_struct *vma; int ret = 0; + /* MakeInvalid is not allowed for calls from userspace. */ + if (mnt_type >= HISI_CACHE_MAINT_MAKEINVALID) + return -EINVAL; + mmap_read_lock_killable(current->mm); vma = vma_lookup(current->mm, vaddr); diff --git a/drivers/soc/hisilicon/hisi_soc_hha.c b/drivers/soc/hisilicon/hisi_soc_hha.c index 2b6ded47d4fe..22a1ec8b8fc9 100644 --- a/drivers/soc/hisilicon/hisi_soc_hha.c +++ b/drivers/soc/hisilicon/hisi_soc_hha.c @@ -61,13 +61,18 @@ static int hisi_hha_cache_do_maintain(struct hisi_soc_comp *comp, { struct hisi_soc_hha *soc_hha = container_of(comp, struct hisi_soc_hha, comp); + phys_addr_t top; int ret = 0; u32 reg; if (!size) return -EINVAL; - if (mnt_type < 0) + addr = ALIGN_DOWN(addr, HISI_HHA_MAINT_ALIGN); + top = ALIGN(addr + size, HISI_HHA_MAINT_ALIGN); + size = top - addr; + + if (mnt_type < 0 || mnt_type >= HISI_CACHE_MAINT_MAX) return -EOPNOTSUPP; /* diff --git a/include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h b/include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h index 5441f6f75b81..8b190941c805 100644 --- a/include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h +++ b/include/uapi/misc/hisi_soc_cache/hisi_soc_cache.h @@ -15,7 +15,9 @@ enum hisi_soc_cache_maint_type { HISI_CACHE_MAINT_CLEANSHARED, HISI_CACHE_MAINT_CLEANINVALID, +#ifdef __KERNEL__ HISI_CACHE_MAINT_MAKEINVALID, +#endif HISI_CACHE_MAINT_MAX }; -- Gitee From d32a57b4ddc64664b65f6a17ac424553ae0568ca Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 26 Aug 2025 10:02:25 +0800 Subject: [PATCH 04/21] soc cache: Fix incorrect size validation ANBZ: #45460 commit 54706fe41c59efd23de41e30a46b7b55722c2aa3 openEuler Check the size, which is controlled by user, by adding it to vm_start and compare with end could be problematic when malicious user passes an arbitrarily big number as size which causes overflow and thus bypass the size check. Fix this by using the size as is to compare with vma range. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 6e3b128df4e7..70d9bb7f3727 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -204,10 +204,17 @@ static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, if (mnt_type >= HISI_CACHE_MAINT_MAKEINVALID) return -EINVAL; - mmap_read_lock_killable(current->mm); + /* Prevent overflow of vaddr + size. */ + if (!size || vaddr + size < vaddr) + return -EINVAL; + + ret = mmap_read_lock_killable(current->mm); + if (ret) + return ret; vma = vma_lookup(current->mm, vaddr); - if (!vma || vaddr + size > vma->vm_end || !size) { + + if (!range_in_vma(vma, vaddr, vaddr + size)) { ret = -EINVAL; goto out; } -- Gitee From 0732b552a90008cda82f85d1f8de045944851ea0 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 26 Aug 2025 10:02:26 +0800 Subject: [PATCH 05/21] soc cache: Fix incorrect error path of ioctl ANBZ: #45460 commit 10cbc1bc29bcc0f7b69c7d978eef9fdde4f6eb17 openEuler Though passing null pointer to kfree() could be harmless, the error path per malloc failure could be confusing when jumping to kfree() with validated null pointer. Fix this by early return instead of jumping to error handling label. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 70d9bb7f3727..37da31610d4d 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -239,10 +239,8 @@ static long hisi_soc_cache_mgmt_ioctl(struct file *file, u32 cmd, unsigned long kzalloc(sizeof(struct hisi_soc_cache_ioctl_param), GFP_KERNEL); long ret; - if (!param) { - ret = -ENOMEM; - goto out; - } + if (!param) + return -ENOMEM; if (copy_from_user(param, (void __user *)arg, sizeof(*param))) { ret = -EFAULT; -- Gitee From 654de7245f28baa52c34e0e147419cc222957d1b Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Mon, 13 Oct 2025 15:17:42 +0800 Subject: [PATCH 06/21] soc cache: support L3 cache lock in framework ANBZ: #45460 commit c4e09ac64bc77f34a64bf3bbc771d320dd7aa726 openEuler. Support L3 cache lock in framework. Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- .../L1-RECOMMEND/arm64/CONFIG_HISI_SOC_CACHE | 1 + drivers/soc/hisilicon/Kconfig | 2 +- .../soc/hisilicon/hisi_soc_cache_framework.c | 271 +++++++++++++++++- .../soc/hisilicon/hisi_soc_cache_framework.h | 15 + 4 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_CACHE diff --git a/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_CACHE b/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_CACHE new file mode 100644 index 000000000000..0088cbcc8e86 --- /dev/null +++ b/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_CACHE @@ -0,0 +1 @@ +CONFIG_HISI_SOC_CACHE=y \ No newline at end of file diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 49ccc25a0d13..6859a6cd0e96 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -19,7 +19,7 @@ config KUNPENG_HCCS health status and port information of HCCS on Kunpeng SoC. config HISI_SOC_CACHE - tristate "HiSilicon Cache driver for Kunpeng SoC" + bool "HiSilicon Cache driver for Kunpeng SoC" depends on ARCH_HISI help This driver provides the basic utilities for drivers of diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 37da31610d4d..11795332f52f 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -26,6 +26,19 @@ #include "hisi_soc_cache_framework.h" +struct hisi_soc_cache_lock_region { + /* physical address of the arena allocated for aligned address */ + unsigned long arena_start; + /* VMA region of locked memory for future release */ + unsigned long vm_start; + unsigned long vm_end; + phys_addr_t addr; + size_t size; + /* Return value of cache lock call */ + int status; + int cpu; +}; + struct hisi_soc_comp_inst { struct list_head node; struct hisi_soc_comp *comp; @@ -40,6 +53,72 @@ struct hisi_soc_comp_list { static struct hisi_soc_comp_list soc_cache_devs[SOC_COMP_TYPE_MAX]; +static int hisi_soc_cache_lock(int cpu, phys_addr_t addr, size_t size) +{ + struct hisi_soc_comp_inst *inst; + struct list_head *head; + int ret = -ENOMEM; + + /* Avoid null pointer when there is no instance onboard. */ + if (soc_cache_devs[HISI_SOC_L3C].inst_num <= 0) + return ret; + + guard(spinlock)(&soc_cache_devs[HISI_SOC_L3C].lock); + + /* Iterate L3C instances to perform operation, break loop once found. */ + head = &soc_cache_devs[HISI_SOC_L3C].node; + list_for_each_entry(inst, head, node) { + if (!cpumask_test_cpu(cpu, &inst->comp->affinity_mask)) + continue; + ret = inst->comp->ops->do_lock(inst->comp, addr, size); + if (ret) + return ret; + } + + list_for_each_entry(inst, head, node) { + if (!cpumask_test_cpu(cpu, &inst->comp->affinity_mask)) + continue; + ret = inst->comp->ops->poll_lock_done(inst->comp, addr, size); + if (ret) + return ret; + } + + return ret; +} + +static int hisi_soc_cache_unlock(int cpu, phys_addr_t addr) +{ + struct hisi_soc_comp_inst *inst; + struct list_head *head; + int ret = 0; + + /* Avoid null pointer when there is no instance onboard. */ + if (soc_cache_devs[HISI_SOC_L3C].inst_num <= 0) + return ret; + + guard(spinlock)(&soc_cache_devs[HISI_SOC_L3C].lock); + + /* Iterate L3C instances to perform operation, break loop once found. */ + head = &soc_cache_devs[HISI_SOC_L3C].node; + list_for_each_entry(inst, head, node) { + if (!cpumask_test_cpu(cpu, &inst->comp->affinity_mask)) + continue; + ret = inst->comp->ops->do_unlock(inst->comp, addr); + if (ret) + return ret; + } + + list_for_each_entry(inst, head, node) { + if (!cpumask_test_cpu(cpu, &inst->comp->affinity_mask)) + continue; + ret = inst->comp->ops->poll_unlock_done(inst->comp, addr); + if (ret) + return ret; + } + + return ret; +} + int hisi_soc_cache_maintain(phys_addr_t addr, size_t size, enum hisi_soc_cache_maint_type mnt_type) { @@ -98,8 +177,15 @@ static const struct mm_walk_ops hisi_soc_cache_maint_walk = { static int hisi_soc_cache_inst_check(const struct hisi_soc_comp *comp, enum hisi_soc_comp_type comp_type) { + struct hisi_soc_comp_ops *ops = comp->ops; + /* Different types of component could have different ops. */ switch (comp_type) { + case HISI_SOC_L3C: + if (!ops->do_lock || !ops->poll_lock_done + || !ops->do_unlock || !ops->poll_unlock_done) + return -EINVAL; + break; case HISI_SOC_HHA: if (!comp->ops->do_maintain || !comp->ops->poll_maintain_done) return -EINVAL; @@ -164,7 +250,7 @@ static void hisi_soc_cache_inst_del(struct hisi_soc_comp *comp, int hisi_soc_comp_inst_add(struct hisi_soc_comp *comp) { - int ret, i = 0; + int ret, i = HISI_SOC_L3C; if (!comp || !comp->ops || comp->comp_type == 0) return -EINVAL; @@ -193,6 +279,187 @@ int hisi_soc_comp_inst_del(struct hisi_soc_comp *comp) } EXPORT_SYMBOL_GPL(hisi_soc_comp_inst_del); +/** + * hisi_soc_cache_aligned_alloc - Allocate memory region to be locked and + * returns address that aligned to the requested + * size. + * @clr: The locked memory region to be allocated for. + * @size: Requested memory size. + * @addr: Pointer of the start physical address of the requested + * memory region. + * + * @return: + * - -ENOMEM: If allocation fails. + * - 0: If allocations succeeds. + * + * Physical address of allocated memory region is requested to be aligned to + * its size. In order to achieve that, add the order of requested memory size + * by 1 to double the size of allocated memory to ensure the existence of size- + * aligned address. After locating the aligned region, release the unused + * pages from both sides to avoid waste. + */ +static int hisi_soc_cache_aligned_alloc(struct hisi_soc_cache_lock_region *clr, + unsigned long size, + unsigned long *addr) +{ + int order = get_order(size) + 1; + unsigned long arena_start; + struct page *pg; + + pg = alloc_contig_pages(1 << order, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, + cpu_to_node(smp_processor_id()), NULL); + if (!pg) + return -ENOMEM; + + arena_start = page_to_phys(pg); + + /* + * Align up the address by the requested size if the address is not + * naturally aligned to the size. + */ + *addr = arena_start % size == 0 + ? arena_start + : arena_start / size * size + size; + + clr->arena_start = arena_start; + + return 0; +} + +/** + * hisi_soc_cache_aligned_free - Free the aligned memory region allcated by + * hisi_soc_cache_aligned_alloc(). + * @clr: The allocated locked memory region. + * + * Since unused memory pages are release in hisi_soc_cache_aligned_alloc(), the + * memory region to be freed here may not be power of 2 numbers of pages. + * Thus split the memory by page order and release them accordingly. + */ +static void hisi_soc_cache_aligned_free(struct hisi_soc_cache_lock_region *clr) +{ + int order = get_order(clr->size) + 1; + + free_contig_range(PHYS_PFN(clr->arena_start), 1 << order); +} + +static void hisi_soc_cache_vm_open(struct vm_area_struct *vma) +{ + struct hisi_soc_cache_lock_region *clr = vma->vm_private_data; + + /* + * Only perform cache lock when the vma passed in is created + * in hisi_soc_cache_mmap. + */ + if (clr->vm_start != vma->vm_start || clr->vm_end != vma->vm_end) + return; + + clr->status = hisi_soc_cache_lock(clr->cpu, clr->addr, clr->size); +} + +static void hisi_soc_cache_vm_close(struct vm_area_struct *vma) +{ + struct hisi_soc_cache_lock_region *clr = vma->vm_private_data; + + /* + * Only perform cache unlock when the vma passed in is created + * in hisi_soc_cache_mmap. + */ + if (clr->vm_start != vma->vm_start || clr->vm_end != vma->vm_end) + return; + + hisi_soc_cache_unlock(clr->cpu, clr->addr); + + hisi_soc_cache_aligned_free(clr); + kfree(clr); + vma->vm_private_data = NULL; +} + +/* + * mremap operation is not supported for HiSilicon SoC cache. + */ +static int hisi_soc_cache_vm_mremap(struct vm_area_struct *vma) +{ + struct hisi_soc_cache_lock_region *clr = vma->vm_private_data; + + /* + * vma region size will be changed as requested by mremap despite the + * callback failure in this function. Thus, change the vma region + * stored in clr according to the parameters to verify if the pages + * should be freed when unmapping. + */ + clr->vm_end = clr->vm_start + (vma->vm_end - vma->vm_start); + pr_err("mremap for HiSilicon SoC locked cache is not supported\n"); + + return -EOPNOTSUPP; +} + +static int hisi_soc_cache_may_split(struct vm_area_struct *area, unsigned long addr) +{ + pr_err("HiSilicon SoC locked cache may not be split.\n"); + return -EINVAL; +} + +static const struct vm_operations_struct hisi_soc_cache_vm_ops = { + .open = hisi_soc_cache_vm_open, + .close = hisi_soc_cache_vm_close, + .may_split = hisi_soc_cache_may_split, + .mremap = hisi_soc_cache_vm_mremap, +}; + +static int hisi_soc_cache_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long size = vma->vm_end - vma->vm_start; + struct hisi_soc_cache_lock_region *clr; + unsigned long addr; + int ret; + + clr = kzalloc(sizeof(*clr), GFP_KERNEL); + if (!clr) + return -ENOMEM; + + ret = hisi_soc_cache_aligned_alloc(clr, size, &addr); + if (ret) + goto out_clr; + + if (vma->vm_pgoff > PAGE_SIZE) + return -EINVAL; + + ret = remap_pfn_range(vma, vma->vm_start, + (addr >> PAGE_SHIFT) + vma->vm_pgoff, + size, vma->vm_page_prot); + if (ret) + goto out_page; + + clr->addr = addr; + clr->size = size; + clr->cpu = smp_processor_id(); + vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND); + + /* + * The vma should not be moved throughout its lifetime, store the + * region for verification. + */ + clr->vm_start = vma->vm_start; + clr->vm_end = vma->vm_end; + + vma->vm_private_data = clr; + vma->vm_ops = &hisi_soc_cache_vm_ops; + hisi_soc_cache_vm_ops.open(vma); + + if (clr->status) { + ret = clr->status; + goto out_page; + } + + return 0; + +out_page: + hisi_soc_cache_aligned_free(clr); +out_clr: + kfree(clr); + return ret; +} + static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, enum hisi_soc_cache_maint_type mnt_type) { @@ -264,6 +531,7 @@ static long hisi_soc_cache_mgmt_ioctl(struct file *file, u32 cmd, unsigned long static const struct file_operations soc_cache_dev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = hisi_soc_cache_mgmt_ioctl, + .mmap = hisi_soc_cache_mmap, }; static struct miscdevice soc_cache_miscdev = { @@ -292,6 +560,7 @@ static void hisi_soc_cache_framework_data_init(void) } static const char *const hisi_soc_cache_item_str[SOC_COMP_TYPE_MAX] = { + "cache", "hha" }; diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.h b/drivers/soc/hisilicon/hisi_soc_cache_framework.h index 9b3de4e50161..67ee9a33f382 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.h +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.h @@ -17,6 +17,7 @@ #include enum hisi_soc_comp_type { + HISI_SOC_L3C, HISI_SOC_HHA, SOC_COMP_TYPE_MAX }; @@ -26,6 +27,12 @@ struct hisi_soc_comp; /** * struct hisi_soc_comp_ops - Callbacks for SoC cache drivers to handle * operation requests. + * + * @lock_enable: lock certain region of L3 cache from being evicted. + * @poll_lock_done: check if the lock operation has succeeded. + * @unlock_enable: unlock the locked region of L3 cache back to normal. + * @poll_unlock_done: check if the unlock operation has succeeded. + operation requests. * @maintain_enable: perform certain cache maintain operation on HHA. * @poll_maintain_done: check if the HHA maintain operation has succeeded. * @@ -41,6 +48,14 @@ struct hisi_soc_comp; * before corresponding done functions being called. */ struct hisi_soc_comp_ops { + int (*do_lock)(struct hisi_soc_comp *comp, + phys_addr_t addr, size_t size); + int (*poll_lock_done)(struct hisi_soc_comp *comp, + phys_addr_t addr, size_t size); + int (*do_unlock)(struct hisi_soc_comp *comp, + phys_addr_t addr); + int (*poll_unlock_done)(struct hisi_soc_comp *comp, + phys_addr_t addr); int (*do_maintain)(struct hisi_soc_comp *comp, phys_addr_t addr, size_t size, enum hisi_soc_cache_maint_type mnt_type); -- Gitee From 64aebe0a0e91e34eca2c2cf1e91556abc964e361 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Mon, 13 Oct 2025 15:17:43 +0800 Subject: [PATCH 07/21] soc cache: L3 cache lockdown support for HiSilicon SoC ANBZ: #45460 commit aa9399126e8e5ee5d3465b0da32939ebe2aa9c4b openEuler. This driver implements the interface exposed by framework, passes cache lock/unlock requests to hardware. 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, make their probing functions unrelated and workaround resource conflict check by replacing devm_ioremap_resource() to devm_ioremap(). Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- .../L1-RECOMMEND/arm64/CONFIG_HISI_SOC_L3C | 1 + drivers/soc/hisilicon/hisi_soc_l3c.c | 610 ++++++++++++++++++ 2 files changed, 611 insertions(+) create mode 100644 anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_L3C create mode 100644 drivers/soc/hisilicon/hisi_soc_l3c.c diff --git a/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_L3C b/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_L3C new file mode 100644 index 000000000000..c0e33a62aeeb --- /dev/null +++ b/anolis/configs/L1-RECOMMEND/arm64/CONFIG_HISI_SOC_L3C @@ -0,0 +1 @@ +CONFIG_HISI_SOC_L3C=m \ No newline at end of file diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/hisi_soc_l3c.c new file mode 100644 index 000000000000..a5a8ac6baeb0 --- /dev/null +++ b/drivers/soc/hisilicon/hisi_soc_l3c.c @@ -0,0 +1,610 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for HiSilicon L3 cache. + * + * Copyright (c) 2024 HiSilicon Technologies Co., Ltd. + * Author: Yushan Wang + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hisi_soc_cache_framework.h" + +#define HISI_L3C_LOCK_CTRL 0x0530 +#define HISI_L3C_LOCK_AREA 0x0534 +#define HISI_L3C_LOCK_START_L 0x0538 +#define HISI_L3C_LOCK_START_H 0x053C + +#define HISI_L3C_DYNAMIC_AUCTRL 0x0404 + +#define HISI_L3C_LOCK_CTRL_POLL_GAP_US 10 + +#define HISI_L3C_MAX_LOCKREGION_SIZE \ + "hisilicon,l3c-max-single-lockregion-size" +#define HISI_L3C_MAX_LOCKREGION_NUM \ + "hisilicon,l3c-lockregion-num" + +/* L3C control register bit definition */ +#define HISI_L3C_LOCK_CTRL_LOCK_EN BIT(0) +#define HISI_L3C_LOCK_CTRL_LOCK_DONE BIT(1) +#define HISI_L3C_LOCK_CTRL_UNLOCK_EN BIT(2) +#define HISI_L3C_LOCK_CTRL_UNLOCK_DONE BIT(3) + +#define HISI_L3C_LOCK_MIN_SIZE (1 * 1024 * 1024) +#define HISI_L3_CACHE_LINE_SIZE 64 + +/* Allow maximum 70% of cache locked. */ +#define HISI_L3C_MAX_LOCK_SIZE(size) ((size) / 10 * 7) + +#define l3c_lock_reg_offset(reg, set) ((reg) + 16 * (set)) + +#define l3c_lock_ctrl_mask(lock_ctrl, mask) ((lock_ctrl) & (mask)) + +#define to_hisi_l3c(p) container_of((p), struct hisi_soc_l3c, comp) + +static int hisi_l3c_cpuhp_state; + +struct hisi_soc_l3c { + struct hisi_soc_comp comp; + cpumask_t associated_cpus; + + /* Stores the first address locked by each register sets. */ + struct xarray lock_sets; + /* Stores if a set of lock control register has been used. */ + u32 reg_used_map; + /* Locks reg_used_map and lock_sets to forbid overlapping access. */ + spinlock_t reg_lock; + + /* Locked memory size range. */ + size_t max_lock_size; + size_t min_lock_size; + size_t locked_size; + + /* Maximum number of locked memory size. */ + int max_lock_num; + + struct hlist_node node; + void __iomem *base; + + /* ID of Super CPU cluster on where the L3 cache locates. */ + int sccl_id; + /* ID of CPU cluster where L3 cache is located. */ + int ccl_id; +}; + +struct hisi_soc_l3c_lock_region { + phys_addr_t addr; + size_t size; +}; + +/** + * hisi_soc_l3c_alloc_lock_reg_set - Allocate an available control register set + * of L3 cache for lock & unlock operations. + * @soc_l3c: The L3C instance on which the register set will be allocated. + * @addr: The address to be locked. + * @size: The size to be locked. + * + * @return: + * - -EBUSY: If there is no available register sets. + * - -ENOMEM: If there is no available memory for lock region struct. + * - -EINVAL: If there is no available cache size for lock. + * - 0: If allocation succeeds. + * + * Maintains the resource of control registers of L3 cache. On allocation, + * the index of a spare set of registers is returned, then the address is + * stored inside for future match of unlock operation. + */ +static int hisi_soc_l3c_alloc_lock_reg_set(struct hisi_soc_l3c *soc_l3c, + phys_addr_t addr, size_t size) +{ + struct hisi_soc_l3c_lock_region *lr; + unsigned long idx; + void *entry; + + if (size > soc_l3c->max_lock_size - soc_l3c->locked_size) + return -EINVAL; + + for (idx = 0; idx < soc_l3c->max_lock_num; ++idx) { + entry = xa_load(&soc_l3c->lock_sets, idx); + if (!entry) + break; + } + + if (idx >= soc_l3c->max_lock_num) + return -EBUSY; + + lr = kzalloc(sizeof(struct hisi_soc_l3c_lock_region), GFP_KERNEL); + if (!lr) + return -ENOMEM; + + lr->addr = addr; + lr->size = size; + + entry = xa_store(&soc_l3c->lock_sets, idx, lr, GFP_KERNEL); + if (xa_is_err(entry)) { + kfree(lr); + return xa_err(entry); + } + + soc_l3c->locked_size += size; + + return idx; +} + +/** + * hisi_soc_l3c_get_locked_reg_set - Get the index of an allocated register set + * by locked address. + * @soc_l3c: The L3C instance on which the register set is allocated. + * @addr: The locked address. + * + * @return: + * - >= 0: index of register set which controls locked memory region of @addr. + * - -EINVAL: If @addr is not locked in this cache. + */ +static int hisi_soc_l3c_get_locked_reg_set(struct hisi_soc_l3c *soc_l3c, + phys_addr_t addr) +{ + struct hisi_soc_l3c_lock_region *entry; + unsigned long idx; + + xa_for_each_range(&soc_l3c->lock_sets, idx, entry, 0, + soc_l3c->max_lock_num) { + if (entry->addr == addr) + return idx; + } + return -EINVAL; +} + +/** + * hisi_soc_l3c_free_lock_reg_set - Free an allocated register set by locked + * address. + * + * @soc_l3c: The L3C instance on which the register set is allocated. + * @regset: ID of Register set to be freed. + */ +static void hisi_soc_l3c_free_lock_reg_set(struct hisi_soc_l3c *soc_l3c, + int regset) +{ + struct hisi_soc_l3c_lock_region *entry; + + if (regset < 0) + return; + + entry = xa_erase(&soc_l3c->lock_sets, regset); + if (!entry) + return; + + soc_l3c->locked_size -= entry->size; + kfree(entry); +} + +static int hisi_l3c_lock_ctrl_wait_finished(struct hisi_soc_l3c *soc_l3c, + int regset, u32 mask) +{ + u32 reg_used_map = soc_l3c->reg_used_map; + void *base = soc_l3c->base; + u32 val; + + /* + * Each HiSilicon L3 cache instance will have lock/unlock done bit set + * to 0 when first put to use even if the device is available. + * A reg_used_map is proposed to record if an instance has been called + * to lock down, then we can determine if it is available by + * reading lock/unlock done bit. + */ + if (!(reg_used_map & BIT(regset))) { + reg_used_map |= BIT(regset); + return 1; + } + + return !readl_poll_timeout_atomic( + base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset), + val, l3c_lock_ctrl_mask(val, mask), + HISI_L3C_LOCK_CTRL_POLL_GAP_US, + jiffies_to_usecs(HZ)); +} + +static int hisi_soc_l3c_do_lock(struct hisi_soc_comp *l3c_comp, + phys_addr_t addr, size_t size) +{ + struct hisi_soc_l3c *soc_l3c = to_hisi_l3c(l3c_comp); + void *base = soc_l3c->base; + int regset; + u32 ctrl; + + if (soc_l3c->max_lock_num == 1 && addr % size != 0) + return -EINVAL; + + if (size < soc_l3c->min_lock_size) + return -EINVAL; + + guard(spinlock)(&soc_l3c->reg_lock); + + regset = hisi_soc_l3c_alloc_lock_reg_set(soc_l3c, addr, size); + if (regset < 0) + return -EBUSY; + + if (!hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, + HISI_L3C_LOCK_CTRL_LOCK_DONE)) { + hisi_soc_l3c_free_lock_reg_set(soc_l3c, regset); + return -EBUSY; + } + + writel(lower_32_bits(addr), + base + l3c_lock_reg_offset(HISI_L3C_LOCK_START_L, regset)); + writel(upper_32_bits(addr), + base + l3c_lock_reg_offset(HISI_L3C_LOCK_START_H, regset)); + writel(size, base + l3c_lock_reg_offset(HISI_L3C_LOCK_AREA, regset)); + + ctrl = readl(base + HISI_L3C_DYNAMIC_AUCTRL); + ctrl |= BIT(regset); + writel(ctrl, base + HISI_L3C_DYNAMIC_AUCTRL); + + ctrl = readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + ctrl = (ctrl | HISI_L3C_LOCK_CTRL_LOCK_EN) & + ~HISI_L3C_LOCK_CTRL_UNLOCK_EN; + writel(ctrl, base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + + return 0; +} + +static int hisi_soc_l3c_poll_lock_done(struct hisi_soc_comp *l3c_comp, + phys_addr_t addr, size_t size) +{ + struct hisi_soc_l3c *soc_l3c = to_hisi_l3c(l3c_comp); + int regset; + + guard(spinlock)(&soc_l3c->reg_lock); + + regset = hisi_soc_l3c_get_locked_reg_set(soc_l3c, addr); + if (regset < 0) + return -EINVAL; + + if (!hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, + HISI_L3C_LOCK_CTRL_LOCK_DONE)) + return -ETIMEDOUT; + + return 0; +} + +static int hisi_soc_l3c_do_unlock(struct hisi_soc_comp *l3c_comp, + phys_addr_t addr) +{ + struct hisi_soc_l3c *soc_l3c = to_hisi_l3c(l3c_comp); + void *base = soc_l3c->base; + int regset; + u32 ctrl; + + guard(spinlock)(&soc_l3c->reg_lock); + + regset = hisi_soc_l3c_get_locked_reg_set(soc_l3c, addr); + if (regset < 0) + return -EINVAL; + + if (!hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, + HISI_L3C_LOCK_CTRL_UNLOCK_DONE)) + return -EBUSY; + + ctrl = readl(base + HISI_L3C_DYNAMIC_AUCTRL); + ctrl &= ~BIT(regset); + writel(ctrl, base + HISI_L3C_DYNAMIC_AUCTRL); + + ctrl = readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + ctrl = (ctrl | HISI_L3C_LOCK_CTRL_UNLOCK_EN) & + ~HISI_L3C_LOCK_CTRL_LOCK_EN; + writel(ctrl, base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + + return 0; +} + +static int hisi_soc_l3c_poll_unlock_done(struct hisi_soc_comp *l3c_comp, + phys_addr_t addr) +{ + struct hisi_soc_l3c *soc_l3c = to_hisi_l3c(l3c_comp); + int regset; + + guard(spinlock)(&soc_l3c->reg_lock); + + regset = hisi_soc_l3c_get_locked_reg_set(soc_l3c, addr); + if (regset < 0) + return -EINVAL; + + if (!hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, + HISI_L3C_LOCK_CTRL_UNLOCK_DONE)) + return -ETIMEDOUT; + + hisi_soc_l3c_free_lock_reg_set(soc_l3c, regset); + + return 0; +} + +/** + * hisi_soc_l3c_remove_locks - Remove all cache locks when the driver exits. + * + * @soc_l3c: The L3C instance on which the cache locks should be removed. + */ +static void hisi_soc_l3c_remove_locks(struct hisi_soc_l3c *soc_l3c) +{ + + void *base = soc_l3c->base; + unsigned long regset; + int timeout; + void *entry; + u32 ctrl; + + guard(spinlock)(&soc_l3c->reg_lock); + + xa_for_each(&soc_l3c->lock_sets, regset, entry) { + timeout = hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, + HISI_L3C_LOCK_CTRL_UNLOCK_DONE); + + ctrl = readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, + regset)); + ctrl = (ctrl | HISI_L3C_LOCK_CTRL_UNLOCK_EN) & + ~HISI_L3C_LOCK_CTRL_LOCK_EN; + writel(ctrl, base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, + regset)); + + timeout = hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, + HISI_L3C_LOCK_CTRL_UNLOCK_DONE); + + /* + * If cache lock remove fails, inform user since the removal of + * driver cannot fail. + */ + if (timeout) + pr_err("failed to remove %lu-th cache lock.\n", regset); + } +} + +static int hisi_soc_l3c_init_lock_capacity(struct hisi_soc_l3c *soc_l3c, + struct device *dev) +{ + int ret; + u32 val; + + ret = device_property_read_u32(dev, HISI_L3C_MAX_LOCKREGION_NUM, &val); + if (ret || val <= 0) + return -EINVAL; + + soc_l3c->max_lock_num = val; + + ret = device_property_read_u32(dev, HISI_L3C_MAX_LOCKREGION_SIZE, &val); + if (ret || val <= 0) + return -EINVAL; + + soc_l3c->max_lock_size = HISI_L3C_MAX_LOCK_SIZE(val); + + soc_l3c->min_lock_size = soc_l3c->max_lock_num == 1 + ? HISI_L3C_LOCK_MIN_SIZE + : HISI_L3_CACHE_LINE_SIZE; + + return 0; +} + +static int hisi_soc_l3c_init_topology(struct hisi_soc_l3c *soc_l3c, + struct device *dev) +{ + soc_l3c->sccl_id = -1; + soc_l3c->ccl_id = -1; + + if (device_property_read_u32(dev, "hisilicon,scl-id", &soc_l3c->sccl_id) + || soc_l3c->sccl_id < 0) + return -EINVAL; + + if (device_property_read_u32(dev, "hisilicon,ccl-id", &soc_l3c->ccl_id) + || soc_l3c->ccl_id < 0) + return -EINVAL; + + return 0; +} + +static void hisi_init_associated_cpus(struct hisi_soc_l3c *soc_l3c) +{ + if (!cpumask_empty(&soc_l3c->associated_cpus)) + return; + cpumask_clear(&soc_l3c->associated_cpus); + cpumask_copy(&soc_l3c->comp.affinity_mask, &soc_l3c->associated_cpus); +} + +static struct hisi_soc_comp_ops hisi_soc_l3c_comp_ops = { + .do_lock = hisi_soc_l3c_do_lock, + .poll_lock_done = hisi_soc_l3c_poll_lock_done, + .do_unlock = hisi_soc_l3c_do_unlock, + .poll_unlock_done = hisi_soc_l3c_poll_unlock_done, +}; + +static struct hisi_soc_comp hisi_soc_l3c_comp = { + .ops = &hisi_soc_l3c_comp_ops, + .comp_type = BIT(HISI_SOC_L3C), +}; + +static int hisi_soc_l3c_probe(struct platform_device *pdev) +{ + struct hisi_soc_l3c *soc_l3c; + struct resource *mem; + int ret = 0; + + soc_l3c = devm_kzalloc(&pdev->dev, sizeof(*soc_l3c), GFP_KERNEL); + if (!soc_l3c) + return -ENOMEM; + + platform_set_drvdata(pdev, soc_l3c); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENODEV; + + /* + * L3C cache driver share the same register region with L3C uncore PMU + * driver in hardware's perspective, none of them should reserve the + * resource to itself only. Here exclusive access verification is + * avoided by calling devm_ioremap instead of devm_ioremap_resource to + * allow both drivers to exist at the same time. + */ + soc_l3c->base = devm_ioremap(&pdev->dev, mem->start, + resource_size(mem)); + if (IS_ERR_OR_NULL(soc_l3c->base)) + return PTR_ERR(soc_l3c->base); + + soc_l3c->comp = hisi_soc_l3c_comp; + soc_l3c->locked_size = 0; + spin_lock_init(&soc_l3c->reg_lock); + xa_init(&soc_l3c->lock_sets); + + ret = hisi_soc_l3c_init_lock_capacity(soc_l3c, &pdev->dev); + if (ret) + goto err_xa; + + hisi_init_associated_cpus(soc_l3c); + + ret = hisi_soc_l3c_init_topology(soc_l3c, &pdev->dev); + if (ret) + goto err_xa; + + ret = cpuhp_state_add_instance(hisi_l3c_cpuhp_state, &soc_l3c->node); + if (ret) + goto err_xa; + + ret = hisi_soc_comp_inst_add(&soc_l3c->comp); + if (ret) + goto err_hotplug; + + return ret; + +err_hotplug: + cpuhp_state_remove_instance_nocalls(hisi_l3c_cpuhp_state, + &soc_l3c->node); + +err_xa: + xa_destroy(&soc_l3c->lock_sets); + return ret; +} + +static int hisi_soc_l3c_remove(struct platform_device *pdev) +{ + struct hisi_soc_l3c *soc_l3c = platform_get_drvdata(pdev); + unsigned long idx; + struct hisi_soc_l3c_lock_region *entry; + + hisi_soc_l3c_remove_locks(soc_l3c); + + hisi_soc_comp_inst_del(&soc_l3c->comp); + + cpuhp_state_remove_instance_nocalls(hisi_l3c_cpuhp_state, + &soc_l3c->node); + + xa_for_each(&soc_l3c->lock_sets, idx, entry) { + entry = xa_erase(&soc_l3c->lock_sets, idx); + kfree(entry); + } + + xa_destroy(&soc_l3c->lock_sets); + + return 0; +} + +static void hisi_read_sccl_and_ccl_id(int *scclp, int *cclp) +{ + u64 mpidr = read_cpuid_mpidr(); + int aff3 = MPIDR_AFFINITY_LEVEL(mpidr, 3); + int aff2 = MPIDR_AFFINITY_LEVEL(mpidr, 2); + int aff1 = MPIDR_AFFINITY_LEVEL(mpidr, 1); + int sccl, ccl; + + if (mpidr & MPIDR_MT_BITMASK) { + sccl = aff3; + ccl = aff2; + } else { + sccl = aff2; + ccl = aff1; + } + + *scclp = sccl; + *cclp = ccl; +} + +static bool hisi_soc_l3c_is_associated(struct hisi_soc_l3c *soc_l3c) +{ + int sccl_id, ccl_id; + + hisi_read_sccl_and_ccl_id(&sccl_id, &ccl_id); + return sccl_id == soc_l3c->sccl_id && ccl_id == soc_l3c->ccl_id; +} + +static int hisi_soc_l3c_online_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct hisi_soc_l3c *soc_l3c = + hlist_entry_safe(node, struct hisi_soc_l3c, node); + + if (!cpumask_test_cpu(cpu, &soc_l3c->associated_cpus)) { + if (!(hisi_soc_l3c_is_associated(soc_l3c))) + return 0; + + cpumask_set_cpu(cpu, &soc_l3c->associated_cpus); + cpumask_copy(&soc_l3c->comp.affinity_mask, + &soc_l3c->associated_cpus); + } + return 0; +} + +static const struct acpi_device_id hisi_l3c_acpi_match[] = { + { "HISI0501", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, hisi_l3c_acpi_match); + +static struct platform_driver hisi_soc_l3c_driver = { + .driver = { + .name = "hisi_soc_l3c", + .acpi_match_table = hisi_l3c_acpi_match, + }, + .probe = hisi_soc_l3c_probe, + .remove = hisi_soc_l3c_remove, +}; + +static int __init hisi_soc_l3c_init(void) +{ + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "hisi_soc_l3c", + hisi_soc_l3c_online_cpu, NULL); + if (ret < 0) + return ret; + hisi_l3c_cpuhp_state = ret; + + ret = platform_driver_register(&hisi_soc_l3c_driver); + if (ret) + cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN); + + return ret; +} +module_init(hisi_soc_l3c_init); + +static void __exit hisi_soc_l3c_exit(void) +{ + platform_driver_unregister(&hisi_soc_l3c_driver); + cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN); +} +module_exit(hisi_soc_l3c_exit); + +MODULE_DESCRIPTION("Driver supporting cache lockdown for Hisilicon L3 cache"); +MODULE_AUTHOR("Yushan Wang "); +MODULE_LICENSE("GPL"); -- Gitee From b940b5ab8403ac1d47091bc1b5bc80d612e2e5be Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:49 +0800 Subject: [PATCH 08/21] soc cache: cleanup: replace dynamically allocated param with local variable ANBZ: #45460 commit 4564d7dcb0f64c912628efd821e1ea8817a27c93 openEuler Replace dynamically allocated param with local variable to save unnecessary procedure. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- .../soc/hisilicon/hisi_soc_cache_framework.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 11795332f52f..94e5f6466777 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -502,29 +502,22 @@ static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, static long hisi_soc_cache_mgmt_ioctl(struct file *file, u32 cmd, unsigned long arg) { - struct hisi_soc_cache_ioctl_param *param = - kzalloc(sizeof(struct hisi_soc_cache_ioctl_param), GFP_KERNEL); + struct hisi_soc_cache_ioctl_param param; long ret; - if (!param) - return -ENOMEM; - - if (copy_from_user(param, (void __user *)arg, sizeof(*param))) { - ret = -EFAULT; - goto out; - } + if (copy_from_user(¶m, (void __user *)arg, sizeof(param))) + return -EFAULT; switch (cmd) { case HISI_CACHE_MAINTAIN: - ret = __hisi_soc_cache_maintain(param->addr, param->size, - param->op_type); + ret = __hisi_soc_cache_maintain(param.addr, param.size, + param.op_type); break; default: ret = -EINVAL; break; } -out: - kfree(param); + return ret; } -- Gitee From 71d00c007309d7fc08373c621923d836abc4d6ab Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Tue, 9 Dec 2025 20:59:50 +0800 Subject: [PATCH 09/21] soc_cache: Fix incorrect use of cpuhp_remove_multi_state parameter ANBZ: #45460 commit 6af9c8827f3d759b5d8cafe89c17426d0818622d openEuler The cpuhp_remove_multi_state was called with CPUHP_AP_ONLINE_DYN instead of the dynamically allocated hisi_l3c_cpuhp_state. This may lead to improper CPU hotplug state removal. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yifan Wu Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_l3c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/hisi_soc_l3c.c index a5a8ac6baeb0..e0bf6cc5b47d 100644 --- a/drivers/soc/hisilicon/hisi_soc_l3c.c +++ b/drivers/soc/hisilicon/hisi_soc_l3c.c @@ -592,7 +592,7 @@ static int __init hisi_soc_l3c_init(void) ret = platform_driver_register(&hisi_soc_l3c_driver); if (ret) - cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN); + cpuhp_remove_multi_state(hisi_l3c_cpuhp_state); return ret; } @@ -601,7 +601,7 @@ module_init(hisi_soc_l3c_init); static void __exit hisi_soc_l3c_exit(void) { platform_driver_unregister(&hisi_soc_l3c_driver); - cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN); + cpuhp_remove_multi_state(hisi_l3c_cpuhp_state); } module_exit(hisi_soc_l3c_exit); -- Gitee From c7e46871eb66f899a891f1830d7d635897330352 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Tue, 9 Dec 2025 20:59:51 +0800 Subject: [PATCH 10/21] soc_cache: Fix error code returning from hisi_soc_l3c_do_lock ANBZ: #45460 commit 2c232e6ad9804a8b7a657c0eaea34b999dd139c7 openEuler Fix the issue by returning the original error code from hisi_soc_l3c_alloc_lock_reg_set, which makes it possible for the caller to distinguish between different failure scenarios. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yifan Wu Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_l3c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/hisi_soc_l3c.c index e0bf6cc5b47d..258502c09e1b 100644 --- a/drivers/soc/hisilicon/hisi_soc_l3c.c +++ b/drivers/soc/hisilicon/hisi_soc_l3c.c @@ -239,7 +239,7 @@ static int hisi_soc_l3c_do_lock(struct hisi_soc_comp *l3c_comp, regset = hisi_soc_l3c_alloc_lock_reg_set(soc_l3c, addr, size); if (regset < 0) - return -EBUSY; + return regset; if (!hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, HISI_L3C_LOCK_CTRL_LOCK_DONE)) { -- Gitee From abc228d4eeeacd2db19f4523db553ccd0d294385 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:52 +0800 Subject: [PATCH 11/21] soc cache: cleanup: fix memory leakage on error path ANBZ: #45460 commit eae8c03a003ca9fb05ed98700758b7c145ae41d4 openEuler Fix memory leakage on error path. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 94e5f6466777..692bc481b22f 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -421,8 +421,10 @@ static int hisi_soc_cache_mmap(struct file *file, struct vm_area_struct *vma) if (ret) goto out_clr; - if (vma->vm_pgoff > PAGE_SIZE) - return -EINVAL; + if (vma->vm_pgoff > PAGE_SIZE) { + ret = -EINVAL; + goto out_clr; + } ret = remap_pfn_range(vma, vma->vm_start, (addr >> PAGE_SHIFT) + vma->vm_pgoff, -- Gitee From 13c9568e96fc180b9e0e42692a5b71202a720fde Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:53 +0800 Subject: [PATCH 12/21] soc cache: cleanup: move judgement of soc cache dev into lock protection ANBZ: #45460 commit 1024d6ddd737650dc368f8f586b976aad34fd64b openEuler SoC cache dev array is under the protection of the spinlock, hence the verification should also be protected. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 692bc481b22f..bef1e95fa041 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -59,12 +59,12 @@ static int hisi_soc_cache_lock(int cpu, phys_addr_t addr, size_t size) struct list_head *head; int ret = -ENOMEM; + guard(spinlock)(&soc_cache_devs[HISI_SOC_L3C].lock); + /* Avoid null pointer when there is no instance onboard. */ if (soc_cache_devs[HISI_SOC_L3C].inst_num <= 0) return ret; - guard(spinlock)(&soc_cache_devs[HISI_SOC_L3C].lock); - /* Iterate L3C instances to perform operation, break loop once found. */ head = &soc_cache_devs[HISI_SOC_L3C].node; list_for_each_entry(inst, head, node) { @@ -92,12 +92,12 @@ static int hisi_soc_cache_unlock(int cpu, phys_addr_t addr) struct list_head *head; int ret = 0; + guard(spinlock)(&soc_cache_devs[HISI_SOC_L3C].lock); + /* Avoid null pointer when there is no instance onboard. */ if (soc_cache_devs[HISI_SOC_L3C].inst_num <= 0) return ret; - guard(spinlock)(&soc_cache_devs[HISI_SOC_L3C].lock); - /* Iterate L3C instances to perform operation, break loop once found. */ head = &soc_cache_devs[HISI_SOC_L3C].node; list_for_each_entry(inst, head, node) { -- Gitee From 814f307ac6125d60be5d0408cbdc6647ecaeac99 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:54 +0800 Subject: [PATCH 13/21] soc cache: cleanup: avoid tag addr from interfering range validation ANBZ: #45460 commit adf0edde1b2ca29b07f4acd28a7ff0ec3402dca9 openEuler The raw address may still have memory tag applied on the high bits of the address, which may interfere the check here. Use untagged variable start to do the validation instead. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index bef1e95fa041..68938e020891 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -483,7 +483,7 @@ static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, vma = vma_lookup(current->mm, vaddr); - if (!range_in_vma(vma, vaddr, vaddr + size)) { + if (!range_in_vma(vma, start, vaddr + size)) { ret = -EINVAL; goto out; } -- Gitee From 6e8fc788c04edfd90266f58aaf47da92a7a61e34 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:55 +0800 Subject: [PATCH 14/21] soc cache: cleanup: Change type of mnt_type ANBZ: #45460 commit 03391a88702e500501676fe339aee94c186bad8a openEuler The type of mnt_type is incorrectly forced changed to unsigned int, which adds the implication that size of unsigned int has be the same as enum. Remove this complication by change the type of local variable mnt_type. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 68938e020891..cb42a010efc7 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -154,9 +154,11 @@ static int hisi_soc_cache_maint_pte_entry(pte_t *pte, unsigned long addr, unsigned long next, struct mm_walk *walk) { #ifdef HISI_SOC_CACHE_LLT - unsigned int mnt_type = *((unsigned int *)walk->priv); + enum hisi_soc_cache_maint_type mnt_type = + *((enum hisi_soc_cache_maint_type *)walk->priv); #else - unsigned int mnt_type = *((unsigned int *)walk->private); + enum hisi_soc_cache_maint_type mnt_type = + *((enum hisi_soc_cache_maint_type *)walk->private); #endif size_t size = next - addr; phys_addr_t paddr; -- Gitee From 7da787f86316eececd019d7739249f07f4a6f284 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:56 +0800 Subject: [PATCH 15/21] soc cache: cleanup: Remove the redundant check of vm_pgoff ANBZ: #45460 commit b32ab547fc1c3e703faf24f342839dc13fc7630a openEuler vma->vm_pgoff has the unit of PAGE_SIZE, this variable is used to represent the offset in mapped file in pages' granuality. The check here is non-sense, and should be shreded. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index cb42a010efc7..92f2da675d41 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -423,11 +423,6 @@ static int hisi_soc_cache_mmap(struct file *file, struct vm_area_struct *vma) if (ret) goto out_clr; - if (vma->vm_pgoff > PAGE_SIZE) { - ret = -EINVAL; - goto out_clr; - } - ret = remap_pfn_range(vma, vma->vm_start, (addr >> PAGE_SHIFT) + vma->vm_pgoff, size, vma->vm_page_prot); -- Gitee From 5c144cc6fe980e6cd9c2ebe95f08116d0cd6f920 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Tue, 9 Dec 2025 20:59:57 +0800 Subject: [PATCH 16/21] soc_cache: Fix component removal order to avoid race condition ANBZ: #45460 commit 4b2aed4250e02a4064618313ca3ef8b43022faf0 openEuler Fix the order to first call hisi_soc_comp_inst_del to ensure no further operations can be triggered, and then call hisi_soc_l3c_remove_locks to safely release the resources. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yifan Wu Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_l3c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/hisi_soc_l3c.c index 258502c09e1b..3e0c6686da0e 100644 --- a/drivers/soc/hisilicon/hisi_soc_l3c.c +++ b/drivers/soc/hisilicon/hisi_soc_l3c.c @@ -504,13 +504,13 @@ static int hisi_soc_l3c_remove(struct platform_device *pdev) unsigned long idx; struct hisi_soc_l3c_lock_region *entry; - hisi_soc_l3c_remove_locks(soc_l3c); - hisi_soc_comp_inst_del(&soc_l3c->comp); cpuhp_state_remove_instance_nocalls(hisi_l3c_cpuhp_state, &soc_l3c->node); + hisi_soc_l3c_remove_locks(soc_l3c); + xa_for_each(&soc_l3c->lock_sets, idx, entry) { entry = xa_erase(&soc_l3c->lock_sets, idx); kfree(entry); -- Gitee From a004e8bd1f937ea8d740ced16ff2abf80dc67be0 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:58 +0800 Subject: [PATCH 17/21] soc cache: Check address while walking pages ANBZ: #45460 commit 3d21633030f156a924710e73c10342165be63f08 openEuler While walking VMA pages, the starting address of a page is validated while ending address is not. If user requests cache maintenance over a memory region, that its start address is not aligned to page size, and the modular of memory region size to page size is smaller than the starting address page offset, cache maintenance may be out of desired region, for example: If user requests cache maintenance to address 0x1002 with size 0x1001, the desired maintain range should be 0x1002-0x2003. But when walking the pages to find the physical address of 0x1001, the driver will only check if 0x1000 is a valid PTE, and if so, maintain of 0x1002-0x2003 will be performed even if 0x2000 does not exists. Fix this by adding a check when walking the page. Some refactor is also applied by changing the interfaces to let walk page callback get the total maintain range. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- .../soc/hisilicon/hisi_soc_cache_framework.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 92f2da675d41..d2dfba19e4c7 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -154,21 +154,24 @@ static int hisi_soc_cache_maint_pte_entry(pte_t *pte, unsigned long addr, unsigned long next, struct mm_walk *walk) { #ifdef HISI_SOC_CACHE_LLT - enum hisi_soc_cache_maint_type mnt_type = - *((enum hisi_soc_cache_maint_type *)walk->priv); + struct hisi_soc_cache_ioctl_param *param = + (struct hisi_soc_cache_ioctl_param *)walk->priv; #else - enum hisi_soc_cache_maint_type mnt_type = - *((enum hisi_soc_cache_maint_type *)walk->private); + struct hisi_soc_cache_ioctl_param *param = + (struct hisi_soc_cache_ioctl_param *)walk->private; #endif size_t size = next - addr; phys_addr_t paddr; + if (next > param->addr + param->size) + return -EINVAL; + if (!pte_present(ptep_get(pte))) return -EINVAL; paddr = PFN_PHYS(pte_pfn(*pte)) + offset_in_page(addr); - return hisi_soc_cache_maintain(paddr, size, mnt_type); + return hisi_soc_cache_maintain(paddr, size, param->op_type); } static const struct mm_walk_ops hisi_soc_cache_maint_walk = { @@ -459,28 +462,26 @@ static int hisi_soc_cache_mmap(struct file *file, struct vm_area_struct *vma) return ret; } -static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, - enum hisi_soc_cache_maint_type mnt_type) +static int __hisi_soc_cache_maintain(struct hisi_soc_cache_ioctl_param *param) { - unsigned long start = untagged_addr(vaddr); + unsigned long start = untagged_addr(param->addr); struct vm_area_struct *vma; int ret = 0; /* MakeInvalid is not allowed for calls from userspace. */ - if (mnt_type >= HISI_CACHE_MAINT_MAKEINVALID) + if (param->op_type >= HISI_CACHE_MAINT_MAKEINVALID) return -EINVAL; /* Prevent overflow of vaddr + size. */ - if (!size || vaddr + size < vaddr) + if (!param->size || start + param->size < start) return -EINVAL; ret = mmap_read_lock_killable(current->mm); if (ret) return ret; - vma = vma_lookup(current->mm, vaddr); - - if (!range_in_vma(vma, start, vaddr + size)) { + vma = vma_lookup(current->mm, param->addr); + if (!range_in_vma(vma, start, start + param->size)) { ret = -EINVAL; goto out; } @@ -491,8 +492,8 @@ static int __hisi_soc_cache_maintain(unsigned long __user vaddr, size_t size, goto out; } - ret = walk_page_range(current->mm, start, start + size, - &hisi_soc_cache_maint_walk, &mnt_type); + ret = walk_page_range(current->mm, start, start + param->size, + &hisi_soc_cache_maint_walk, param); out: mmap_read_unlock(current->mm); @@ -509,8 +510,7 @@ static long hisi_soc_cache_mgmt_ioctl(struct file *file, u32 cmd, unsigned long switch (cmd) { case HISI_CACHE_MAINTAIN: - ret = __hisi_soc_cache_maintain(param.addr, param.size, - param.op_type); + ret = __hisi_soc_cache_maintain(¶m); break; default: ret = -EINVAL; -- Gitee From 1884d0353a8ce222b37bfc14238598ec7de9b161 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 20:59:59 +0800 Subject: [PATCH 18/21] soc cache: fix walk page parameter and drop incorrect check ANBZ: #45460 commit 346d400ed19b8fa04fd0ce20b67007cf33c7aaad openEuler During walking pages, if the memory region assigned is within a pmd, the page offset will be reserved, but if multiple pmds are involved, the offset will not be reserved, causing incorrect failure of page range check and the required range. Fix this by align the requested memory region to PAGE_SIZE, and eliminate the unnecessary check. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- .../soc/hisilicon/hisi_soc_cache_framework.c | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index d2dfba19e4c7..52bd2dc9fa84 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -154,23 +154,17 @@ static int hisi_soc_cache_maint_pte_entry(pte_t *pte, unsigned long addr, unsigned long next, struct mm_walk *walk) { #ifdef HISI_SOC_CACHE_LLT - struct hisi_soc_cache_ioctl_param *param = - (struct hisi_soc_cache_ioctl_param *)walk->priv; + struct hisi_soc_cache_ioctl_param *param = walk->priv; #else - struct hisi_soc_cache_ioctl_param *param = - (struct hisi_soc_cache_ioctl_param *)walk->private; + struct hisi_soc_cache_ioctl_param *param = walk->private; #endif - size_t size = next - addr; - phys_addr_t paddr; - - if (next > param->addr + param->size) - return -EINVAL; + size_t size = min(next - addr, param->size + param->addr - addr); + unsigned long offset = offset_in_page(max(addr, param->addr)); + phys_addr_t paddr = PFN_PHYS(pte_pfn(*pte)) + offset; if (!pte_present(ptep_get(pte))) return -EINVAL; - paddr = PFN_PHYS(pte_pfn(*pte)) + offset_in_page(addr); - return hisi_soc_cache_maintain(paddr, size, param->op_type); } @@ -492,9 +486,9 @@ static int __hisi_soc_cache_maintain(struct hisi_soc_cache_ioctl_param *param) goto out; } - ret = walk_page_range(current->mm, start, start + param->size, + ret = walk_page_range(current->mm, PAGE_ALIGN_DOWN(start), + PAGE_ALIGN(start + param->size), &hisi_soc_cache_maint_walk, param); - out: mmap_read_unlock(current->mm); return ret; -- Gitee From 4ddf3412a397d0ab2b8760ce1c127c0ffa68b379 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 21:00:00 +0800 Subject: [PATCH 19/21] soc cache: Drop redundant vm_pgoff ANBZ: #45460 commit 012bbaaa8480e808759e2b957ffb37dd3f28a5b9 openEuler Drop redundant vm_pgoff since every mmap will have a new vma being created, apply cache lock only at the beginning of a vma. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_cache_framework.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_cache_framework.c b/drivers/soc/hisilicon/hisi_soc_cache_framework.c index 52bd2dc9fa84..40d5a5e942da 100644 --- a/drivers/soc/hisilicon/hisi_soc_cache_framework.c +++ b/drivers/soc/hisilicon/hisi_soc_cache_framework.c @@ -420,9 +420,8 @@ static int hisi_soc_cache_mmap(struct file *file, struct vm_area_struct *vma) if (ret) goto out_clr; - ret = remap_pfn_range(vma, vma->vm_start, - (addr >> PAGE_SHIFT) + vma->vm_pgoff, - size, vma->vm_page_prot); + ret = remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, size, + vma->vm_page_prot); if (ret) goto out_page; -- Gitee From da8e482c12092ba12658c1bafd330dfa4da7e06e Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 21:00:01 +0800 Subject: [PATCH 20/21] soc cache: Don't poll before removing all locks ANBZ: #45460 commit 107e5d07a336ea2997a74535a34e1fa714f0e27c openEuler Firstly, all register operations and polls are guraded by the spinlock, so operations of registers in parallel is not possible. Thus, the polling for completion before removing all locks is redundant. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/hisi_soc_l3c.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/hisi_soc_l3c.c index 3e0c6686da0e..0aec6766b34b 100644 --- a/drivers/soc/hisilicon/hisi_soc_l3c.c +++ b/drivers/soc/hisilicon/hisi_soc_l3c.c @@ -352,9 +352,6 @@ static void hisi_soc_l3c_remove_locks(struct hisi_soc_l3c *soc_l3c) guard(spinlock)(&soc_l3c->reg_lock); xa_for_each(&soc_l3c->lock_sets, regset, entry) { - timeout = hisi_l3c_lock_ctrl_wait_finished(soc_l3c, regset, - HISI_L3C_LOCK_CTRL_UNLOCK_DONE); - ctrl = readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); ctrl = (ctrl | HISI_L3C_LOCK_CTRL_UNLOCK_EN) & -- Gitee From f308e00927cb550cac14ab63eef3459d7f26f6c5 Mon Sep 17 00:00:00 2001 From: Yushan Wang Date: Tue, 9 Dec 2025 21:00:02 +0800 Subject: [PATCH 21/21] soc cache: Add compilation config for hisi_soc_l3c ANBZ: #45460 commit 718937e27ea86125c4ef32ba724748426d457c33 openEuler Add compilation config for hisi_soc_l3c driver. Fixes: e6ecc3b028b8 ("soc cache: Add framework driver for HiSilicon SoC cache") Signed-off-by: Yushan Wang Signed-off-by: Hongye Lin Signed-off-by: qiushengming Signed-off-by: zhangxinghao --- drivers/soc/hisilicon/Kconfig | 11 +++++++++++ drivers/soc/hisilicon/Makefile | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 6859a6cd0e96..419aede252fa 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -29,6 +29,17 @@ config HISI_SOC_CACHE If either HiSilicon L3 cache driver or HiSilicon Hydra Home Agent driver is needed, say yes. +config HISI_SOC_L3C + tristate "HiSilicon L3 Cache device driver" + depends on ARM64 && ACPI || COMPILE_TEST + depends on HISI_SOC_CACHE + help + This driver provides the functions to lock L3 cache entries from + being evicted for better performance. + + This driver can be built as a module. If so, the module will be + called hisi_soc_l3c. + config HISI_SOC_HHA tristate "HiSilicon Hydra Home Agent (HHA) device driver" depends on ARM64 && ACPI || COMPILE_TEST diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile index 0d3bcdbec6b8..497c66ab8b85 100644 --- a/drivers/soc/hisilicon/Makefile +++ b/drivers/soc/hisilicon/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_KUNPENG_HCCS) += kunpeng_hccs.o obj-$(CONFIG_HISI_SOC_CACHE) += hisi_soc_cache_framework.o obj-$(CONFIG_HISI_SOC_HHA) += hisi_soc_hha.o +obj-$(CONFIG_HISI_SOC_L3C) += hisi_soc_l3c.o -- Gitee