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.

at v4.19-rc2 338 lines 8.8 kB view raw
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/slab.h> 17#include <linux/soc/qcom/llcc-qcom.h> 18 19#define ACTIVATE BIT(0) 20#define DEACTIVATE BIT(1) 21#define ACT_CTRL_OPCODE_ACTIVATE BIT(0) 22#define ACT_CTRL_OPCODE_DEACTIVATE BIT(1) 23#define ACT_CTRL_ACT_TRIG BIT(0) 24#define ACT_CTRL_OPCODE_SHIFT 0x01 25#define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02 26#define ATTR1_FIXED_SIZE_SHIFT 0x03 27#define ATTR1_PRIORITY_SHIFT 0x04 28#define ATTR1_MAX_CAP_SHIFT 0x10 29#define ATTR0_RES_WAYS_MASK GENMASK(11, 0) 30#define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16) 31#define ATTR0_BONUS_WAYS_SHIFT 0x10 32#define LLCC_STATUS_READ_DELAY 100 33 34#define CACHE_LINE_SIZE_SHIFT 6 35 36#define LLCC_COMMON_STATUS0 0x0003000c 37#define LLCC_LB_CNT_MASK GENMASK(31, 28) 38#define LLCC_LB_CNT_SHIFT 28 39 40#define MAX_CAP_TO_BYTES(n) (n * SZ_1K) 41#define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K) 42#define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K) 43#define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n) 44#define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n) 45 46#define BANK_OFFSET_STRIDE 0x80000 47 48static struct llcc_drv_data *drv_data; 49 50static const struct regmap_config llcc_regmap_config = { 51 .reg_bits = 32, 52 .reg_stride = 4, 53 .val_bits = 32, 54 .fast_io = true, 55}; 56 57/** 58 * llcc_slice_getd - get llcc slice descriptor 59 * @uid: usecase_id for the client 60 * 61 * A pointer to llcc slice descriptor will be returned on success and 62 * and error pointer is returned on failure 63 */ 64struct llcc_slice_desc *llcc_slice_getd(u32 uid) 65{ 66 const struct llcc_slice_config *cfg; 67 struct llcc_slice_desc *desc; 68 u32 sz, count; 69 70 cfg = drv_data->cfg; 71 sz = drv_data->cfg_size; 72 73 for (count = 0; cfg && count < sz; count++, cfg++) 74 if (cfg->usecase_id == uid) 75 break; 76 77 if (count == sz || !cfg) 78 return ERR_PTR(-ENODEV); 79 80 desc = kzalloc(sizeof(*desc), GFP_KERNEL); 81 if (!desc) 82 return ERR_PTR(-ENOMEM); 83 84 desc->slice_id = cfg->slice_id; 85 desc->slice_size = cfg->max_cap; 86 87 return desc; 88} 89EXPORT_SYMBOL_GPL(llcc_slice_getd); 90 91/** 92 * llcc_slice_putd - llcc slice descritpor 93 * @desc: Pointer to llcc slice descriptor 94 */ 95void llcc_slice_putd(struct llcc_slice_desc *desc) 96{ 97 kfree(desc); 98} 99EXPORT_SYMBOL_GPL(llcc_slice_putd); 100 101static int llcc_update_act_ctrl(u32 sid, 102 u32 act_ctrl_reg_val, u32 status) 103{ 104 u32 act_ctrl_reg; 105 u32 status_reg; 106 u32 slice_status; 107 int ret; 108 109 act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid); 110 status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid); 111 112 /* Set the ACTIVE trigger */ 113 act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; 114 ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 115 if (ret) 116 return ret; 117 118 /* Clear the ACTIVE trigger */ 119 act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; 120 ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 121 if (ret) 122 return ret; 123 124 ret = regmap_read_poll_timeout(drv_data->regmap, status_reg, 125 slice_status, !(slice_status & status), 126 0, LLCC_STATUS_READ_DELAY); 127 return ret; 128} 129 130/** 131 * llcc_slice_activate - Activate the llcc slice 132 * @desc: Pointer to llcc slice descriptor 133 * 134 * A value of zero will be returned on success and a negative errno will 135 * be returned in error cases 136 */ 137int llcc_slice_activate(struct llcc_slice_desc *desc) 138{ 139 int ret; 140 u32 act_ctrl_val; 141 142 mutex_lock(&drv_data->lock); 143 if (test_bit(desc->slice_id, drv_data->bitmap)) { 144 mutex_unlock(&drv_data->lock); 145 return 0; 146 } 147 148 act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT; 149 150 ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val, 151 DEACTIVATE); 152 if (ret) { 153 mutex_unlock(&drv_data->lock); 154 return ret; 155 } 156 157 __set_bit(desc->slice_id, drv_data->bitmap); 158 mutex_unlock(&drv_data->lock); 159 160 return ret; 161} 162EXPORT_SYMBOL_GPL(llcc_slice_activate); 163 164/** 165 * llcc_slice_deactivate - Deactivate the llcc slice 166 * @desc: Pointer to llcc slice descriptor 167 * 168 * A value of zero will be returned on success and a negative errno will 169 * be returned in error cases 170 */ 171int llcc_slice_deactivate(struct llcc_slice_desc *desc) 172{ 173 u32 act_ctrl_val; 174 int ret; 175 176 mutex_lock(&drv_data->lock); 177 if (!test_bit(desc->slice_id, drv_data->bitmap)) { 178 mutex_unlock(&drv_data->lock); 179 return 0; 180 } 181 act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT; 182 183 ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val, 184 ACTIVATE); 185 if (ret) { 186 mutex_unlock(&drv_data->lock); 187 return ret; 188 } 189 190 __clear_bit(desc->slice_id, drv_data->bitmap); 191 mutex_unlock(&drv_data->lock); 192 193 return ret; 194} 195EXPORT_SYMBOL_GPL(llcc_slice_deactivate); 196 197/** 198 * llcc_get_slice_id - return the slice id 199 * @desc: Pointer to llcc slice descriptor 200 */ 201int llcc_get_slice_id(struct llcc_slice_desc *desc) 202{ 203 return desc->slice_id; 204} 205EXPORT_SYMBOL_GPL(llcc_get_slice_id); 206 207/** 208 * llcc_get_slice_size - return the slice id 209 * @desc: Pointer to llcc slice descriptor 210 */ 211size_t llcc_get_slice_size(struct llcc_slice_desc *desc) 212{ 213 return desc->slice_size; 214} 215EXPORT_SYMBOL_GPL(llcc_get_slice_size); 216 217static int qcom_llcc_cfg_program(struct platform_device *pdev) 218{ 219 int i; 220 u32 attr1_cfg; 221 u32 attr0_cfg; 222 u32 attr1_val; 223 u32 attr0_val; 224 u32 max_cap_cacheline; 225 u32 sz; 226 int ret; 227 const struct llcc_slice_config *llcc_table; 228 struct llcc_slice_desc desc; 229 u32 bcast_off = drv_data->bcast_off; 230 231 sz = drv_data->cfg_size; 232 llcc_table = drv_data->cfg; 233 234 for (i = 0; i < sz; i++) { 235 attr1_cfg = bcast_off + 236 LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); 237 attr0_cfg = bcast_off + 238 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->regmap, attr1_cfg, attr1_val); 264 if (ret) 265 return ret; 266 ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val); 267 if (ret) 268 return ret; 269 if (llcc_table[i].activate_on_init) { 270 desc.slice_id = llcc_table[i].slice_id; 271 ret = llcc_slice_activate(&desc); 272 } 273 } 274 return ret; 275} 276 277int qcom_llcc_probe(struct platform_device *pdev, 278 const struct llcc_slice_config *llcc_cfg, u32 sz) 279{ 280 u32 num_banks; 281 struct device *dev = &pdev->dev; 282 struct resource *res; 283 void __iomem *base; 284 int ret, i; 285 286 drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); 287 if (!drv_data) 288 return -ENOMEM; 289 290 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 291 base = devm_ioremap_resource(&pdev->dev, res); 292 if (IS_ERR(base)) 293 return PTR_ERR(base); 294 295 drv_data->regmap = devm_regmap_init_mmio(dev, base, 296 &llcc_regmap_config); 297 if (IS_ERR(drv_data->regmap)) 298 return PTR_ERR(drv_data->regmap); 299 300 ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, 301 &num_banks); 302 if (ret) 303 return ret; 304 305 num_banks &= LLCC_LB_CNT_MASK; 306 num_banks >>= LLCC_LB_CNT_SHIFT; 307 drv_data->num_banks = num_banks; 308 309 for (i = 0; i < sz; i++) 310 if (llcc_cfg[i].slice_id > drv_data->max_slices) 311 drv_data->max_slices = llcc_cfg[i].slice_id; 312 313 drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32), 314 GFP_KERNEL); 315 if (!drv_data->offsets) 316 return -ENOMEM; 317 318 for (i = 0; i < num_banks; i++) 319 drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; 320 321 drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE; 322 323 drv_data->bitmap = devm_kcalloc(dev, 324 BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), 325 GFP_KERNEL); 326 if (!drv_data->bitmap) 327 return -ENOMEM; 328 329 drv_data->cfg = llcc_cfg; 330 drv_data->cfg_size = sz; 331 mutex_init(&drv_data->lock); 332 platform_set_drvdata(pdev, drv_data); 333 334 return qcom_llcc_cfg_program(pdev); 335} 336EXPORT_SYMBOL_GPL(qcom_llcc_probe); 337 338MODULE_LICENSE("GPL v2");