Commit 918bd789 authored by Badal Nilawar's avatar Badal Nilawar Committed by Lucas De Marchi
Browse files

drm/xe/xe_late_bind_fw: Introduce xe_late_bind_fw



Introduce xe_late_bind_fw to enable firmware loading for the devices,
such as the fan controller, during the driver probe. Typically,
firmware for such devices are part of IFWI flash image but can be
replaced at probe after OEM tuning.
This patch binds mei late binding component to enable firmware loading.

v2:
 - Add devm_add_action_or_reset to remove the component (Daniele)
 - Add INTEL_MEI_GSC check in xe_late_bind_init() (Daniele)
v3:
 - Fail driver probe if late bind initialization fails,
   add has_late_bind flag (Daniele)
v4:
 - %s/I915_COMPONENT_LATE_BIND/INTEL_COMPONENT_LATE_BIND/
v6:
 - rebased
v7:
 - rebased
 - In xe_late_bind_init, use drm_err when returning an error to
   stop the probe (Lucas)
 - Use imperative mode in commit message (Lucas)

Signed-off-by: default avatarBadal Nilawar <badal.nilawar@intel.com>
Reviewed-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://lore.kernel.org/r/20250905154953.3974335-4-badal.nilawar@intel.com


Signed-off-by: default avatarLucas De Marchi <lucas.demarchi@intel.com>
parent 741eeabb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ xe-y += xe_bb.o \
	xe_hw_error.o \
	xe_hw_fence.o \
	xe_irq.o \
	xe_late_bind_fw.o \
	xe_lrc.o \
	xe_migrate.o \
	xe_mmio.o \
+5 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include "xe_hwmon.h"
#include "xe_i2c.h"
#include "xe_irq.h"
#include "xe_late_bind_fw.h"
#include "xe_mmio.h"
#include "xe_module.h"
#include "xe_nvm.h"
@@ -903,6 +904,10 @@ int xe_device_probe(struct xe_device *xe)
	if (err)
		return err;

	err = xe_late_bind_init(&xe->late_bind);
	if (err)
		return err;

	err = xe_oa_init(xe);
	if (err)
		return err;
+6 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@

#include "xe_devcoredump_types.h"
#include "xe_heci_gsc.h"
#include "xe_late_bind_fw_types.h"
#include "xe_lmtt_types.h"
#include "xe_memirq_types.h"
#include "xe_oa_types.h"
@@ -280,6 +281,8 @@ struct xe_device {
		u8 has_heci_cscfi:1;
		/** @info.has_heci_gscfi: device has heci gscfi */
		u8 has_heci_gscfi:1;
		/** @info.has_late_bind: Device has firmware late binding support */
		u8 has_late_bind:1;
		/** @info.has_llc: Device has a shared CPU+GPU last level cache */
		u8 has_llc:1;
		/** @info.has_mbx_power_limits: Device has support to manage power limits using
@@ -533,6 +536,9 @@ struct xe_device {
	/** @nvm: discrete graphics non-volatile memory */
	struct intel_dg_nvm_dev *nvm;

	/** @late_bind: xe mei late bind interface */
	struct xe_late_bind late_bind;

	/** @oa: oa observation subsystem */
	struct xe_oa oa;

+84 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2025 Intel Corporation
 */

#include <linux/component.h>
#include <linux/delay.h>

#include <drm/drm_managed.h>
#include <drm/intel/i915_component.h>
#include <drm/intel/intel_lb_mei_interface.h>
#include <drm/drm_print.h>

#include "xe_device.h"
#include "xe_late_bind_fw.h"

static struct xe_device *
late_bind_to_xe(struct xe_late_bind *late_bind)
{
	return container_of(late_bind, struct xe_device, late_bind);
}

static int xe_late_bind_component_bind(struct device *xe_kdev,
				       struct device *mei_kdev, void *data)
{
	struct xe_device *xe = kdev_to_xe_device(xe_kdev);
	struct xe_late_bind *late_bind = &xe->late_bind;

	late_bind->component.ops = data;
	late_bind->component.mei_dev = mei_kdev;

	return 0;
}

static void xe_late_bind_component_unbind(struct device *xe_kdev,
					  struct device *mei_kdev, void *data)
{
	struct xe_device *xe = kdev_to_xe_device(xe_kdev);
	struct xe_late_bind *late_bind = &xe->late_bind;

	late_bind->component.ops = NULL;
}

static const struct component_ops xe_late_bind_component_ops = {
	.bind   = xe_late_bind_component_bind,
	.unbind = xe_late_bind_component_unbind,
};

static void xe_late_bind_remove(void *arg)
{
	struct xe_late_bind *late_bind = arg;
	struct xe_device *xe = late_bind_to_xe(late_bind);

	component_del(xe->drm.dev, &xe_late_bind_component_ops);
}

/**
 * xe_late_bind_init() - add xe mei late binding component
 * @late_bind: pointer to late bind structure.
 *
 * Return: 0 if the initialization was successful, a negative errno otherwise.
 */
int xe_late_bind_init(struct xe_late_bind *late_bind)
{
	struct xe_device *xe = late_bind_to_xe(late_bind);
	int err;

	if (!xe->info.has_late_bind)
		return 0;

	if (!IS_ENABLED(CONFIG_INTEL_MEI_LB) || !IS_ENABLED(CONFIG_INTEL_MEI_GSC)) {
		drm_info(&xe->drm, "Can't init xe mei late bind missing mei component\n");
		return 0;
	}

	err = component_add_typed(xe->drm.dev, &xe_late_bind_component_ops,
				  INTEL_COMPONENT_LB);
	if (err < 0) {
		drm_err(&xe->drm, "Failed to add mei late bind component (%pe)\n", ERR_PTR(err));
		return err;
	}

	return devm_add_action_or_reset(xe->drm.dev, xe_late_bind_remove, late_bind);
}
+15 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT */
/*
 * Copyright © 2025 Intel Corporation
 */

#ifndef _XE_LATE_BIND_FW_H_
#define _XE_LATE_BIND_FW_H_

#include <linux/types.h>

struct xe_late_bind;

int xe_late_bind_init(struct xe_late_bind *late_bind);

#endif
Loading