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 = >->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(>->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 = >->info.hwconfig;
1608781f051SJohn Harrison
1618781f051SJohn Harrison kfree(hwconfig->ptr);
1628781f051SJohn Harrison hwconfig->size = 0;
1638781f051SJohn Harrison hwconfig->ptr = NULL;
1648781f051SJohn Harrison }
165