brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · af2c817 Raw
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