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_huc.h" 10 #include "i915_drv.h" 11 12 /** 13 * DOC: HuC 14 * 15 * The HuC is a dedicated microcontroller for usage in media HEVC (High 16 * Efficiency Video Coding) operations. Userspace can directly use the firmware 17 * capabilities by adding HuC specific commands to batch buffers. 18 * 19 * The kernel driver is only responsible for loading the HuC firmware and 20 * triggering its security authentication, which is performed by the GuC. For 21 * The GuC to correctly perform the authentication, the HuC binary must be 22 * loaded before the GuC one. Loading the HuC is optional; however, not using 23 * the HuC might negatively impact power usage and/or performance of media 24 * workloads, depending on the use-cases. 25 * 26 * See https://github.com/intel/media-driver for the latest details on HuC 27 * functionality. 28 */ 29 30 /** 31 * DOC: HuC Memory Management 32 * 33 * Similarly to the GuC, the HuC can't do any memory allocations on its own, 34 * with the difference being that the allocations for HuC usage are handled by 35 * the userspace driver instead of the kernel one. The HuC accesses the memory 36 * via the PPGTT belonging to the context loaded on the VCS executing the 37 * HuC-specific commands. 38 */ 39 40 void intel_huc_init_early(struct intel_huc *huc) 41 { 42 struct drm_i915_private *i915 = huc_to_gt(huc)->i915; 43 44 intel_uc_fw_init_early(&huc->fw, INTEL_UC_FW_TYPE_HUC); 45 46 if (GRAPHICS_VER(i915) >= 11) { 47 huc->status.reg = GEN11_HUC_KERNEL_LOAD_INFO; 48 huc->status.mask = HUC_LOAD_SUCCESSFUL; 49 huc->status.value = HUC_LOAD_SUCCESSFUL; 50 } else { 51 huc->status.reg = HUC_STATUS2; 52 huc->status.mask = HUC_FW_VERIFIED; 53 huc->status.value = HUC_FW_VERIFIED; 54 } 55 } 56 57 int intel_huc_init(struct intel_huc *huc) 58 { 59 struct drm_i915_private *i915 = huc_to_gt(huc)->i915; 60 int err; 61 62 err = intel_uc_fw_init(&huc->fw); 63 if (err) 64 goto out; 65 66 intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOADABLE); 67 68 return 0; 69 70 out: 71 i915_probe_error(i915, "failed with %d\n", err); 72 return err; 73 } 74 75 void intel_huc_fini(struct intel_huc *huc) 76 { 77 if (!intel_uc_fw_is_loadable(&huc->fw)) 78 return; 79 80 intel_uc_fw_fini(&huc->fw); 81 } 82 83 /** 84 * intel_huc_auth() - Authenticate HuC uCode 85 * @huc: intel_huc structure 86 * 87 * Called after HuC and GuC firmware loading during intel_uc_init_hw(). 88 * 89 * This function invokes the GuC action to authenticate the HuC firmware, 90 * passing the offset of the RSA signature to intel_guc_auth_huc(). It then 91 * waits for up to 50ms for firmware verification ACK. 92 */ 93 int intel_huc_auth(struct intel_huc *huc) 94 { 95 struct intel_gt *gt = huc_to_gt(huc); 96 struct intel_guc *guc = >->uc.guc; 97 int ret; 98 99 GEM_BUG_ON(intel_huc_is_authenticated(huc)); 100 101 if (!intel_uc_fw_is_loaded(&huc->fw)) 102 return -ENOEXEC; 103 104 ret = i915_inject_probe_error(gt->i915, -ENXIO); 105 if (ret) 106 goto fail; 107 108 ret = intel_guc_auth_huc(guc, 109 intel_guc_ggtt_offset(guc, huc->fw.rsa_data)); 110 if (ret) { 111 DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret); 112 goto fail; 113 } 114 115 /* Check authentication status, it should be done by now */ 116 ret = __intel_wait_for_register(gt->uncore, 117 huc->status.reg, 118 huc->status.mask, 119 huc->status.value, 120 2, 50, NULL); 121 if (ret) { 122 DRM_ERROR("HuC: Firmware not verified %d\n", ret); 123 goto fail; 124 } 125 126 intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); 127 drm_info(>->i915->drm, "HuC authenticated\n"); 128 return 0; 129 130 fail: 131 i915_probe_error(gt->i915, "HuC: Authentication failed %d\n", ret); 132 intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); 133 return ret; 134 } 135 136 /** 137 * intel_huc_check_status() - check HuC status 138 * @huc: intel_huc structure 139 * 140 * This function reads status register to verify if HuC 141 * firmware was successfully loaded. 142 * 143 * Returns: 144 * * -ENODEV if HuC is not present on this platform, 145 * * -EOPNOTSUPP if HuC firmware is disabled, 146 * * -ENOPKG if HuC firmware was not installed, 147 * * -ENOEXEC if HuC firmware is invalid or mismatched, 148 * * 0 if HuC firmware is not running, 149 * * 1 if HuC firmware is authenticated and running. 150 */ 151 int intel_huc_check_status(struct intel_huc *huc) 152 { 153 struct intel_gt *gt = huc_to_gt(huc); 154 intel_wakeref_t wakeref; 155 u32 status = 0; 156 157 switch (__intel_uc_fw_status(&huc->fw)) { 158 case INTEL_UC_FIRMWARE_NOT_SUPPORTED: 159 return -ENODEV; 160 case INTEL_UC_FIRMWARE_DISABLED: 161 return -EOPNOTSUPP; 162 case INTEL_UC_FIRMWARE_MISSING: 163 return -ENOPKG; 164 case INTEL_UC_FIRMWARE_ERROR: 165 return -ENOEXEC; 166 default: 167 break; 168 } 169 170 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 171 status = intel_uncore_read(gt->uncore, huc->status.reg); 172 173 return (status & huc->status.mask) == huc->status.value; 174 } 175 176 /** 177 * intel_huc_load_status - dump information about HuC load status 178 * @huc: the HuC 179 * @p: the &drm_printer 180 * 181 * Pretty printer for HuC load status. 182 */ 183 void intel_huc_load_status(struct intel_huc *huc, struct drm_printer *p) 184 { 185 struct intel_gt *gt = huc_to_gt(huc); 186 intel_wakeref_t wakeref; 187 188 if (!intel_huc_is_supported(huc)) { 189 drm_printf(p, "HuC not supported\n"); 190 return; 191 } 192 193 if (!intel_huc_is_wanted(huc)) { 194 drm_printf(p, "HuC disabled\n"); 195 return; 196 } 197 198 intel_uc_fw_dump(&huc->fw, p); 199 200 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 201 drm_printf(p, "HuC status: 0x%08x\n", 202 intel_uncore_read(gt->uncore, huc->status.reg)); 203 } 204