/* * FIXME: xe_migrate_copy does not work with stolen mem yet, so we use * a memcpy for now.
*/
storage = kmalloc(fw_size, GFP_KERNEL); if (!storage) return -ENOMEM;
bo = xe_bo_create_pin_map(xe, tile, NULL, GSC_VER_PKT_SZ * 2,
ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM |
XE_BO_FLAG_GGTT); if (IS_ERR(bo)) {
xe_gt_err(gt, "failed to allocate bo for GSC version query\n"); return PTR_ERR(bo);
}
staticint gsc_fw_wait(struct xe_gt *gt)
{ /* * GSC load can take up to 250ms from the moment the instruction is * executed by the GSCCS. To account for possible submission delays or * other issues, we use a 500ms timeout in the wait here.
*/ return xe_mmio_wait32(>->mmio, HECI_FWSTS1(MTL_GSC_HECI1_BASE),
HECI1_FWSTS1_INIT_COMPLETE,
HECI1_FWSTS1_INIT_COMPLETE,
500 * USEC_PER_MSEC, NULL, false);
}
/* we should only be here if the init step were successful */
xe_assert(xe, xe_uc_fw_is_loadable(&gsc->fw) && gsc->q);
if (gsc_fw_is_loaded(gt)) {
xe_gt_err(gt, "GSC already loaded at upload time\n"); return -EEXIST;
}
err = memcpy_fw(gsc); if (err) {
xe_gt_err(gt, "Failed to memcpy GSC FW\n"); return err;
}
/* * GSC is only killed by an FLR, so we need to trigger one on unload to * make sure we stop it. This is because we assign a chunk of memory to * the GSC as part of the FW load, so we need to make sure it stops * using it when we release it to the system on driver unload. Note that * this is not a problem of the unload per-se, because the GSC will not * touch that memory unless there are requests for it coming from the * driver; therefore, no accesses will happen while Xe is not loaded, * but if we re-load the driver then the GSC might wake up and try to * access that old memory location again. * Given that an FLR is a very disruptive action (see the FLR function * for details), we want to do it as the last action before releasing * the access to the MMIO bar, which means we need to do it as part of * mmio cleanup.
*/
xe->needs_flr_on_fini = true;
err = emit_gsc_upload(gsc); if (err) {
xe_gt_err(gt, "Failed to emit GSC FW upload (%pe)\n", ERR_PTR(err)); return err;
}
err = gsc_fw_wait(gt); if (err) {
xe_gt_err(gt, "Failed to wait for GSC load (%pe)\n", ERR_PTR(err)); return err;
}
err = query_compatibility_version(gsc); if (err) return err;
err = xe_uc_fw_check_version_requirements(&gsc->fw); if (err) return err;
if (XE_WA(tile->primary_gt, 14018094691)) {
fw_ref = xe_force_wake_get(gt_to_fw(tile->primary_gt), XE_FORCEWAKE_ALL);
/* * If the forcewake fails we want to keep going, because the worst * case outcome in failing to apply the WA is that PXP won't work, * which is not fatal. Forcewake get warns implicitly in case of failure
*/
xe_gt_mcr_multicast_write(tile->primary_gt,
EU_SYSTOLIC_LIC_THROTTLE_CTL_WITH_LOCK,
EU_SYSTOLIC_LIC_THROTTLE_CTL_LOCK_BIT);
}
ret = gsc_upload(gsc);
if (XE_WA(tile->primary_gt, 14018094691))
xe_force_wake_put(gt_to_fw(tile->primary_gt), fw_ref);
/* * Starting on Xe2, the GSCCS engine reset is a 2-step process. When the * driver or the GuC hit the GDRST register, the CS is immediately reset * and a success is reported, but the GSC shim keeps resetting in the * background. While the shim reset is ongoing, the CS is able to accept * new context submission, but any commands that require the shim will * be stalled until the reset is completed. This means that we can keep * submitting to the GSCCS as long as we make sure that the preemption * timeout is big enough to cover any delay introduced by the reset. * When the shim reset completes, a specific CS interrupt is triggered, * in response to which we need to check the GSCI_TIMER_STATUS register * to see if the reset was successful or not. * Note that the GSCI_TIMER_STATUS register is not power save/restored, * so it gets reset on MC6 entry. However, a reset failure stops MC6, * so in that scenario we're always guaranteed to find the correct * value.
*/
er_status = xe_mmio_read32(>->mmio, GSCI_TIMER_STATUS) & GSCI_TIMER_STATUS_VALUE;
if (er_status == GSCI_TIMER_STATUS_TIMER_EXPIRED) { /* * XXX: we should trigger an FLR here, but we don't have support * for that yet. Since we can't recover from the error, we * declare the device as wedged.
*/
xe_gt_err(gt, "GSC ER timed out!\n");
xe_device_declare_wedged(gt_to_xe(gt)); return -EIO;
}
if (actions & GSC_ACTION_ER_COMPLETE) {
ret = gsc_er_complete(gt); if (ret) goto out;
}
if (actions & GSC_ACTION_FW_LOAD) {
ret = gsc_upload_and_init(gsc); if (ret && ret != -EEXIST)
xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_LOAD_FAIL); else
xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_RUNNING);
}
if (actions & GSC_ACTION_SW_PROXY)
xe_gsc_proxy_request_handler(gsc);
/* The GSC uC is only available on the media GT */ if (tile->media_gt && (gt != tile->media_gt)) {
xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_NOT_SUPPORTED); return 0;
}
/* * Some platforms can have GuC but not GSC. That would cause * xe_uc_fw_init(gsc) to return a "not supported" failure code and abort * all firmware loading. So check for GSC being enabled before * propagating the failure back up. That way the higher level will keep * going and load GuC as appropriate.
*/
ret = xe_uc_fw_init(&gsc->fw); if (!xe_uc_fw_is_enabled(&gsc->fw)) return 0; elseif (ret) goto out;
ret = xe_gsc_proxy_init(gsc); if (ret && ret != -ENODEV) goto out;
if (!xe_uc_fw_is_loadable(&gsc->fw) || !gsc->q) return;
/* * The GSC HW is only reset by driver FLR or D3cold entry. We don't * support the former at runtime, while the latter is only supported on * DGFX, for which we don't support GSC. Therefore, if GSC failed to * load previously there is no need to try again because the HW is * stuck in the error state.
*/
xe_assert(xe, !IS_DGFX(xe)); if (xe_uc_fw_is_in_error_state(&gsc->fw)) return;
/* GSC FW survives GT reset and D3Hot */ if (gsc_fw_is_loaded(gt)) { if (xe_gsc_proxy_init_done(gsc))
xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_RUNNING); else
xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_TRANSFERRED); return;
}
/* * If the GSC FW load or the proxy init are interrupted, the only way * to recover it is to do an FLR and reload the GSC from scratch. * Therefore, let's wait for the init to complete before stopping * operations. The proxy init is the last step, so we can just wait on * that
*/
ret = xe_gsc_wait_for_proxy_init_done(gsc); if (ret)
xe_gt_err(gt, "failed to wait for GSC init completion before uc stop\n");
}
/* * wa_14015076503: if the GSC FW is loaded, we need to alert it before doing a * GSC engine reset by writing a notification bit in the GS1 register and then * triggering an interrupt to GSC; from the interrupt it will take up to 200ms * for the FW to get prepare for the reset, so we need to wait for that amount * of time. * After the reset is complete we need to then clear the GS1 register.
*/ void xe_gsc_wa_14015076503(struct xe_gt *gt, bool prep)
{
u32 gs1_set = prep ? HECI_H_GS1_ER_PREP : 0;
u32 gs1_clr = prep ? 0 : HECI_H_GS1_ER_PREP;
/* WA only applies if the GSC is loaded */ if (!XE_WA(gt, 14015076503) || !gsc_fw_is_loaded(gt)) return;
if (prep) { /* make sure the reset bit is clear when writing the CSR reg */
xe_mmio_rmw32(>->mmio, HECI_H_CSR(MTL_GSC_HECI2_BASE),
HECI_H_CSR_RST, HECI_H_CSR_IG);
msleep(200);
}
}
/** * xe_gsc_print_info - print info about GSC FW status * @gsc: the GSC structure * @p: the printer to be used to print the info
*/ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p)
{ struct xe_gt *gt = gsc_to_gt(gsc); struct xe_mmio *mmio = >->mmio; unsignedint fw_ref;
xe_uc_fw_print(&gsc->fw, p);
drm_printf(p, "\tfound security version %u\n", gsc->security_version);
if (!xe_uc_fw_is_enabled(&gsc->fw)) return;
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); if (!fw_ref) return;
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.