Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6cd5a72c authored by Arkadiusz Hiler's avatar Arkadiusz Hiler Committed by Joonas Lahtinen
Browse files

drm/i915/guc: Simplify intel_guc_init_hw()



Current version of intel_guc_init_hw() does a lot:
 - cares about submission
 - loads huc
 - implement WA

This change offloads some of the logic to intel_uc_init_hw(), which now
cares about the above.

v2: rename guc_hw_reset and fix typo in define name (M. Wajdeczko)
v3: rename once again
v4: remove spurious comments and add some style (J. Lahtinen)
v5: flow changes, got rid of dead checks (M. Wajdeczko)
v6: rebase
v7: rebase & onion teardown (J. Lahtinen)

Cc: Anusha Srivatsa <anusha.srivatsa@intel.com>
Cc: Michal Winiarski <michal.winiarski@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: default avatarArkadiusz Hiler <arkadiusz.hiler@intel.com>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
parent d2be9f2f
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -4541,7 +4541,7 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv)
	intel_mocs_init_l3cc_table(dev_priv);
	intel_mocs_init_l3cc_table(dev_priv);


	/* We can't enable contexts until all firmware is loaded */
	/* We can't enable contexts until all firmware is loaded */
	ret = intel_guc_init_hw(&dev_priv->guc);
	ret = intel_uc_init_hw(dev_priv);
	if (ret)
	if (ret)
		goto out;
		goto out;


+9 −129
Original line number Original line Diff line number Diff line
@@ -344,24 +344,6 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
	return ret;
	return ret;
}
}


static int guc_hw_reset(struct drm_i915_private *dev_priv)
{
	int ret;
	u32 guc_status;

	ret = intel_guc_reset(dev_priv);
	if (ret) {
		DRM_ERROR("GuC reset failed, ret = %d\n", ret);
		return ret;
	}

	guc_status = I915_READ(GUC_STATUS);
	WARN(!(guc_status & GS_MIA_IN_RESET),
	     "GuC status: 0x%x, MIA core expected to be in reset\n", guc_status);

	return ret;
}

/**
/**
 * intel_guc_init_hw() - finish preparing the GuC for activity
 * intel_guc_init_hw() - finish preparing the GuC for activity
 * @guc: intel_guc structure
 * @guc: intel_guc structure
@@ -379,41 +361,22 @@ int intel_guc_init_hw(struct intel_guc *guc)
{
{
	struct drm_i915_private *dev_priv = guc_to_i915(guc);
	struct drm_i915_private *dev_priv = guc_to_i915(guc);
	const char *fw_path = guc->fw.path;
	const char *fw_path = guc->fw.path;
	int retries, ret, err;
	int ret;


	DRM_DEBUG_DRIVER("GuC fw status: path %s, fetch %s, load %s\n",
	DRM_DEBUG_DRIVER("GuC fw status: path %s, fetch %s, load %s\n",
		fw_path,
		fw_path,
		intel_uc_fw_status_repr(guc->fw.fetch_status),
		intel_uc_fw_status_repr(guc->fw.fetch_status),
		intel_uc_fw_status_repr(guc->fw.load_status));
		intel_uc_fw_status_repr(guc->fw.load_status));


	/* Loading forbidden, or no firmware to load? */
	if (!fw_path) {
	if (!i915.enable_guc_loading) {
		return -ENXIO;
		err = 0;
		goto fail;
	} else if (fw_path == NULL) {
		/* Device is known to have no uCode (e.g. no GuC) */
		err = -ENXIO;
		goto fail;
	} else if (*fw_path == '\0') {
	} else if (*fw_path == '\0') {
		/* Device has a GuC but we don't know what f/w to load? */
		WARN(1, "No GuC firmware known for this platform!\n");
		WARN(1, "No GuC firmware known for this platform!\n");
		err = -ENODEV;
		return -ENODEV;
		goto fail;
	}
	}


	/* Fetch failed, or already fetched but failed to load? */
	if (guc->fw.fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
	if (guc->fw.fetch_status != INTEL_UC_FIRMWARE_SUCCESS) {
		return -EIO;
		err = -EIO;
		goto fail;
	} else if (guc->fw.load_status == INTEL_UC_FIRMWARE_FAIL) {
		err = -ENOEXEC;
		goto fail;
	}

	gen9_reset_guc_interrupts(dev_priv);

	/* We need to notify the guc whenever we change the GGTT */
	i915_ggtt_enable_guc(dev_priv);


	guc->fw.load_status = INTEL_UC_FIRMWARE_PENDING;
	guc->fw.load_status = INTEL_UC_FIRMWARE_PENDING;


@@ -421,102 +384,19 @@ int intel_guc_init_hw(struct intel_guc *guc)
		intel_uc_fw_status_repr(guc->fw.fetch_status),
		intel_uc_fw_status_repr(guc->fw.fetch_status),
		intel_uc_fw_status_repr(guc->fw.load_status));
		intel_uc_fw_status_repr(guc->fw.load_status));


	err = i915_guc_submission_init(dev_priv);
	ret = guc_ucode_xfer(dev_priv);
	if (err)
		goto fail;

	/*
	 * WaEnableuKernelHeaderValidFix:skl,bxt
	 * For BXT, this is only upto B0 but below WA is required for later
	 * steppings also so this is extended as well.
	 */
	/* WaEnableGuCBootHashCheckNotSet:skl,bxt */
	for (retries = 3; ; ) {
		/*
		 * Always reset the GuC just before (re)loading, so
		 * that the state and timing are fairly predictable
		 */
		err = guc_hw_reset(dev_priv);
		if (err)
			goto fail;

		intel_huc_init_hw(&dev_priv->huc);
		err = guc_ucode_xfer(dev_priv);
		if (!err)
			break;


		if (--retries == 0)
	if (ret)
			goto fail;
		return -EAGAIN;

		DRM_INFO("GuC fw load failed: %d; will reset and "
			 "retry %d more time(s)\n", err, retries);
	}


	guc->fw.load_status = INTEL_UC_FIRMWARE_SUCCESS;
	guc->fw.load_status = INTEL_UC_FIRMWARE_SUCCESS;


	intel_guc_auth_huc(dev_priv);

	if (i915.enable_guc_submission) {
		if (i915.guc_log_level >= 0)
			gen9_enable_guc_interrupts(dev_priv);

		err = i915_guc_submission_enable(dev_priv);
		if (err)
			goto fail;
	}

	DRM_INFO("GuC %s (firmware %s [version %u.%u])\n",
	DRM_INFO("GuC %s (firmware %s [version %u.%u])\n",
		 i915.enable_guc_submission ? "submission enabled" : "loaded",
		 i915.enable_guc_submission ? "submission enabled" : "loaded",
		 guc->fw.path,
		 guc->fw.path,
		 guc->fw.major_ver_found, guc->fw.minor_ver_found);
		 guc->fw.major_ver_found, guc->fw.minor_ver_found);


	return 0;
	return 0;

