From nobody Tue Dec 2 00:04:44 2025 Received: from canpmsgout04.his.huawei.com (canpmsgout04.his.huawei.com [113.46.200.219]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B4DF52C17A3 for ; Tue, 25 Nov 2025 08:05:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.219 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764057951; cv=none; b=G9hMjoCw8cS50Xiz0cfaaPABK4xkBobVYj8u0RmDGC2YCwY0P7GlGf5Kw7wwgEdjjgTGgpf5RN5Gt4uw5dr3s6KTd1JBip6S5Yzs7Yg0f6KgdzfJ1WfmN0o+WbJEEIgAxUqZrpZzHPDurChlNyFOZgZ19yyKkOuBIVJwM0RCPTo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764057951; c=relaxed/simple; bh=E+lJOlva4fmbJi50nxowAMrXIAmQpCkmriQ/2KhGZqo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Hjgz/PEQFvkmIYpoSOEriCy7fH5XhqAw16F52cK6P4xnpxnBojRQNXWbnM8H+1VQU47doRKjbLNczNKp3+eLk/95yMGcUqmrxIbTbG2G/RCtZuhCV9PAtaUCzjVZxz2lPXN/Io2eal24zzbMguuBpj3NImwtpspptgj6oxowmvw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=DQNcWiNH; arc=none smtp.client-ip=113.46.200.219 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="DQNcWiNH" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=Qcc6sWEXHj7N6jp+Pyy3mHEKKIBCTC8ZsQ5o7TgMOWg=; b=DQNcWiNHXUlU1dgas7wFqx9J8MFlphk58+ZxdlJBWnfaVkrU5H7AC6TrIXnW1dxsvToq+0Qny pgCg0g5UIcej3QJZsiM6h/lBNxCdkCmf5vRlbCNRcWdZxmNUFoo0ILt4LJ6DRITgKTQRF9+okD4 CR6MX2kHDyqetNKeHxuj9EI= Received: from mail.maildlp.com (unknown [172.19.88.194]) by canpmsgout04.his.huawei.com (SkyGuard) with ESMTPS id 4dFwF7696xz1prMf; Tue, 25 Nov 2025 16:03:55 +0800 (CST) Received: from dggemv712-chm.china.huawei.com (unknown [10.1.198.32]) by mail.maildlp.com (Postfix) with ESMTPS id 3D839140156; Tue, 25 Nov 2025 16:05:44 +0800 (CST) Received: from kwepemn100008.china.huawei.com (7.202.194.111) by dggemv712-chm.china.huawei.com (10.1.198.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 25 Nov 2025 16:05:44 +0800 Received: from localhost.huawei.com (10.90.31.46) by kwepemn100008.china.huawei.com (7.202.194.111) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 25 Nov 2025 16:05:43 +0800 From: Yushan Wang To: , , , , , CC: , , Subject: [RFC PATCH 1/3] soc cache: L3 cache driver for HiSilicon SoC Date: Tue, 25 Nov 2025 16:05:40 +0800 Message-ID: <20251125080542.3721829-2-wangyushan12@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20251125080542.3721829-1-wangyushan12@huawei.com> References: <20251125080542.3721829-1-wangyushan12@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: kwepems500002.china.huawei.com (7.221.188.17) To kwepemn100008.china.huawei.com (7.202.194.111) Content-Type: text/plain; charset="utf-8" The driver will create a file of `/dev/hisi_l3c` on init, mmap operations to it will allocate a memory region that is guaranteed to be placed in L3 cache. The driver also provides unmap() to deallocated the locked memory. The driver also provides an ioctl interface for user to get cache lock information, such as lock restrictions and locked sizes. Signed-off-by: Yushan Wang --- .../userspace-api/ioctl/ioctl-number.rst | 1 + drivers/soc/hisilicon/Kconfig | 10 + drivers/soc/hisilicon/Makefile | 2 + drivers/soc/hisilicon/hisi_soc_l3c.c | 359 ++++++++++++++++++ include/uapi/misc/hisi_l3c.h | 28 ++ 5 files changed, 400 insertions(+) create mode 100644 drivers/soc/hisilicon/hisi_soc_l3c.c create mode 100644 include/uapi/misc/hisi_l3c.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documenta= tion/userspace-api/ioctl/ioctl-number.rst index 7c527a01d1cf..759469386e60 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -385,6 +385,7 @@ Code Seq# Include File = Comments 0xB8 01-02 uapi/misc/mrvl_cn10k_dpi.h Mar= vell CN10K DPI driver 0xB8 all uapi/linux/mshv.h Mic= rosoft Hyper-V /dev/mshv driver +0xBA all uapi/misc/hisi_soc_cache.h HiS= ilicon SoC cache driver 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h Dea= d since 6.15 0xCA 10-2F uapi/misc/ocxl.h diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 6d7c244d2e78..ea16dffccd5e 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -21,4 +21,14 @@ config KUNPENG_HCCS health status and port information of HCCS, or reducing system power consumption on Kunpeng SoC. =20 +config HISI_SOC_L3C + bool "HiSilicon L3 Cache device driver" + depends on ARM64 && ACPI || COMPILE_TEST + 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. + endmenu diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile index 226e747e70d6..16ff2c73c4a5 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) +=3D kunpeng_hccs.o + +obj-$(CONFIG_HISI_SOC_L3C) +=3D hisi_soc_l3c.o diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/h= isi_soc_l3c.c new file mode 100644 index 000000000000..2c196c4dfff1 --- /dev/null +++ b/drivers/soc/hisilicon/hisi_soc_l3c.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for HiSilicon L3 cache. + * + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. + * Author: Yushan Wang + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define to_hisi_l3c(p) container_of((p), struct hisi_l3c, comp) + +/** + * struct hisi_soc_comp - Struct of HiSilicon SoC cache components. + * + * @node: list node of hisi_soc_comp_list. + * @ops: possible operations a component may perform. + * @affinity_mask: cpus that associate with this component. + * @private: component specific data. + */ +struct hisi_soc_comp { + struct list_head node; + struct hisi_soc_comp_ops *ops; + cpumask_t affinity_mask; + void *private; +}; + +/** + * struct hisi_soc_comp_ops - Callbacks for SoC cache drivers to handle + * operation requests. + * + * @do_lock: lock certain region of L3 cache from being evicted. + * @poll_lock_done: check if the lock operation has succeeded. + * @do_unlock: unlock the locked region of L3 cache back to normal. + * @poll_unlock_done: check if the unlock operation has succeeded. + operation requests. + * + * Operations are decoupled into two phases so that framework does not have + * to wait for one operation to finish before calling the next when multip= le + * hardwares onboard. + * + * Implementers must implement the functions in pairs. Implementation sho= uld + * 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_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); +}; + +struct hisi_l3c_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_list { + struct list_head node; + /* protects list of HiSilicon SoC cache components */ + spinlock_t lock; +}; + +static struct hisi_soc_comp_list l3c_devs; + +static int hisi_l3c_lock(int cpu, phys_addr_t addr, size_t size) +{ + struct hisi_soc_comp *comp; + int ret; + + guard(spinlock)(&l3c_devs.lock); + + /* When there is no instance onboard, no locked memory is available. */ + if (list_empty(&l3c_devs.node)) + return -ENOMEM; + + /* Lock need to be performed on each channel of associated L3 cache. */ + list_for_each_entry(comp, &l3c_devs.node, node) { + if (!cpumask_test_cpu(cpu, &comp->affinity_mask)) + continue; + ret =3D comp->ops->do_lock(comp, addr, size); + if (ret) + return ret; + } + + list_for_each_entry(comp, &l3c_devs.node, node) { + if (!cpumask_test_cpu(cpu, &comp->affinity_mask)) + continue; + ret =3D comp->ops->poll_lock_done(comp, addr, size); + if (ret) + return ret; + } + + return 0; +} + +static int hisi_l3c_unlock(int cpu, phys_addr_t addr) +{ + struct hisi_soc_comp *comp; + int ret; + + guard(spinlock)(&l3c_devs.lock); + + if (list_empty(&l3c_devs.node)) + return -EINVAL; + + /* Perform unlock on each channel of associated L3 cache. */ + list_for_each_entry(comp, &l3c_devs.node, node) { + if (!cpumask_test_cpu(cpu, &comp->affinity_mask)) + continue; + ret =3D comp->ops->do_unlock(comp, addr); + if (ret) + return ret; + } + + list_for_each_entry(comp, &l3c_devs.node, node) { + if (!cpumask_test_cpu(cpu, &comp->affinity_mask)) + continue; + ret =3D comp->ops->poll_unlock_done(comp, addr); + if (ret) + return ret; + } + + return 0; +} + +static void hisi_soc_comp_add(struct hisi_soc_comp *comp) +{ + guard(spinlock)(&l3c_devs.lock); + list_add_tail(&comp->node, &l3c_devs.node); +} + +/* Null @comp means to delete all instances. */ +static int hisi_soc_comp_del(struct hisi_soc_comp *comp) +{ + struct hisi_soc_comp *entry, *tmp; + + guard(spinlock)(&l3c_devs.lock); + list_for_each_entry_safe(entry, tmp, &l3c_devs.node, node) { + if (comp && comp !=3D entry) + continue; + + list_del(&entry->node); + + /* Only continue to delete nodes when @comp is NULL */ + if (comp) + break; + } + + return 0; +} + +static void hisi_l3c_vm_open(struct vm_area_struct *vma) +{ + struct hisi_l3c_lock_region *clr =3D vma->vm_private_data; + + /* + * Only perform cache lock when the vma passed in is created in + * hisi_l3c_mmap. + */ + if (clr->vm_start !=3D vma->vm_start || clr->vm_end !=3D vma->vm_end) + return; + + clr->status =3D hisi_l3c_lock(clr->cpu, clr->addr, clr->size); +} + +static void hisi_l3c_vm_close(struct vm_area_struct *vma) +{ + struct hisi_l3c_lock_region *clr =3D vma->vm_private_data; + int order =3D get_order(clr->size); + + /* + * Only perform cache unlock when the vma passed in is created + * in hisi_l3c_mmap. + */ + if (clr->vm_start !=3D vma->vm_start || clr->vm_end !=3D vma->vm_end) + return; + + hisi_l3c_unlock(clr->cpu, clr->addr); + + free_contig_range(PHYS_PFN(clr->addr), 1 << order); + kfree(clr); + vma->vm_private_data =3D NULL; +} + +/* mremap operation is not supported for HiSilicon SoC cache. */ +static int hisi_l3c_vm_mremap(struct vm_area_struct *vma) +{ + struct hisi_l3c_lock_region *clr =3D 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 =3D 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_l3c_may_split(struct vm_area_struct *area, unsigned long a= ddr) +{ + pr_err("HiSilicon SoC locked cache may not be split.\n"); + return -EINVAL; +} + +static const struct vm_operations_struct hisi_l3c_vm_ops =3D { + .open =3D hisi_l3c_vm_open, + .close =3D hisi_l3c_vm_close, + .may_split =3D hisi_l3c_may_split, + .mremap =3D hisi_l3c_vm_mremap, +}; + +static int hisi_l3c_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long size =3D vma->vm_end - vma->vm_start; + int order =3D get_order(size); + unsigned long addr; + struct page *pg; + int ret; + + struct hisi_l3c_lock_region *clr __free(kfree) =3D kzalloc(sizeof(*clr), = GFP_KERNEL); + if (!clr) + return -ENOMEM; + + /* Continuous physical memory is required for L3 cache lock. */ + pg =3D alloc_contig_pages(1 << order, GFP_KERNEL | __GFP_NOWARN | __GFP_Z= ERO, + cpu_to_node(smp_processor_id()), NULL); + if (!pg) + return -ENOMEM; + + addr =3D page_to_phys(pg); + *clr =3D (struct hisi_l3c_lock_region) { + .addr =3D addr, + .size =3D size, + .cpu =3D smp_processor_id(), + /* vma should not be moved, store here for validation */ + .vm_start =3D vma->vm_start, + .vm_end =3D vma->vm_end, + }; + + vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND); + vma->vm_ops =3D &hisi_l3c_vm_ops; + vma->vm_private_data =3D clr; + + hisi_l3c_vm_ops.open(vma); + if (clr->status) { + ret =3D clr->status; + goto out_page; + } + + ret =3D remap_pfn_range(vma, vma->vm_start, PFN_DOWN(addr), size, + vma->vm_page_prot); + if (ret) + goto out_page; + + /* Save clr from being freed when lock succeeds. */ + vma->vm_private_data =3D no_free_ptr(clr); + + return 0; + +out_page: + free_contig_range(PHYS_PFN(clr->addr), 1 << order); + return ret; +} + +static int hisi_l3c_lock_restriction(unsigned long arg) +{ + void __user *uarg =3D (void __user *)arg; + int cpu =3D smp_processor_id(); + struct hisi_soc_comp *comp; + + if (list_empty(&l3c_devs.node)) + return -ENODEV; + + list_for_each_entry(comp, &l3c_devs.node, node) { + if (!cpumask_test_cpu(cpu, &comp->affinity_mask)) + continue; + + if (!comp->private) + return -ENOENT; + + if (copy_to_user(uarg, comp->private, sizeof(struct hisi_l3c_lock_info))) + return -EFAULT; + + return 0; + } + + return -ENODEV; +} + +static long hisi_l3c_ioctl(struct file *file, u32 cmd, unsigned long arg) +{ + switch (cmd) { + case HISI_L3C_LOCK_INFO: + return hisi_l3c_lock_restriction(arg); + default: + return -EINVAL; + } +} + +static const struct file_operations l3c_dev_fops =3D { + .owner =3D THIS_MODULE, + .unlocked_ioctl =3D hisi_l3c_ioctl, + .mmap =3D hisi_l3c_mmap, +}; + +static struct miscdevice l3c_miscdev =3D { + .minor =3D MISC_DYNAMIC_MINOR, + .name =3D "hisi_l3c", + .fops =3D &l3c_dev_fops, + .mode =3D 0600, +}; + +static int __init hisi_l3c_init(void) +{ + spin_lock_init(&l3c_devs.lock); + INIT_LIST_HEAD(&l3c_devs.node); + + return misc_register(&l3c_miscdev); +} +module_init(hisi_l3c_init); + +static void __exit hisi_l3c_exit(void) +{ + misc_deregister(&l3c_miscdev); + hisi_soc_comp_del(NULL); +} +module_exit(hisi_l3c_exit); + +MODULE_DESCRIPTION("Hisilicon L3 Cache Driver"); +MODULE_AUTHOR("Yushan Wang "); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/misc/hisi_l3c.h b/include/uapi/misc/hisi_l3c.h new file mode 100644 index 000000000000..73086977a34e --- /dev/null +++ b/include/uapi/misc/hisi_l3c.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* Copyright (c) 2024 HiSilicon Technologies Co., Ltd. */ +#ifndef _UAPI_HISI_SOC_L3C_H +#define _UAPI_HISI_SOC_L3C_H + +#include + +/* HISI_L3C_INFO: cache lock info for HiSilicon SoC */ +#define HISI_L3C_LOCK_INFO _IOW(0xBA, 1, unsigned long) + +/** + * struct hisi_l3c_info - User data for hisi cache operates. + * @lock_region_num: available locked memory region on a L3C instance + * @lock_size: available size to be locked of the L3C instance. + * @address_alignment: if the L3C lock requires locked region physical sta= rt + * address to be aligned with the memory region size. + * @max_lock_size: maximum locked memory size on a L3C instance. + * @min_lock_size: minimum locked memory size on a L3C instance. + */ +struct hisi_l3c_lock_info { + unsigned int lock_region_num; + size_t lock_size; + bool address_alignment; + size_t max_lock_size; + size_t min_lock_size; +}; + +#endif --=20 2.33.0 From nobody Tue Dec 2 00:04:44 2025 Received: from canpmsgout11.his.huawei.com (canpmsgout11.his.huawei.com [113.46.200.226]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0C70C2D2391 for ; Tue, 25 Nov 2025 08:05:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.226 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764057952; cv=none; b=rc4fllwlZN10Tj7GDO1BWCfxk8jFK5HpvliMnxWxyt3ulQr4YH5Z2rtwDLNgjyPawRYDa6IgprDns5A05lizZ4cuJkU9bAIF7VL3SAFl4ckk/LoB77KbLBQqlWq18gSPbvuzogYTfDhlPn7YZAaNfThTgSMJG9USWPbMlL57jLs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764057952; c=relaxed/simple; bh=/PUww0uUiTI5RpsB1EzYJ2UkUF3dSf8qN3WztPrBjC4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lGjF6WBuRW/Q4HMiZyX9EEamKfD//QSVGaAtepY/+TgQPpj8CzFyo4UOvagdGkjBjlqfNV9pbFdPb4OtEOU54/ABFJVpnN2XdfxEiDqXILLQloPtoH+aTsMWGn1DhvHFA3egFHHYu+vvRGs7hTzUoNj7sLfy95VMmaIL1jaJ260= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=Rga2IjF2; arc=none smtp.client-ip=113.46.200.226 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="Rga2IjF2" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=yjf9nElP4xRo/evEet3Ndawinw3/P3yEeqcpeGgXScI=; b=Rga2IjF2HlNF7ekhZSdD4p3e4SOzBEOPMtAIootld1mBOdMFmpvxUQ8dR2Oe+i+zdDHhjn14U iyhSBheEltYWmVmmnxvoFu5L1quM39QERlqqppWPitbi8odee+c8UCiczuXoCEqSGlQJRY5xrh+ ChDj1pzB3WecjiV/fJX3gQY= Received: from mail.maildlp.com (unknown [172.19.88.234]) by canpmsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4dFwF933hXzKm4X; Tue, 25 Nov 2025 16:03:57 +0800 (CST) Received: from dggemv705-chm.china.huawei.com (unknown [10.3.19.32]) by mail.maildlp.com (Postfix) with ESMTPS id 60095140259; Tue, 25 Nov 2025 16:05:45 +0800 (CST) Received: from kwepemn100008.china.huawei.com (7.202.194.111) by dggemv705-chm.china.huawei.com (10.3.19.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 25 Nov 2025 16:05:44 +0800 Received: from localhost.huawei.com (10.90.31.46) by kwepemn100008.china.huawei.com (7.202.194.111) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 25 Nov 2025 16:05:43 +0800 From: Yushan Wang To: , , , , , CC: , , Subject: [RFC PATCH 2/3] soc cache: L3 cache lockdown support for HiSilicon SoC Date: Tue, 25 Nov 2025 16:05:41 +0800 Message-ID: <20251125080542.3721829-3-wangyushan12@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20251125080542.3721829-1-wangyushan12@huawei.com> References: <20251125080542.3721829-1-wangyushan12@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: kwepems500002.china.huawei.com (7.221.188.17) To kwepemn100008.china.huawei.com (7.202.194.111) Content-Type: text/plain; charset="utf-8" This driver implements the interface exposed by framework, passes cache lock/unlock requests to hardware. The number of locked memory region is limited according to firmware, and the total size of locked memory regions must be less than 70% of cache size. Signed-off-by: Yushan Wang --- drivers/soc/hisilicon/hisi_soc_l3c.c | 520 ++++++++++++++++++++++++++- 1 file changed, 519 insertions(+), 1 deletion(-) diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/h= isi_soc_l3c.c index 2c196c4dfff1..1e3419436173 100644 --- a/drivers/soc/hisilicon/hisi_soc_l3c.c +++ b/drivers/soc/hisilicon/hisi_soc_l3c.c @@ -8,19 +8,49 @@ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt =20 +#include #include +#include #include +#include +#include #include #include #include +#include #include #include #include +#include =20 #include =20 #include =20 +#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_LOCK_CTRL_POLL_MAX_US 10000 + +/* 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 to_hisi_l3c(p) container_of((p), struct hisi_l3c, comp) =20 /** @@ -85,8 +115,280 @@ struct hisi_soc_comp_list { spinlock_t lock; }; =20 +struct hisi_l3c { + struct hisi_soc_comp comp; + cpumask_t associated_cpus; + + /* Stores the first address locked by each register sets. */ + struct xarray lock_sets; + /* Locks lock_sets to forbid overlapping access. */ + spinlock_t reg_lock; + + 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; +}; + +static int hisi_l3c_cpuhp_state; + static struct hisi_soc_comp_list l3c_devs; =20 +/** + * hisi_l3c_alloc_lock_reg_set - Allocate an available control register set + * of L3 cache for lock & unlock operations. + * @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_l3c_alloc_lock_reg_set(struct hisi_l3c *l3c, phys_addr_t a= ddr, size_t size) +{ + struct hisi_l3c_lock_info *info =3D l3c->comp.private; + struct hisi_l3c_lock_region *lr; + void *entry; + int idx, ret; + + if (size > info->lock_size) + return -EINVAL; + + for (idx =3D 0; idx < info->lock_region_num; ++idx) { + entry =3D xa_load(&l3c->lock_sets, idx); + if (!entry) + break; + } + + if (idx > info->lock_region_num) + return -EBUSY; + + lr =3D kzalloc(sizeof(*lr), GFP_KERNEL); + if (!lr) + return -ENOMEM; + + lr->addr =3D addr; + lr->size =3D size; + + ret =3D xa_alloc(&l3c->lock_sets, &idx, lr, xa_limit_31b, GFP_KERNEL); + if (ret) { + kfree(lr); + return ret; + } + + info->lock_size -=3D size; + info->lock_region_num -=3D 1; + + return idx; +} + +/** + * hisi_l3c_get_locked_reg_set - Get the index of an allocated register set + * by locked address. + * @l3c: The L3C instance on which the register set is allocated. + * @addr: The locked address. + * + * @return: + * - >=3D 0: index of register set which controls locked memory region o= f @addr. + * - -EINVAL: If @addr is not locked in this cache. + */ +static int hisi_l3c_get_locked_reg_set(struct hisi_l3c *l3c, phys_addr_t a= ddr) +{ + struct hisi_l3c_lock_region *entry; + unsigned long idx; + + xa_for_each(&l3c->lock_sets, idx, entry) { + if (entry->addr =3D=3D addr) + return idx; + } + return -EINVAL; +} + +/** + * hisi_l3c_free_lock_reg_set - Free an allocated register set by locked + * address. + * + * @l3c: The L3C instance on which the register set is allocated. + * @regset: ID of Register set to be freed. + */ +static void hisi_l3c_free_lock_reg_set(struct hisi_l3c *l3c, int regset) +{ + struct hisi_l3c_lock_info *info =3D l3c->comp.private; + struct hisi_l3c_lock_region *entry; + + if (regset < 0) + return; + + entry =3D xa_erase(&l3c->lock_sets, regset); + if (!entry) + return; + + info->lock_size +=3D entry->size; + info->lock_region_num +=3D 1; + kfree(entry); +} + +static bool hisi_l3c_lock_wait_finished(struct hisi_l3c *l3c, int regset) +{ + void *reg =3D l3c->base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset); + /* Wait until neither lock or unlock operation is going on. */ + u32 mask =3D HISI_L3C_LOCK_CTRL_LOCK_DONE | HISI_L3C_LOCK_CTRL_UNLOCK_DON= E; + u32 val; + + /* + * Lock/unlock done bits are initially 0 if no lock operation was ever + * issued, and will be set until next operation comes. + * Check if this is the first lock operation after boot by checking if + * the register is 0. If so, proceed with the operation. + */ + val =3D readl(reg); + if (!val) + return true; + + return !readl_poll_timeout_atomic(reg, val, val & mask, + HISI_L3C_LOCK_CTRL_POLL_GAP_US, + HISI_L3C_LOCK_CTRL_POLL_MAX_US); +} + +static int hisi_l3c_do_lock(struct hisi_soc_comp *comp, phys_addr_t addr, = size_t size) +{ + struct hisi_l3c *l3c =3D to_hisi_l3c(comp); + struct hisi_l3c_lock_info *info =3D l3c->comp.private; + void *base =3D l3c->base; + int regset; + u32 ctrl; + + if (info->address_alignment && addr % size !=3D 0) + return -EINVAL; + + if (size < info->min_lock_size || size > info->max_lock_size) + return -EINVAL; + + guard(spinlock)(&l3c->reg_lock); + + regset =3D hisi_l3c_alloc_lock_reg_set(l3c, addr, size); + if (regset < 0) + return -EBUSY; + + if (!hisi_l3c_lock_wait_finished(l3c, regset)) { + hisi_l3c_free_lock_reg_set(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 =3D readl(base + HISI_L3C_DYNAMIC_AUCTRL); + ctrl |=3D BIT(regset); + writel(ctrl, base + HISI_L3C_DYNAMIC_AUCTRL); + + ctrl =3D readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + ctrl =3D (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_l3c_poll_lock_done(struct hisi_soc_comp *comp, phys_addr_t= addr, size_t size) +{ + struct hisi_l3c *l3c =3D to_hisi_l3c(comp); + int regset; + + guard(spinlock)(&l3c->reg_lock); + + regset =3D hisi_l3c_get_locked_reg_set(l3c, addr); + if (regset < 0) + return -EINVAL; + + if (!hisi_l3c_lock_wait_finished(l3c, regset)) + return -ETIMEDOUT; + + return 0; +} + +static int hisi_l3c_do_unlock(struct hisi_soc_comp *comp, phys_addr_t addr) +{ + struct hisi_l3c *l3c =3D to_hisi_l3c(comp); + void *base =3D l3c->base; + int regset; + u32 ctrl; + + guard(spinlock)(&l3c->reg_lock); + + regset =3D hisi_l3c_get_locked_reg_set(l3c, addr); + if (regset < 0) + return -EINVAL; + + if (!hisi_l3c_lock_wait_finished(l3c, regset)) + return -EBUSY; + + ctrl =3D readl(base + HISI_L3C_DYNAMIC_AUCTRL); + ctrl &=3D ~BIT(regset); + writel(ctrl, base + HISI_L3C_DYNAMIC_AUCTRL); + + ctrl =3D readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + ctrl =3D (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_l3c_poll_unlock_done(struct hisi_soc_comp *comp, phys_addr= _t addr) +{ + struct hisi_l3c *l3c =3D to_hisi_l3c(comp); + int regset; + + guard(spinlock)(&l3c->reg_lock); + + regset =3D hisi_l3c_get_locked_reg_set(l3c, addr); + if (regset < 0) + return -EINVAL; + + if (!hisi_l3c_lock_wait_finished(l3c, regset)) + return -ETIMEDOUT; + + hisi_l3c_free_lock_reg_set(l3c, regset); + + return 0; +} + +static void hisi_l3c_remove_locks(struct hisi_l3c *l3c) +{ + void *base =3D l3c->base; + unsigned long regset; + void *entry; + + guard(spinlock)(&l3c->reg_lock); + + xa_for_each(&l3c->lock_sets, regset, entry) { + int timeout; + u32 ctrl; + + ctrl =3D readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + ctrl =3D (ctrl | HISI_L3C_LOCK_CTRL_UNLOCK_EN) & ~HISI_L3C_LOCK_CTRL_LOC= K_EN; + writel(ctrl, base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset)); + + timeout =3D hisi_l3c_lock_wait_finished(l3c, regset); + if (timeout) + pr_err("failed to remove %lu-th cache lock.\n", regset); + } +} + static int hisi_l3c_lock(int cpu, phys_addr_t addr, size_t size) { struct hisi_soc_comp *comp; @@ -315,6 +617,196 @@ static int hisi_l3c_lock_restriction(unsigned long ar= g) return -ENODEV; } =20 +static int hisi_l3c_init_lock_capacity(struct hisi_l3c *l3c, struct device= *dev) +{ + int ret; + u32 val; + + struct hisi_l3c_lock_info *info __free(kfree) =3D kmalloc(sizeof(*info), = GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret =3D device_property_read_u32(dev, "hisilicon,l3c-lockregion-num", &va= l); + if (ret || val <=3D 0) + return -EINVAL; + + info->lock_region_num =3D val; + + ret =3D device_property_read_u32(dev, "hisilicon,l3c-max-single-lockregio= n-size", &val); + if (ret || val <=3D 0) + return -EINVAL; + + info->lock_size =3D HISI_L3C_MAX_LOCK_SIZE(val); + info->address_alignment =3D info->lock_region_num =3D=3D 1; + info->max_lock_size =3D HISI_L3C_MAX_LOCK_SIZE(val); + info->min_lock_size =3D info->lock_region_num =3D=3D 1 + ? HISI_L3C_LOCK_MIN_SIZE + : HISI_L3_CACHE_LINE_SIZE; + + l3c->comp.private =3D no_free_ptr(info); + + return 0; +} + +static int hisi_l3c_init_topology(struct hisi_l3c *l3c, struct device *dev) +{ + l3c->sccl_id =3D -1; + l3c->ccl_id =3D -1; + + if (device_property_read_u32(dev, "hisilicon,scl-id", &l3c->sccl_id) || + l3c->sccl_id < 0) + return -EINVAL; + + if (device_property_read_u32(dev, "hisilicon,ccl-id", &l3c->ccl_id) || + l3c->ccl_id < 0) + return -EINVAL; + + return 0; +} + +static void hisi_init_associated_cpus(struct hisi_l3c *l3c) +{ + if (!cpumask_empty(&l3c->associated_cpus)) + return; + cpumask_clear(&l3c->associated_cpus); + cpumask_copy(&l3c->comp.affinity_mask, &l3c->associated_cpus); +} + +static struct hisi_soc_comp_ops hisi_comp_ops =3D { + .do_lock =3D hisi_l3c_do_lock, + .poll_lock_done =3D hisi_l3c_poll_lock_done, + .do_unlock =3D hisi_l3c_do_unlock, + .poll_unlock_done =3D hisi_l3c_poll_unlock_done, +}; + +static struct hisi_soc_comp hisi_comp =3D { + .ops =3D &hisi_comp_ops, +}; + +static int hisi_l3c_probe(struct platform_device *pdev) +{ + struct hisi_l3c *l3c; + struct resource *mem; + int ret; + + l3c =3D devm_kzalloc(&pdev->dev, sizeof(*l3c), GFP_KERNEL); + if (!l3c) + return -ENOMEM; + + platform_set_drvdata(pdev, l3c); + + mem =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENODEV; + + l3c->base =3D devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); + if (IS_ERR_OR_NULL(l3c->base)) + return PTR_ERR(l3c->base); + + l3c->comp =3D hisi_comp; + spin_lock_init(&l3c->reg_lock); + xa_init_flags(&l3c->lock_sets, XA_FLAGS_ALLOC); + + ret =3D hisi_l3c_init_lock_capacity(l3c, &pdev->dev); + if (ret) + goto err_xa; + + hisi_init_associated_cpus(l3c); + + ret =3D hisi_l3c_init_topology(l3c, &pdev->dev); + if (ret) + goto err_xa; + + ret =3D cpuhp_state_add_instance(hisi_l3c_cpuhp_state, &l3c->node); + if (ret) + goto err_xa; + + hisi_soc_comp_add(&l3c->comp); + + return 0; + +err_xa: + xa_destroy(&l3c->lock_sets); + return ret; +} + +static void hisi_l3c_remove(struct platform_device *pdev) +{ + struct hisi_l3c *l3c =3D platform_get_drvdata(pdev); + unsigned long idx; + struct hisi_l3c_lock_region *entry; + + hisi_l3c_remove_locks(l3c); + + hisi_soc_comp_del(&l3c->comp); + + cpuhp_state_remove_instance_nocalls(hisi_l3c_cpuhp_state, &l3c->node); + + xa_for_each(&l3c->lock_sets, idx, entry) + entry =3D xa_erase(&l3c->lock_sets, idx); + + xa_destroy(&l3c->lock_sets); +} + +static void hisi_read_sccl_and_ccl_id(int *scclp, int *cclp) +{ + u64 mpidr =3D read_cpuid_mpidr(); + int aff3 =3D MPIDR_AFFINITY_LEVEL(mpidr, 3); + int aff2 =3D MPIDR_AFFINITY_LEVEL(mpidr, 2); + int aff1 =3D MPIDR_AFFINITY_LEVEL(mpidr, 1); + int sccl, ccl; + + if (mpidr & MPIDR_MT_BITMASK) { + sccl =3D aff3; + ccl =3D aff2; + } else { + sccl =3D aff2; + ccl =3D aff1; + } + + *scclp =3D sccl; + *cclp =3D ccl; +} + +static bool hisi_l3c_is_associated(struct hisi_l3c *l3c) +{ + int sccl_id, ccl_id; + + hisi_read_sccl_and_ccl_id(&sccl_id, &ccl_id); + + return sccl_id =3D=3D l3c->sccl_id && ccl_id =3D=3D l3c->ccl_id; +} + +static int hisi_l3c_online_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct hisi_l3c *l3c =3D hlist_entry_safe(node, struct hisi_l3c, node); + + if (!cpumask_test_cpu(cpu, &l3c->associated_cpus)) { + if (!(hisi_l3c_is_associated(l3c))) + return 0; + + cpumask_set_cpu(cpu, &l3c->associated_cpus); + cpumask_copy(&l3c->comp.affinity_mask, + &l3c->associated_cpus); + } + return 0; +} + +static const struct acpi_device_id hisi_l3c_acpi_match[] =3D { + { "HISI0501", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, hisi_l3c_acpi_match); + +static struct platform_driver hisi_l3c_driver =3D { + .driver =3D { + .name =3D "hisi_l3c", + .acpi_match_table =3D hisi_l3c_acpi_match, + }, + .probe =3D hisi_l3c_probe, + .remove =3D hisi_l3c_remove, +}; + static long hisi_l3c_ioctl(struct file *file, u32 cmd, unsigned long arg) { switch (cmd) { @@ -340,15 +832,41 @@ static struct miscdevice l3c_miscdev =3D { =20 static int __init hisi_l3c_init(void) { + int ret; + spin_lock_init(&l3c_devs.lock); INIT_LIST_HEAD(&l3c_devs.node); =20 - return misc_register(&l3c_miscdev); + ret =3D misc_register(&l3c_miscdev); + if (ret) + return ret; + + ret =3D cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "hisi_l3c", + hisi_l3c_online_cpu, NULL); + if (ret < 0) + goto err_hp; + + hisi_l3c_cpuhp_state =3D ret; + + ret =3D platform_driver_register(&hisi_l3c_driver); + if (ret) + goto err_plat; + + return 0; + +err_plat: + cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN); +err_hp: + misc_deregister(&l3c_miscdev); + + return ret; } module_init(hisi_l3c_init); =20 static void __exit hisi_l3c_exit(void) { + platform_driver_unregister(&hisi_l3c_driver); + cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN); misc_deregister(&l3c_miscdev); hisi_soc_comp_del(NULL); } --=20 2.33.0 From nobody Tue Dec 2 00:04:44 2025 Received: from canpmsgout09.his.huawei.com (canpmsgout09.his.huawei.com [113.46.200.224]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0EB052D7DEC for ; Tue, 25 Nov 2025 08:05:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.224 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764057951; cv=none; b=j6XlxDiBxC8+fRrGjT6HB6HqHoJEvO+i3FoyzSErnAAxs0QHyUiXkz+WC0qUhr/oMS6WnfyiG+UIXRV+iTBFmoA3sxx1eKoltq1HXh9Nc+Z5X5IA6Ha5gmFzP9UyA1FUf3G6L1wGInLEfi5FDct/xastX3Gla95M8TWgWiHSYp0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764057951; c=relaxed/simple; bh=EnYX2UbL4GddxkZu9waYCL7vrgbYwTKSekAJgSe9nr8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=D60D9D3EC59cNzoKlf8//CWPsZxlshm8zpAlXRvSFaPGbBf01Ey5V1X8VGRMNE2SIyYZuX1j7XSUanHUQ3l9aOY5ChxNTmCO3u6NS8Gp/xTMabjYIXWMPJs1QEAg7EM6Mr5tagkmgYmjMIKdRO1Dsv4yEyqIi5xD7yV6VMkJj7c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=DoBGe1S1; arc=none smtp.client-ip=113.46.200.224 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="DoBGe1S1" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=FIhvSaeXNVcgqaB/0/kSz3ZRqQlMg/6LhK/Kbe7gdXA=; b=DoBGe1S1EeQpw8EMjWENPNfAJYc4TlyAaXdEboG+ccEeiPuSFWR30xsQ7Yyc9niq5iykCpf3v hzSG88BluTdFACffiKDvfr1+kXSKAYyDGfIZtEt+wBDdSyTGGLBG7wbo4PvzHLhjvZT1mRbZHx0 wSFjxCcisZQDFOyN6btCvi0= Received: from mail.maildlp.com (unknown [172.19.88.234]) by canpmsgout09.his.huawei.com (SkyGuard) with ESMTPS id 4dFwF95BPzz1cyrt; Tue, 25 Nov 2025 16:03:57 +0800 (CST) Received: from dggemv705-chm.china.huawei.com (unknown [10.3.19.32]) by mail.maildlp.com (Postfix) with ESMTPS id 6912D1402C4; Tue, 25 Nov 2025 16:05:45 +0800 (CST) Received: from kwepemn100008.china.huawei.com (7.202.194.111) by dggemv705-chm.china.huawei.com (10.3.19.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 25 Nov 2025 16:05:44 +0800 Received: from localhost.huawei.com (10.90.31.46) by kwepemn100008.china.huawei.com (7.202.194.111) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 25 Nov 2025 16:05:44 +0800 From: Yushan Wang To: , , , , , CC: , , Subject: [RFC PATCH 3/3] Documentation: soc cache: Add documentation to HiSilicon SoC cache Date: Tue, 25 Nov 2025 16:05:42 +0800 Message-ID: <20251125080542.3721829-4-wangyushan12@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20251125080542.3721829-1-wangyushan12@huawei.com> References: <20251125080542.3721829-1-wangyushan12@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: kwepems500002.china.huawei.com (7.221.188.17) To kwepemn100008.china.huawei.com (7.202.194.111) Content-Type: text/plain; charset="utf-8" Add necessary documentation to HiSilicon SoC cache for reference. Signed-off-by: Yushan Wang --- Documentation/driver-api/hisi-soc-cache.rst | 62 +++++++++++++++++++++ Documentation/driver-api/index.rst | 1 + 2 files changed, 63 insertions(+) create mode 100644 Documentation/driver-api/hisi-soc-cache.rst diff --git a/Documentation/driver-api/hisi-soc-cache.rst b/Documentation/dr= iver-api/hisi-soc-cache.rst new file mode 100644 index 000000000000..a0da7ff20e44 --- /dev/null +++ b/Documentation/driver-api/hisi-soc-cache.rst @@ -0,0 +1,62 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +HiSilicon SoC Cache Driver +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +Introduction +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +HiSilicon SoC cache provides the capabilities of preventing given range of +memory from being evicted from L3 cache. The driver exports the lockdown A= PI to +userspace, allowing allocation of memory that is guranteed to be placed in= L3 +cache, thus decreasing average memory access latency. + +Usage +=3D=3D=3D=3D=3D + +Kernel built with CONFIG_HISI_SOC_CACHE on will have the device file at +`/dev/hisi_l3c`, cache operations can be performed through it. + +mmap(): +------- + +This interface can be used to allocate memory that is guranteed to not be +evicted out of HiSilicon L3 cache. Newly allocated memory will be prefetch= ed to +L3 cache automatically. + +Users should set `PROT_READ` or `PROT_WRITE` to enable read/write to the m= emory +region. Once mmap call succeeds, read and write can be applied to the memo= ry +region indicated by the returned pointer. + +Calling `munmap()` to the pointer can be used to unlock the memory regions. + +Restrictions of the cache lockdown are listed below: + - Only limited number of memory regions are supported, the exact number = is + reported by firmware. + - Sum of the sizes of locked memory regions should be less than 70% of t= he + total size of cache instance. + - Lock/unlock can only be performed during allocation/deallocation, lock= ing + existing memory is not supported yet. + +ioctl(): +-------- + +This interface provides useful information of HiSilicon L3 cache. + +HISI_L3C_LOCK_INFO + - struct hisi_l3c_lock_info (read) + + Gets detailed information of L3 cache lock restrictions. + +This ioctl call returns the detailed information of HiSilicon L3 cache lock +restriction. Information will be presented in the form of:: + + struct hisi_l3c_lock_info { + unsigned int lock_region_num; + size_t lock_size; + bool address_alignment; + size_t max_lock_size; + size_t min_lock_size; + }; + +User may perform a query before issueing cache lock to check for available +resource. diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/= index.rst index 3e2a270bd828..a4be1fc67230 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -94,6 +94,7 @@ Subsystem-specific APIs aperture generic-counter gpio/index + hisi-soc-cache hsi hte/index i2c --=20 2.33.0