summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/xe/xe_uc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/xe/xe_uc.c')
-rw-r--r--drivers/gpu/drm/xe/xe_uc.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c
new file mode 100644
index 000000000000..465bda355443
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_uc.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include "xe_uc.h"
+
+#include "xe_assert.h"
+#include "xe_device.h"
+#include "xe_gsc.h"
+#include "xe_gsc_proxy.h"
+#include "xe_gt.h"
+#include "xe_gt_printk.h"
+#include "xe_gt_sriov_vf.h"
+#include "xe_guc.h"
+#include "xe_guc_pc.h"
+#include "xe_guc_engine_activity.h"
+#include "xe_huc.h"
+#include "xe_sriov.h"
+#include "xe_uc_fw.h"
+#include "xe_wopcm.h"
+
+static struct xe_gt *
+uc_to_gt(struct xe_uc *uc)
+{
+ return container_of(uc, struct xe_gt, uc);
+}
+
+static struct xe_device *
+uc_to_xe(struct xe_uc *uc)
+{
+ return gt_to_xe(uc_to_gt(uc));
+}
+
+/* Should be called once at driver load only */
+int xe_uc_init_noalloc(struct xe_uc *uc)
+{
+ int ret;
+
+ ret = xe_guc_init_noalloc(&uc->guc);
+ if (ret)
+ goto err;
+
+ /* HuC and GSC have no early dependencies and will be initialized during xe_uc_init(). */
+ return 0;
+
+err:
+ xe_gt_err(uc_to_gt(uc), "Failed to early initialize uC (%pe)\n", ERR_PTR(ret));
+ return ret;
+}
+
+int xe_uc_init(struct xe_uc *uc)
+{
+ int ret;
+
+ /*
+ * We call the GuC/HuC/GSC init functions even if GuC submission is off
+ * to correctly move our tracking of the FW state to "disabled".
+ */
+ ret = xe_guc_init(&uc->guc);
+ if (ret)
+ goto err;
+
+ ret = xe_huc_init(&uc->huc);
+ if (ret)
+ goto err;
+
+ ret = xe_gsc_init(&uc->gsc);
+ if (ret)
+ goto err;
+
+ if (!xe_device_uc_enabled(uc_to_xe(uc)))
+ return 0;
+
+ if (!IS_SRIOV_VF(uc_to_xe(uc))) {
+ ret = xe_wopcm_init(&uc->wopcm);
+ if (ret)
+ goto err;
+ }
+
+ ret = xe_guc_min_load_for_hwconfig(&uc->guc);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ xe_gt_err(uc_to_gt(uc), "Failed to initialize uC (%pe)\n", ERR_PTR(ret));
+ return ret;
+}
+
+/**
+ * xe_uc_init_post_hwconfig - init Uc post hwconfig load
+ * @uc: The UC object
+ *
+ * Return: 0 on success, negative error code on error.
+ */
+int xe_uc_init_post_hwconfig(struct xe_uc *uc)
+{
+ int err;
+
+ /* GuC submission not enabled, nothing to do */
+ if (!xe_device_uc_enabled(uc_to_xe(uc)))
+ return 0;
+
+ err = xe_uc_sanitize_reset(uc);
+ if (err)
+ return err;
+
+ err = xe_guc_init_post_hwconfig(&uc->guc);
+ if (err)
+ return err;
+
+ err = xe_huc_init_post_hwconfig(&uc->huc);
+ if (err)
+ return err;
+
+ return xe_gsc_init_post_hwconfig(&uc->gsc);
+}
+
+static int uc_reset(struct xe_uc *uc)
+{
+ struct xe_device *xe = uc_to_xe(uc);
+ int ret;
+
+ ret = xe_guc_reset(&uc->guc);
+ if (ret) {
+ drm_err(&xe->drm, "Failed to reset GuC, ret = %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void xe_uc_sanitize(struct xe_uc *uc)
+{
+ xe_huc_sanitize(&uc->huc);
+ xe_guc_sanitize(&uc->guc);
+}
+
+int xe_uc_sanitize_reset(struct xe_uc *uc)
+{
+ xe_uc_sanitize(uc);
+
+ return uc_reset(uc);
+}
+
+static int vf_uc_load_hw(struct xe_uc *uc)
+{
+ int err;
+
+ err = xe_uc_sanitize_reset(uc);
+ if (err)
+ return err;
+
+ err = xe_guc_enable_communication(&uc->guc);
+ if (err)
+ return err;
+
+ err = xe_gt_sriov_vf_connect(uc_to_gt(uc));
+ if (err)
+ goto err_out;
+
+ uc->guc.submission_state.enabled = true;
+
+ err = xe_guc_opt_in_features_enable(&uc->guc);
+ if (err)
+ goto err_out;
+
+ err = xe_gt_record_default_lrcs(uc_to_gt(uc));
+ if (err)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ xe_guc_sanitize(&uc->guc);
+ return err;
+}
+
+/*
+ * Should be called during driver load, after every GT reset, and after every
+ * suspend to reload / auth the firmwares.
+ */
+int xe_uc_load_hw(struct xe_uc *uc)
+{
+ int ret;
+
+ /* GuC submission not enabled, nothing to do */
+ if (!xe_device_uc_enabled(uc_to_xe(uc)))
+ return 0;
+
+ if (IS_SRIOV_VF(uc_to_xe(uc)))
+ return vf_uc_load_hw(uc);
+
+ ret = xe_huc_upload(&uc->huc);
+ if (ret)
+ return ret;
+
+ ret = xe_guc_upload(&uc->guc);
+ if (ret)
+ return ret;
+
+ ret = xe_guc_enable_communication(&uc->guc);
+ if (ret)
+ return ret;
+
+ ret = xe_gt_record_default_lrcs(uc_to_gt(uc));
+ if (ret)
+ goto err_out;
+
+ ret = xe_guc_post_load_init(&uc->guc);
+ if (ret)
+ goto err_out;
+
+ ret = xe_guc_pc_start(&uc->guc.pc);
+ if (ret)
+ goto err_out;
+
+ xe_guc_engine_activity_enable_stats(&uc->guc);
+
+ /* We don't fail the driver load if HuC fails to auth, but let's warn */
+ ret = xe_huc_auth(&uc->huc, XE_HUC_AUTH_VIA_GUC);
+ xe_gt_assert(uc_to_gt(uc), !ret);
+
+ /* GSC load is async */
+ xe_gsc_load_start(&uc->gsc);
+
+ return 0;
+
+err_out:
+ xe_guc_sanitize(&uc->guc);
+ return ret;
+}
+
+int xe_uc_reset_prepare(struct xe_uc *uc)
+{
+ /* GuC submission not enabled, nothing to do */
+ if (!xe_device_uc_enabled(uc_to_xe(uc)))
+ return 0;
+
+ return xe_guc_reset_prepare(&uc->guc);
+}
+
+void xe_uc_gucrc_disable(struct xe_uc *uc)
+{
+ XE_WARN_ON(xe_guc_pc_gucrc_disable(&uc->guc.pc));
+}
+
+void xe_uc_stop_prepare(struct xe_uc *uc)
+{
+ xe_gsc_stop_prepare(&uc->gsc);
+ xe_guc_stop_prepare(&uc->guc);
+}
+
+void xe_uc_stop(struct xe_uc *uc)
+{
+ /* GuC submission not enabled, nothing to do */
+ if (!xe_device_uc_enabled(uc_to_xe(uc)))
+ return;
+
+ xe_guc_stop(&uc->guc);
+}
+
+int xe_uc_start(struct xe_uc *uc)
+{
+ /* GuC submission not enabled, nothing to do */
+ if (!xe_device_uc_enabled(uc_to_xe(uc)))
+ return 0;
+
+ return xe_guc_start(&uc->guc);
+}
+
+static void uc_reset_wait(struct xe_uc *uc)
+{
+ int ret;
+
+again:
+ xe_guc_reset_wait(&uc->guc);
+
+ ret = xe_uc_reset_prepare(uc);
+ if (ret)
+ goto again;
+}
+
+void xe_uc_suspend_prepare(struct xe_uc *uc)
+{
+ xe_gsc_wait_for_worker_completion(&uc->gsc);
+ xe_guc_stop_prepare(&uc->guc);
+}
+
+int xe_uc_suspend(struct xe_uc *uc)
+{
+ /* GuC submission not enabled, nothing to do */
+ if (!xe_device_uc_enabled(uc_to_xe(uc)))
+ return 0;
+
+ uc_reset_wait(uc);
+
+ xe_uc_stop(uc);
+
+ return xe_guc_suspend(&uc->guc);
+}
+
+/**
+ * xe_uc_declare_wedged() - Declare UC wedged
+ * @uc: the UC object
+ *
+ * Wedge the UC which stops all submission, saves desired debug state, and
+ * cleans up anything which could timeout.
+ */
+void xe_uc_declare_wedged(struct xe_uc *uc)
+{
+ xe_gt_assert(uc_to_gt(uc), uc_to_xe(uc)->wedged.mode);
+
+ xe_guc_declare_wedged(&uc->guc);
+}