359 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2022 Intel Corporation4 */5 6#include <linux/types.h>7 8#include "gt/intel_gt.h"9#include "gt/intel_gt_print.h"10#include "intel_gsc_fw.h"11#include "intel_gsc_proxy.h"12#include "intel_gsc_uc.h"13#include "i915_drv.h"14#include "i915_reg.h"15 16static void gsc_work(struct work_struct *work)17{18 struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work);19 struct intel_gt *gt = gsc_uc_to_gt(gsc);20 intel_wakeref_t wakeref;21 u32 actions;22 int ret;23 24 wakeref = intel_runtime_pm_get(gt->uncore->rpm);25 26 spin_lock_irq(gt->irq_lock);27 actions = gsc->gsc_work_actions;28 gsc->gsc_work_actions = 0;29 spin_unlock_irq(gt->irq_lock);30 31 if (actions & GSC_ACTION_FW_LOAD) {32 ret = intel_gsc_uc_fw_upload(gsc);33 if (!ret)34 /* setup proxy on a new load */35 actions |= GSC_ACTION_SW_PROXY;36 else if (ret != -EEXIST)37 goto out_put;38 39 /*40 * The HuC auth can be done both before or after the proxy init;41 * if done after, a proxy request will be issued and must be42 * serviced before the authentication can complete.43 * Since this worker also handles proxy requests, we can't44 * perform an action that requires the proxy from within it and45 * then stall waiting for it, because we'd be blocking the46 * service path. Therefore, it is easier for us to load HuC47 * first and do proxy later. The GSC will ack the HuC auth and48 * then send the HuC proxy request as part of the proxy init49 * flow.50 * Note that we can only do the GSC auth if the GuC auth was51 * successful.52 */53 if (intel_uc_uses_huc(>->uc) &&54 intel_huc_is_authenticated(>->uc.huc, INTEL_HUC_AUTH_BY_GUC))55 intel_huc_auth(>->uc.huc, INTEL_HUC_AUTH_BY_GSC);56 }57 58 if (actions & GSC_ACTION_SW_PROXY) {59 if (!intel_gsc_uc_fw_init_done(gsc)) {60 gt_err(gt, "Proxy request received with GSC not loaded!\n");61 goto out_put;62 }63 64 ret = intel_gsc_proxy_request_handler(gsc);65 if (ret) {66 if (actions & GSC_ACTION_FW_LOAD) {67 /*68 * A proxy failure right after firmware load means the proxy-init69 * step has failed so mark GSC as not usable after this70 */71 gt_err(gt, "GSC proxy handler failed to init\n");72 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL);73 }74 goto out_put;75 }76 77 /* mark the GSC FW init as done the first time we run this */78 if (actions & GSC_ACTION_FW_LOAD) {79 /*80 * If there is a proxy establishment error, the GSC might still81 * complete the request handling cleanly, so we need to check the82 * status register to check if the proxy init was actually successful83 */84 if (intel_gsc_uc_fw_proxy_init_done(gsc, false)) {85 gt_dbg(gt, "GSC Proxy initialized\n");86 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_RUNNING);87 } else {88 gt_err(gt, "GSC status reports proxy init not complete\n");89 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL);90 }91 }92 }93 94out_put:95 intel_runtime_pm_put(gt->uncore->rpm, wakeref);96}97 98static bool gsc_engine_supported(struct intel_gt *gt)99{100 intel_engine_mask_t mask;101 102 /*103 * We reach here from i915_driver_early_probe for the primary GT before104 * its engine mask is set, so we use the device info engine mask for it.105 * For other GTs we expect the GT-specific mask to be set before we106 * call this function.107 */108 GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask);109 110 if (gt_is_root(gt))111 mask = INTEL_INFO(gt->i915)->platform_engine_mask;112 else113 mask = gt->info.engine_mask;114 115 return __HAS_ENGINE(mask, GSC0);116}117 118void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)119{120 struct intel_gt *gt = gsc_uc_to_gt(gsc);121 122 /*123 * GSC FW needs to be copied to a dedicated memory allocations for124 * loading (see gsc->local), so we don't need to GGTT map the FW image125 * itself into GGTT.126 */127 intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC, false);128 INIT_WORK(&gsc->work, gsc_work);129 130 /* we can arrive here from i915_driver_early_probe for primary131 * GT with it being not fully setup hence check device info's132 * engine mask133 */134 if (!gsc_engine_supported(gt)) {135 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);136 return;137 }138 139 gsc->wq = alloc_ordered_workqueue("i915_gsc", 0);140 if (!gsc->wq) {141 gt_err(gt, "failed to allocate WQ for GSC, disabling FW\n");142 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);143 }144}145 146static int gsc_allocate_and_map_vma(struct intel_gsc_uc *gsc, u32 size)147{148 struct intel_gt *gt = gsc_uc_to_gt(gsc);149 struct drm_i915_gem_object *obj;150 struct i915_vma *vma;151 void __iomem *vaddr;152 int ret = 0;153 154 /*155 * The GSC FW doesn't immediately suspend after becoming idle, so there156 * is a chance that it could still be awake after we successfully157 * return from the pci suspend function, even if there are no pending158 * operations.159 * The FW might therefore try to access memory for its suspend operation160 * after the kernel has completed the HW suspend flow; this can cause161 * issues if the FW is mapped in normal RAM memory, as some of the162 * involved HW units might've already lost power.163 * The driver must therefore avoid this situation and the recommended164 * way to do so is to use stolen memory for the GSC memory allocation,165 * because stolen memory takes a different path in HW and it is166 * guaranteed to always work as long as the GPU itself is awake (which167 * it must be if the GSC is awake).168 */169 obj = i915_gem_object_create_stolen(gt->i915, size);170 if (IS_ERR(obj))171 return PTR_ERR(obj);172 173 vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);174 if (IS_ERR(vma)) {175 ret = PTR_ERR(vma);176 goto err;177 }178 179 vaddr = i915_vma_pin_iomap(vma);180 i915_vma_unpin(vma);181 if (IS_ERR(vaddr)) {182 ret = PTR_ERR(vaddr);183 goto err;184 }185 186 i915_vma_make_unshrinkable(vma);187 188 gsc->local = vma;189 gsc->local_vaddr = vaddr;190 191 return 0;192 193err:194 i915_gem_object_put(obj);195 return ret;196}197 198static void gsc_unmap_and_free_vma(struct intel_gsc_uc *gsc)199{200 struct i915_vma *vma = fetch_and_zero(&gsc->local);201 202 if (!vma)203 return;204 205 gsc->local_vaddr = NULL;206 i915_vma_unpin_iomap(vma);207 i915_gem_object_put(vma->obj);208}209 210int intel_gsc_uc_init(struct intel_gsc_uc *gsc)211{212 static struct lock_class_key gsc_lock;213 struct intel_gt *gt = gsc_uc_to_gt(gsc);214 struct intel_engine_cs *engine = gt->engine[GSC0];215 struct intel_context *ce;216 int err;217 218 err = intel_uc_fw_init(&gsc->fw);219 if (err)220 goto out;221 222 err = gsc_allocate_and_map_vma(gsc, SZ_4M);223 if (err)224 goto out_fw;225 226 ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K,227 I915_GEM_HWS_GSC_ADDR,228 &gsc_lock, "gsc_context");229 if (IS_ERR(ce)) {230 gt_err(gt, "failed to create GSC CS ctx for FW communication\n");231 err = PTR_ERR(ce);232 goto out_vma;233 }234 235 gsc->ce = ce;236 237 /* if we fail to init proxy we still want to load GSC for PM */238 intel_gsc_proxy_init(gsc);239 240 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE);241 242 return 0;243 244out_vma:245 gsc_unmap_and_free_vma(gsc);246out_fw:247 intel_uc_fw_fini(&gsc->fw);248out:249 gt_probe_error(gt, "GSC init failed %pe\n", ERR_PTR(err));250 return err;251}252 253void intel_gsc_uc_fini(struct intel_gsc_uc *gsc)254{255 if (!intel_uc_fw_is_loadable(&gsc->fw))256 return;257 258 flush_work(&gsc->work);259 if (gsc->wq) {260 destroy_workqueue(gsc->wq);261 gsc->wq = NULL;262 }263 264 intel_gsc_proxy_fini(gsc);265 266 if (gsc->ce)267 intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce));268 269 gsc_unmap_and_free_vma(gsc);270 271 intel_uc_fw_fini(&gsc->fw);272}273 274void intel_gsc_uc_flush_work(struct intel_gsc_uc *gsc)275{276 if (!intel_uc_fw_is_loadable(&gsc->fw))277 return;278 279 flush_work(&gsc->work);280}281 282void intel_gsc_uc_resume(struct intel_gsc_uc *gsc)283{284 if (!intel_uc_fw_is_loadable(&gsc->fw))285 return;286 287 /*288 * we only want to start the GSC worker from here in the actual resume289 * flow and not during driver load. This is because GSC load is slow and290 * therefore we want to make sure that the default state init completes291 * first to not slow down the init thread. A separate call to292 * intel_gsc_uc_load_start will ensure that the GSC is loaded during293 * driver load.294 */295 if (!gsc_uc_to_gt(gsc)->engine[GSC0]->default_state)296 return;297 298 intel_gsc_uc_load_start(gsc);299}300 301void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc)302{303 struct intel_gt *gt = gsc_uc_to_gt(gsc);304 305 if (!intel_uc_fw_is_loadable(&gsc->fw) || intel_uc_fw_is_in_error(&gsc->fw))306 return;307 308 if (intel_gsc_uc_fw_init_done(gsc))309 return;310 311 spin_lock_irq(gt->irq_lock);312 gsc->gsc_work_actions |= GSC_ACTION_FW_LOAD;313 spin_unlock_irq(gt->irq_lock);314 315 queue_work(gsc->wq, &gsc->work);316}317 318void intel_gsc_uc_load_status(struct intel_gsc_uc *gsc, struct drm_printer *p)319{320 struct intel_gt *gt = gsc_uc_to_gt(gsc);321 struct intel_uncore *uncore = gt->uncore;322 intel_wakeref_t wakeref;323 324 if (!intel_gsc_uc_is_supported(gsc)) {325 drm_printf(p, "GSC not supported\n");326 return;327 }328 329 if (!intel_gsc_uc_is_wanted(gsc)) {330 drm_printf(p, "GSC disabled\n");331 return;332 }333 334 drm_printf(p, "GSC firmware: %s\n", gsc->fw.file_selected.path);335 if (gsc->fw.file_selected.path != gsc->fw.file_wanted.path)336 drm_printf(p, "GSC firmware wanted: %s\n", gsc->fw.file_wanted.path);337 drm_printf(p, "\tstatus: %s\n", intel_uc_fw_status_repr(gsc->fw.status));338 339 drm_printf(p, "Release: %u.%u.%u.%u\n",340 gsc->release.major, gsc->release.minor,341 gsc->release.patch, gsc->release.build);342 343 drm_printf(p, "Compatibility Version: %u.%u [min expected %u.%u]\n",344 gsc->fw.file_selected.ver.major, gsc->fw.file_selected.ver.minor,345 gsc->fw.file_wanted.ver.major, gsc->fw.file_wanted.ver.minor);346 347 drm_printf(p, "SVN: %u\n", gsc->security_version);348 349 with_intel_runtime_pm(uncore->rpm, wakeref) {350 u32 i;351 352 for (i = 1; i <= 6; i++) {353 u32 status = intel_uncore_read(uncore,354 HECI_FWSTS(MTL_GSC_HECI1_BASE, i));355 drm_printf(p, "HECI1 FWSTST%u = 0x%08x\n", i, status);356 }357 }358}359