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 return 0; 128 129 fail: 130 i915_probe_error(gt->i915, "HuC: Authentication failed %d\n", ret); 131 intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); 132 return ret; 133 } 134 135 /** 136 * intel_huc_check_status() - check HuC status 137 * @huc: intel_huc structure 138 * 139 * This function reads status register to verify if HuC 140 * firmware was successfully loaded. 141 * 142 * Returns: 143 * * -ENODEV if HuC is not present on this platform, 144 * * -EOPNOTSUPP if HuC firmware is disabled, 145 * * -ENOPKG if HuC firmware was not installed, 146 * * -ENOEXEC if HuC firmware is invalid or mismatched, 147 * * 0 if HuC firmware is not running, 148 * * 1 if HuC firmware is authenticated and running. 149 */ 150 int intel_huc_check_status(struct intel_huc *huc) 151 { 152 struct intel_gt *gt = huc_to_gt(huc); 153 intel_wakeref_t wakeref; 154 u32 status = 0; 155 156 switch (__intel_uc_fw_status(&huc->fw)) { 157 case INTEL_UC_FIRMWARE_NOT_SUPPORTED: 158 return -ENODEV; 159 case INTEL_UC_FIRMWARE_DISABLED: 160 return -EOPNOTSUPP; 161 case INTEL_UC_FIRMWARE_MISSING: 162 return -ENOPKG; 163 case INTEL_UC_FIRMWARE_ERROR: 164 return -ENOEXEC; 165 default: 166 break; 167 } 168 169 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 170 status = intel_uncore_read(gt->uncore, huc->status.reg); 171 172 return (status & huc->status.mask) == huc->status.value; 173 } 174 175 /** 176 * intel_huc_load_status - dump information about HuC load status 177 * @huc: the HuC 178 * @p: the &drm_printer 179 * 180 * Pretty printer for HuC load status. 181 */ 182 void intel_huc_load_status(struct intel_huc *huc, struct drm_printer *p) 183 { 184 struct intel_gt *gt = huc_to_gt(huc); 185 intel_wakeref_t wakeref; 186 187 if (!intel_huc_is_supported(huc)) { 188 drm_printf(p, "HuC not supported\n"); 189 return; 190 } 191 192 if (!intel_huc_is_wanted(huc)) { 193 drm_printf(p, "HuC disabled\n"); 194 return; 195 } 196 197 intel_uc_fw_dump(&huc->fw, p); 198 199 with_intel_runtime_pm(gt->uncore->rpm, wakeref) 200 drm_printf(p, "HuC status: 0x%08x\n", 201 intel_uncore_read(gt->uncore, huc->status.reg)); 202 } 203