xref: /linux/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/gh100.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1 /* SPDX-License-Identifier: MIT
2  *
3  * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
4  */
5 #include "priv.h"
6 
7 #include <nvhw/drf.h>
8 #include <nvhw/ref/gh100/dev_fsp_pri.h>
9 #include <nvhw/ref/gh100/dev_therm.h>
10 
11 #include <nvrm/nvtypes.h>
12 
13 #define MCTP_HEADER_VERSION          3:0
14 #define MCTP_HEADER_RSVD             7:4
15 
16 #define MCTP_HEADER_DEID            15:8
17 #define MCTP_HEADER_SEID            23:16
18 
19 #define MCTP_HEADER_TAG             26:24
20 #define MCTP_HEADER_TO              27:27
21 #define MCTP_HEADER_SEQ             29:28
22 #define MCTP_HEADER_EOM             30:30
23 #define MCTP_HEADER_SOM             31:31
24 
25 #define MCTP_MSG_HEADER_TYPE         6:0
26 #define MCTP_MSG_HEADER_IC           7:7
27 
28 #define MCTP_MSG_HEADER_VENDOR_ID   23:8
29 #define MCTP_MSG_HEADER_NVDM_TYPE   31:24
30 
31 #define MCTP_MSG_HEADER_TYPE_VENDOR_PCI 0x7e
32 #define MCTP_MSG_HEADER_VENDOR_ID_NV    0x10de
33 
34 #define NVDM_TYPE_COT                   0x14
35 #define NVDM_TYPE_FSP_RESPONSE          0x15
36 
37 #pragma pack(1)
38 typedef struct nvdm_payload_cot
39 {
40     NvU16 version;
41     NvU16 size;
42     NvU64 gspFmcSysmemOffset;
43     NvU64 frtsSysmemOffset;
44     NvU32 frtsSysmemSize;
45 
46     // Note this is an offset from the end of FB
47     NvU64 frtsVidmemOffset;
48     NvU32 frtsVidmemSize;
49 
50     // Authentication related fields
51     NvU32 hash384[12];
52     NvU32 publicKey[96];
53     NvU32 signature[96];
54 
55     NvU64 gspBootArgsSysmemOffset;
56 } NVDM_PAYLOAD_COT;
57 #pragma pack()
58 
59 #pragma pack(1)
60 typedef struct
61 {
62     NvU32 taskId;
63     NvU32 commandNvdmType;
64     NvU32 errorCode;
65 } NVDM_PAYLOAD_COMMAND_RESPONSE;
66 #pragma pack()
67 
68 static u32
69 gh100_fsp_poll(struct nvkm_fsp *fsp)
70 {
71 	struct nvkm_device *device = fsp->subdev.device;
72 	u32 head, tail;
73 
74 	head = nvkm_rd32(device, NV_PFSP_MSGQ_HEAD(0));
75 	tail = nvkm_rd32(device, NV_PFSP_MSGQ_TAIL(0));
76 
77 	if (head == tail)
78 		return 0;
79 
80 	return (tail - head) + sizeof(u32); /* TAIL points at last DWORD written. */
81 }
82 
83 static int
84 gh100_fsp_recv(struct nvkm_fsp *fsp, u8 *packet, u32 max_packet_size)
85 {
86 	struct nvkm_device *device = fsp->subdev.device;
87 	u32 packet_size;
88 	int ret;
89 
90 	packet_size = gh100_fsp_poll(fsp);
91 	if (!packet_size || WARN_ON(packet_size % 4 || packet_size > max_packet_size))
92 		return -EINVAL;
93 
94 	ret = nvkm_falcon_pio_rd(&fsp->falcon, 0, EMEM, 0, packet, 0, packet_size);
95 	if (ret)
96 		return ret;
97 
98 	nvkm_wr32(device, NV_PFSP_MSGQ_TAIL(0), 0);
99 	nvkm_wr32(device, NV_PFSP_MSGQ_HEAD(0), 0);
100 
101 	return packet_size;
102 }
103 
104 static int
105 gh100_fsp_wait(struct nvkm_fsp *fsp)
106 {
107 	int time = 1000;
108 
109 	do {
110 		if (gh100_fsp_poll(fsp))
111 			return 0;
112 
113 		usleep_range(1000, 2000);
114 	} while(time--);
115 
116 	return -ETIMEDOUT;
117 }
118 
119 static int
120 gh100_fsp_send(struct nvkm_fsp *fsp, const u8 *packet, u32 packet_size)
121 {
122 	struct nvkm_device *device = fsp->subdev.device;
123 	int time = 1000, ret;
124 
125 	if (WARN_ON(packet_size % sizeof(u32)))
126 		return -EINVAL;
127 
128 	/* Ensure any previously sent message has been consumed. */
129 	do {
130 		u32 head = nvkm_rd32(device, NV_PFSP_QUEUE_HEAD(0));
131 		u32 tail = nvkm_rd32(device, NV_PFSP_QUEUE_TAIL(0));
132 
133 		if (tail == head)
134 			break;
135 
136 		usleep_range(1000, 2000);
137 	} while(time--);
138 
139 	if (time < 0)
140 		return -ETIMEDOUT;
141 
142 	/* Write message to EMEM. */
143 	ret = nvkm_falcon_pio_wr(&fsp->falcon, packet, 0, 0, EMEM, 0, packet_size, 0, false);
144 	if (ret)
145 		return ret;
146 
147 	/* Update queue pointers - TAIL points at last DWORD written. */
148 	nvkm_wr32(device, NV_PFSP_QUEUE_TAIL(0), packet_size - sizeof(u32));
149 	nvkm_wr32(device, NV_PFSP_QUEUE_HEAD(0), 0);
150 	return 0;
151 }
152 
153 static int
154 gh100_fsp_send_sync(struct nvkm_fsp *fsp, u8 nvdm_type, const u8 *packet, u32 packet_size)
155 {
156 	struct nvkm_subdev *subdev = &fsp->subdev;
157 	struct {
158 		u32 mctp_header;
159 		u32 nvdm_header;
160 		NVDM_PAYLOAD_COMMAND_RESPONSE response;
161 	} reply;
162 	int ret;
163 
164 	ret = gh100_fsp_send(fsp, packet, packet_size);
165 	if (ret)
166 		return ret;
167 
168 	ret = gh100_fsp_wait(fsp);
169 	if (ret)
170 		return ret;
171 
172 	ret = gh100_fsp_recv(fsp, (u8 *)&reply, sizeof(reply));
173 	if (ret < 0)
174 		return ret;
175 
176 	if (NVVAL_TEST(reply.mctp_header, MCTP, HEADER, SOM, !=, 1) ||
177 	    NVVAL_TEST(reply.mctp_header, MCTP, HEADER, EOM, !=, 1)) {
178 		nvkm_error(subdev, "unexpected MCTP header in reply: 0x%08x\n", reply.mctp_header);
179 		return -EIO;
180 	}
181 
182 	if (NVDEF_TEST(reply.nvdm_header, MCTP, MSG_HEADER, TYPE, !=, VENDOR_PCI) ||
183 	    NVDEF_TEST(reply.nvdm_header, MCTP, MSG_HEADER, VENDOR_ID, !=, NV) ||
184 	    NVVAL_TEST(reply.nvdm_header, MCTP, MSG_HEADER, NVDM_TYPE, !=, NVDM_TYPE_FSP_RESPONSE)) {
185 		nvkm_error(subdev, "unexpected NVDM header in reply: 0x%08x\n", reply.nvdm_header);
186 		return -EIO;
187 	}
188 
189 	if (reply.response.commandNvdmType != nvdm_type) {
190 		nvkm_error(subdev, "expected NVDM type 0x%02x in reply, got 0x%02x\n",
191 			   nvdm_type, reply.response.commandNvdmType);
192 		return -EIO;
193 	}
194 
195 	if (reply.response.errorCode) {
196 		nvkm_error(subdev, "NVDM command 0x%02x failed with error 0x%08x\n",
197 			   nvdm_type, reply.response.errorCode);
198 		return -EIO;
199 	}
200 
201 	return 0;
202 }
203 
204 int
205 gh100_fsp_boot_gsp_fmc(struct nvkm_fsp *fsp, u64 args_addr, u32 rsvd_size, bool resume,
206 		       u64 img_addr, const u8 *hash, const u8 *pkey, const u8 *sig)
207 {
208 	struct {
209 		u32 mctp_header;
210 		u32 nvdm_header;
211 		NVDM_PAYLOAD_COT cot;
212 	} msg = {};
213 
214 	msg.mctp_header = NVVAL(MCTP, HEADER, SOM, 1) |
215 			  NVVAL(MCTP, HEADER, EOM, 1) |
216 			  NVVAL(MCTP, HEADER, SEID, 0) |
217 			  NVVAL(MCTP, HEADER, SEQ, 0);
218 
219 	msg.nvdm_header = NVDEF(MCTP, MSG_HEADER, TYPE, VENDOR_PCI) |
220 			  NVDEF(MCTP, MSG_HEADER, VENDOR_ID, NV) |
221 			  NVVAL(MCTP, MSG_HEADER, NVDM_TYPE, NVDM_TYPE_COT);
222 
223 	msg.cot.version = fsp->func->cot.version;
224 	msg.cot.size = sizeof(msg.cot);
225 	msg.cot.gspFmcSysmemOffset = img_addr;
226 	if (!resume) {
227 		msg.cot.frtsVidmemOffset = ALIGN(rsvd_size, 0x200000);
228 		msg.cot.frtsVidmemSize = 0x100000;
229 	}
230 
231 	memcpy(msg.cot.hash384, hash, fsp->func->cot.size_hash);
232 	memcpy(msg.cot.publicKey, pkey, fsp->func->cot.size_pkey);
233 	memcpy(msg.cot.signature, sig, fsp->func->cot.size_sig);
234 
235 	msg.cot.gspBootArgsSysmemOffset = args_addr;
236 
237 	return gh100_fsp_send_sync(fsp, NVDM_TYPE_COT, (const u8 *)&msg, sizeof(msg));
238 }
239 
240 int
241 gh100_fsp_wait_secure_boot(struct nvkm_fsp *fsp)
242 {
243 	struct nvkm_device *device = fsp->subdev.device;
244 	unsigned timeout_ms = 4000;
245 
246 	do {
247 		u32 status = NVKM_RD32(device, NV_THERM, I2CS_SCRATCH, FSP_BOOT_COMPLETE_STATUS);
248 
249 		if (status == NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS)
250 			return 0;
251 
252 		usleep_range(1000, 2000);
253 	} while (timeout_ms--);
254 
255 	return -ETIMEDOUT;
256 }
257 
258 static const struct nvkm_fsp_func
259 gh100_fsp = {
260 	.wait_secure_boot = gh100_fsp_wait_secure_boot,
261 	.cot = {
262 		.version = 1,
263 		.size_hash = 48,
264 		.size_pkey = 384,
265 		.size_sig = 384,
266 		.boot_gsp_fmc = gh100_fsp_boot_gsp_fmc,
267 	},
268 };
269 
270 int
271 gh100_fsp_new(struct nvkm_device *device,
272 	      enum nvkm_subdev_type type, int inst, struct nvkm_fsp **pfsp)
273 {
274 	return nvkm_fsp_new_(&gh100_fsp, device, type, inst, pfsp);
275 }
276