From: Ma Wupeng mawupeng1@huawei.com
Add support for l3t & l0.
Last Level Cache driver for platforms such Kunpeng 920. This provides interfaces to enable LLC cache lockdown.
L0 driver for platforms such Kunpeng 920. This provides interfaces to for user to alloc and lock memory.
Changelog since v1: - return -EINVAL if sccl_to_node_id return err. - code refactoring in hisi_lockdown.c
Changelog since v2: - code cleanup in hisi_lockdown.c
Changelog since v3: - adjusting the patch order - cleanup in l3t.c - rename get_page_policy_node to get_vma_policy_node - export symbol cpu_logical_map without GPL
Changelog since v4: - fix UAF.
Ma Wupeng (6): export symbol alloc_contig_pages arm64: export cpu_logical_map mm/mempolicy: Add and export get_page_policy_node hisi: l3t: Add L3 cache driver for hisi hisi: l0: Add support for l0 arm64: config: Enable hisi l3t & l0 by default
arch/arm64/configs/openeuler_defconfig | 2 + arch/arm64/kernel/setup.c | 1 + drivers/soc/hisilicon/Kconfig | 18 ++ drivers/soc/hisilicon/Makefile | 3 + drivers/soc/hisilicon/hisi_l0.c | 173 ++++++++++++++++ drivers/soc/hisilicon/hisi_l3t.h | 45 +++++ drivers/soc/hisilicon/hisi_lockdown.c | 140 +++++++++++++ drivers/soc/hisilicon/l3t.c | 263 +++++++++++++++++++++++++ include/linux/mempolicy.h | 4 + mm/mempolicy.c | 23 +++ mm/page_alloc.c | 1 + 11 files changed, 673 insertions(+) create mode 100644 drivers/soc/hisilicon/hisi_l0.c create mode 100644 drivers/soc/hisilicon/hisi_l3t.h create mode 100644 drivers/soc/hisilicon/hisi_lockdown.c create mode 100644 drivers/soc/hisilicon/l3t.c
From: Ma Wupeng mawupeng1@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9UDJX
--------------------------------
Commit b951aaff5035 (mm: enable page allocation tagging) export alloc_contig_pages in mainline linux, in order to alloc continue page which buddy system can not handle. Export it.
Signed-off-by: Ma Wupeng mawupeng1@huawei.com --- mm/page_alloc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 1ba392f11e6b..8dc3ba5bd56c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -9356,6 +9356,7 @@ struct page *alloc_contig_pages(unsigned long nr_pages, gfp_t gfp_mask, } return NULL; } +EXPORT_SYMBOL(alloc_contig_pages); #endif /* CONFIG_CONTIG_ALLOC */
void free_contig_range(unsigned long pfn, unsigned int nr_pages)
From: Ma Wupeng mawupeng1@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9UDJX
--------------------------------
cpu_logical_map or MPIDR is used to store cpu's affinity info, export it.
Signed-off-by: Ma Wupeng mawupeng1@huawei.com --- arch/arm64/kernel/setup.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 2148f5cbb5d0..18e457bbb7a3 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -358,6 +358,7 @@ u64 cpu_logical_map(int cpu) { return __cpu_logical_map[cpu]; } +EXPORT_SYMBOL(cpu_logical_map);
void __init __no_sanitize_address setup_arch(char **cmdline_p) {
From: Ma Wupeng mawupeng1@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9UDJX
--------------------------------
Function get_page_policy_node is used to return a suitable nid for order-0 page allocation.
Signed-off-by: Ma Wupeng mawupeng1@huawei.com --- include/linux/mempolicy.h | 4 ++++ mm/mempolicy.c | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index d4920e4a3e38..40abd3957294 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -161,6 +161,10 @@ extern nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *policy);
extern unsigned int mempolicy_slab_node(void);
+int get_vma_policy_node(struct vm_area_struct *vma, unsigned long addr, + gfp_t gfp_flags, struct mempolicy **mpol, + nodemask_t **nodemask); + extern enum zone_type policy_zone;
static inline void check_highest_zone(enum zone_type k) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 81bd26fb661f..f7c1cda0a9fe 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2198,6 +2198,29 @@ static inline unsigned interleave_nid(struct mempolicy *pol, return interleave_nodes(pol); }
+/* get policy node for order-0 page */ +int get_vma_policy_node(struct vm_area_struct *vma, unsigned long addr, + gfp_t gfp_flags, struct mempolicy **mpol, + nodemask_t **nodemask) +{ + int nid, mode; + + *mpol = get_vma_policy(vma, addr); + *nodemask = NULL; + mode = (*mpol)->mode; + + if (unlikely(mode == MPOL_INTERLEAVE)) { + nid = interleave_nid(*mpol, vma, addr, PAGE_SHIFT); + } else { + nid = policy_node(gfp_flags, *mpol, numa_node_id()); + if ((*mpol)->mode == MPOL_BIND || mode == MPOL_PREFERRED_MANY) + *nodemask = &(*mpol)->v.nodes; + } + + return nid; +} +EXPORT_SYMBOL_GPL(get_vma_policy_node); + #ifdef CONFIG_HUGETLBFS /* * huge_node(@vma, @addr, @gfp_flags, @mpol)
From: Ma Wupeng mawupeng1@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9UDJX
--------------------------------
Last Level Cache driver for platforms such Kunpeng 920. This provides interfaces to enable LLC cache lockdown.
Signed-off-by: Ma Wupeng mawupeng1@huawei.com --- drivers/soc/hisilicon/Kconfig | 9 + drivers/soc/hisilicon/Makefile | 2 + drivers/soc/hisilicon/hisi_l3t.h | 45 +++++ drivers/soc/hisilicon/hisi_lockdown.c | 140 ++++++++++++++ drivers/soc/hisilicon/l3t.c | 263 ++++++++++++++++++++++++++ 5 files changed, 459 insertions(+) create mode 100644 drivers/soc/hisilicon/hisi_l3t.h create mode 100644 drivers/soc/hisilicon/hisi_lockdown.c create mode 100644 drivers/soc/hisilicon/l3t.c
diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 45754528873e..19c4f4602d51 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -54,4 +54,13 @@ config HISI_HBMDEV_ACLS
If not sure say no.
+config HISI_L3T + tristate "Add support for l3t" + depends on ARM64 && ACPI + help + Last Level Cache driver for platforms such Kunpeng 920. This provides + interfaces to enable LLC cache lockdown. + + If not sure say no. + endmenu diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile index e0f966d1ed6d..022d83eccc79 100644 --- a/drivers/soc/hisilicon/Makefile +++ b/drivers/soc/hisilicon/Makefile @@ -4,3 +4,5 @@ obj-$(CONFIG_KUNPENG_HCCS) += kunpeng_hccs.o obj-$(CONFIG_HISI_HBMDEV) += hisi_hbmdev.o obj-$(CONFIG_HISI_HBMCACHE) += hisi_hbmcache.o obj-$(CONFIG_ARM64_PBHA) += pbha.o +hisi_l3t-objs := hisi_lockdown.o l3t.o +obj-$(CONFIG_HISI_L3T) += hisi_l3t.o diff --git a/drivers/soc/hisilicon/hisi_l3t.h b/drivers/soc/hisilicon/hisi_l3t.h new file mode 100644 index 000000000000..422e8a4b04bc --- /dev/null +++ b/drivers/soc/hisilicon/hisi_l3t.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Huawei Technologies Co., Ltd. 2024. All rights reserved. + */ + +#ifndef _HISI_L3T_H +#define _HISI_L3T_H + +/* L3T register definition */ +#define L3T_VERSION 0x1cf0 +#define L3T_LOCK_CTRL 0x0440 +#define L3T_LOCK_AREA 0x0444 +#define L3T_LOCK_START_L 0x0448 +#define L3T_LOCK_START_H 0x044C +#define L3T_LOCK_STEP 0x10 + +#define L3T_REG_NUM 4 + +extern struct mutex l3t_mutex; + +struct hisi_l3t { + struct device *dev; + void __iomem *base; + int sccl_id; + int ccl_id; + int nid; +}; + +struct hisi_sccl { + int nid; /* numa node id */ + int ccl_cnt; /* ccl count for this sccl */ + struct hisi_l3t **l3t; +}; + +struct hisi_sccl *hisi_l3t_get_sccl(int nid); +void hisi_l3t_read(struct hisi_l3t *l3t, int slot_idx, unsigned long *s_addr, + int *size); +void hisi_l3t_lock(struct hisi_l3t *l3t, int slot_idx, unsigned long s_addr, + int size); +void hisi_l3t_unlock(struct hisi_l3t *l3t, int slot_idx); + +int l3t_shared_lock(int nid, unsigned long pfn, unsigned long size); +int l3t_shared_unlock(int nid, unsigned long pfn, unsigned long size); + +#endif diff --git a/drivers/soc/hisilicon/hisi_lockdown.c b/drivers/soc/hisilicon/hisi_lockdown.c new file mode 100644 index 000000000000..344e9ddaa7cd --- /dev/null +++ b/drivers/soc/hisilicon/hisi_lockdown.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Huawei Technologies Co., Ltd. 2024. All rights reserved. + */ + +#define pr_fmt(fmt) "hisi_l3t: " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/kallsyms.h> +#include <linux/mm.h> + +#include "hisi_l3t.h" + +struct hisi_l3t_ops { + bool (*l3t_slot_test)(struct hisi_l3t *l3t, int slot_idx, + unsigned long addr, int size); + void (*l3t_slot_action)(struct hisi_l3t *l3t, int slot_idx, + unsigned long addr, int size); +}; + +static int hisi_l3t_sccl_action(struct hisi_sccl *sccl, unsigned long addr, + int size, struct hisi_l3t_ops *ops) +{ + struct hisi_l3t *l3t; + int i, slot_idx; + + /* + * in shared mode, all l3t belongs to one sccl is the same. + * use the first l3t to test. + */ + l3t = sccl->l3t[0]; + + mutex_lock(&l3t_mutex); + for (slot_idx = 0; slot_idx < L3T_REG_NUM; slot_idx++) { + if (ops->l3t_slot_test(l3t, slot_idx, addr, size)) + break; + } + + if (slot_idx >= L3T_REG_NUM) { + mutex_unlock(&l3t_mutex); + return -EINVAL; + } + + for (i = 0; i < sccl->ccl_cnt; i++) { + l3t = sccl->l3t[i]; + if (l3t) + ops->l3t_slot_action(l3t, slot_idx, addr, size); + } + mutex_unlock(&l3t_mutex); + + return 0; +} + +struct hisi_sccl *get_valid_sccl(int nid) +{ + struct hisi_sccl *sccl; + + sccl = hisi_l3t_get_sccl(nid); + if (!sccl || !sccl->ccl_cnt) + return NULL; + + if (!sccl->l3t || !sccl->l3t[0]) + return NULL; + + return sccl; +} + +static bool hisi_l3t_test_empty(struct hisi_l3t *l3t, int slot_idx, + unsigned long __always_unused addr, + int __always_unused size) +{ + unsigned long _addr; + int _size; + + hisi_l3t_read(l3t, slot_idx, &_addr, &_size); + + return _addr == 0; +} + +int l3t_shared_lock(int nid, unsigned long pfn, unsigned long size) +{ + struct hisi_l3t_ops ops = { + .l3t_slot_test = hisi_l3t_test_empty, + .l3t_slot_action = hisi_l3t_lock, + }; + struct hisi_sccl *sccl; + int ret; + + sccl = get_valid_sccl(nid); + if (!sccl) + return -ENODEV; + + ret = hisi_l3t_sccl_action(sccl, pfn << PAGE_SHIFT, size, &ops); + if (ret) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(l3t_shared_lock); + +static bool hisi_l3t_test_equal(struct hisi_l3t *l3t, int slot_idx, + unsigned long addr, int size) +{ + unsigned long _addr; + int _size; + + hisi_l3t_read(l3t, slot_idx, &_addr, &_size); + + return (_addr == addr && _size == size); +} + +static void hisi_l3t_do_unlock(struct hisi_l3t *l3t, int slot_idx, + unsigned long __always_unused addr, + int __always_unused size) +{ + hisi_l3t_unlock(l3t, slot_idx); +} + +int l3t_shared_unlock(int nid, unsigned long pfn, unsigned long size) +{ + struct hisi_l3t_ops ops = { + .l3t_slot_test = hisi_l3t_test_equal, + .l3t_slot_action = hisi_l3t_do_unlock, + }; + struct hisi_sccl *sccl; + int ret; + + sccl = get_valid_sccl(nid); + if (!sccl) + return -ENODEV; + + ret = hisi_l3t_sccl_action(sccl, pfn << PAGE_SHIFT, size, &ops); + if (ret) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(l3t_shared_unlock); diff --git a/drivers/soc/hisilicon/l3t.c b/drivers/soc/hisilicon/l3t.c new file mode 100644 index 000000000000..82e7026c2d0a --- /dev/null +++ b/drivers/soc/hisilicon/l3t.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Huawei Technologies Co., Ltd. 2024. All rights reserved. + */ + +#define pr_fmt(fmt) "hisi_l3t: " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/kallsyms.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/smp.h> +#include <linux/xarray.h> +#include <linux/irqchip.h> + +#include "hisi_l3t.h" + +#define LOCK_EN BIT(0) +#define LOCK_DONE BIT(1) +#define UNLOCK_EN BIT(2) +#define UNLOCK_DONE BIT(3) + +DEFINE_MUTEX(l3t_mutex); +static DEFINE_XARRAY(l3t_mapping); + +static const struct acpi_device_id hisi_l3t_acpi_match[] = { + { "HISI0501", }, + {} +}; +MODULE_DEVICE_TABLE(acpi, hisi_l3t_acpi_match); + +static int sccl_to_node_id(int id) +{ + int sccl_id, cpu; + u64 mpidr; + + for_each_possible_cpu(cpu) { + mpidr = cpu_logical_map(cpu); + sccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 3); + if (sccl_id == id) + return cpu_to_node(cpu); + } + + pr_err("invalid sccl id: %d\n", id); + return -EINVAL; +} + +static int hisi_l3t_init_data(struct platform_device *pdev, + struct hisi_l3t *l3t) +{ + if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", + &l3t->sccl_id)) + return -EINVAL; + + if (device_property_read_u32(&pdev->dev, "hisilicon,ccl-id", + &l3t->ccl_id)) + return -EINVAL; + + l3t->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(l3t->base)) + return PTR_ERR(l3t->base); + + l3t->nid = sccl_to_node_id(l3t->sccl_id); + if (l3t->nid < 0) + return -EINVAL; + + return 0; +} + +static int hisi_l3t_insert_to_sccl(struct hisi_sccl *sccl, struct hisi_l3t *l3t) +{ + void *tmp_l3t; + + if (sccl->ccl_cnt < l3t->ccl_id) + goto set; + + tmp_l3t = krealloc(sccl->l3t, + (l3t->ccl_id + 1) * sizeof(struct hisi_l3t *), + GFP_KERNEL); + if (!tmp_l3t) + return -ENOMEM; + + sccl->ccl_cnt = l3t->ccl_id + 1; + sccl->l3t = tmp_l3t; + +set: + sccl->l3t[l3t->ccl_id] = l3t; + return 0; +} + +/* + * Use xarray to store the mapping b/t nid to sccl + * all ccls belong be one sccl is store with vla in sccl->l3t + */ +static int hisi_l3t_init_mapping(struct device *dev, struct hisi_l3t *l3t) +{ + struct hisi_sccl *sccl; + int ret = -ENOMEM; + + mutex_lock(&l3t_mutex); + sccl = xa_load(&l3t_mapping, l3t->nid); + if (!sccl) { + sccl = devm_kzalloc(dev, sizeof(*sccl), GFP_KERNEL); + if (!sccl) + goto unlock; + sccl->nid = l3t->nid; + + xa_store(&l3t_mapping, l3t->nid, sccl, GFP_KERNEL); + } + + ret = hisi_l3t_insert_to_sccl(sccl, l3t); +unlock: + mutex_unlock(&l3t_mutex); + + return ret; +} + +static int hisi_l3t_probe(struct platform_device *pdev) +{ + struct hisi_l3t *l3t; + int ret; + + l3t = devm_kzalloc(&pdev->dev, sizeof(*l3t), GFP_KERNEL); + if (!l3t) + return -ENOMEM; + + platform_set_drvdata(pdev, l3t); + + ret = hisi_l3t_init_data(pdev, l3t); + if (!ret) { + l3t->dev = &pdev->dev; + ret = hisi_l3t_init_mapping(&pdev->dev, l3t); + } + + return ret; +} + +static struct platform_driver hisi_l3t_driver = { + .driver = { + .name = "hisi_l3t", + .acpi_match_table = ACPI_PTR(hisi_l3t_acpi_match), + .suppress_bind_attrs = true, + }, + .probe = hisi_l3t_probe, +}; + +/* write bit b_update and wait bit b_wait to be zero */ +static void __l3t_update_and_wait(void __iomem *addr, u32 b_update, u32 b_wait) +{ + u32 val; + + writel(b_update, addr); + + do { + val = readl(addr); + } while ((val & b_wait) == 0); +} + +static void __l3t_maintain(void __iomem *addr, int slot_idx, + unsigned long s_addr, int size, bool lock) +{ + if (slot_idx < 0 || slot_idx >= L3T_REG_NUM) { + pr_err("slot index is invalid: %d\n", slot_idx); + return; + } + + if (!addr) { + pr_err("invalid unlock addr\n"); + return; + } + + addr += slot_idx * L3T_LOCK_STEP; + + writeq(s_addr, addr + L3T_LOCK_START_L); + writel(size, addr + L3T_LOCK_AREA); + + if (lock) + __l3t_update_and_wait(addr + L3T_LOCK_CTRL, LOCK_EN, LOCK_DONE); + else + __l3t_update_and_wait(addr + L3T_LOCK_CTRL, UNLOCK_EN, + UNLOCK_DONE); +} + +void hisi_l3t_lock(struct hisi_l3t *l3t, int slot_idx, unsigned long s_addr, + int size) +{ + __l3t_maintain(l3t->base, slot_idx, s_addr, size, true); + + pr_debug("lock success. addr: %#lx, slot: %d, s_addr: %#lx, size: %#x\n", + (unsigned long)l3t->base, slot_idx, s_addr, size); +} + +void hisi_l3t_unlock(struct hisi_l3t *l3t, int slot_idx) +{ + __l3t_maintain(l3t->base, slot_idx, 0, 0, false); + + pr_debug("unlock success. addr: %#lx, slot: %d\n", + (unsigned long)l3t->base, slot_idx); +} + +static void hisi_l3t_read_inner(void __iomem *addr, int locksel, + unsigned long *s_addr, int *size) +{ + if (!addr) { + *s_addr = 0; + *size = 0; + pr_err("invalid unlock addr\n"); + return; + } + + *s_addr = readq(addr + L3T_LOCK_START_L + locksel * L3T_LOCK_STEP); + *size = readl(addr + L3T_LOCK_AREA + locksel * L3T_LOCK_STEP); +} + +void hisi_l3t_read(struct hisi_l3t *l3t, int slot_idx, unsigned long *s_addr, + int *size) +{ + if (slot_idx < 0 || slot_idx >= L3T_REG_NUM) { + pr_err("slot index is invalid: %d\n", slot_idx); + return; + } + + return hisi_l3t_read_inner(l3t->base, slot_idx, s_addr, size); +} + +struct hisi_sccl *hisi_l3t_get_sccl(int nid) +{ + return xa_load(&l3t_mapping, nid); +} + +static int __init hisi_l3t_init(void) +{ + mutex_init(&l3t_mutex); + xa_init(&l3t_mapping); + + return platform_driver_register(&hisi_l3t_driver); +} +module_init(hisi_l3t_init); + +static void hisi_l3t_destroy_sccl(void) +{ + struct hisi_sccl *sccl; + unsigned long nid; + + xa_for_each(&l3t_mapping, nid, sccl) + kfree(sccl->l3t); +} + +static void __exit hisi_l3t_exit(void) +{ + hisi_l3t_destroy_sccl(); + xa_destroy(&l3t_mapping); + + platform_driver_unregister(&hisi_l3t_driver); +} +module_exit(hisi_l3t_exit); + +MODULE_DESCRIPTION("HiSilicon SoC L3T driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ma Wupeng mawupeng1@huawei.com");
From: Ma Wupeng mawupeng1@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9UDJX
--------------------------------
L0 driver for platforms such Kunpeng 920. This provides interfaces to for user to alloc and lock memory.
Signed-off-by: Ma Wupeng mawupeng1@huawei.com --- drivers/soc/hisilicon/Kconfig | 9 ++ drivers/soc/hisilicon/Makefile | 1 + drivers/soc/hisilicon/hisi_l0.c | 173 ++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 drivers/soc/hisilicon/hisi_l0.c
diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 19c4f4602d51..90d8036ae658 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -63,4 +63,13 @@ config HISI_L3T
If not sure say no.
+config HISI_L0 + tristate "Add support L0 cache" + depends on ARM64 && HISI_L3T + help + L0 driver for platforms such Kunpeng 920. This provides interfaces to + for user to alloc and lock memory + + If not sure say no. + endmenu diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile index 022d83eccc79..d91b8ed30306 100644 --- a/drivers/soc/hisilicon/Makefile +++ b/drivers/soc/hisilicon/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_HISI_HBMCACHE) += hisi_hbmcache.o obj-$(CONFIG_ARM64_PBHA) += pbha.o hisi_l3t-objs := hisi_lockdown.o l3t.o obj-$(CONFIG_HISI_L3T) += hisi_l3t.o +obj-$(CONFIG_HISI_L0) += hisi_l0.o diff --git a/drivers/soc/hisilicon/hisi_l0.c b/drivers/soc/hisilicon/hisi_l0.c new file mode 100644 index 000000000000..5a6e8c3c14d7 --- /dev/null +++ b/drivers/soc/hisilicon/hisi_l0.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Huawei Technologies Co., Ltd. 2024. All rights reserved. + */ + +#define pr_fmt(fmt) "hisi_l0: " fmt + +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/miscdevice.h> +#include <linux/kallsyms.h> +#include <linux/mm.h> +#include <linux/gfp.h> +#include <linux/mempolicy.h> +#include <linux/pfn_t.h> + +#include "hisi_l3t.h" + +struct l0_vma_data { + struct page *page; + unsigned long size; + int nid; +}; + +static int get_node_node(struct vm_area_struct *vma) +{ + struct mempolicy *pol; + nodemask_t *nmask; + int nid; + + nid = get_vma_policy_node(vma, vma->vm_start, GFP_KERNEL, &pol, &nmask); + if (pol->mode == MPOL_BIND || pol->mode == MPOL_PREFERRED_MANY) + nid = first_node(*nmask); + + return nid; +} + +static vm_fault_t __l0_pmd_fault(struct vm_fault *vmf) +{ + unsigned long pmd_addr = vmf->address & PMD_MASK; + struct l0_vma_data *data; + unsigned long pfn; + + data = vmf->vma->vm_private_data; + if (!data) { + pr_err("%s: pid: %d invalid internal data\n", current->comm, + current->pid); + return VM_FAULT_SIGBUS; + } + + if (PAGE_ALIGN(vmf->vma->vm_end - vmf->vma->vm_start) != data->size) { + pr_err("%s: pid: %d invalid vma size, start: %#lx, end: %#lx, size: %#lx\n", + current->comm, current->pid, vmf->vma->vm_start, + vmf->vma->vm_end, data->size); + return VM_FAULT_SIGBUS; + } + + /* if we are outside of the VMA */ + if (pmd_addr < vmf->vma->vm_start || + (pmd_addr + PMD_SIZE) > vmf->vma->vm_end) + return VM_FAULT_SIGBUS; + + pfn = page_to_pfn(data->page) + + ((pmd_addr - vmf->vma->vm_start) >> PAGE_SHIFT); + + return vmf_insert_pfn_pmd(vmf, pfn_to_pfn_t(pfn), vmf->flags & FAULT_FLAG_WRITE); +} + +static vm_fault_t l0_huge_fault(struct vm_fault *vmf, + enum page_entry_size pe_size) +{ + pr_debug("%s: pid: %d %s (%#lx - %#lx) size = %d\n", current->comm, + current->pid, + (vmf->flags & FAULT_FLAG_WRITE) ? "write" : "read", + vmf->vma->vm_start, vmf->vma->vm_end, pe_size); + + if (pe_size == PE_SIZE_PMD) + return __l0_pmd_fault(vmf); + + return VM_FAULT_SIGBUS; +} + +static void l0_vma_close(struct vm_area_struct *vma) +{ + struct l0_vma_data *data; + + data = (struct l0_vma_data *)vma->vm_private_data; + if (!data) { + pr_err("invalid internal data\n"); + return; + } + + l3t_shared_unlock(data->nid, page_to_pfn(data->page), data->size); + free_contig_range(page_to_pfn(data->page), data->size >> PAGE_SHIFT); + + kfree(data); +} + +static const struct vm_operations_struct l0_vm_ops = { + .huge_fault = l0_huge_fault, + .close = l0_vma_close, +}; + +static int l0_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long cont_size = PAGE_ALIGN(vma->vm_end - vma->vm_start); + struct l0_vma_data *data; + int page_cnt, nid, ret; + struct page *page; + + pr_debug("vma_start: %#lx, vma_end: %#lx vma_flags: %pGv\n", + vma->vm_start, vma->vm_end, &vma->vm_flags); + + if ((vma->vm_start % PMD_SIZE) || (vma->vm_end % PMD_SIZE)) { + pr_err("vma addr should align PMD_SIZE\n"); + return -EINVAL; + } + + data = kzalloc(sizeof(struct l0_vma_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + page_cnt = cont_size >> PAGE_SHIFT; + + nid = get_node_node(vma); + + page = alloc_contig_pages(page_cnt, GFP_KERNEL, nid, NULL); + if (!page) { + pr_err("alloc continue memory failed, size: %#lx\n", cont_size); + ret = -ENOMEM; + goto free_data; + } + + ret = l3t_shared_lock(nid, page_to_pfn(page), cont_size); + if (ret) { + pr_err("l3t lock failed, ret: %d\n", ret); + ret = -ENOMEM; + goto free_page; + } + + data->page = page; + data->size = cont_size; + data->nid = nid; + + vma->vm_ops = &l0_vm_ops; + vma->vm_flags |= (VM_MIXEDMAP | VM_DONTCOPY | VM_DONTEXPAND); + vma->vm_private_data = data; + + return 0; +free_page: + free_contig_range(page_to_pfn(page), page_cnt); +free_data: + kfree(data); + return ret; +} + +static const struct file_operations l0_fops = { + .owner = THIS_MODULE, + .mmap = l0_mmap, +}; + +static struct miscdevice l0_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "hisi_l0", + .fops = &l0_fops, +}; +module_misc_device(l0_dev); + +MODULE_DESCRIPTION("HiSilicon SoC L0 driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ma Wupeng mawupeng1@huawei.com");
From: Ma Wupeng mawupeng1@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9UDJX
--------------------------------
Enable hisi l3t & l0 for arm64 by default.
Signed-off-by: Ma Wupeng mawupeng1@huawei.com --- arch/arm64/configs/openeuler_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index a83bf85e289b..dd553b7d2b6e 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -6107,6 +6107,8 @@ CONFIG_QCOM_KRYO_L2_ACCESSORS=y CONFIG_KUNPENG_HCCS=m # CONFIG_HISI_HBMDEV is not set # CONFIG_HISI_HBMCACHE is not set +CONFIG_HISI_L3T=m +CONFIG_HISI_L0=m # end of Hisilicon SoC drivers # end of SOC (System On Chip) specific Drivers
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/8511 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/D...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/8511 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/D...