if (actions & GSC_ACTION_FW_LOAD) {
ret = intel_gsc_uc_fw_upload(gsc); if (!ret) /* setup proxy on a new load */
actions |= GSC_ACTION_SW_PROXY; elseif (ret != -EEXIST) goto out_put;
/* * The HuC auth can be done both before or after the proxy init; * if done after, a proxy request will be issued and must be * serviced before the authentication can complete. * Since this worker also handles proxy requests, we can't * perform an action that requires the proxy from within it and * then stall waiting for it, because we'd be blocking the * service path. Therefore, it is easier for us to load HuC * first and do proxy later. The GSC will ack the HuC auth and * then send the HuC proxy request as part of the proxy init * flow. * Note that we can only do the GSC auth if the GuC auth was * successful.
*/ if (intel_uc_uses_huc(>->uc) &&
intel_huc_is_authenticated(>->uc.huc, INTEL_HUC_AUTH_BY_GUC))
intel_huc_auth(>->uc.huc, INTEL_HUC_AUTH_BY_GSC);
}
if (actions & GSC_ACTION_SW_PROXY) { if (!intel_gsc_uc_fw_init_done(gsc)) {
gt_err(gt, "Proxy request received with GSC not loaded!\n"); goto out_put;
}
ret = intel_gsc_proxy_request_handler(gsc); if (ret) { if (actions & GSC_ACTION_FW_LOAD) { /* * A proxy failure right after firmware load means the proxy-init * step has failed so mark GSC as not usable after this
*/
gt_err(gt, "GSC proxy handler failed to init\n");
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL);
} goto out_put;
}
/* mark the GSC FW init as done the first time we run this */ if (actions & GSC_ACTION_FW_LOAD) { /* * If there is a proxy establishment error, the GSC might still * complete the request handling cleanly, so we need to check the * status register to check if the proxy init was actually successful
*/ if (intel_gsc_uc_fw_proxy_init_done(gsc, false)) {
gt_dbg(gt, "GSC Proxy initialized\n");
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_RUNNING);
} else {
gt_err(gt, "GSC status reports proxy init not complete\n");
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL);
}
}
}
/* * We reach here from i915_driver_early_probe for the primary GT before * its engine mask is set, so we use the device info engine mask for it. * For other GTs we expect the GT-specific mask to be set before we * call this function.
*/
GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask);
if (gt_is_root(gt))
mask = INTEL_INFO(gt->i915)->platform_engine_mask; else
mask = gt->info.engine_mask;
/* * GSC FW needs to be copied to a dedicated memory allocations for * loading (see gsc->local), so we don't need to GGTT map the FW image * itself into GGTT.
*/
intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC, false);
INIT_WORK(&gsc->work, gsc_work);
/* we can arrive here from i915_driver_early_probe for primary * GT with it being not fully setup hence check device info's * engine mask
*/ if (!gsc_engine_supported(gt)) {
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED); return;
}
gsc->wq = alloc_ordered_workqueue("i915_gsc", 0); if (!gsc->wq) {
gt_err(gt, "failed to allocate WQ for GSC, disabling FW\n");
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);
}
}
/* * The GSC FW doesn't immediately suspend after becoming idle, so there * is a chance that it could still be awake after we successfully * return from the pci suspend function, even if there are no pending * operations. * The FW might therefore try to access memory for its suspend operation * after the kernel has completed the HW suspend flow; this can cause * issues if the FW is mapped in normal RAM memory, as some of the * involved HW units might've already lost power. * The driver must therefore avoid this situation and the recommended * way to do so is to use stolen memory for the GSC memory allocation, * because stolen memory takes a different path in HW and it is * guaranteed to always work as long as the GPU itself is awake (which * it must be if the GSC is awake).
*/
obj = i915_gem_object_create_stolen(gt->i915, size); if (IS_ERR(obj)) return PTR_ERR(obj);
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); if (IS_ERR(vma)) {
ret = PTR_ERR(vma); goto err;
}
vaddr = i915_vma_pin_iomap(vma);
i915_vma_unpin(vma); if (IS_ERR(vaddr)) {
ret = PTR_ERR(vaddr); goto err;
}
void intel_gsc_uc_fini(struct intel_gsc_uc *gsc)
{ if (!intel_uc_fw_is_loadable(&gsc->fw)) return;
flush_work(&gsc->work); if (gsc->wq) {
destroy_workqueue(gsc->wq);
gsc->wq = NULL;
}
intel_gsc_proxy_fini(gsc);
if (gsc->ce)
intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce));
gsc_unmap_and_free_vma(gsc);
intel_uc_fw_fini(&gsc->fw);
}
void intel_gsc_uc_flush_work(struct intel_gsc_uc *gsc)
{ if (!intel_uc_fw_is_loadable(&gsc->fw)) return;
flush_work(&gsc->work);
}
void intel_gsc_uc_resume(struct intel_gsc_uc *gsc)
{ if (!intel_uc_fw_is_loadable(&gsc->fw)) return;
/* * we only want to start the GSC worker from here in the actual resume * flow and not during driver load. This is because GSC load is slow and * therefore we want to make sure that the default state init completes * first to not slow down the init thread. A separate call to * intel_gsc_uc_load_start will ensure that the GSC is loaded during * driver load.
*/ if (!gsc_uc_to_gt(gsc)->engine[GSC0]->default_state) return;
for (i = 1; i <= 6; i++) {
u32 status = intel_uncore_read(uncore,
HECI_FWSTS(MTL_GSC_HECI1_BASE, i));
drm_printf(p, "HECI1 FWSTST%u = 0x%08x\n", i, status);
}
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.0 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.