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
gh100_fsp_poll(struct nvkm_fsp * fsp)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
gh100_fsp_recv(struct nvkm_fsp * fsp,u8 * packet,u32 max_packet_size)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
gh100_fsp_wait(struct nvkm_fsp * fsp)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
gh100_fsp_send(struct nvkm_fsp * fsp,const u8 * packet,u32 packet_size)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
gh100_fsp_send_sync(struct nvkm_fsp * fsp,u8 nvdm_type,const u8 * packet,u32 packet_size)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
gh100_fsp_boot_gsp_fmc(struct nvkm_fsp * fsp,u64 args_addr,u32 rsvd_size,bool resume,u64 img_addr,const u8 * hash,const u8 * pkey,const u8 * sig)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
gh100_fsp_wait_secure_boot(struct nvkm_fsp * fsp)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
gh100_fsp_new(struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_fsp ** pfsp)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