203 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2022 Intel Corporation4 */5 6#include "xe_guc_hwconfig.h"7 8#include <drm/drm_managed.h>9#include <drm/drm_print.h>10 11#include "abi/guc_actions_abi.h"12#include "xe_bo.h"13#include "xe_device.h"14#include "xe_gt.h"15#include "xe_guc.h"16#include "xe_map.h"17 18static int send_get_hwconfig(struct xe_guc *guc, u64 ggtt_addr, u32 size)19{20 u32 action[] = {21 XE_GUC_ACTION_GET_HWCONFIG,22 lower_32_bits(ggtt_addr),23 upper_32_bits(ggtt_addr),24 size,25 };26 27 return xe_guc_mmio_send(guc, action, ARRAY_SIZE(action));28}29 30static int guc_hwconfig_size(struct xe_guc *guc, u32 *size)31{32 int ret = send_get_hwconfig(guc, 0, 0);33 34 if (ret < 0)35 return ret;36 37 *size = ret;38 return 0;39}40 41static int guc_hwconfig_copy(struct xe_guc *guc)42{43 int ret = send_get_hwconfig(guc, xe_bo_ggtt_addr(guc->hwconfig.bo),44 guc->hwconfig.size);45 46 if (ret < 0)47 return ret;48 49 return 0;50}51 52int xe_guc_hwconfig_init(struct xe_guc *guc)53{54 struct xe_device *xe = guc_to_xe(guc);55 struct xe_gt *gt = guc_to_gt(guc);56 struct xe_tile *tile = gt_to_tile(gt);57 struct xe_bo *bo;58 u32 size;59 int err;60 61 /* Initialization already done */62 if (guc->hwconfig.bo)63 return 0;64 65 /*66 * All hwconfig the same across GTs so only GT0 needs to be configured67 */68 if (gt->info.id != XE_GT0)69 return 0;70 71 /* ADL_P, DG2+ supports hwconfig table */72 if (GRAPHICS_VERx100(xe) < 1255 && xe->info.platform != XE_ALDERLAKE_P)73 return 0;74 75 err = guc_hwconfig_size(guc, &size);76 if (err)77 return err;78 if (!size)79 return -EINVAL;80 81 bo = xe_managed_bo_create_pin_map(xe, tile, PAGE_ALIGN(size),82 XE_BO_FLAG_SYSTEM |83 XE_BO_FLAG_GGTT |84 XE_BO_FLAG_GGTT_INVALIDATE);85 if (IS_ERR(bo))86 return PTR_ERR(bo);87 guc->hwconfig.bo = bo;88 guc->hwconfig.size = size;89 90 return guc_hwconfig_copy(guc);91}92 93u32 xe_guc_hwconfig_size(struct xe_guc *guc)94{95 return !guc->hwconfig.bo ? 0 : guc->hwconfig.size;96}97 98void xe_guc_hwconfig_copy(struct xe_guc *guc, void *dst)99{100 struct xe_device *xe = guc_to_xe(guc);101 102 XE_WARN_ON(!guc->hwconfig.bo);103 104 xe_map_memcpy_from(xe, dst, &guc->hwconfig.bo->vmap, 0,105 guc->hwconfig.size);106}107 108void xe_guc_hwconfig_dump(struct xe_guc *guc, struct drm_printer *p)109{110 size_t size = xe_guc_hwconfig_size(guc);111 u32 *hwconfig;112 u64 num_dw;113 u32 extra_bytes;114 int i = 0;115 116 if (size == 0) {117 drm_printf(p, "No hwconfig available\n");118 return;119 }120 121 num_dw = div_u64_rem(size, sizeof(u32), &extra_bytes);122 123 hwconfig = kzalloc(size, GFP_KERNEL);124 if (!hwconfig) {125 drm_printf(p, "Error: could not allocate hwconfig memory\n");126 return;127 }128 129 xe_guc_hwconfig_copy(guc, hwconfig);130 131 /* An entry requires at least three dwords for key, length, value */132 while (i + 3 <= num_dw) {133 u32 attribute = hwconfig[i++];134 u32 len_dw = hwconfig[i++];135 136 if (i + len_dw > num_dw) {137 drm_printf(p, "Error: Attribute %u is %u dwords, but only %llu remain\n",138 attribute, len_dw, num_dw - i);139 len_dw = num_dw - i;140 }141 142 /*143 * If it's a single dword (as most hwconfig attributes are),144 * then it's probably a number that makes sense to display145 * in decimal form. In the rare cases where it's more than146 * one dword, just print it in hex form and let the user147 * figure out how to interpret it.148 */149 if (len_dw == 1)150 drm_printf(p, "[%2u] = %u\n", attribute, hwconfig[i]);151 else152 drm_printf(p, "[%2u] = { %*ph }\n", attribute,153 (int)(len_dw * sizeof(u32)), &hwconfig[i]);154 i += len_dw;155 }156 157 if (i < num_dw || extra_bytes)158 drm_printf(p, "Error: %llu extra bytes at end of hwconfig\n",159 (num_dw - i) * sizeof(u32) + extra_bytes);160 161 kfree(hwconfig);162}163 164/*165 * Lookup a specific 32-bit attribute value in the GuC's hwconfig table.166 */167int xe_guc_hwconfig_lookup_u32(struct xe_guc *guc, u32 attribute, u32 *val)168{169 size_t size = xe_guc_hwconfig_size(guc);170 u64 num_dw = div_u64(size, sizeof(u32));171 u32 *hwconfig;172 bool found = false;173 int i = 0;174 175 if (num_dw == 0)176 return -EINVAL;177 178 hwconfig = kzalloc(size, GFP_KERNEL);179 if (!hwconfig)180 return -ENOMEM;181 182 xe_guc_hwconfig_copy(guc, hwconfig);183 184 /* An entry requires at least three dwords for key, length, value */185 while (i + 3 <= num_dw) {186 u32 key = hwconfig[i++];187 u32 len_dw = hwconfig[i++];188 189 if (key != attribute) {190 i += len_dw;191 continue;192 }193 194 *val = hwconfig[i];195 found = true;196 break;197 }198 199 kfree(hwconfig);200 201 return found ? 0 : -ENOENT;202}203