1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * System Control and Management Interface (SCMI) Message Protocol Quirks 4 * 5 * Copyright (C) 2025 ARM Ltd. 6 */ 7 8 /** 9 * DOC: Theory of operation 10 * 11 * A framework to define SCMI quirks and their activation conditions based on 12 * existing static_keys kernel facilities. 13 * 14 * Quirks are named and their activation conditions defined using the macro 15 * DEFINE_SCMI_QUIRK() in this file. 16 * 17 * After a quirk is defined, a corresponding entry must also be added to the 18 * global @scmi_quirks_table in this file using __DECLARE_SCMI_QUIRK_ENTRY(). 19 * 20 * Additionally a corresponding quirk declaration must be added also to the 21 * quirk.h file using DECLARE_SCMI_QUIRK(). 22 * 23 * The needed quirk code-snippet itself will be defined local to the SCMI code 24 * that is meant to fix and will be associated to the previously defined quirk 25 * and related activation conditions using the macro SCMI_QUIRK(). 26 * 27 * At runtime, during the SCMI stack probe sequence, once the SCMI Server had 28 * advertised the running platform Vendor, SubVendor and Implementation Version 29 * data, all the defined quirks matching the activation conditions will be 30 * enabled. 31 * 32 * Example 33 * 34 * quirk.c 35 * ------- 36 * DEFINE_SCMI_QUIRK(fix_me, "vendor", "subvend", "0x12000-0x30000", 37 * "someone,plat_A", "another,plat_b", "vend,sku"); 38 * 39 * static struct scmi_quirk *scmi_quirks_table[] = { 40 * ... 41 * __DECLARE_SCMI_QUIRK_ENTRY(fix_me), 42 * NULL 43 * }; 44 * 45 * quirk.h 46 * ------- 47 * DECLARE_SCMI_QUIRK(fix_me); 48 * 49 * <somewhere_in_the_scmi_stack.c> 50 * ------------------------------ 51 * 52 * #define QUIRK_CODE_SNIPPET_FIX_ME() \ 53 * ({ \ 54 * if (p->condition) \ 55 * a_ptr->calculated_val = 123; \ 56 * }) 57 * 58 * 59 * int some_function_to_fix(int param, struct something *p) 60 * { 61 * struct some_strut *a_ptr; 62 * 63 * a_ptr = some_load_func(p); 64 * SCMI_QUIRK(fix_me, QUIRK_CODE_SNIPPET_FIX_ME); 65 * some_more_func(a_ptr); 66 * ... 67 * 68 * return 0; 69 * } 70 * 71 */ 72 73 #include <linux/ctype.h> 74 #include <linux/cleanup.h> 75 #include <linux/device.h> 76 #include <linux/export.h> 77 #include <linux/hashtable.h> 78 #include <linux/kstrtox.h> 79 #include <linux/of.h> 80 #include <linux/slab.h> 81 #include <linux/static_key.h> 82 #include <linux/string.h> 83 #include <linux/stringhash.h> 84 #include <linux/types.h> 85 86 #include "quirks.h" 87 88 #define SCMI_QUIRKS_HT_SZ 4 89 90 struct scmi_quirk { 91 bool enabled; 92 const char *name; 93 const char *vendor; 94 const char *sub_vendor_id; 95 const char *impl_ver_range; 96 u32 start_range; 97 u32 end_range; 98 struct static_key_false *key; 99 struct hlist_node hash; 100 unsigned int hkey; 101 const char *const compats[]; 102 }; 103 104 #define __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ...) \ 105 static struct scmi_quirk scmi_quirk_entry_ ## _qn = { \ 106 .name = __stringify(quirk_ ## _qn), \ 107 .vendor = _ven, \ 108 .sub_vendor_id = _sub, \ 109 .impl_ver_range = _impl, \ 110 .key = &(scmi_quirk_ ## _qn), \ 111 .compats = { __VA_ARGS__ __VA_OPT__(,) NULL }, \ 112 } 113 114 #define __DECLARE_SCMI_QUIRK_ENTRY(_qn) (&(scmi_quirk_entry_ ## _qn)) 115 116 /* 117 * Define a quirk by name and provide the matching tokens where: 118 * 119 * _qn: A string which will be used to build the quirk and the global 120 * static_key names. 121 * _ven : SCMI Vendor ID string match, NULL means any. 122 * _sub : SCMI SubVendor ID string match, NULL means any. 123 * _impl : SCMI Implementation Version string match, NULL means any. 124 * This string can be used to express version ranges which will be 125 * interpreted as follows: 126 * 127 * NULL [0, 0xFFFFFFFF] 128 * "X" [X, X] 129 * "X-" [X, 0xFFFFFFFF] 130 * "-X" [0, X] 131 * "X-Y" [X, Y] 132 * 133 * with X <= Y and <v> in [X, Y] meaning X <= <v> <= Y 134 * 135 * ... : An optional variadic macros argument used to provide a comma-separated 136 * list of compatible strings matches; when no variadic argument is 137 * provided, ANY compatible will match this quirk. 138 * 139 * This implicitly define also a properly named global static-key that 140 * will be used to dynamically enable the quirk at initialization time. 141 * 142 * Note that it is possible to associate multiple quirks to the same 143 * matching pattern, if your firmware quality is really astounding :P 144 * 145 * Example: 146 * 147 * Compatibles list NOT provided, so ANY compatible will match: 148 * 149 * DEFINE_SCMI_QUIRK(my_new_issue, "Vend", "SVend", "0x12000-0x30000"); 150 * 151 * 152 * A few compatibles provided to match against: 153 * 154 * DEFINE_SCMI_QUIRK(my_new_issue, "Vend", "SVend", "0x12000-0x30000", 155 * "xvend,plat_a", "xvend,plat_b", "xvend,sku_name"); 156 */ 157 #define DEFINE_SCMI_QUIRK(_qn, _ven, _sub, _impl, ...) \ 158 DEFINE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn); \ 159 __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ##__VA_ARGS__) 160 161 /* 162 * Same as DEFINE_SCMI_QUIRK but EXPORTED: this is meant to address quirks 163 * that possibly reside in code that is included in loadable kernel modules 164 * that needs to be able to access the global static keys at runtime to 165 * determine if enabled or not. (see SCMI_QUIRK to understand usage) 166 */ 167 #define DEFINE_SCMI_QUIRK_EXPORTED(_qn, _ven, _sub, _impl, ...) \ 168 DEFINE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn); \ 169 EXPORT_SYMBOL_GPL(scmi_quirk_ ## _qn); \ 170 __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ##__VA_ARGS__) 171 172 /* Global Quirks Definitions */ 173 DEFINE_SCMI_QUIRK(clock_rates_triplet_out_of_spec, NULL, NULL, NULL); 174 DEFINE_SCMI_QUIRK(perf_level_get_fc_force, "Qualcomm", NULL, "0x20000-"); 175 176 /* 177 * Quirks Pointers Array 178 * 179 * This is filled at compile-time with the list of pointers to all the currently 180 * defined quirks descriptors. 181 */ 182 static struct scmi_quirk *scmi_quirks_table[] = { 183 __DECLARE_SCMI_QUIRK_ENTRY(clock_rates_triplet_out_of_spec), 184 __DECLARE_SCMI_QUIRK_ENTRY(perf_level_get_fc_force), 185 NULL 186 }; 187 188 /* 189 * Quirks HashTable 190 * 191 * A run-time populated hashtable containing all the defined quirks descriptors 192 * hashed by matching pattern. 193 */ 194 static DEFINE_READ_MOSTLY_HASHTABLE(scmi_quirks_ht, SCMI_QUIRKS_HT_SZ); 195 196 static unsigned int scmi_quirk_signature(const char *vend, const char *sub_vend) 197 { 198 char *signature, *p; 199 unsigned int hash32; 200 unsigned long hash = 0; 201 202 /* vendor_id/sub_vendor_id guaranteed <= SCMI_SHORT_NAME_MAX_SIZE */ 203 signature = kasprintf(GFP_KERNEL, "|%s|%s|", vend ?: "", sub_vend ?: ""); 204 if (!signature) 205 return 0; 206 207 pr_debug("SCMI Quirk Signature >>>%s<<<\n", signature); 208 209 p = signature; 210 while (*p) 211 hash = partial_name_hash(tolower(*p++), hash); 212 hash32 = end_name_hash(hash); 213 214 kfree(signature); 215 216 return hash32; 217 } 218 219 static int scmi_quirk_range_parse(struct scmi_quirk *quirk) 220 { 221 const char *last, *first __free(kfree) = NULL; 222 size_t len; 223 char *sep; 224 int ret; 225 226 quirk->start_range = 0; 227 quirk->end_range = 0xFFFFFFFF; 228 len = quirk->impl_ver_range ? strlen(quirk->impl_ver_range) : 0; 229 if (!len) 230 return 0; 231 232 first = kmemdup(quirk->impl_ver_range, len + 1, GFP_KERNEL); 233 if (!first) 234 return -ENOMEM; 235 236 last = first + len - 1; 237 sep = strchr(first, '-'); 238 if (sep) 239 *sep = '\0'; 240 241 if (sep == first) /* -X */ 242 ret = kstrtouint(first + 1, 0, &quirk->end_range); 243 else /* X OR X- OR X-y */ 244 ret = kstrtouint(first, 0, &quirk->start_range); 245 if (ret) 246 return ret; 247 248 if (!sep) 249 quirk->end_range = quirk->start_range; 250 else if (sep != last) /* x-Y */ 251 ret = kstrtouint(sep + 1, 0, &quirk->end_range); 252 253 if (quirk->start_range > quirk->end_range) 254 return -EINVAL; 255 256 return ret; 257 } 258 259 void scmi_quirks_initialize(void) 260 { 261 struct scmi_quirk *quirk; 262 int i; 263 264 for (i = 0, quirk = scmi_quirks_table[0]; quirk; 265 i++, quirk = scmi_quirks_table[i]) { 266 int ret; 267 268 ret = scmi_quirk_range_parse(quirk); 269 if (ret) { 270 pr_err("SCMI skip QUIRK [%s] - BAD RANGE - |%s|\n", 271 quirk->name, quirk->impl_ver_range); 272 continue; 273 } 274 quirk->hkey = scmi_quirk_signature(quirk->vendor, 275 quirk->sub_vendor_id); 276 277 hash_add(scmi_quirks_ht, &quirk->hash, quirk->hkey); 278 279 pr_debug("Registered SCMI QUIRK [%s] -- %p - Key [0x%08X] - %s/%s/[0x%08X-0x%08X]\n", 280 quirk->name, quirk, quirk->hkey, 281 quirk->vendor, quirk->sub_vendor_id, 282 quirk->start_range, quirk->end_range); 283 } 284 285 pr_debug("SCMI Quirks initialized\n"); 286 } 287 288 void scmi_quirks_enable(struct device *dev, const char *vend, 289 const char *subv, const u32 impl) 290 { 291 for (int i = 3; i >= 0; i--) { 292 struct scmi_quirk *quirk; 293 unsigned int hkey; 294 295 hkey = scmi_quirk_signature(i > 1 ? vend : NULL, 296 i > 2 ? subv : NULL); 297 298 /* 299 * Note that there could be multiple matches so we 300 * will enable multiple quirk part of a hash collision 301 * domain...BUT we cannot assume that ALL quirks on the 302 * same collision domain are a full match. 303 */ 304 hash_for_each_possible(scmi_quirks_ht, quirk, hash, hkey) { 305 if (quirk->enabled || quirk->hkey != hkey || 306 impl < quirk->start_range || 307 impl > quirk->end_range) 308 continue; 309 310 if (quirk->compats[0] && 311 !of_machine_compatible_match(quirk->compats)) 312 continue; 313 314 dev_info(dev, "Enabling SCMI Quirk [%s]\n", 315 quirk->name); 316 317 dev_dbg(dev, 318 "Quirk matched on: %s/%s/%s/[0x%08X-0x%08X]\n", 319 quirk->compats[0], quirk->vendor, 320 quirk->sub_vendor_id, 321 quirk->start_range, quirk->end_range); 322 323 static_branch_enable(quirk->key); 324 quirk->enabled = true; 325 } 326 } 327 } 328