File Index
Files and directories
Sign in
FILE

gh100.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/nouveau/nvkm/subdev/fsp/gh100.c C
  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)
 38typedef 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)
 60typedef struct
 61{
 62    NvU32 taskId;
 63    NvU32 commandNvdmType;
 64    NvU32 errorCode;
 65} NVDM_PAYLOAD_COMMAND_RESPONSE;
 66#pragma pack()
 67
 68static u32
 69gh100_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
 83static int
 84gh100_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
104static int
105gh100_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
119static int
120gh100_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
153static int
154gh100_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
204int
205gh100_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
240int
241gh100_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
258static const struct nvkm_fsp_func
259gh100_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
270int
271gh100_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}
~/ Read-only file preview.