165 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2022 Intel Corporation4 */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 DWords24 * 8, // Value25 *26 * ATTR_SOME_MASK,27 * 3,28 * 0x00FFFFFFFF, 0xFFFFFFFF, 0xFF000000,29 * };30 *31 * The attribute ids are defined in a hardware spec.32 */33 34static 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 52static 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 the58 * 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 71static 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 95static 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 HWConfig107 *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 */111static 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 available141 *142 * Retrieve the HWConfig table if available on the current platform.143 */144int 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 HWConfig154 *155 * Free up the memory allocation holding the table.156 */157void 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