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