1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2022 Intel Corporation 4 */ 5 6 #include <linux/types.h> 7 8 #include "gt/intel_gt.h" 9 #include "intel_gsc_uc.h" 10 #include "intel_gsc_fw.h" 11 #include "i915_drv.h" 12 13 static void gsc_work(struct work_struct *work) 14 { 15 struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work); 16 struct intel_gt *gt = gsc_uc_to_gt(gsc); 17 intel_wakeref_t wakeref; 18 19 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 20 intel_gsc_uc_fw_upload(gsc); 21 } 22 23 static bool gsc_engine_supported(struct intel_gt *gt) 24 { 25 intel_engine_mask_t mask; 26 27 /* 28 * We reach here from i915_driver_early_probe for the primary GT before 29 * its engine mask is set, so we use the device info engine mask for it. 30 * For other GTs we expect the GT-specific mask to be set before we 31 * call this function. 32 */ 33 GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask); 34 35 if (gt_is_root(gt)) 36 mask = RUNTIME_INFO(gt->i915)->platform_engine_mask; 37 else 38 mask = gt->info.engine_mask; 39 40 return __HAS_ENGINE(mask, GSC0); 41 } 42 43 void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc) 44 { 45 intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC); 46 INIT_WORK(&gsc->work, gsc_work); 47 48 /* we can arrive here from i915_driver_early_probe for primary 49 * GT with it being not fully setup hence check device info's 50 * engine mask 51 */ 52 if (!gsc_engine_supported(gsc_uc_to_gt(gsc))) { 53 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED); 54 return; 55 } 56 } 57 58 int intel_gsc_uc_init(struct intel_gsc_uc *gsc) 59 { 60 static struct lock_class_key gsc_lock; 61 struct intel_gt *gt = gsc_uc_to_gt(gsc); 62 struct drm_i915_private *i915 = gt->i915; 63 struct intel_engine_cs *engine = gt->engine[GSC0]; 64 struct intel_context *ce; 65 struct i915_vma *vma; 66 int err; 67 68 err = intel_uc_fw_init(&gsc->fw); 69 if (err) 70 goto out; 71 72 vma = intel_guc_allocate_vma(>->uc.guc, SZ_8M); 73 if (IS_ERR(vma)) { 74 err = PTR_ERR(vma); 75 goto out_fw; 76 } 77 78 gsc->local = vma; 79 80 ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K, 81 I915_GEM_HWS_GSC_ADDR, 82 &gsc_lock, "gsc_context"); 83 if (IS_ERR(ce)) { 84 drm_err(>->i915->drm, 85 "failed to create GSC CS ctx for FW communication\n"); 86 err = PTR_ERR(ce); 87 goto out_vma; 88 } 89 90 gsc->ce = ce; 91 92 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE); 93 94 return 0; 95 96 out_vma: 97 i915_vma_unpin_and_release(&gsc->local, 0); 98 out_fw: 99 intel_uc_fw_fini(&gsc->fw); 100 out: 101 i915_probe_error(i915, "failed with %d\n", err); 102 return err; 103 } 104 105 void intel_gsc_uc_fini(struct intel_gsc_uc *gsc) 106 { 107 if (!intel_uc_fw_is_loadable(&gsc->fw)) 108 return; 109 110 flush_work(&gsc->work); 111 112 if (gsc->ce) 113 intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce)); 114 115 i915_vma_unpin_and_release(&gsc->local, 0); 116 117 intel_uc_fw_fini(&gsc->fw); 118 } 119 120 void intel_gsc_uc_suspend(struct intel_gsc_uc *gsc) 121 { 122 if (!intel_uc_fw_is_loadable(&gsc->fw)) 123 return; 124 125 flush_work(&gsc->work); 126 } 127 128 void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc) 129 { 130 if (!intel_uc_fw_is_loadable(&gsc->fw)) 131 return; 132 133 if (intel_gsc_uc_fw_init_done(gsc)) 134 return; 135 136 queue_work(system_unbound_wq, &gsc->work); 137 } 138