From nobody Tue Dec 2 00:44:26 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