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 "gt/intel_gt_print.h" 10 #include "intel_gsc_uc.h" 11 #include "intel_gsc_fw.h" 12 #include "i915_drv.h" 13 14 static void gsc_work(struct work_struct *work) 15 { 16 struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work); 17 struct intel_gt *gt = gsc_uc_to_gt(gsc); 18 intel_wakeref_t wakeref; 19 20 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 21 intel_gsc_uc_fw_upload(gsc); 22 } 23 24 static bool gsc_engine_supported(struct intel_gt *gt) 25 { 26 intel_engine_mask_t mask; 27 28 /* 29 * We reach here from i915_driver_early_probe for the primary GT before 30 * its engine mask is set, so we use the device info engine mask for it. 31 * For other GTs we expect the GT-specific mask to be set before we 32 * call this function. 33 */ 34 GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask); 35 36 if (gt_is_root(gt)) 37 mask = RUNTIME_INFO(gt->i915)->platform_engine_mask; 38 else 39 mask = gt->info.engine_mask; 40 41 return __HAS_ENGINE(mask, GSC0); 42 } 43 44 void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc) 45 { 46 intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC); 47 INIT_WORK(&gsc->work, gsc_work); 48 49 /* we can arrive here from i915_driver_early_probe for primary 50 * GT with it being not fully setup hence check device info's 51 * engine mask 52 */ 53 if (!gsc_engine_supported(gsc_uc_to_gt(gsc))) { 54 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED); 55 return; 56 } 57 } 58 59 int intel_gsc_uc_init(struct intel_gsc_uc *gsc) 60 { 61 static struct lock_class_key gsc_lock; 62 struct intel_gt *gt = gsc_uc_to_gt(gsc); 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 gt_err(gt, "failed to create GSC CS ctx for FW communication\n"); 85 err = PTR_ERR(ce); 86 goto out_vma; 87 } 88 89 gsc->ce = ce; 90 91 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE); 92 93 return 0; 94 95 out_vma: 96 i915_vma_unpin_and_release(&gsc->local, 0); 97 out_fw: 98 intel_uc_fw_fini(&gsc->fw); 99 out: 100 gt_probe_error(gt, "GSC init failed %pe\n", ERR_PTR(err)); 101 return err; 102 } 103 104 void intel_gsc_uc_fini(struct intel_gsc_uc *gsc) 105 { 106 if (!intel_uc_fw_is_loadable(&gsc->fw)) 107 return; 108 109 flush_work(&gsc->work); 110 111 if (gsc->ce) 112 intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce)); 113 114 i915_vma_unpin_and_release(&gsc->local, 0); 115 116 intel_uc_fw_fini(&gsc->fw); 117 } 118 119 void intel_gsc_uc_flush_work(struct intel_gsc_uc *gsc) 120 { 121 if (!intel_uc_fw_is_loadable(&gsc->fw)) 122 return; 123 124 flush_work(&gsc->work); 125 } 126 127 void intel_gsc_uc_resume(struct intel_gsc_uc *gsc) 128 { 129 if (!intel_uc_fw_is_loadable(&gsc->fw)) 130 return; 131 132 /* 133 * we only want to start the GSC worker from here in the actual resume 134 * flow and not during driver load. This is because GSC load is slow and 135 * therefore we want to make sure that the default state init completes 136 * first to not slow down the init thread. A separate call to 137 * intel_gsc_uc_load_start will ensure that the GSC is loaded during 138 * driver load. 139 */ 140 if (!gsc_uc_to_gt(gsc)->engine[GSC0]->default_state) 141 return; 142 143 intel_gsc_uc_load_start(gsc); 144 } 145 146 void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc) 147 { 148 if (!intel_uc_fw_is_loadable(&gsc->fw)) 149 return; 150 151 if (intel_gsc_uc_fw_init_done(gsc)) 152 return; 153 154 queue_work(system_unbound_wq, &gsc->work); 155 } 156