1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Register cache access API - maple tree based cache 4 // 5 // Copyright 2023 Arm, Ltd 6 // 7 // Author: Mark Brown <broonie@kernel.org> 8 9 #include <linux/debugfs.h> 10 #include <linux/device.h> 11 #include <linux/maple_tree.h> 12 #include <linux/slab.h> 13 14 #include "internal.h" 15 16 static int regcache_maple_read(struct regmap *map, 17 unsigned int reg, unsigned int *value) 18 { 19 struct maple_tree *mt = map->cache; 20 MA_STATE(mas, mt, reg, reg); 21 unsigned long *entry; 22 23 rcu_read_lock(); 24 25 entry = mas_walk(&mas); 26 if (!entry) { 27 rcu_read_unlock(); 28 return -ENOENT; 29 } 30 31 *value = entry[reg - mas.index]; 32 33 rcu_read_unlock(); 34 35 return 0; 36 } 37 38 static int regcache_maple_write(struct regmap *map, unsigned int reg, 39 unsigned int val) 40 { 41 struct maple_tree *mt = map->cache; 42 MA_STATE(mas, mt, reg, reg); 43 unsigned long *entry, *upper, *lower; 44 unsigned long index, last; 45 size_t lower_sz, upper_sz; 46 int ret; 47 48 rcu_read_lock(); 49 50 entry = mas_walk(&mas); 51 if (entry) { 52 entry[reg - mas.index] = val; 53 rcu_read_unlock(); 54 return 0; 55 } 56 57 /* Any adjacent entries to extend/merge? */ 58 mas_set_range(&mas, reg - 1, reg + 1); 59 index = reg; 60 last = reg; 61 62 lower = mas_find(&mas, reg - 1); 63 if (lower) { 64 index = mas.index; 65 lower_sz = (mas.last - mas.index + 1) * sizeof(unsigned long); 66 } 67 68 upper = mas_find(&mas, reg + 1); 69 if (upper) { 70 last = mas.last; 71 upper_sz = (mas.last - mas.index + 1) * sizeof(unsigned long); 72 } 73 74 rcu_read_unlock(); 75 76 entry = kmalloc((last - index + 1) * sizeof(unsigned long), 77 GFP_KERNEL); 78 if (!entry) 79 return -ENOMEM; 80 81 if (lower) 82 memcpy(entry, lower, lower_sz); 83 entry[reg - index] = val; 84 if (upper) 85 memcpy(&entry[reg - index + 1], upper, upper_sz); 86 87 /* 88 * This is safe because the regmap lock means the Maple lock 89 * is redundant, but we need to take it due to lockdep asserts 90 * in the maple tree code. 91 */ 92 mas_lock(&mas); 93 94 mas_set_range(&mas, index, last); 95 ret = mas_store_gfp(&mas, entry, GFP_KERNEL); 96 97 mas_unlock(&mas); 98 99 if (ret == 0) { 100 kfree(lower); 101 kfree(upper); 102 } 103 104 return ret; 105 } 106 107 static int regcache_maple_drop(struct regmap *map, unsigned int min, 108 unsigned int max) 109 { 110 struct maple_tree *mt = map->cache; 111 MA_STATE(mas, mt, min, max); 112 unsigned long *entry, *lower, *upper; 113 unsigned long lower_index, lower_last; 114 unsigned long upper_index, upper_last; 115 int ret; 116 117 lower = NULL; 118 upper = NULL; 119 120 mas_lock(&mas); 121 122 mas_for_each(&mas, entry, max) { 123 /* 124 * This is safe because the regmap lock means the 125 * Maple lock is redundant, but we need to take it due 126 * to lockdep asserts in the maple tree code. 127 */ 128 mas_unlock(&mas); 129 130 /* Do we need to save any of this entry? */ 131 if (mas.index < min) { 132 lower_index = mas.index; 133 lower_last = min -1; 134 135 lower = kmemdup(entry, ((min - mas.index) * 136 sizeof(unsigned long)), 137 GFP_KERNEL); 138 if (!lower) { 139 ret = -ENOMEM; 140 goto out_unlocked; 141 } 142 } 143 144 if (mas.last > max) { 145 upper_index = max + 1; 146 upper_last = mas.last; 147 148 upper = kmemdup(&entry[max + 1], 149 ((mas.last - max) * 150 sizeof(unsigned long)), 151 GFP_KERNEL); 152 if (!upper) { 153 ret = -ENOMEM; 154 goto out_unlocked; 155 } 156 } 157 158 kfree(entry); 159 mas_lock(&mas); 160 mas_erase(&mas); 161 162 /* Insert new nodes with the saved data */ 163 if (lower) { 164 mas_set_range(&mas, lower_index, lower_last); 165 ret = mas_store_gfp(&mas, lower, GFP_KERNEL); 166 if (ret != 0) 167 goto out; 168 lower = NULL; 169 } 170 171 if (upper) { 172 mas_set_range(&mas, upper_index, upper_last); 173 ret = mas_store_gfp(&mas, upper, GFP_KERNEL); 174 if (ret != 0) 175 goto out; 176 upper = NULL; 177 } 178 } 179 180 out: 181 mas_unlock(&mas); 182 out_unlocked: 183 kfree(lower); 184 kfree(upper); 185 186 return ret; 187 } 188 189 static int regcache_maple_sync(struct regmap *map, unsigned int min, 190 unsigned int max) 191 { 192 struct maple_tree *mt = map->cache; 193 unsigned long *entry; 194 MA_STATE(mas, mt, min, max); 195 unsigned long lmin = min; 196 unsigned long lmax = max; 197 unsigned int r; 198 int ret; 199 200 map->cache_bypass = true; 201 202 rcu_read_lock(); 203 204 mas_for_each(&mas, entry, max) { 205 for (r = max(mas.index, lmin); r <= min(mas.last, lmax); r++) { 206 mas_pause(&mas); 207 rcu_read_unlock(); 208 ret = regcache_sync_val(map, r, entry[r - mas.index]); 209 if (ret != 0) 210 goto out; 211 rcu_read_lock(); 212 } 213 } 214 215 rcu_read_unlock(); 216 217 out: 218 map->cache_bypass = false; 219 220 return ret; 221 } 222 223 static int regcache_maple_exit(struct regmap *map) 224 { 225 struct maple_tree *mt = map->cache; 226 MA_STATE(mas, mt, 0, UINT_MAX); 227 unsigned int *entry;; 228 229 /* if we've already been called then just return */ 230 if (!mt) 231 return 0; 232 233 mas_lock(&mas); 234 mas_for_each(&mas, entry, UINT_MAX) 235 kfree(entry); 236 __mt_destroy(mt); 237 mas_unlock(&mas); 238 239 kfree(mt); 240 map->cache = NULL; 241 242 return 0; 243 } 244 245 static int regcache_maple_init(struct regmap *map) 246 { 247 struct maple_tree *mt; 248 int i; 249 int ret; 250 251 mt = kmalloc(sizeof(*mt), GFP_KERNEL); 252 if (!mt) 253 return -ENOMEM; 254 map->cache = mt; 255 256 mt_init(mt); 257 258 for (i = 0; i < map->num_reg_defaults; i++) { 259 ret = regcache_maple_write(map, 260 map->reg_defaults[i].reg, 261 map->reg_defaults[i].def); 262 if (ret) 263 goto err; 264 } 265 266 return 0; 267 268 err: 269 regcache_maple_exit(map); 270 return ret; 271 } 272 273 struct regcache_ops regcache_maple_ops = { 274 .type = REGCACHE_MAPLE, 275 .name = "maple", 276 .init = regcache_maple_init, 277 .exit = regcache_maple_exit, 278 .read = regcache_maple_read, 279 .write = regcache_maple_write, 280 .drop = regcache_maple_drop, 281 .sync = regcache_maple_sync, 282 }; 283