fail:
	if (guc->fw.load_status == INTEL_UC_FIRMWARE_PENDING)
		guc->fw.load_status = INTEL_UC_FIRMWARE_FAIL;

	i915_guc_submission_disable(dev_priv);
	i915_guc_submission_fini(dev_priv);
	i915_ggtt_disable_guc(dev_priv);

	/*
	 * We've failed to load the firmware :(
	 *
	 * Decide whether to disable GuC submission and fall back to
	 * execlist mode, and whether to hide the error by returning
	 * zero or to return -EIO, which the caller will treat as a
	 * nonfatal error (i.e. it doesn't prevent driver load, but
	 * marks the GPU as wedged until reset).
	 */
	if (i915.enable_guc_loading > 1) {
		ret = -EIO;
	} else if (i915.enable_guc_submission > 1) {
		ret = -EIO;
	} else {
		ret = 0;
	}

	if (err == 0 && !HAS_GUC_UCODE(dev_priv))
		;	/* Don't mention the GuC! */
	else if (err == 0)
		DRM_INFO("GuC firmware load skipped\n");
	else if (ret != -EIO)
		DRM_NOTE("GuC firmware load failed: %d\n", err);
	else
		DRM_WARN("GuC firmware load failed: %d\n", err);

	if (i915.enable_guc_submission) {
		if (fw_path == NULL)
			DRM_INFO("GuC submission without firmware not supported\n");
		if (ret == 0)
			DRM_NOTE("Falling back from GuC submission to execlist mode\n");
		else
			DRM_ERROR("GuC init failed: %d\n", ret);
	}
	i915.enable_guc_submission = 0;

	return ret;
}
}




+111 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,27 @@
#include "intel_uc.h"
#include "intel_uc.h"
#include <linux/firmware.h>
#include <linux/firmware.h>


/* Reset GuC providing us with fresh state for both GuC and HuC.
 */
static int __intel_uc_reset_hw(struct drm_i915_private *dev_priv)
{
	int ret;
	u32 guc_status;

	ret = intel_guc_reset(dev_priv);
	if (ret) {
		DRM_ERROR("GuC reset failed, ret = %d\n", ret);
		return ret;
	}

	guc_status = I915_READ(GUC_STATUS);
	WARN(!(guc_status & GS_MIA_IN_RESET),
	     "GuC status: 0x%x, MIA core expected to be in reset\n",
	     guc_status);

	return ret;
}

