1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2022 Intel Corporation 4 */ 5 6 #include "gt/intel_gt.h" 7 #include "gt/intel_hwconfig.h" 8 #include "i915_drv.h" 9 #include "i915_memcpy.h" 10 #include "intel_guc_print.h" 11 12 /* 13 * GuC has a blob containing hardware configuration information (HWConfig). 14 * This is formatted as a simple and flexible KLV (Key/Length/Value) table. 15 * 16 * For example, a minimal version could be: 17 * enum device_attr { 18 * ATTR_SOME_VALUE = 0, 19 * ATTR_SOME_MASK = 1, 20 * }; 21 * 22 * static const u32 hwconfig[] = { 23 * ATTR_SOME_VALUE, 24 * 1, // Value Length in DWords 25 * 8, // Value 26 * 27 * ATTR_SOME_MASK, 28 * 3, 29 * 0x00FFFFFFFF, 0xFFFFFFFF, 0xFF000000, 30 * }; 31 * 32 * The attribute ids are defined in a hardware spec. 33 */ 34 35 static int __guc_action_get_hwconfig(struct intel_guc *guc, 36 u32 ggtt_offset, u32 ggtt_size) 37 { 38 u32 action[] = { 39 INTEL_GUC_ACTION_GET_HWCONFIG, 40 lower_32_bits(ggtt_offset), 41 upper_32_bits(ggtt_offset), 42 ggtt_size, 43 }; 44 int ret; 45 46 guc_dbg(guc, "Querying HW config table: size = %d, offset = 0x%08X\n", 47 ggtt_size, ggtt_offset); 48 ret = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0); 49 if (ret == -ENXIO) 50 return -ENOENT; 51 52 return ret; 53 } 54 55 static int guc_hwconfig_discover_size(struct intel_guc *guc, struct intel_hwconfig *hwconfig) 56 { 57 int ret; 58 59 /* 60 * Sending a query with zero offset and size will return the 61 * size of the blob. 62 */ 63 ret = __guc_action_get_hwconfig(guc, 0, 0); 64 if (ret < 0) 65 return ret; 66 67 if (ret == 0) 68 return -EINVAL; 69 70 hwconfig->size = ret; 71 return 0; 72 } 73 74 static int guc_hwconfig_fill_buffer(struct intel_guc *guc, struct intel_hwconfig *hwconfig) 75 { 76 struct i915_vma *vma; 77 u32 ggtt_offset; 78 void *vaddr; 79 int ret; 80 81 GEM_BUG_ON(!hwconfig->size); 82 83 ret = intel_guc_allocate_and_map_vma(guc, hwconfig->size, &vma, &vaddr); 84 if (ret) 85 return ret; 86 87 ggtt_offset = intel_guc_ggtt_offset(guc, vma); 88 89 ret = __guc_action_get_hwconfig(guc, ggtt_offset, hwconfig->size); 90 if (ret >= 0) 91 memcpy(hwconfig->ptr, vaddr, hwconfig->size); 92 93 i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP); 94 95 return ret; 96 } 97 98 static bool has_table(struct drm_i915_private *i915) 99 { 100 if (IS_ALDERLAKE_P(i915) && !IS_ALDERLAKE_P_N(i915)) 101 return true; 102 if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55)) 103 return true; 104 105 return false; 106 } 107 108 /* 109 * intel_guc_hwconfig_init - Initialize the HWConfig 110 * 111 * Retrieve the HWConfig table from the GuC and save it locally. 112 * It can then be queried on demand by other users later on. 113 */ 114 static int guc_hwconfig_init(struct intel_gt *gt) 115 { 116 struct intel_hwconfig *hwconfig = >->info.hwconfig; 117 struct intel_guc *guc = gt_to_guc(gt); 118 int ret; 119 120 if (!has_table(gt->i915)) 121 return 0; 122 123 ret = guc_hwconfig_discover_size(guc, hwconfig); 124 if (ret) 125 return ret; 126 127 hwconfig->ptr = kmalloc(hwconfig->size, GFP_KERNEL); 128 if (!hwconfig->ptr) { 129 hwconfig->size = 0; 130 return -ENOMEM; 131 } 132 133 ret = guc_hwconfig_fill_buffer(guc, hwconfig); 134 if (ret < 0) { 135 intel_gt_fini_hwconfig(gt); 136 return ret; 137 } 138 139 return 0; 140 } 141 142 /* 143 * intel_gt_init_hwconfig - Initialize the HWConfig if available 144 * 145 * Retrieve the HWConfig table if available on the current platform. 146 */ 147 int intel_gt_init_hwconfig(struct intel_gt *gt) 148 { 149 if (!intel_uc_uses_guc(>->uc)) 150 return 0; 151 152 return guc_hwconfig_init(gt); 153 } 154 155 /* 156 * intel_gt_fini_hwconfig - Finalize the HWConfig 157 * 158 * Free up the memory allocation holding the table. 159 */ 160 void intel_gt_fini_hwconfig(struct intel_gt *gt) 161 { 162 struct intel_hwconfig *hwconfig = >->info.hwconfig; 163 164 kfree(hwconfig->ptr); 165 hwconfig->size = 0; 166 hwconfig->ptr = NULL; 167 } 168