xref: /linux/drivers/gpu/drm/xe/xe_huc.c (revision 8cdcef1c2f82d207aa8b2a02298fbc17191c6261)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2022 Intel Corporation
4  */
5 
6 #include "xe_huc.h"
7 
8 #include "regs/xe_guc_regs.h"
9 #include "xe_assert.h"
10 #include "xe_bo.h"
11 #include "xe_device.h"
12 #include "xe_force_wake.h"
13 #include "xe_gt.h"
14 #include "xe_guc.h"
15 #include "xe_mmio.h"
16 #include "xe_uc_fw.h"
17 
18 static struct xe_gt *
19 huc_to_gt(struct xe_huc *huc)
20 {
21 	return container_of(huc, struct xe_gt, uc.huc);
22 }
23 
24 static struct xe_device *
25 huc_to_xe(struct xe_huc *huc)
26 {
27 	return gt_to_xe(huc_to_gt(huc));
28 }
29 
30 static struct xe_guc *
31 huc_to_guc(struct xe_huc *huc)
32 {
33 	return &container_of(huc, struct xe_uc, huc)->guc;
34 }
35 
36 int xe_huc_init(struct xe_huc *huc)
37 {
38 	struct xe_gt *gt = huc_to_gt(huc);
39 	struct xe_tile *tile = gt_to_tile(gt);
40 	struct xe_device *xe = gt_to_xe(gt);
41 	int ret;
42 
43 	huc->fw.type = XE_UC_FW_TYPE_HUC;
44 
45 	/* On platforms with a media GT the HuC is only available there */
46 	if (tile->media_gt && (gt != tile->media_gt)) {
47 		xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_NOT_SUPPORTED);
48 		return 0;
49 	}
50 
51 	ret = xe_uc_fw_init(&huc->fw);
52 	if (ret)
53 		goto out;
54 
55 	if (!xe_uc_fw_is_enabled(&huc->fw))
56 		return 0;
57 
58 	xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_LOADABLE);
59 
60 	return 0;
61 
62 out:
63 	drm_err(&xe->drm, "HuC init failed with %d", ret);
64 	return ret;
65 }
66 
67 int xe_huc_upload(struct xe_huc *huc)
68 {
69 	if (!xe_uc_fw_is_loadable(&huc->fw))
70 		return 0;
71 	return xe_uc_fw_upload(&huc->fw, 0, HUC_UKERNEL);
72 }
73 
74 int xe_huc_auth(struct xe_huc *huc)
75 {
76 	struct xe_device *xe = huc_to_xe(huc);
77 	struct xe_gt *gt = huc_to_gt(huc);
78 	struct xe_guc *guc = huc_to_guc(huc);
79 	int ret;
80 
81 	if (!xe_uc_fw_is_loadable(&huc->fw))
82 		return 0;
83 
84 	xe_assert(xe, !xe_uc_fw_is_running(&huc->fw));
85 
86 	/* On newer platforms the HuC survives reset, so no need to re-auth */
87 	if (xe_mmio_read32(gt, HUC_KERNEL_LOAD_INFO) & HUC_LOAD_SUCCESSFUL) {
88 		xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_RUNNING);
89 		return 0;
90 	}
91 
92 	if (!xe_uc_fw_is_loaded(&huc->fw))
93 		return -ENOEXEC;
94 
95 	ret = xe_guc_auth_huc(guc, xe_bo_ggtt_addr(huc->fw.bo) +
96 			      xe_uc_fw_rsa_offset(&huc->fw));
97 	if (ret) {
98 		drm_err(&xe->drm, "HuC: GuC did not ack Auth request %d\n",
99 			ret);
100 		goto fail;
101 	}
102 
103 	ret = xe_mmio_wait32(gt, HUC_KERNEL_LOAD_INFO, HUC_LOAD_SUCCESSFUL,
104 			     HUC_LOAD_SUCCESSFUL, 100000, NULL, false);
105 	if (ret) {
106 		drm_err(&xe->drm, "HuC: Firmware not verified %d\n", ret);
107 		goto fail;
108 	}
109 
110 	xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_RUNNING);
111 	drm_dbg(&xe->drm, "HuC authenticated\n");
112 
113 	return 0;
114 
115 fail:
116 	drm_err(&xe->drm, "HuC authentication failed %d\n", ret);
117 	xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_LOAD_FAIL);
118 
119 	return ret;
120 }
121 
122 void xe_huc_sanitize(struct xe_huc *huc)
123 {
124 	if (!xe_uc_fw_is_loadable(&huc->fw))
125 		return;
126 	xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_LOADABLE);
127 }
128 
129 void xe_huc_print_info(struct xe_huc *huc, struct drm_printer *p)
130 {
131 	struct xe_gt *gt = huc_to_gt(huc);
132 	int err;
133 
134 	xe_uc_fw_print(&huc->fw, p);
135 
136 	if (!xe_uc_fw_is_enabled(&huc->fw))
137 		return;
138 
139 	err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
140 	if (err)
141 		return;
142 
143 	drm_printf(p, "\nHuC status: 0x%08x\n",
144 		   xe_mmio_read32(gt, HUC_KERNEL_LOAD_INFO));
145 
146 	xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
147 }
148