1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2016-2019 Intel Corporation 4 */ 5 6 #include <linux/types.h> 7 8 #include "gt/intel_gt.h" 9 #include "intel_guc_reg.h" 10 #include "intel_huc.h" 11 #include "i915_drv.h" 12 13 /** 14 * DOC: HuC 15 * 16 * The HuC is a dedicated microcontroller for usage in media HEVC (High 17 * Efficiency Video Coding) operations. Userspace can directly use the firmware 18 * capabilities by adding HuC specific commands to batch buffers. 19 * 20 * The kernel driver is only responsible for loading the HuC firmware and 21 * triggering its security authentication, which is performed by the GuC on 22 * older platforms and by the GSC on newer ones. For the GuC to correctly 23 * perform the authentication, the HuC binary must be loaded before the GuC one. 24 * Loading the HuC is optional; however, not using the HuC might negatively 25 * impact power usage and/or performance of media workloads, depending on the 26 * use-cases. 27 * HuC must be reloaded on events that cause the WOPCM to lose its contents 28 * (S3/S4, FLR); GuC-authenticated HuC must also be reloaded on GuC/GT reset, 29 * while GSC-managed HuC will survive that. 30 * 31 * See https://github.com/intel/media-driver for the latest details on HuC 32 * functionality. 33 */ 34 35 /** 36 * DOC: HuC Memory Management 37 * 38 * Similarly to the GuC, the HuC can't do any memory allocations on its own, 39 * with the difference being that the allocations for HuC usage are handled by 40 * the userspace driver instead of the kernel one. The HuC accesses the memory 41 * via the PPGTT belonging to the context loaded on the VCS executing the 42 * HuC-specific commands. 43 */ 44 45 void intel_huc_init_early(struct intel_huc *huc) 46 { 47 struct drm_i915_private *i915 = huc_to_gt(huc)->i915; 48 49 intel_uc_fw_init_early(&huc->fw, INTEL_UC_FW_TYPE_HUC); 50 51 if (GRAPHICS_VER(i915) >= 11) { 52 huc->status.reg = GEN11_HUC_KERNEL_LOAD_INFO; 53 huc->status.mask = HUC_LOAD_SUCCESSFUL; 54 huc->status.value = HUC_LOAD_SUCCESSFUL; 55 } else { 56 huc->status.reg = HUC_STATUS2; 57 huc->status.mask = HUC_FW_VERIFIED; 58 huc->status.value = HUC_FW_VERIFIED; 59 } 60 } 61 62 #define HUC_LOAD_MODE_STRING(x) (x ? "GSC" : "legacy") 63 static int check_huc_loading_mode(struct intel_huc *huc) 64 { 65 struct intel_gt *gt = huc_to_gt(huc); 66 bool fw_needs_gsc = intel_huc_is_loaded_by_gsc(huc); 67 bool hw_uses_gsc = false; 68 69 /* 70 * The fuse for HuC load via GSC is only valid on platforms that have 71 * GuC deprivilege. 72 */ 73 if (HAS_GUC_DEPRIVILEGE(gt->i915)) 74 hw_uses_gsc = intel_uncore_read(gt->uncore, GUC_SHIM_CONTROL2) & 75 GSC_LOADS_HUC; 76 77 if (fw_needs_gsc != hw_uses_gsc) { 78 drm_err(>->i915->drm, 79 "mismatch between HuC FW (%s) and HW (%s) load modes\n", 80 HUC_LOAD_MODE_STRING(fw_needs_gsc), 81 HUC_LOAD_MODE_STRING(hw_uses_gsc)); 82 return -ENOEXEC; 83 } 84 85 /* make sure we can access the GSC via the mei driver if we need it */ 86 if (!(IS_ENABLED(CONFIG_INTEL_MEI_PXP) && IS_ENABLED(CONFIG_INTEL_MEI_GSC)) && 87 fw_needs_gsc) { 88 drm_info(>->i915->drm, 89 "Can't load HuC due to missing MEI modules\n"); 90 return -EIO; 91 } 92 93 drm_dbg(>->i915->drm, "GSC loads huc=%s\n", str_yes_no(fw_needs_gsc)); 94 95 return 0; 96 } 97 98 int intel_huc_init(struct intel_huc *huc) 99 { 100 struct drm_i915_private *i915 = huc_to_gt(huc)->i915; 101 int err; 102 103 err = check_huc_loading_mode(huc); 104 if (err) 105 goto out; 106 107 err = intel_uc_fw_init(&huc->fw); 108 if (err) 109 goto out; 110 111 intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOADABLE); 112 113 return 0; 114 115 out: 116 drm_info(&i915->drm, "HuC init failed with %d\n", err); 117 return err; 118 } 119 120 void intel_huc_fini(struct intel_huc *huc) 121 { 122 if (!intel_uc_fw_is_loadable(&huc->fw)) 123 return; 124 125 intel_uc_fw_fini(&huc->fw); 126 } 127 128 /** 129 * intel_huc_auth() - Authenticate HuC uCode 130 * @huc: intel_huc structure 131 * 132 * Called after HuC and GuC firmware loading during intel_uc_init_hw(). 133 * 134 * This function invokes the GuC action to authenticate the HuC firmware, 135 * passing the offset of the RSA signature to intel_guc_auth_huc(). It then 136 * waits for up to 50ms for firmware verification ACK. 137 */ 138 int intel_huc_auth(struct intel_huc *huc) 139 { 140 struct intel_gt *gt = huc_to_gt(huc); 141 struct intel_guc *guc = >->uc.guc; 142 int ret; 143 144 if (!intel_uc_fw_is_loaded(&huc->fw)) 145 return -ENOEXEC; 146 147 /* GSC will do the auth */ 148 if (intel_huc_is_loaded_by_gsc(huc)) 149 return -ENODEV; 150 151 ret = i915_inject_probe_error(gt->i915, -ENXIO); 152 if (ret) 153 goto fail; 154 155 GEM_BUG_ON(intel_uc_fw_is_running(&huc->fw)); 156 157 ret = intel_guc_auth_huc(guc, intel_guc_ggtt_offset(guc, huc->fw.rsa_data)); 158 if (ret) { 159 DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret); 160 goto fail; 161 } 162 163 /* Check authentication status, it should be done by now */ 164 ret = __intel_wait_for_register(gt->uncore, 165 huc->status.reg, 166 huc->status.mask, 167 huc->status.value, 168 2, 50, NULL); 169 if (ret) { 170 DRM_ERROR("HuC: Firmware not verified %d\n", ret); 171 goto fail; 172 } 173 174 intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); 175 drm_info(>->i915->drm, "HuC authenticated\n"); 176 return 0; 177 178 fail: 179 i915_probe_error(gt->i915, "HuC: Authentication failed %d\n", ret); 180 intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); 181 return ret; 182 } 183 184 static bool huc_is_authenticated(struct intel_huc *huc) 185 { 186 struct intel_gt *gt = huc_to_gt(huc); 187 intel_wakeref_t wakeref; 188 u32 status = 0; 189 190 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 191 status = intel_uncore_read(gt->uncore, huc->status.reg); 192 193 return (status & huc->status.mask) == huc->status.value; 194 } 195 196 /** 197 * intel_huc_check_status() - check HuC status 198 * @huc: intel_huc structure 199 * 200 * This function reads status register to verify if HuC 201 * firmware was successfully loaded. 202 * 203 * Returns: 204 * * -ENODEV if HuC is not present on this platform, 205 * * -EOPNOTSUPP if HuC firmware is disabled, 206 * * -ENOPKG if HuC firmware was not installed, 207 * * -ENOEXEC if HuC firmware is invalid or mismatched, 208 * * 0 if HuC firmware is not running, 209 * * 1 if HuC firmware is authenticated and running. 210 */ 211 int intel_huc_check_status(struct intel_huc *huc) 212 { 213 switch (__intel_uc_fw_status(&huc->fw)) { 214 case INTEL_UC_FIRMWARE_NOT_SUPPORTED: 215 return -ENODEV; 216 case INTEL_UC_FIRMWARE_DISABLED: 217 return -EOPNOTSUPP; 218 case INTEL_UC_FIRMWARE_MISSING: 219 return -ENOPKG; 220 case INTEL_UC_FIRMWARE_ERROR: 221 return -ENOEXEC; 222 default: 223 break; 224 } 225 226 return huc_is_authenticated(huc); 227 } 228 229 void intel_huc_update_auth_status(struct intel_huc *huc) 230 { 231 if (!intel_uc_fw_is_loadable(&huc->fw)) 232 return; 233 234 if (huc_is_authenticated(huc)) 235 intel_uc_fw_change_status(&huc->fw, 236 INTEL_UC_FIRMWARE_RUNNING); 237 } 238 239 /** 240 * intel_huc_load_status - dump information about HuC load status 241 * @huc: the HuC 242 * @p: the &drm_printer 243 * 244 * Pretty printer for HuC load status. 245 */ 246 void intel_huc_load_status(struct intel_huc *huc, struct drm_printer *p) 247 { 248 struct intel_gt *gt = huc_to_gt(huc); 249 intel_wakeref_t wakeref; 250 251 if (!intel_huc_is_supported(huc)) { 252 drm_printf(p, "HuC not supported\n"); 253 return; 254 } 255 256 if (!intel_huc_is_wanted(huc)) { 257 drm_printf(p, "HuC disabled\n"); 258 return; 259 } 260 261 intel_uc_fw_dump(&huc->fw, p); 262 263 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 264 drm_printf(p, "HuC status: 0x%08x\n", 265 intel_uncore_read(gt->uncore, huc->status.reg)); 266 } 267