Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2022 Intel Corporation
  4 */
  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 DWords
 24 *     8,		// Value
 25 *
 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 the
 58	 * 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 HWConfig
107 *
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 = &gt->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 available
141 *
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(&gt->uc))
147		return 0;
148
149	return guc_hwconfig_init(gt);
150}
151
152/*
153 * intel_gt_fini_hwconfig - Finalize the HWConfig
154 *
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 = &gt->info.hwconfig;
160
161	kfree(hwconfig->ptr);
162	hwconfig->size = 0;
163	hwconfig->ptr = NULL;
164}