void intel_uc_sanitize_options(struct drm_i915_private *dev_priv)
void intel_uc_sanitize_options(struct drm_i915_private *dev_priv)
{
{
	if (!HAS_GUC(dev_priv)) {
	if (!HAS_GUC(dev_priv)) {
@@ -63,6 +84,96 @@ void intel_uc_init_fw(struct drm_i915_private *dev_priv)
	intel_guc_init_fw(&dev_priv->guc);
	intel_guc_init_fw(&dev_priv->guc);
}
}


int intel_uc_init_hw(struct drm_i915_private *dev_priv)
{
	int ret, attempts;

	/* GuC not enabled, nothing to do */
	if (!i915.enable_guc_loading)
		return 0;

	gen9_reset_guc_interrupts(dev_priv);

	/* We need to notify the guc whenever we change the GGTT */
	i915_ggtt_enable_guc(dev_priv);

	if (i915.enable_guc_submission) {
		ret = i915_guc_submission_init(dev_priv);
		if (ret)
			goto err;
	}

	/* WaEnableuKernelHeaderValidFix:skl */
	/* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */
	if (IS_GEN9(dev_priv))
		attempts = 3;
	else
		attempts = 1;

	while (attempts--) {
		/*
		 * Always reset the GuC just before (re)loading, so
		 * that the state and timing are fairly predictable
		 */
		ret = __intel_uc_reset_hw(dev_priv);
		if (ret)
			goto err_submission;

		intel_huc_init_hw(&dev_priv->huc);
		ret = intel_guc_init_hw(&dev_priv->guc);
		if (ret == 0 || ret != -EAGAIN)
			break;

		DRM_DEBUG_DRIVER("GuC fw load failed: %d; will reset and "
				 "retry %d more time(s)\n", ret, attempts);
	}

	/* Did we succeded or run out of retries? */
	if (ret)
		goto err_submission;

	intel_guc_auth_huc(dev_priv);
	if (i915.enable_guc_submission) {
		if (i915.guc_log_level >= 0)
			gen9_enable_guc_interrupts(dev_priv);

		ret = i915_guc_submission_enable(dev_priv);
		if (ret)
			goto err_submission;
	}

	return 0;

	/*
	 * We've failed to load the firmware :(
	 *
	 * Decide whether to disable GuC submission and fall back to
	 * execlist mode, and whether to hide the error by returning
	 * zero or to return -EIO, which the caller will treat as a
	 * nonfatal error (i.e. it doesn't prevent driver load, but
	 * marks the GPU as wedged until reset).
	 */
err_submission:
	if (i915.enable_guc_submission)
		i915_guc_submission_fini(dev_priv);

err:
	i915_ggtt_disable_guc(dev_priv);

	DRM_ERROR("GuC init failed\n");
	if (i915.enable_guc_loading > 1 || i915.enable_guc_submission > 1)
		ret = -EIO;
	else
		ret = 0;

	if (i915.enable_guc_submission) {
		i915.enable_guc_submission = 0;
		DRM_NOTE("Falling back from GuC submission to execlist mode\n");
	}

	return ret;
}

/*
/*
 * Read GuC command/status register (SOFT_SCRATCH_0)
 * Read GuC command/status register (SOFT_SCRATCH_0)
 * Return true if it contains a response rather than a command
 * Return true if it contains a response rather than a command
+1 −0
Original line number Original line Diff line number Diff line
@@ -187,6 +187,7 @@ struct intel_huc {
void intel_uc_sanitize_options(struct drm_i915_private *dev_priv);
void intel_uc_sanitize_options(struct drm_i915_private *dev_priv);
void intel_uc_init_early(struct drm_i915_private *dev_priv);
void intel_uc_init_early(struct drm_i915_private *dev_priv);
void intel_uc_init_fw(struct drm_i915_private *dev_priv);
void intel_uc_init_fw(struct drm_i915_private *dev_priv);
int intel_uc_init_hw(struct drm_i915_private *dev_priv);
void intel_uc_prepare_fw(struct drm_i915_private *dev_priv,
void intel_uc_prepare_fw(struct drm_i915_private *dev_priv,
			 struct intel_uc_fw *uc_fw);
			 struct intel_uc_fw *uc_fw);
int intel_guc_send(struct intel_guc *guc, const u32 *action, u32 len);
int intel_guc_send(struct intel_guc *guc, const u32 *action, u32 len);