]> Git Repo - linux.git/blob - drivers/soc/qcom/llcc-slice.c
blk-mq: punt failed direct issue to dispatch list
[linux.git] / drivers / soc / qcom / llcc-slice.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
4  *
5  */
6
7 #include <linux/bitmap.h>
8 #include <linux/bitops.h>
9 #include <linux/device.h>
10 #include <linux/io.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/of_device.h>
15 #include <linux/regmap.h>
16 #include <linux/sizes.h>
17 #include <linux/slab.h>
18 #include <linux/soc/qcom/llcc-qcom.h>
19
20 #define ACTIVATE                      BIT(0)
21 #define DEACTIVATE                    BIT(1)
22 #define ACT_CTRL_OPCODE_ACTIVATE      BIT(0)
23 #define ACT_CTRL_OPCODE_DEACTIVATE    BIT(1)
24 #define ACT_CTRL_ACT_TRIG             BIT(0)
25 #define ACT_CTRL_OPCODE_SHIFT         0x01
26 #define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
27 #define ATTR1_FIXED_SIZE_SHIFT        0x03
28 #define ATTR1_PRIORITY_SHIFT          0x04
29 #define ATTR1_MAX_CAP_SHIFT           0x10
30 #define ATTR0_RES_WAYS_MASK           GENMASK(11, 0)
31 #define ATTR0_BONUS_WAYS_MASK         GENMASK(27, 16)
32 #define ATTR0_BONUS_WAYS_SHIFT        0x10
33 #define LLCC_STATUS_READ_DELAY        100
34
35 #define CACHE_LINE_SIZE_SHIFT         6
36
37 #define LLCC_COMMON_STATUS0           0x0003000c
38 #define LLCC_LB_CNT_MASK              GENMASK(31, 28)
39 #define LLCC_LB_CNT_SHIFT             28
40
41 #define MAX_CAP_TO_BYTES(n)           (n * SZ_1K)
42 #define LLCC_TRP_ACT_CTRLn(n)         (n * SZ_4K)
43 #define LLCC_TRP_STATUSn(n)           (4 + n * SZ_4K)
44 #define LLCC_TRP_ATTR0_CFGn(n)        (0x21000 + SZ_8 * n)
45 #define LLCC_TRP_ATTR1_CFGn(n)        (0x21004 + SZ_8 * n)
46
47 #define BANK_OFFSET_STRIDE            0x80000
48
49 static struct llcc_drv_data *drv_data;
50
51 static const struct regmap_config llcc_regmap_config = {
52         .reg_bits = 32,
53         .reg_stride = 4,
54         .val_bits = 32,
55         .fast_io = true,
56 };
57
58 /**
59  * llcc_slice_getd - get llcc slice descriptor
60  * @uid: usecase_id for the client
61  *
62  * A pointer to llcc slice descriptor will be returned on success and
63  * and error pointer is returned on failure
64  */
65 struct llcc_slice_desc *llcc_slice_getd(u32 uid)
66 {
67         const struct llcc_slice_config *cfg;
68         struct llcc_slice_desc *desc;
69         u32 sz, count;
70
71         cfg = drv_data->cfg;
72         sz = drv_data->cfg_size;
73
74         for (count = 0; cfg && count < sz; count++, cfg++)
75                 if (cfg->usecase_id == uid)
76                         break;
77
78         if (count == sz || !cfg)
79                 return ERR_PTR(-ENODEV);
80
81         desc = kzalloc(sizeof(*desc), GFP_KERNEL);
82         if (!desc)
83                 return ERR_PTR(-ENOMEM);
84
85         desc->slice_id = cfg->slice_id;
86         desc->slice_size = cfg->max_cap;
87
88         return desc;
89 }
90 EXPORT_SYMBOL_GPL(llcc_slice_getd);
91
92 /**
93  * llcc_slice_putd - llcc slice descritpor
94  * @desc: Pointer to llcc slice descriptor
95  */
96 void llcc_slice_putd(struct llcc_slice_desc *desc)
97 {
98         kfree(desc);
99 }
100 EXPORT_SYMBOL_GPL(llcc_slice_putd);
101
102 static int llcc_update_act_ctrl(u32 sid,
103                                 u32 act_ctrl_reg_val, u32 status)
104 {
105         u32 act_ctrl_reg;
106         u32 status_reg;
107         u32 slice_status;
108         int ret;
109
110         act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
111         status_reg = LLCC_TRP_STATUSn(sid);
112
113         /* Set the ACTIVE trigger */
114         act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
115         ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
116                                 act_ctrl_reg_val);
117         if (ret)
118                 return ret;
119
120         /* Clear the ACTIVE trigger */
121         act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
122         ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
123                                 act_ctrl_reg_val);
124         if (ret)
125                 return ret;
126
127         ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
128                                       slice_status, !(slice_status & status),
129                                       0, LLCC_STATUS_READ_DELAY);
130         return ret;
131 }
132
133 /**
134  * llcc_slice_activate - Activate the llcc slice
135  * @desc: Pointer to llcc slice descriptor
136  *
137  * A value of zero will be returned on success and a negative errno will
138  * be returned in error cases
139  */
140 int llcc_slice_activate(struct llcc_slice_desc *desc)
141 {
142         int ret;
143         u32 act_ctrl_val;
144
145         mutex_lock(&drv_data->lock);
146         if (test_bit(desc->slice_id, drv_data->bitmap)) {
147                 mutex_unlock(&drv_data->lock);
148                 return 0;
149         }
150
151         act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT;
152
153         ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
154                                   DEACTIVATE);
155         if (ret) {
156                 mutex_unlock(&drv_data->lock);
157                 return ret;
158         }
159
160         __set_bit(desc->slice_id, drv_data->bitmap);
161         mutex_unlock(&drv_data->lock);
162
163         return ret;
164 }
165 EXPORT_SYMBOL_GPL(llcc_slice_activate);
166
167 /**
168  * llcc_slice_deactivate - Deactivate the llcc slice
169  * @desc: Pointer to llcc slice descriptor
170  *
171  * A value of zero will be returned on success and a negative errno will
172  * be returned in error cases
173  */
174 int llcc_slice_deactivate(struct llcc_slice_desc *desc)
175 {
176         u32 act_ctrl_val;
177         int ret;
178
179         mutex_lock(&drv_data->lock);
180         if (!test_bit(desc->slice_id, drv_data->bitmap)) {
181                 mutex_unlock(&drv_data->lock);
182                 return 0;
183         }
184         act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT;
185
186         ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
187                                   ACTIVATE);
188         if (ret) {
189                 mutex_unlock(&drv_data->lock);
190                 return ret;
191         }
192
193         __clear_bit(desc->slice_id, drv_data->bitmap);
194         mutex_unlock(&drv_data->lock);
195
196         return ret;
197 }
198 EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
199
200 /**
201  * llcc_get_slice_id - return the slice id
202  * @desc: Pointer to llcc slice descriptor
203  */
204 int llcc_get_slice_id(struct llcc_slice_desc *desc)
205 {
206         return desc->slice_id;
207 }
208 EXPORT_SYMBOL_GPL(llcc_get_slice_id);
209
210 /**
211  * llcc_get_slice_size - return the slice id
212  * @desc: Pointer to llcc slice descriptor
213  */
214 size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
215 {
216         return desc->slice_size;
217 }
218 EXPORT_SYMBOL_GPL(llcc_get_slice_size);
219
220 static int qcom_llcc_cfg_program(struct platform_device *pdev)
221 {
222         int i;
223         u32 attr1_cfg;
224         u32 attr0_cfg;
225         u32 attr1_val;
226         u32 attr0_val;
227         u32 max_cap_cacheline;
228         u32 sz;
229         int ret = 0;
230         const struct llcc_slice_config *llcc_table;
231         struct llcc_slice_desc desc;
232
233         sz = drv_data->cfg_size;
234         llcc_table = drv_data->cfg;
235
236         for (i = 0; i < sz; i++) {
237                 attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
238                 attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
239
240                 attr1_val = llcc_table[i].cache_mode;
241                 attr1_val |= llcc_table[i].probe_target_ways <<
242                                 ATTR1_PROBE_TARGET_WAYS_SHIFT;
243                 attr1_val |= llcc_table[i].fixed_size <<
244                                 ATTR1_FIXED_SIZE_SHIFT;
245                 attr1_val |= llcc_table[i].priority <<
246                                 ATTR1_PRIORITY_SHIFT;
247
248                 max_cap_cacheline = MAX_CAP_TO_BYTES(llcc_table[i].max_cap);
249
250                 /* LLCC instances can vary for each target.
251                  * The SW writes to broadcast register which gets propagated
252                  * to each llcc instace (llcc0,.. llccN).
253                  * Since the size of the memory is divided equally amongst the
254                  * llcc instances, we need to configure the max cap accordingly.
255                  */
256                 max_cap_cacheline = max_cap_cacheline / drv_data->num_banks;
257                 max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT;
258                 attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT;
259
260                 attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
261                 attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
262
263                 ret = regmap_write(drv_data->bcast_regmap, attr1_cfg,
264                                         attr1_val);
265                 if (ret)
266                         return ret;
267                 ret = regmap_write(drv_data->bcast_regmap, attr0_cfg,
268                                         attr0_val);
269                 if (ret)
270                         return ret;
271                 if (llcc_table[i].activate_on_init) {
272                         desc.slice_id = llcc_table[i].slice_id;
273                         ret = llcc_slice_activate(&desc);
274                 }
275         }
276         return ret;
277 }
278
279 int qcom_llcc_probe(struct platform_device *pdev,
280                       const struct llcc_slice_config *llcc_cfg, u32 sz)
281 {
282         u32 num_banks;
283         struct device *dev = &pdev->dev;
284         struct resource *llcc_banks_res, *llcc_bcast_res;
285         void __iomem *llcc_banks_base, *llcc_bcast_base;
286         int ret, i;
287         struct platform_device *llcc_edac;
288
289         drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
290         if (!drv_data)
291                 return -ENOMEM;
292
293         llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
294                                                         "llcc_base");
295         llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res);
296         if (IS_ERR(llcc_banks_base))
297                 return PTR_ERR(llcc_banks_base);
298
299         drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base,
300                                                 &llcc_regmap_config);
301         if (IS_ERR(drv_data->regmap))
302                 return PTR_ERR(drv_data->regmap);
303
304         llcc_bcast_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
305                                                         "llcc_broadcast_base");
306         llcc_bcast_base = devm_ioremap_resource(&pdev->dev, llcc_bcast_res);
307         if (IS_ERR(llcc_bcast_base))
308                 return PTR_ERR(llcc_bcast_base);
309
310         drv_data->bcast_regmap = devm_regmap_init_mmio(dev, llcc_bcast_base,
311                                                         &llcc_regmap_config);
312         if (IS_ERR(drv_data->bcast_regmap))
313                 return PTR_ERR(drv_data->bcast_regmap);
314
315         ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
316                                                 &num_banks);
317         if (ret)
318                 return ret;
319
320         num_banks &= LLCC_LB_CNT_MASK;
321         num_banks >>= LLCC_LB_CNT_SHIFT;
322         drv_data->num_banks = num_banks;
323
324         for (i = 0; i < sz; i++)
325                 if (llcc_cfg[i].slice_id > drv_data->max_slices)
326                         drv_data->max_slices = llcc_cfg[i].slice_id;
327
328         drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32),
329                                                         GFP_KERNEL);
330         if (!drv_data->offsets)
331                 return -ENOMEM;
332
333         for (i = 0; i < num_banks; i++)
334                 drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
335
336         drv_data->bitmap = devm_kcalloc(dev,
337         BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
338                                                 GFP_KERNEL);
339         if (!drv_data->bitmap)
340                 return -ENOMEM;
341
342         drv_data->cfg = llcc_cfg;
343         drv_data->cfg_size = sz;
344         mutex_init(&drv_data->lock);
345         platform_set_drvdata(pdev, drv_data);
346
347         ret = qcom_llcc_cfg_program(pdev);
348         if (ret)
349                 return ret;
350
351         drv_data->ecc_irq = platform_get_irq(pdev, 0);
352         if (drv_data->ecc_irq >= 0) {
353                 llcc_edac = platform_device_register_data(&pdev->dev,
354                                                 "qcom_llcc_edac", -1, drv_data,
355                                                 sizeof(*drv_data));
356                 if (IS_ERR(llcc_edac))
357                         dev_err(dev, "Failed to register llcc edac driver\n");
358         }
359
360         return ret;
361 }
362 EXPORT_SYMBOL_GPL(qcom_llcc_probe);
363
364 MODULE_LICENSE("GPL v2");
This page took 0.051586 seconds and 4 git commands to generate.