xref: /linux/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/r535.c (revision 24168c5e6dfbdd5b414f048f47f75d64533296ca)
1 /*
2  * Copyright 2023 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #include "priv.h"
23 
24 #include <subdev/gsp.h>
25 
26 #include <nvhw/drf.h>
27 
28 #include <nvrm/nvtypes.h>
29 #include <nvrm/535.113.01/common/sdk/nvidia/inc/class/cl84a0.h>
30 #include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080internal.h>
31 #include <nvrm/535.113.01/common/sdk/nvidia/inc/nvos.h>
32 #include <nvrm/535.113.01/nvidia/generated/g_fbsr_nvoc.h>
33 #include <nvrm/535.113.01/nvidia/generated/g_rpc-structures.h>
34 #include <nvrm/535.113.01/nvidia/kernel/inc/vgpu/rpc_global_enums.h>
35 
36 struct fbsr_item {
37 	const char *type;
38 	u64 addr;
39 	u64 size;
40 
41 	struct list_head head;
42 };
43 
44 struct fbsr {
45 	struct list_head items;
46 
47 	u64 size;
48 	int regions;
49 
50 	struct nvkm_gsp_client client;
51 	struct nvkm_gsp_device device;
52 
53 	u64 hmemory;
54 	u64 sys_offset;
55 };
56 
57 static int
58 fbsr_memlist(struct nvkm_gsp_device *device, u32 handle, enum nvkm_memory_target aper,
59 	     u64 phys, u64 size, struct sg_table *sgt, struct nvkm_gsp_object *object)
60 {
61 	struct nvkm_gsp_client *client = device->object.client;
62 	struct nvkm_gsp *gsp = client->gsp;
63 	const u32 pages = size / GSP_PAGE_SIZE;
64 	rpc_alloc_memory_v13_01 *rpc;
65 	int ret;
66 
67 	rpc = nvkm_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_ALLOC_MEMORY,
68 			       sizeof(*rpc) + pages * sizeof(rpc->pteDesc.pte_pde[0]));
69 	if (IS_ERR(rpc))
70 		return PTR_ERR(rpc);
71 
72 	rpc->hClient = client->object.handle;
73 	rpc->hDevice = device->object.handle;
74 	rpc->hMemory = handle;
75 	if (aper == NVKM_MEM_TARGET_HOST) {
76 		rpc->hClass = NV01_MEMORY_LIST_SYSTEM;
77 		rpc->flags = NVDEF(NVOS02, FLAGS, PHYSICALITY, NONCONTIGUOUS) |
78 			     NVDEF(NVOS02, FLAGS, LOCATION, PCI) |
79 			     NVDEF(NVOS02, FLAGS, MAPPING, NO_MAP);
80 	} else {
81 		rpc->hClass = NV01_MEMORY_LIST_FBMEM;
82 		rpc->flags = NVDEF(NVOS02, FLAGS, PHYSICALITY, CONTIGUOUS) |
83 			     NVDEF(NVOS02, FLAGS, LOCATION, VIDMEM) |
84 			     NVDEF(NVOS02, FLAGS, MAPPING, NO_MAP);
85 		rpc->format = 6; /* NV_MMU_PTE_KIND_GENERIC_MEMORY */
86 	}
87 	rpc->pteAdjust = 0;
88 	rpc->length = size;
89 	rpc->pageCount = pages;
90 	rpc->pteDesc.idr = 0;
91 	rpc->pteDesc.reserved1 = 0;
92 	rpc->pteDesc.length = pages;
93 
94 	if (sgt) {
95 		struct scatterlist *sgl;
96 		int pte = 0, idx;
97 
98 		for_each_sgtable_dma_sg(sgt, sgl, idx) {
99 			for (int i = 0; i < sg_dma_len(sgl) / GSP_PAGE_SIZE; i++)
100 				rpc->pteDesc.pte_pde[pte++].pte = (sg_dma_address(sgl) >> 12) + i;
101 
102 		}
103 	} else {
104 		for (int i = 0; i < pages; i++)
105 			rpc->pteDesc.pte_pde[i].pte = (phys >> 12) + i;
106 	}
107 
108 	ret = nvkm_gsp_rpc_wr(gsp, rpc, true);
109 	if (ret)
110 		return ret;
111 
112 	object->client = device->object.client;
113 	object->parent = &device->object;
114 	object->handle = handle;
115 	return 0;
116 }
117 
118 static int
119 fbsr_send(struct fbsr *fbsr, struct fbsr_item *item)
120 {
121 	NV2080_CTRL_INTERNAL_FBSR_SEND_REGION_INFO_PARAMS *ctrl;
122 	struct nvkm_gsp *gsp = fbsr->client.gsp;
123 	struct nvkm_gsp_object memlist;
124 	int ret;
125 
126 	ret = fbsr_memlist(&fbsr->device, fbsr->hmemory, NVKM_MEM_TARGET_VRAM,
127 			   item->addr, item->size, NULL, &memlist);
128 	if (ret)
129 		return ret;
130 
131 	ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,
132 				    NV2080_CTRL_CMD_INTERNAL_FBSR_SEND_REGION_INFO,
133 				    sizeof(*ctrl));
134 	if (IS_ERR(ctrl)) {
135 		ret = PTR_ERR(ctrl);
136 		goto done;
137 	}
138 
139 	ctrl->fbsrType = FBSR_TYPE_DMA;
140 	ctrl->hClient = fbsr->client.object.handle;
141 	ctrl->hVidMem = fbsr->hmemory++;
142 	ctrl->vidOffset = 0;
143 	ctrl->sysOffset = fbsr->sys_offset;
144 	ctrl->size = item->size;
145 
146 	ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
147 done:
148 	nvkm_gsp_rm_free(&memlist);
149 	if (ret)
150 		return ret;
151 
152 	fbsr->sys_offset += item->size;
153 	return 0;
154 }
155 
156 static int
157 fbsr_init(struct fbsr *fbsr, struct sg_table *sgt, u64 items_size)
158 {
159 	NV2080_CTRL_INTERNAL_FBSR_INIT_PARAMS *ctrl;
160 	struct nvkm_gsp *gsp = fbsr->client.gsp;
161 	struct nvkm_gsp_object memlist;
162 	int ret;
163 
164 	ret = fbsr_memlist(&fbsr->device, fbsr->hmemory, NVKM_MEM_TARGET_HOST,
165 			   0, fbsr->size, sgt, &memlist);
166 	if (ret)
167 		return ret;
168 
169 	ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,
170 				    NV2080_CTRL_CMD_INTERNAL_FBSR_INIT, sizeof(*ctrl));
171 	if (IS_ERR(ctrl))
172 		return PTR_ERR(ctrl);
173 
174 	ctrl->fbsrType = FBSR_TYPE_DMA;
175 	ctrl->numRegions = fbsr->regions;
176 	ctrl->hClient = fbsr->client.object.handle;
177 	ctrl->hSysMem = fbsr->hmemory++;
178 	ctrl->gspFbAllocsSysOffset = items_size;
179 
180 	ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
181 	if (ret)
182 		return ret;
183 
184 	nvkm_gsp_rm_free(&memlist);
185 	return 0;
186 }
187 
188 static bool
189 fbsr_vram(struct fbsr *fbsr, const char *type, u64 addr, u64 size)
190 {
191 	struct fbsr_item *item;
192 
193 	if (!(item = kzalloc(sizeof(*item), GFP_KERNEL)))
194 		return false;
195 
196 	item->type = type;
197 	item->addr = addr;
198 	item->size = size;
199 	list_add_tail(&item->head, &fbsr->items);
200 	return true;
201 }
202 
203 static bool
204 fbsr_inst(struct fbsr *fbsr, const char *type, struct nvkm_memory *memory)
205 {
206 	return fbsr_vram(fbsr, type, nvkm_memory_addr(memory), nvkm_memory_size(memory));
207 }
208 
209 static void
210 r535_instmem_resume(struct nvkm_instmem *imem)
211 {
212 	/* RM has restored VRAM contents already, so just need to free the sysmem buffer. */
213 	if (imem->rm.fbsr_valid) {
214 		nvkm_gsp_sg_free(imem->subdev.device, &imem->rm.fbsr);
215 		imem->rm.fbsr_valid = false;
216 	}
217 }
218 
219 static int
220 r535_instmem_suspend(struct nvkm_instmem *imem)
221 {
222 	struct nvkm_subdev *subdev = &imem->subdev;
223 	struct nvkm_device *device = subdev->device;
224 	struct nvkm_gsp *gsp = device->gsp;
225 	struct nvkm_instobj *iobj;
226 	struct fbsr fbsr = {};
227 	struct fbsr_item *item, *temp;
228 	u64 items_size;
229 	int ret;
230 
231 	INIT_LIST_HEAD(&fbsr.items);
232 	fbsr.hmemory = 0xcaf00003;
233 
234 	/* Create a list of all regions we need RM to save during suspend. */
235 	list_for_each_entry(iobj, &imem->list, head) {
236 		if (iobj->preserve) {
237 			if (!fbsr_inst(&fbsr, "inst", &iobj->memory))
238 				return -ENOMEM;
239 		}
240 	}
241 
242 	list_for_each_entry(iobj, &imem->boot, head) {
243 		if (!fbsr_inst(&fbsr, "boot", &iobj->memory))
244 			return -ENOMEM;
245 	}
246 
247 	if (!fbsr_vram(&fbsr, "gsp-non-wpr", gsp->fb.heap.addr, gsp->fb.heap.size))
248 		return -ENOMEM;
249 
250 	/* Determine memory requirements. */
251 	list_for_each_entry(item, &fbsr.items, head) {
252 		nvkm_debug(subdev, "fbsr: %016llx %016llx %s\n",
253 			   item->addr, item->size, item->type);
254 		fbsr.size += item->size;
255 		fbsr.regions++;
256 	}
257 
258 	items_size = fbsr.size;
259 	nvkm_debug(subdev, "fbsr: %d regions (0x%llx bytes)\n", fbsr.regions, items_size);
260 
261 	fbsr.size += gsp->fb.rsvd_size;
262 	fbsr.size += gsp->fb.bios.vga_workspace.size;
263 	nvkm_debug(subdev, "fbsr: size: 0x%llx bytes\n", fbsr.size);
264 
265 	ret = nvkm_gsp_sg(gsp->subdev.device, fbsr.size, &imem->rm.fbsr);
266 	if (ret)
267 		goto done;
268 
269 	/* Tell RM about the sysmem which will hold VRAM contents across suspend. */
270 	ret = nvkm_gsp_client_device_ctor(gsp, &fbsr.client, &fbsr.device);
271 	if (ret)
272 		goto done_sgt;
273 
274 	ret = fbsr_init(&fbsr, &imem->rm.fbsr, items_size);
275 	if (WARN_ON(ret))
276 		goto done_sgt;
277 
278 	/* Send VRAM regions that need saving. */
279 	list_for_each_entry(item, &fbsr.items, head) {
280 		ret = fbsr_send(&fbsr, item);
281 		if (WARN_ON(ret))
282 			goto done_sgt;
283 	}
284 
285 	imem->rm.fbsr_valid = true;
286 
287 	/* Cleanup everything except the sysmem backup, which will be removed after resume. */
288 done_sgt:
289 	if (ret) /* ... unless we failed already. */
290 		nvkm_gsp_sg_free(device, &imem->rm.fbsr);
291 done:
292 	list_for_each_entry_safe(item, temp, &fbsr.items, head) {
293 		list_del(&item->head);
294 		kfree(item);
295 	}
296 
297 	nvkm_gsp_device_dtor(&fbsr.device);
298 	nvkm_gsp_client_dtor(&fbsr.client);
299 	return ret;
300 }
301 
302 static void *
303 r535_instmem_dtor(struct nvkm_instmem *imem)
304 {
305 	kfree(imem->func);
306 	return imem;
307 }
308 
309 int
310 r535_instmem_new(const struct nvkm_instmem_func *hw,
311 		 struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
312 		 struct nvkm_instmem **pinstmem)
313 {
314 	struct nvkm_instmem_func *rm;
315 	int ret;
316 
317 	if (!(rm = kzalloc(sizeof(*rm), GFP_KERNEL)))
318 		return -ENOMEM;
319 
320 	rm->dtor = r535_instmem_dtor;
321 	rm->fini = hw->fini;
322 	rm->suspend = r535_instmem_suspend;
323 	rm->resume  = r535_instmem_resume;
324 	rm->memory_new = hw->memory_new;
325 	rm->memory_wrap = hw->memory_wrap;
326 	rm->zero = false;
327 
328 	ret = nv50_instmem_new_(rm, device, type, inst, pinstmem);
329 	if (ret)
330 		kfree(rm);
331 
332 	return ret;
333 }
334