Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent

Hydra Home Agent is a device used to maintain cache coherency. Add support
for explicit cache maintenance operations using it. A system has multiple
of these agents. Whilst only one agent is responsible for a given cache
line, interleave means that for a range operation, responsibility for the
cache lines making up the range will typically be spread across multiple
instances.

Put this driver on a new Kconfig menu under drivers/cache. The short
description as memory hotplug like operations is intended to cover
the somewhat complex set of cases where this unit applies and differentiate
it clearly from typical non coherent DMA flows.

Co-developed-by: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>

authored by

Yushan Wang and committed by
Conor Dooley
2ec3b54a 4d1608d0

+218
+22
drivers/cache/Kconfig
··· 32 32 Support for the StarLink cache controller IP from StarFive. 33 33 34 34 endif #CACHEMAINT_FOR_DMA 35 + 36 + menuconfig CACHEMAINT_FOR_HOTPLUG 37 + bool "Cache management for memory hot plug like operations" 38 + depends on GENERIC_CPU_CACHE_MAINTENANCE 39 + help 40 + These drivers implement cache management for flows where it is necessary 41 + to flush data from all host caches. 42 + 43 + if CACHEMAINT_FOR_HOTPLUG 44 + 45 + config HISI_SOC_HHA 46 + tristate "HiSilicon Hydra Home Agent (HHA) device driver" 47 + depends on (ARM64 && ACPI) || COMPILE_TEST 48 + help 49 + The Hydra Home Agent (HHA) is responsible for cache coherency 50 + on the SoC. This drivers enables the cache maintenance functions of 51 + the HHA. 52 + 53 + This driver can be built as a module. If so, the module will be 54 + called hisi_soc_hha. 55 + 56 + endif #CACHEMAINT_FOR_HOTPLUG
+2
drivers/cache/Makefile
··· 3 3 obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o 4 4 obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o 5 5 obj-$(CONFIG_STARFIVE_STARLINK_CACHE) += starfive_starlink_cache.o 6 + 7 + obj-$(CONFIG_HISI_SOC_HHA) += hisi_soc_hha.o
+194
drivers/cache/hisi_soc_hha.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for HiSilicon Hydra Home Agent (HHA). 4 + * 5 + * Copyright (c) 2025 HiSilicon Technologies Co., Ltd. 6 + * Author: Yicong Yang <yangyicong@hisilicon.com> 7 + * Yushan Wang <wangyushan12@huawei.com> 8 + * 9 + * A system typically contains multiple HHAs. Each is responsible for a subset 10 + * of the physical addresses in the system, but interleave can make the mapping 11 + * from a particular cache line to a responsible HHA complex. As such no 12 + * filtering is done in the driver, with the hardware being responsible for 13 + * responding with success for even if it was not responsible for any addresses 14 + * in the range on which the operation was requested. 15 + */ 16 + 17 + #include <linux/bitfield.h> 18 + #include <linux/cache_coherency.h> 19 + #include <linux/dev_printk.h> 20 + #include <linux/init.h> 21 + #include <linux/io.h> 22 + #include <linux/iopoll.h> 23 + #include <linux/kernel.h> 24 + #include <linux/memregion.h> 25 + #include <linux/module.h> 26 + #include <linux/mod_devicetable.h> 27 + #include <linux/mutex.h> 28 + #include <linux/platform_device.h> 29 + 30 + #define HISI_HHA_CTRL 0x5004 31 + #define HISI_HHA_CTRL_EN BIT(0) 32 + #define HISI_HHA_CTRL_RANGE BIT(1) 33 + #define HISI_HHA_CTRL_TYPE GENMASK(3, 2) 34 + #define HISI_HHA_START_L 0x5008 35 + #define HISI_HHA_START_H 0x500c 36 + #define HISI_HHA_LEN_L 0x5010 37 + #define HISI_HHA_LEN_H 0x5014 38 + 39 + /* The maintain operation performs in a 128 Byte granularity */ 40 + #define HISI_HHA_MAINT_ALIGN 128 41 + 42 + #define HISI_HHA_POLL_GAP_US 10 43 + #define HISI_HHA_POLL_TIMEOUT_US 50000 44 + 45 + struct hisi_soc_hha { 46 + /* Must be first element */ 47 + struct cache_coherency_ops_inst cci; 48 + /* Locks HHA instance to forbid overlapping access. */ 49 + struct mutex lock; 50 + void __iomem *base; 51 + }; 52 + 53 + static bool hisi_hha_cache_maintain_wait_finished(struct hisi_soc_hha *soc_hha) 54 + { 55 + u32 val; 56 + 57 + return !readl_poll_timeout_atomic(soc_hha->base + HISI_HHA_CTRL, val, 58 + !(val & HISI_HHA_CTRL_EN), 59 + HISI_HHA_POLL_GAP_US, 60 + HISI_HHA_POLL_TIMEOUT_US); 61 + } 62 + 63 + static int hisi_soc_hha_wbinv(struct cache_coherency_ops_inst *cci, 64 + struct cc_inval_params *invp) 65 + { 66 + struct hisi_soc_hha *soc_hha = 67 + container_of(cci, struct hisi_soc_hha, cci); 68 + phys_addr_t top, addr = invp->addr; 69 + size_t size = invp->size; 70 + u32 reg; 71 + 72 + if (!size) 73 + return -EINVAL; 74 + 75 + addr = ALIGN_DOWN(addr, HISI_HHA_MAINT_ALIGN); 76 + top = ALIGN(addr + size, HISI_HHA_MAINT_ALIGN); 77 + size = top - addr; 78 + 79 + guard(mutex)(&soc_hha->lock); 80 + 81 + if (!hisi_hha_cache_maintain_wait_finished(soc_hha)) 82 + return -EBUSY; 83 + 84 + /* 85 + * Hardware will search for addresses ranging [addr, addr + size - 1], 86 + * last byte included, and perform maintenance in 128 byte granules 87 + * on those cachelines which contain the addresses. If a given instance 88 + * is either not responsible for a cacheline or that cacheline is not 89 + * currently present then the search will fail, no operation will be 90 + * necessary and the device will report success. 91 + */ 92 + size -= 1; 93 + 94 + writel(lower_32_bits(addr), soc_hha->base + HISI_HHA_START_L); 95 + writel(upper_32_bits(addr), soc_hha->base + HISI_HHA_START_H); 96 + writel(lower_32_bits(size), soc_hha->base + HISI_HHA_LEN_L); 97 + writel(upper_32_bits(size), soc_hha->base + HISI_HHA_LEN_H); 98 + 99 + reg = FIELD_PREP(HISI_HHA_CTRL_TYPE, 1); /* Clean Invalid */ 100 + reg |= HISI_HHA_CTRL_RANGE | HISI_HHA_CTRL_EN; 101 + writel(reg, soc_hha->base + HISI_HHA_CTRL); 102 + 103 + return 0; 104 + } 105 + 106 + static int hisi_soc_hha_done(struct cache_coherency_ops_inst *cci) 107 + { 108 + struct hisi_soc_hha *soc_hha = 109 + container_of(cci, struct hisi_soc_hha, cci); 110 + 111 + guard(mutex)(&soc_hha->lock); 112 + if (!hisi_hha_cache_maintain_wait_finished(soc_hha)) 113 + return -ETIMEDOUT; 114 + 115 + return 0; 116 + } 117 + 118 + static const struct cache_coherency_ops hha_ops = { 119 + .wbinv = hisi_soc_hha_wbinv, 120 + .done = hisi_soc_hha_done, 121 + }; 122 + 123 + static int hisi_soc_hha_probe(struct platform_device *pdev) 124 + { 125 + struct hisi_soc_hha *soc_hha; 126 + struct resource *mem; 127 + int ret; 128 + 129 + soc_hha = cache_coherency_ops_instance_alloc(&hha_ops, 130 + struct hisi_soc_hha, cci); 131 + if (!soc_hha) 132 + return -ENOMEM; 133 + 134 + platform_set_drvdata(pdev, soc_hha); 135 + 136 + mutex_init(&soc_hha->lock); 137 + 138 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 139 + if (!mem) { 140 + ret = -ENOMEM; 141 + goto err_free_cci; 142 + } 143 + 144 + soc_hha->base = ioremap(mem->start, resource_size(mem)); 145 + if (!soc_hha->base) { 146 + ret = dev_err_probe(&pdev->dev, -ENOMEM, 147 + "failed to remap io memory"); 148 + goto err_free_cci; 149 + } 150 + 151 + ret = cache_coherency_ops_instance_register(&soc_hha->cci); 152 + if (ret) 153 + goto err_iounmap; 154 + 155 + return 0; 156 + 157 + err_iounmap: 158 + iounmap(soc_hha->base); 159 + err_free_cci: 160 + cache_coherency_ops_instance_put(&soc_hha->cci); 161 + return ret; 162 + } 163 + 164 + static void hisi_soc_hha_remove(struct platform_device *pdev) 165 + { 166 + struct hisi_soc_hha *soc_hha = platform_get_drvdata(pdev); 167 + 168 + cache_coherency_ops_instance_unregister(&soc_hha->cci); 169 + iounmap(soc_hha->base); 170 + cache_coherency_ops_instance_put(&soc_hha->cci); 171 + } 172 + 173 + static const struct acpi_device_id hisi_soc_hha_ids[] = { 174 + { "HISI0511", }, 175 + { } 176 + }; 177 + MODULE_DEVICE_TABLE(acpi, hisi_soc_hha_ids); 178 + 179 + static struct platform_driver hisi_soc_hha_driver = { 180 + .driver = { 181 + .name = "hisi_soc_hha", 182 + .acpi_match_table = hisi_soc_hha_ids, 183 + }, 184 + .probe = hisi_soc_hha_probe, 185 + .remove = hisi_soc_hha_remove, 186 + }; 187 + 188 + module_platform_driver(hisi_soc_hha_driver); 189 + 190 + MODULE_IMPORT_NS("CACHE_COHERENCY"); 191 + MODULE_DESCRIPTION("HiSilicon Hydra Home Agent driver supporting cache maintenance"); 192 + MODULE_AUTHOR("Yicong Yang <yangyicong@hisilicon.com>"); 193 + MODULE_AUTHOR("Yushan Wang <wangyushan12@huawei.com>"); 194 + MODULE_LICENSE("GPL");