1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2024 Intel Corporation 4 */ 5 6 #include <linux/bitfield.h> 7 #include <kunit/static_stub.h> 8 #include <drm/drm_print.h> 9 10 #include "abi/guc_klvs_abi.h" 11 #include "abi/xe_driver_klvs_abi.h" 12 #include "xe_guc_klv_helpers.h" 13 #include "xe_guc_klv_thresholds_set.h" 14 15 #define make_u64(hi, lo) ((u64)((u64)(u32)(hi) << 32 | (u32)(lo))) 16 17 static bool is_group_key(u16 key) 18 { 19 KUNIT_STATIC_STUB_REDIRECT(is_group_key, key); 20 return false; 21 } 22 23 static bool is_reserved_key(u16 key) 24 { 25 return in_range(key, GUC_KLV_RESERVED_RANGE_START, GUC_KLV_RESERVED_RANGE_LEN); 26 } 27 28 /** 29 * xe_guc_klv_key_to_string - Convert KLV key into friendly name. 30 * @key: the `GuC KLV`_ key 31 * 32 * Return: name of the KLV key. 33 */ 34 const char *xe_guc_klv_key_to_string(u16 key) 35 { 36 switch (key) { 37 /* GuC Global Config KLVs */ 38 case GUC_KLV_GLOBAL_CFG_GROUP_SCHEDULING_AVAILABLE_KEY: 39 return "group_scheduling_available"; 40 case GUC_KLV_GLOBAL_CFG_NUM_PAGING_ENGINE_INSTANCES_KEY: 41 return "num_paging_engine_instances"; 42 /* VGT POLICY keys */ 43 case GUC_KLV_VGT_POLICY_SCHED_IF_IDLE_KEY: 44 return "sched_if_idle"; 45 case GUC_KLV_VGT_POLICY_ADVERSE_SAMPLE_PERIOD_KEY: 46 return "sample_period"; 47 case GUC_KLV_VGT_POLICY_ENGINE_GROUP_CONFIG_KEY: 48 return "engine_group_config"; 49 case GUC_KLV_VGT_POLICY_RESET_AFTER_VF_SWITCH_KEY: 50 return "reset_engine"; 51 /* VF CFG keys */ 52 case GUC_KLV_VF_CFG_GGTT_START_KEY: 53 return "ggtt_start"; 54 case GUC_KLV_VF_CFG_GGTT_SIZE_KEY: 55 return "ggtt_size"; 56 case GUC_KLV_VF_CFG_LMEM_SIZE_KEY: 57 return "lmem_size"; 58 case GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY: 59 return "num_contexts"; 60 case GUC_KLV_VF_CFG_TILE_MASK_KEY: 61 return "tile_mask"; 62 case GUC_KLV_VF_CFG_NUM_DOORBELLS_KEY: 63 return "num_doorbells"; 64 case GUC_KLV_VF_CFG_EXEC_QUANTUM_KEY: 65 return "exec_quantum"; 66 case GUC_KLV_VF_CFG_PREEMPT_TIMEOUT_KEY: 67 return "preempt_timeout"; 68 case GUC_KLV_VF_CFG_BEGIN_DOORBELL_ID_KEY: 69 return "begin_db_id"; 70 case GUC_KLV_VF_CFG_BEGIN_CONTEXT_ID_KEY: 71 return "begin_ctx_id"; 72 case GUC_KLV_VF_CFG_SCHED_PRIORITY_KEY: 73 return "sched_priority"; 74 case GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_KEY: 75 return "sched_groups_exec_quantum"; 76 case GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_KEY: 77 return "sched_groups_preempt_timeout"; 78 79 /* VF CFG threshold keys */ 80 #define define_threshold_key_to_string_case(TAG, NAME, ...) \ 81 \ 82 case MAKE_GUC_KLV_VF_CFG_THRESHOLD_KEY(TAG): \ 83 return #NAME; 84 85 /* private: auto-generated case statements */ 86 MAKE_XE_GUC_KLV_THRESHOLDS_SET(define_threshold_key_to_string_case) 87 #undef define_threshold_key_to_string_case 88 89 /* driver KLVs */ 90 case MIGRATION_KLV_DEVICE_DEVID_KEY: 91 return "migration_devid"; 92 case MIGRATION_KLV_DEVICE_REVID_KEY: 93 return "migration_revid"; 94 95 default: 96 if (is_reserved_key(key)) 97 return "(reserved)"; 98 return "(unknown)"; 99 } 100 } 101 102 /** 103 * xe_guc_klv_print_one() - Print single `GuC KLV`_. 104 * @key: KLV key 105 * @len: KLV length (in u32 dwords) of the KLV @value 106 * @value: KLV value (as array of @len u32 dwords) 107 * @p: the &drm_printer 108 * 109 * The buffer may contain more than one KLV. 110 */ 111 void xe_guc_klv_print_one(u16 key, u16 len, const u32 *value, struct drm_printer *p) 112 { 113 const char *name = xe_guc_klv_key_to_string(key); 114 115 if (is_group_key(key)) { 116 struct drm_printer gp = drm_line_printer(p, name, 0); 117 118 drm_printf(p, "{ key %#06x : group %u dwords } # %s\n", 119 key, len, name); 120 121 /* print group recursively */ 122 xe_guc_klv_print(value, len, &gp); 123 return; 124 } 125 126 switch (len) { 127 case 0: 128 drm_printf(p, "{ key %#06x : no value } # %s\n", key, name); 129 break; 130 case 1: 131 drm_printf(p, "{ key %#06x : 32b value %u } # %s\n", 132 key, value[0], name); 133 break; 134 case 2: 135 drm_printf(p, "{ key %#06x : 64b value %#llx } # %s\n", 136 key, make_u64(value[1], value[0]), name); 137 break; 138 default: 139 drm_printf(p, "{ key %#06x : %zu bytes %*ph } # %s\n", 140 key, len * sizeof(u32), (int)(len * sizeof(u32)), 141 value, name); 142 break; 143 } 144 } 145 146 /** 147 * xe_guc_klv_print - Print content of the buffer with `GuC KLV`_. 148 * @klvs: the buffer with KLVs 149 * @num_dwords: number of dwords (u32) available in the buffer 150 * @p: the &drm_printer 151 * 152 * The buffer may contain more than one KLV. 153 */ 154 void xe_guc_klv_print(const u32 *klvs, u32 num_dwords, struct drm_printer *p) 155 { 156 while (num_dwords >= GUC_KLV_LEN_MIN) { 157 u32 key = FIELD_GET(GUC_KLV_0_KEY, klvs[0]); 158 u32 len = FIELD_GET(GUC_KLV_0_LEN, klvs[0]); 159 160 klvs += GUC_KLV_LEN_MIN; 161 num_dwords -= GUC_KLV_LEN_MIN; 162 163 if (num_dwords < len) { 164 drm_printf(p, "{ key %#06x : truncated %zu of %zu bytes %*ph } # %s\n", 165 key, num_dwords * sizeof(u32), len * sizeof(u32), 166 (int)(num_dwords * sizeof(u32)), klvs, 167 xe_guc_klv_key_to_string(key)); 168 return; 169 } 170 171 xe_guc_klv_print_one(key, len, klvs, p); 172 173 klvs += len; 174 num_dwords -= len; 175 } 176 177 /* we don't expect any leftovers, fix if KLV header is ever changed */ 178 BUILD_BUG_ON(GUC_KLV_LEN_MIN > 1); 179 } 180 181 /** 182 * xe_guc_klv_count - Count KLVs present in the buffer. 183 * @klvs: the buffer with KLVs 184 * @num_dwords: number of dwords (u32) in the buffer 185 * 186 * Return: number of recognized KLVs or 187 * a negative error code if KLV buffer is truncated. 188 */ 189 int xe_guc_klv_count(const u32 *klvs, u32 num_dwords) 190 { 191 int num_klvs = 0; 192 193 while (num_dwords >= GUC_KLV_LEN_MIN) { 194 u32 len = FIELD_GET(GUC_KLV_0_LEN, klvs[0]); 195 196 if (num_dwords < len + GUC_KLV_LEN_MIN) 197 break; 198 199 klvs += GUC_KLV_LEN_MIN + len; 200 num_dwords -= GUC_KLV_LEN_MIN + len; 201 num_klvs++; 202 } 203 204 return num_dwords ? -ENODATA : num_klvs; 205 } 206 207 static size_t to_num_bytes(u16 dwords) 208 { 209 return dwords * sizeof(u32); 210 } 211 212 static u16 to_num_dwords(size_t size) 213 { 214 return round_up(size, sizeof(u32)) / sizeof(u32); 215 } 216 217 /** 218 * xe_guc_klv_encode_u32() - Encode 32-bit value as KLV. 219 * @klvs: the buffer where to place KLV 220 * @avail: number of dwords (u32) available in the buffer 221 * @key: key to be used 222 * @value: value to be encoded 223 * 224 * Return: pointer to the buffer location past the encoded KLV or 225 * an ERR_PTR if there was no space to encode the KLV. 226 */ 227 u32 *xe_guc_klv_encode_u32(u32 *klvs, u32 avail, u16 key, u32 value) 228 { 229 u16 len = to_num_dwords(sizeof(u32)); 230 231 if (IS_ERR(klvs)) 232 return klvs; 233 234 if (avail < GUC_KLV_LEN_MIN + len) 235 return ERR_PTR(-ENOSPC); 236 237 *klvs++ = PREP_GUC_KLV(key, len); 238 *klvs++ = value; 239 return klvs; 240 } 241 242 /** 243 * xe_guc_klv_encode_u64() - Encode 64-bit value as KLV. 244 * @klvs: the buffer where to place KLV 245 * @avail: number of dwords (u32) available in the buffer 246 * @key: key to be used 247 * @value: value to be encoded 248 * 249 * Return: pointer to the buffer location past the encoded KLV or 250 * an ERR_PTR if there was no space to encode the KLV. 251 */ 252 u32 *xe_guc_klv_encode_u64(u32 *klvs, u32 avail, u16 key, u64 value) 253 { 254 u16 len = to_num_dwords(sizeof(u64)); 255 256 if (IS_ERR(klvs)) 257 return klvs; 258 259 if (avail < GUC_KLV_LEN_MIN + len) 260 return ERR_PTR(-ENOSPC); 261 262 *klvs++ = PREP_GUC_KLV(key, len); 263 *klvs++ = lower_32_bits(value); 264 *klvs++ = upper_32_bits(value); 265 return klvs; 266 } 267 268 /** 269 * xe_guc_klv_encode_string() - Encode string as KLV. 270 * @klvs: the buffer where to place KLV 271 * @avail: number of dwords (u32) available in the buffer 272 * @key: key to be used 273 * @s: string to be encoded 274 * 275 * Return: pointer to the buffer location past the encoded KLV or 276 * an ERR_PTR if there was no space to encode the KLV. 277 */ 278 u32 *xe_guc_klv_encode_string(u32 *klvs, u32 avail, u16 key, const char *s) 279 { 280 size_t longest = to_num_bytes(FIELD_MAX(GUC_KLV_0_LEN)); 281 size_t size = strnlen(s, longest) + 1; /* \0 */ 282 u16 len = to_num_dwords(size); 283 284 if (IS_ERR(klvs)) 285 return klvs; 286 287 if (size > longest) 288 return ERR_PTR(-E2BIG); 289 290 if (avail < GUC_KLV_LEN_MIN + len) 291 return ERR_PTR(-ENOSPC); 292 293 *klvs++ = PREP_GUC_KLV(key, len); 294 strscpy_pad((void *)klvs, s, to_num_bytes(len)); 295 return klvs + len; 296 } 297 298 /** 299 * xe_guc_klv_encode_object() - Encode object using custom encoder as single KLV. 300 * @klvs: the buffer where to place KLV 301 * @avail: number of dwords (u32) available in the buffer 302 * @key: key to be used 303 * @obj: opaque object pointer 304 * @encoder: function pointer to the custom encoder 305 * 306 * Return: pointer to the buffer location past the encoded KLV or 307 * an ERR_PTR if there was no space to encode the KLV. 308 */ 309 u32 *xe_guc_klv_encode_object(u32 *klvs, u32 avail, u16 key, const void *obj, 310 u32 *(*encoder)(u32 *klvs, u32 avail, const void *obj)) 311 { 312 u32 *end; 313 314 if (IS_ERR(klvs)) 315 return klvs; 316 317 if (avail < GUC_KLV_LEN_MIN) 318 return ERR_PTR(-ENOSPC); 319 320 if (avail > GUC_KLV_LEN_MIN + FIELD_MAX(GUC_KLV_0_LEN)) 321 avail = GUC_KLV_LEN_MIN + FIELD_MAX(GUC_KLV_0_LEN); 322 323 end = encoder(klvs + GUC_KLV_LEN_MIN, avail - GUC_KLV_LEN_MIN, obj); 324 if (IS_ERR(end)) 325 return end; 326 327 if (WARN_ON(end < klvs + GUC_KLV_LEN_MIN)) 328 return ERR_PTR(-EPIPE); 329 330 if (WARN_ON(end > klvs + avail)) 331 return ERR_PTR(-EFBIG); 332 333 *klvs = PREP_GUC_KLV(key, end - (klvs + GUC_KLV_LEN_MIN)); 334 return end; 335 } 336 337 /** 338 * xe_guc_klv_parser() - Parse and decode stream of KLVs. 339 * @klvs: the buffer with KLVs 340 * @num_dwords: number of dwords (u32) available in the buffer 341 * @obj: opaque pointer to be used by the @decoder function 342 * @decoder: pointer to the decoder function 343 * 344 * Return: The sum of all results returned by the decoder or 345 * an -errno on decoder or buffer failure. 346 */ 347 int xe_guc_klv_parser(const u32 *klvs, u32 num_dwords, void *obj, 348 int (*decoder)(void *obj, u16 key, u16 len, const u32 *value)) 349 { 350 int total = 0; 351 int ret; 352 353 while (num_dwords >= GUC_KLV_LEN_MIN) { 354 u16 key = FIELD_GET(GUC_KLV_0_KEY, klvs[0]); 355 u16 len = FIELD_GET(GUC_KLV_0_LEN, klvs[0]); 356 357 klvs += GUC_KLV_LEN_MIN; 358 num_dwords -= GUC_KLV_LEN_MIN; 359 360 if (num_dwords < len) 361 return -ENODATA; 362 363 ret = decoder(obj, key, len, klvs); 364 if (ret < 0) 365 return ret; 366 total += ret; 367 368 klvs += len; 369 num_dwords -= len; 370 } 371 372 return total; 373 } 374 375 #if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST) 376 #include "tests/xe_guc_klv_helpers_kunit.c" 377 #endif 378