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