xref: /linux/drivers/gpu/drm/i915/gt/uc/intel_guc_hwconfig.c (revision db5d28c0bfe566908719bec8e25443aabecbb802)
18781f051SJohn Harrison // SPDX-License-Identifier: MIT
28781f051SJohn Harrison /*
38781f051SJohn Harrison  * Copyright © 2022 Intel Corporation
48781f051SJohn Harrison  */
58781f051SJohn Harrison 
68781f051SJohn Harrison #include "gt/intel_gt.h"
78781f051SJohn Harrison #include "gt/intel_hwconfig.h"
88781f051SJohn Harrison #include "i915_drv.h"
98781f051SJohn Harrison #include "i915_memcpy.h"
108781f051SJohn Harrison 
118781f051SJohn Harrison /*
128781f051SJohn Harrison  * GuC has a blob containing hardware configuration information (HWConfig).
138781f051SJohn Harrison  * This is formatted as a simple and flexible KLV (Key/Length/Value) table.
148781f051SJohn Harrison  *
158781f051SJohn Harrison  * For example, a minimal version could be:
168781f051SJohn Harrison  *   enum device_attr {
178781f051SJohn Harrison  *     ATTR_SOME_VALUE = 0,
188781f051SJohn Harrison  *     ATTR_SOME_MASK  = 1,
198781f051SJohn Harrison  *   };
208781f051SJohn Harrison  *
218781f051SJohn Harrison  *   static const u32 hwconfig[] = {
228781f051SJohn Harrison  *     ATTR_SOME_VALUE,
238781f051SJohn Harrison  *     1,		// Value Length in DWords
248781f051SJohn Harrison  *     8,		// Value
258781f051SJohn Harrison  *
268781f051SJohn Harrison  *     ATTR_SOME_MASK,
278781f051SJohn Harrison  *     3,
288781f051SJohn Harrison  *     0x00FFFFFFFF, 0xFFFFFFFF, 0xFF000000,
298781f051SJohn Harrison  *   };
308781f051SJohn Harrison  *
318781f051SJohn Harrison  * The attribute ids are defined in a hardware spec.
328781f051SJohn Harrison  */
338781f051SJohn Harrison 
__guc_action_get_hwconfig(struct intel_guc * guc,u32 ggtt_offset,u32 ggtt_size)348781f051SJohn Harrison static int __guc_action_get_hwconfig(struct intel_guc *guc,
358781f051SJohn Harrison 				     u32 ggtt_offset, u32 ggtt_size)
368781f051SJohn Harrison {
378781f051SJohn Harrison 	u32 action[] = {
388781f051SJohn Harrison 		INTEL_GUC_ACTION_GET_HWCONFIG,
398781f051SJohn Harrison 		lower_32_bits(ggtt_offset),
408781f051SJohn Harrison 		upper_32_bits(ggtt_offset),
418781f051SJohn Harrison 		ggtt_size,
428781f051SJohn Harrison 	};
438781f051SJohn Harrison 	int ret;
448781f051SJohn Harrison 
458781f051SJohn Harrison 	ret = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0);
468781f051SJohn Harrison 	if (ret == -ENXIO)
478781f051SJohn Harrison 		return -ENOENT;
488781f051SJohn Harrison 
498781f051SJohn Harrison 	return ret;
508781f051SJohn Harrison }
518781f051SJohn Harrison 
guc_hwconfig_discover_size(struct intel_guc * guc,struct intel_hwconfig * hwconfig)528781f051SJohn Harrison static int guc_hwconfig_discover_size(struct intel_guc *guc, struct intel_hwconfig *hwconfig)
538781f051SJohn Harrison {
548781f051SJohn Harrison 	int ret;
558781f051SJohn Harrison 
568781f051SJohn Harrison 	/*
578781f051SJohn Harrison 	 * Sending a query with zero offset and size will return the
588781f051SJohn Harrison 	 * size of the blob.
598781f051SJohn Harrison 	 */
608781f051SJohn Harrison 	ret = __guc_action_get_hwconfig(guc, 0, 0);
618781f051SJohn Harrison 	if (ret < 0)
628781f051SJohn Harrison 		return ret;
638781f051SJohn Harrison 
648781f051SJohn Harrison 	if (ret == 0)
658781f051SJohn Harrison 		return -EINVAL;
668781f051SJohn Harrison 
678781f051SJohn Harrison 	hwconfig->size = ret;
688781f051SJohn Harrison 	return 0;
698781f051SJohn Harrison }
708781f051SJohn Harrison 
guc_hwconfig_fill_buffer(struct intel_guc * guc,struct intel_hwconfig * hwconfig)718781f051SJohn Harrison static int guc_hwconfig_fill_buffer(struct intel_guc *guc, struct intel_hwconfig *hwconfig)
728781f051SJohn Harrison {
738781f051SJohn Harrison 	struct i915_vma *vma;
748781f051SJohn Harrison 	u32 ggtt_offset;
758781f051SJohn Harrison 	void *vaddr;
768781f051SJohn Harrison 	int ret;
778781f051SJohn Harrison 
788781f051SJohn Harrison 	GEM_BUG_ON(!hwconfig->size);
798781f051SJohn Harrison 
808781f051SJohn Harrison 	ret = intel_guc_allocate_and_map_vma(guc, hwconfig->size, &vma, &vaddr);
818781f051SJohn Harrison 	if (ret)
828781f051SJohn Harrison 		return ret;
838781f051SJohn Harrison 
848781f051SJohn Harrison 	ggtt_offset = intel_guc_ggtt_offset(guc, vma);
858781f051SJohn Harrison 
868781f051SJohn Harrison 	ret = __guc_action_get_hwconfig(guc, ggtt_offset, hwconfig->size);
878781f051SJohn Harrison 	if (ret >= 0)
888781f051SJohn Harrison 		memcpy(hwconfig->ptr, vaddr, hwconfig->size);
898781f051SJohn Harrison 
908781f051SJohn Harrison 	i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
918781f051SJohn Harrison 
928781f051SJohn Harrison 	return ret;
938781f051SJohn Harrison }
948781f051SJohn Harrison 
has_table(struct drm_i915_private * i915)958781f051SJohn Harrison static bool has_table(struct drm_i915_private *i915)
968781f051SJohn Harrison {
976373b793SAnusha Srivatsa 	if (IS_ALDERLAKE_P(i915) && !IS_ALDERLAKE_P_N(i915))
988781f051SJohn Harrison 		return true;
9916e214d4SMatt Roper 	if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55))
100bcfc713fSRodrigo Vivi 		return true;
1018781f051SJohn Harrison 
1028781f051SJohn Harrison 	return false;
1038781f051SJohn Harrison }
1048781f051SJohn Harrison 
1052447c731SLee Jones /*
1068781f051SJohn Harrison  * intel_guc_hwconfig_init - Initialize the HWConfig
1078781f051SJohn Harrison  *
1088781f051SJohn Harrison  * Retrieve the HWConfig table from the GuC and save it locally.
1098781f051SJohn Harrison  * It can then be queried on demand by other users later on.
1108781f051SJohn Harrison  */
guc_hwconfig_init(struct intel_gt * gt)1118781f051SJohn Harrison static int guc_hwconfig_init(struct intel_gt *gt)
1128781f051SJohn Harrison {
1138781f051SJohn Harrison 	struct intel_hwconfig *hwconfig = &gt->info.hwconfig;
114*3f2f20daSAndi Shyti 	struct intel_guc *guc = gt_to_guc(gt);
1158781f051SJohn Harrison 	int ret;
1168781f051SJohn Harrison 
1178781f051SJohn Harrison 	if (!has_table(gt->i915))
1188781f051SJohn Harrison 		return 0;
1198781f051SJohn Harrison 
1208781f051SJohn Harrison 	ret = guc_hwconfig_discover_size(guc, hwconfig);
1218781f051SJohn Harrison 	if (ret)
1228781f051SJohn Harrison 		return ret;
1238781f051SJohn Harrison 
1248781f051SJohn Harrison 	hwconfig->ptr = kmalloc(hwconfig->size, GFP_KERNEL);
1258781f051SJohn Harrison 	if (!hwconfig->ptr) {
1268781f051SJohn Harrison 		hwconfig->size = 0;
1278781f051SJohn Harrison 		return -ENOMEM;
1288781f051SJohn Harrison 	}
1298781f051SJohn Harrison 
1308781f051SJohn Harrison 	ret = guc_hwconfig_fill_buffer(guc, hwconfig);
1318781f051SJohn Harrison 	if (ret < 0) {
1328781f051SJohn Harrison 		intel_gt_fini_hwconfig(gt);
1338781f051SJohn Harrison 		return ret;
1348781f051SJohn Harrison 	}
1358781f051SJohn Harrison 
1368781f051SJohn Harrison 	return 0;
1378781f051SJohn Harrison }
1388781f051SJohn Harrison 
1392447c731SLee Jones /*
1408781f051SJohn Harrison  * intel_gt_init_hwconfig - Initialize the HWConfig if available
1418781f051SJohn Harrison  *
1428781f051SJohn Harrison  * Retrieve the HWConfig table if available on the current platform.
1438781f051SJohn Harrison  */
intel_gt_init_hwconfig(struct intel_gt * gt)1448781f051SJohn Harrison int intel_gt_init_hwconfig(struct intel_gt *gt)
1458781f051SJohn Harrison {
1468781f051SJohn Harrison 	if (!intel_uc_uses_guc(&gt->uc))
1478781f051SJohn Harrison 		return 0;
1488781f051SJohn Harrison 
1498781f051SJohn Harrison 	return guc_hwconfig_init(gt);
1508781f051SJohn Harrison }
1518781f051SJohn Harrison 
1522447c731SLee Jones /*
1538781f051SJohn Harrison  * intel_gt_fini_hwconfig - Finalize the HWConfig
1548781f051SJohn Harrison  *
1558781f051SJohn Harrison  * Free up the memory allocation holding the table.
1568781f051SJohn Harrison  */
intel_gt_fini_hwconfig(struct intel_gt * gt)1578781f051SJohn Harrison void intel_gt_fini_hwconfig(struct intel_gt *gt)
1588781f051SJohn Harrison {
1598781f051SJohn Harrison 	struct intel_hwconfig *hwconfig = &gt->info.hwconfig;
1608781f051SJohn Harrison 
1618781f051SJohn Harrison 	kfree(hwconfig->ptr);
1628781f051SJohn Harrison 	hwconfig->size = 0;
1638781f051SJohn Harrison 	hwconfig->ptr = NULL;
1648781f051SJohn Harrison }
165