File Index
Files and directories
Sign in
FILE

xe_late_bind_fw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/xe/xe_late_bind_fw.c C
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2025 Intel Corporation
  4 */
  5
  6#include <linux/component.h>
  7#include <linux/delay.h>
  8#include <linux/firmware.h>
  9
 10#include <drm/drm_managed.h>
 11#include <drm/intel/i915_component.h>
 12#include <drm/intel/intel_lb_mei_interface.h>
 13#include <drm/drm_print.h>
 14
 15#include "xe_device.h"
 16#include "xe_late_bind_fw.h"
 17#include "xe_pcode.h"
 18#include "xe_pcode_api.h"
 19#include "xe_pm.h"
 20
 21/*
 22 * The component should load quite quickly in most cases, but it could take
 23 * a bit. Using a very big timeout just to cover the worst case scenario
 24 */
 25#define LB_INIT_TIMEOUT_MS 20000
 26
 27/*
 28 * Retry interval set to 6 seconds, in steps of 200 ms, to allow time for
 29 * other OS components to release the MEI CL handle
 30 */
 31#define LB_FW_LOAD_RETRY_MAXCOUNT 30
 32#define LB_FW_LOAD_RETRY_PAUSE_MS 200
 33
 34static const u32 fw_id_to_type[] = {
 35		[XE_LB_FW_FAN_CONTROL] = INTEL_LB_TYPE_FAN_CONTROL,
 36	};
 37
 38static const char * const fw_id_to_name[] = {
 39		[XE_LB_FW_FAN_CONTROL] = "fan_control",
 40	};
 41
 42static struct xe_device *
 43late_bind_to_xe(struct xe_late_bind *late_bind)
 44{
 45	return container_of(late_bind, struct xe_device, late_bind);
 46}
 47
 48static struct xe_device *
 49late_bind_fw_to_xe(struct xe_late_bind_fw *lb_fw)
 50{
 51	return container_of(lb_fw, struct xe_device, late_bind.late_bind_fw[lb_fw->id]);
 52}
 53
 54/* Refer to the "Late Bind based Firmware Layout" documentation entry for details */
 55static int parse_cpd_header(struct xe_late_bind_fw *lb_fw,
 56			    const void *data, size_t size, const char *manifest_entry)
 57{
 58	struct xe_device *xe = late_bind_fw_to_xe(lb_fw);
 59	const struct gsc_cpd_header_v2 *header = data;
 60	const struct gsc_manifest_header *manifest;
 61	const struct gsc_cpd_entry *entry;
 62	size_t min_size = sizeof(*header);
 63	u32 offset = 0;
 64	int i;
 65
 66	/* manifest_entry is mandatory */
 67	xe_assert(xe, manifest_entry);
 68
 69	if (size < min_size || header->header_marker != GSC_CPD_HEADER_MARKER)
 70		return -ENOENT;
 71
 72	if (header->header_length < sizeof(struct gsc_cpd_header_v2)) {
 73		drm_err(&xe->drm, "%s late binding fw: Invalid CPD header length %u!\n",
 74			fw_id_to_name[lb_fw->id], header->header_length);
 75		return -EINVAL;
 76	}
 77
 78	min_size = header->header_length + sizeof(struct gsc_cpd_entry) * header->num_of_entries;
 79	if (size < min_size) {
 80		drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
 81			fw_id_to_name[lb_fw->id], size, min_size);
 82		return -ENODATA;
 83	}
 84
 85	/* Look for the manifest first */
 86	entry = (void *)header + header->header_length;
 87	for (i = 0; i < header->num_of_entries; i++, entry++)
 88		if (strcmp(entry->name, manifest_entry) == 0)
 89			offset = entry->offset & GSC_CPD_ENTRY_OFFSET_MASK;
 90
 91	if (!offset) {
 92		drm_err(&xe->drm, "%s late binding fw: Failed to find manifest_entry\n",
 93			fw_id_to_name[lb_fw->id]);
 94		return -ENODATA;
 95	}
 96
 97	min_size = offset + sizeof(struct gsc_manifest_header);
 98	if (size < min_size) {
 99		drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
100			fw_id_to_name[lb_fw->id], size, min_size);
101		return -ENODATA;
102	}
103
104	manifest = data + offset;
105
106	lb_fw->version = manifest->fw_version;
107
108	return 0;
109}
110
111/* Refer to the "Late Bind based Firmware Layout" documentation entry for details */
112static int parse_lb_layout(struct xe_late_bind_fw *lb_fw,
113			   const void *data, size_t size, const char *fpt_entry)
114{
115	struct xe_device *xe = late_bind_fw_to_xe(lb_fw);
116	const struct csc_fpt_header *header = data;
117	const struct csc_fpt_entry *entry;
118	size_t min_size = sizeof(*header);
119	u32 offset = 0;
120	int i;
121
122	/* fpt_entry is mandatory */
123	xe_assert(xe, fpt_entry);
124
125	if (size < min_size || header->header_marker != CSC_FPT_HEADER_MARKER)
126		return -ENOENT;
127
128	if (header->header_length < sizeof(struct csc_fpt_header)) {
129		drm_err(&xe->drm, "%s late binding fw: Invalid FPT header length %u!\n",
130			fw_id_to_name[lb_fw->id], header->header_length);
131		return -EINVAL;
132	}
133
134	min_size = header->header_length + sizeof(struct csc_fpt_entry) * header->num_of_entries;
135	if (size < min_size) {
136		drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
137			fw_id_to_name[lb_fw->id], size, min_size);
138		return -ENODATA;
139	}
140
141	/* Look for the cpd header first */
142	entry = (void *)header + header->header_length;
143	for (i = 0; i < header->num_of_entries; i++, entry++)
144		if (strcmp(entry->name, fpt_entry) == 0)
145			offset = entry->offset;
146
147	if (!offset) {
148		drm_err(&xe->drm, "%s late binding fw: Failed to find fpt_entry\n",
149			fw_id_to_name[lb_fw->id]);
150		return -ENODATA;
151	}
152
153	min_size = offset + sizeof(struct gsc_cpd_header_v2);
154	if (size < min_size) {
155		drm_err(&xe->drm, "%s late binding fw: too small! %zu < %zu\n",
156			fw_id_to_name[lb_fw->id], size, min_size);
157		return -ENODATA;
158	}
159
160	return parse_cpd_header(lb_fw, data + offset, size - offset, "LTES.man");
161}
162
163static const char *xe_late_bind_parse_status(uint32_t status)
164{
165	switch (status) {
166	case INTEL_LB_STATUS_SUCCESS:
167		return "success";
168	case INTEL_LB_STATUS_4ID_MISMATCH:
169		return "4Id Mismatch";
170	case INTEL_LB_STATUS_ARB_FAILURE:
171		return "ARB Failure";
172	case INTEL_LB_STATUS_GENERAL_ERROR:
173		return "General Error";
174	case INTEL_LB_STATUS_INVALID_PARAMS:
175		return "Invalid Params";
176	case INTEL_LB_STATUS_INVALID_SIGNATURE:
177		return "Invalid Signature";
178	case INTEL_LB_STATUS_INVALID_PAYLOAD:
179		return "Invalid Payload";
180	case INTEL_LB_STATUS_TIMEOUT:
181		return "Timeout";
182	default:
183		return "Unknown error";
184	}
185}
186
187static int xe_late_bind_fw_num_fans(struct xe_late_bind *late_bind, u32 *num_fans)
188{
189	struct xe_device *xe = late_bind_to_xe(late_bind);
190	struct xe_tile *root_tile = xe_device_get_root_tile(xe);
191
192	return xe_pcode_read(root_tile,
193			     PCODE_MBOX(FAN_SPEED_CONTROL, FSC_READ_NUM_FANS, 0), num_fans, NULL);
194}
195
196void xe_late_bind_wait_for_worker_completion(struct xe_late_bind *late_bind)
197{
198	struct xe_device *xe = late_bind_to_xe(late_bind);
199	struct xe_late_bind_fw *lbfw;
200	int fw_id;
201
202	for (fw_id = 0; fw_id < XE_LB_FW_MAX_ID; fw_id++) {
203		lbfw = &late_bind->late_bind_fw[fw_id];
204		if (lbfw->payload && late_bind->wq) {
205			drm_dbg(&xe->drm, "Flush work: load %s firmware\n",
206				fw_id_to_name[lbfw->id]);
207			flush_work(&lbfw->work);
208		}
209	}
210}
211
212static void xe_late_bind_work(struct work_struct *work)
213{
214	struct xe_late_bind_fw *lbfw = container_of(work, struct xe_late_bind_fw, work);
215	struct xe_late_bind *late_bind = container_of(lbfw, struct xe_late_bind,
216						      late_bind_fw[lbfw->id]);
217	struct xe_device *xe = late_bind_to_xe(late_bind);
218	int retry = LB_FW_LOAD_RETRY_MAXCOUNT;
219	int ret;
220	int slept;
221
222	xe_device_assert_mem_access(xe);
223
224	/* we can queue this before the component is bound */
225	for (slept = 0; slept < LB_INIT_TIMEOUT_MS; slept += 100) {
226		if (late_bind->component.ops)
227			break;
228		msleep(100);
229	}
230
231	if (!late_bind->component.ops) {
232		drm_err(&xe->drm, "Late bind component not bound\n");
233		/* Do not re-attempt fw load */
234		drmm_kfree(&xe->drm, (void *)lbfw->payload);
235		lbfw->payload = NULL;
236		goto out;
237	}
238
239	drm_dbg(&xe->drm, "Load %s firmware\n", fw_id_to_name[lbfw->id]);
240
241	do {
242		ret = late_bind->component.ops->push_payload(late_bind->component.mei_dev,
243							     lbfw->type,
244							     lbfw->flags,
245							     lbfw->payload,
246							     lbfw->payload_size);
247		if (!ret)
248			break;
249		msleep(LB_FW_LOAD_RETRY_PAUSE_MS);
250	} while (--retry && ret == -EBUSY);
251
252	if (!ret) {
253		drm_dbg(&xe->drm, "Load %s firmware successful\n",
254			fw_id_to_name[lbfw->id]);
255		goto out;
256	}
257
258	if (ret > 0)
259		drm_err(&xe->drm, "Load %s firmware failed with err %d, %s\n",
260			fw_id_to_name[lbfw->id], ret, xe_late_bind_parse_status(ret));
261	else
262		drm_err(&xe->drm, "Load %s firmware failed with err %d",
263			fw_id_to_name[lbfw->id], ret);
264	/* Do not re-attempt fw load */
265	drmm_kfree(&xe->drm, (void *)lbfw->payload);
266	lbfw->payload = NULL;
267
268out:
269	xe_pm_runtime_put(xe);
270}
271
272int xe_late_bind_fw_load(struct xe_late_bind *late_bind)
273{
274	struct xe_device *xe = late_bind_to_xe(late_bind);
275	struct xe_late_bind_fw *lbfw;
276	int fw_id;
277
278	if (!late_bind->component_added)
279		return -ENODEV;
280
281	if (late_bind->disable)
282		return 0;
283
284	for (fw_id = 0; fw_id < XE_LB_FW_MAX_ID; fw_id++) {
285		lbfw = &late_bind->late_bind_fw[fw_id];
286		if (lbfw->payload) {
287			xe_pm_runtime_get_noresume(xe);
288			queue_work(late_bind->wq, &lbfw->work);
289		}
290	}
291	return 0;
292}
293
294static int __xe_late_bind_fw_init(struct xe_late_bind *late_bind, u32 fw_id)
295{
296	struct xe_device *xe = late_bind_to_xe(late_bind);
297	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
298	struct xe_late_bind_fw *lb_fw;
299	const struct firmware *fw;
300	u32 num_fans;
301	int ret;
302
303	if (fw_id >= XE_LB_FW_MAX_ID)
304		return -EINVAL;
305
306	lb_fw = &late_bind->late_bind_fw[fw_id];
307
308	lb_fw->id = fw_id;
309	lb_fw->type = fw_id_to_type[lb_fw->id];
310	lb_fw->flags &= ~INTEL_LB_FLAG_IS_PERSISTENT;
311
312	if (lb_fw->type == INTEL_LB_TYPE_FAN_CONTROL) {
313		ret = xe_late_bind_fw_num_fans(late_bind, &num_fans);
314		if (ret) {
315			drm_dbg(&xe->drm, "Failed to read number of fans: %d\n", ret);
316			return 0; /* Not a fatal error, continue without fan control */
317		}
318		drm_dbg(&xe->drm, "Number of Fans: %d\n", num_fans);
319		if (!num_fans)
320			return 0;
321	}
322
323	snprintf(lb_fw->blob_path, sizeof(lb_fw->blob_path), "xe/%s_8086_%04x_%04x_%04x.bin",
324		 fw_id_to_name[lb_fw->id], pdev->device,
325		 pdev->subsystem_vendor, pdev->subsystem_device);
326
327	drm_dbg(&xe->drm, "Request late binding firmware %s\n", lb_fw->blob_path);
328	ret = firmware_request_nowarn(&fw, lb_fw->blob_path, xe->drm.dev);
329	if (ret) {
330		drm_dbg(&xe->drm, "%s late binding fw not available for current device",
331			fw_id_to_name[lb_fw->id]);
332		return 0;
333	}
334
335	if (fw->size > XE_LB_MAX_PAYLOAD_SIZE) {
336		drm_err(&xe->drm, "Firmware %s size %zu is larger than max pay load size %u\n",
337			lb_fw->blob_path, fw->size, XE_LB_MAX_PAYLOAD_SIZE);
338		release_firmware(fw);
339		return -ENODATA;
340	}
341
342	ret = parse_lb_layout(lb_fw, fw->data, fw->size, "LTES");
343	if (ret)
344		return ret;
345
346	lb_fw->payload_size = fw->size;
347	lb_fw->payload = drmm_kzalloc(&xe->drm, lb_fw->payload_size, GFP_KERNEL);
348	if (!lb_fw->payload) {
349		release_firmware(fw);
350		return -ENOMEM;
351	}
352
353	drm_info(&xe->drm, "Using %s firmware from %s version %u.%u.%u.%u\n",
354		 fw_id_to_name[lb_fw->id], lb_fw->blob_path,
355		 lb_fw->version.major, lb_fw->version.minor,
356		 lb_fw->version.hotfix, lb_fw->version.build);
357
358	memcpy((void *)lb_fw->payload, fw->data, lb_fw->payload_size);
359	release_firmware(fw);
360	INIT_WORK(&lb_fw->work, xe_late_bind_work);
361
362	return 0;
363}
364
365static int xe_late_bind_fw_init(struct xe_late_bind *late_bind)
366{
367	int ret;
368	int fw_id;
369
370	late_bind->wq = alloc_ordered_workqueue("late-bind-ordered-wq", 0);
371	if (!late_bind->wq)
372		return -ENOMEM;
373
374	for (fw_id = 0; fw_id < XE_LB_FW_MAX_ID; fw_id++) {
375		ret = __xe_late_bind_fw_init(late_bind, fw_id);
376		if (ret)
377			return ret;
378	}
379
380	return 0;
381}
382
383static int xe_late_bind_component_bind(struct device *xe_kdev,
384				       struct device *mei_kdev, void *data)
385{
386	struct xe_device *xe = kdev_to_xe_device(xe_kdev);
387	struct xe_late_bind *late_bind = &xe->late_bind;
388
389	late_bind->component.ops = data;
390	late_bind->component.mei_dev = mei_kdev;
391
392	return 0;
393}
394
395static void xe_late_bind_component_unbind(struct device *xe_kdev,
396					  struct device *mei_kdev, void *data)
397{
398	struct xe_device *xe = kdev_to_xe_device(xe_kdev);
399	struct xe_late_bind *late_bind = &xe->late_bind;
400
401	xe_late_bind_wait_for_worker_completion(late_bind);
402
403	late_bind->component.ops = NULL;
404}
405
406static const struct component_ops xe_late_bind_component_ops = {
407	.bind   = xe_late_bind_component_bind,
408	.unbind = xe_late_bind_component_unbind,
409};
410
411static void xe_late_bind_remove(void *arg)
412{
413	struct xe_late_bind *late_bind = arg;
414	struct xe_device *xe = late_bind_to_xe(late_bind);
415
416	xe_late_bind_wait_for_worker_completion(late_bind);
417
418	late_bind->component_added = false;
419
420	component_del(xe->drm.dev, &xe_late_bind_component_ops);
421	if (late_bind->wq) {
422		destroy_workqueue(late_bind->wq);
423		late_bind->wq = NULL;
424	}
425}
426
427/**
428 * xe_late_bind_init() - add xe mei late binding component
429 * @late_bind: pointer to late bind structure.
430 *
431 * Return: 0 if the initialization was successful, a negative errno otherwise.
432 */
433int xe_late_bind_init(struct xe_late_bind *late_bind)
434{
435	struct xe_device *xe = late_bind_to_xe(late_bind);
436	int err;
437
438	if (!xe->info.has_late_bind)
439		return 0;
440
441	if (!IS_ENABLED(CONFIG_INTEL_MEI_LB) || !IS_ENABLED(CONFIG_INTEL_MEI_GSC)) {
442		drm_info(&xe->drm, "Can't init xe mei late bind missing mei component\n");
443		return 0;
444	}
445
446	err = component_add_typed(xe->drm.dev, &xe_late_bind_component_ops,
447				  INTEL_COMPONENT_LB);
448	if (err < 0) {
449		drm_err(&xe->drm, "Failed to add mei late bind component (%pe)\n", ERR_PTR(err));
450		return err;
451	}
452
453	late_bind->component_added = true;
454
455	err = devm_add_action_or_reset(xe->drm.dev, xe_late_bind_remove, late_bind);
456	if (err)
457		return err;
458
459	err = xe_late_bind_fw_init(late_bind);
460	if (err)
461		return err;
462
463	return xe_late_bind_fw_load(late_bind);
464}
~/ Read-only file preview.