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/mutex.h>
27 #include <linux/platform_device.h>
28
29 #define HISI_HHA_CTRL 0x5004
30 #define HISI_HHA_CTRL_EN BIT(0)
31 #define HISI_HHA_CTRL_RANGE BIT(1)
32 #define HISI_HHA_CTRL_TYPE GENMASK(3, 2)
33 #define HISI_HHA_START_L 0x5008
34 #define HISI_HHA_START_H 0x500c
35 #define HISI_HHA_LEN_L 0x5010
36 #define HISI_HHA_LEN_H 0x5014
37
38 /* The maintain operation performs in a 128 Byte granularity */
39 #define HISI_HHA_MAINT_ALIGN 128
40
41 #define HISI_HHA_POLL_GAP_US 10
42 #define HISI_HHA_POLL_TIMEOUT_US 50000
43
44 struct hisi_soc_hha {
45 /* Must be first element */
46 struct cache_coherency_ops_inst cci;
47 /* Locks HHA instance to forbid overlapping access. */
48 struct mutex lock;
49 void __iomem *base;
50 };
51
hisi_hha_cache_maintain_wait_finished(struct hisi_soc_hha * soc_hha)52 static bool hisi_hha_cache_maintain_wait_finished(struct hisi_soc_hha *soc_hha)
53 {
54 u32 val;
55
56 return !readl_poll_timeout_atomic(soc_hha->base + HISI_HHA_CTRL, val,
57 !(val & HISI_HHA_CTRL_EN),
58 HISI_HHA_POLL_GAP_US,
59 HISI_HHA_POLL_TIMEOUT_US);
60 }
61
hisi_soc_hha_wbinv(struct cache_coherency_ops_inst * cci,struct cc_inval_params * invp)62 static int hisi_soc_hha_wbinv(struct cache_coherency_ops_inst *cci,
63 struct cc_inval_params *invp)
64 {
65 struct hisi_soc_hha *soc_hha =
66 container_of(cci, struct hisi_soc_hha, cci);
67 phys_addr_t top, addr = invp->addr;
68 size_t size = invp->size;
69 u32 reg;
70
71 if (!size)
72 return -EINVAL;
73
74 addr = ALIGN_DOWN(addr, HISI_HHA_MAINT_ALIGN);
75 top = ALIGN(addr + size, HISI_HHA_MAINT_ALIGN);
76 size = top - addr;
77
78 guard(mutex)(&soc_hha->lock);
79
80 if (!hisi_hha_cache_maintain_wait_finished(soc_hha))
81 return -EBUSY;
82
83 /*
84 * Hardware will search for addresses ranging [addr, addr + size - 1],
85 * last byte included, and perform maintenance in 128 byte granules
86 * on those cachelines which contain the addresses. If a given instance
87 * is either not responsible for a cacheline or that cacheline is not
88 * currently present then the search will fail, no operation will be
89 * necessary and the device will report success.
90 */
91 size -= 1;
92
93 writel(lower_32_bits(addr), soc_hha->base + HISI_HHA_START_L);
94 writel(upper_32_bits(addr), soc_hha->base + HISI_HHA_START_H);
95 writel(lower_32_bits(size), soc_hha->base + HISI_HHA_LEN_L);
96 writel(upper_32_bits(size), soc_hha->base + HISI_HHA_LEN_H);
97
98 reg = FIELD_PREP(HISI_HHA_CTRL_TYPE, 1); /* Clean Invalid */
99 reg |= HISI_HHA_CTRL_RANGE | HISI_HHA_CTRL_EN;
100 writel(reg, soc_hha->base + HISI_HHA_CTRL);
101
102 return 0;
103 }
104
hisi_soc_hha_done(struct cache_coherency_ops_inst * cci)105 static int hisi_soc_hha_done(struct cache_coherency_ops_inst *cci)
106 {
107 struct hisi_soc_hha *soc_hha =
108 container_of(cci, struct hisi_soc_hha, cci);
109
110 guard(mutex)(&soc_hha->lock);
111 if (!hisi_hha_cache_maintain_wait_finished(soc_hha))
112 return -ETIMEDOUT;
113
114 return 0;
115 }
116
117 static const struct cache_coherency_ops hha_ops = {
118 .wbinv = hisi_soc_hha_wbinv,
119 .done = hisi_soc_hha_done,
120 };
121
hisi_soc_hha_probe(struct platform_device * pdev)122 static int hisi_soc_hha_probe(struct platform_device *pdev)
123 {
124 struct hisi_soc_hha *soc_hha;
125 struct resource *mem;
126 int ret;
127
128 soc_hha = cache_coherency_ops_instance_alloc(&hha_ops,
129 struct hisi_soc_hha, cci);
130 if (!soc_hha)
131 return -ENOMEM;
132
133 platform_set_drvdata(pdev, soc_hha);
134
135 mutex_init(&soc_hha->lock);
136
137 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
138 if (!mem) {
139 ret = -ENOMEM;
140 goto err_free_cci;
141 }
142
143 soc_hha->base = ioremap(mem->start, resource_size(mem));
144 if (!soc_hha->base) {
145 ret = dev_err_probe(&pdev->dev, -ENOMEM,
146 "failed to remap io memory");
147 goto err_free_cci;
148 }
149
150 ret = cache_coherency_ops_instance_register(&soc_hha->cci);
151 if (ret)
152 goto err_iounmap;
153
154 return 0;
155
156 err_iounmap:
157 iounmap(soc_hha->base);
158 err_free_cci:
159 cache_coherency_ops_instance_put(&soc_hha->cci);
160 return ret;
161 }
162
hisi_soc_hha_remove(struct platform_device * pdev)163 static void hisi_soc_hha_remove(struct platform_device *pdev)
164 {
165 struct hisi_soc_hha *soc_hha = platform_get_drvdata(pdev);
166
167 cache_coherency_ops_instance_unregister(&soc_hha->cci);
168 iounmap(soc_hha->base);
169 cache_coherency_ops_instance_put(&soc_hha->cci);
170 }
171
172 static const struct acpi_device_id hisi_soc_hha_ids[] = {
173 { "HISI0511", },
174 { }
175 };
176 MODULE_DEVICE_TABLE(acpi, hisi_soc_hha_ids);
177
178 static struct platform_driver hisi_soc_hha_driver = {
179 .driver = {
180 .name = "hisi_soc_hha",
181 .acpi_match_table = hisi_soc_hha_ids,
182 },
183 .probe = hisi_soc_hha_probe,
184 .remove = hisi_soc_hha_remove,
185 };
186
187 module_platform_driver(hisi_soc_hha_driver);
188
189 MODULE_IMPORT_NS("CACHE_COHERENCY");
190 MODULE_DESCRIPTION("HiSilicon Hydra Home Agent driver supporting cache maintenance");
191 MODULE_AUTHOR("Yicong Yang <yangyicong@hisilicon.com>");
192 MODULE_AUTHOR("Yushan Wang <wangyushan12@huawei.com>");
193 MODULE_LICENSE("GPL");
194