1 #include "nouveau_device.h"
2
3 #include "nouveau_context.h"
4
5 #include "drm-uapi/nouveau_drm.h"
6 #include "util/hash_table.h"
7 #include "util/u_debug.h"
8 #include "util/os_file.h"
9 #include "util/os_misc.h"
10
11 #include <fcntl.h>
12 #include <nouveau/nvif/ioctl.h>
13 #include <nvif/cl0080.h>
14 #include <nvif/class.h>
15 #include <unistd.h>
16 #include <xf86drm.h>
17
18 static uint8_t
sm_for_chipset(uint16_t chipset)19 sm_for_chipset(uint16_t chipset)
20 {
21 if (chipset >= 0x190)
22 return 89;
23 // GH100 is older than AD10X, but is SM90
24 else if (chipset >= 0x180)
25 return 90;
26 else if (chipset == 0x17b)
27 return 87;
28 else if (chipset >= 0x172)
29 return 86;
30 else if (chipset >= 0x170)
31 return 80;
32 else if (chipset >= 0x160)
33 return 75;
34 else if (chipset >= 0x14b)
35 return 72;
36 else if (chipset >= 0x140)
37 return 70;
38 else if (chipset >= 0x13b)
39 return 62;
40 else if (chipset >= 0x132)
41 return 61;
42 else if (chipset >= 0x130)
43 return 60;
44 else if (chipset >= 0x12b)
45 return 53;
46 else if (chipset >= 0x120)
47 return 52;
48 else if (chipset >= 0x110)
49 return 50;
50 // TODO: 37
51 else if (chipset >= 0x0f0)
52 return 35;
53 else if (chipset >= 0x0ea)
54 return 32;
55 else if (chipset >= 0x0e0)
56 return 30;
57 // GF110 is SM20
58 else if (chipset == 0x0c8)
59 return 20;
60 else if (chipset >= 0x0c1)
61 return 21;
62 else if (chipset >= 0x0c0)
63 return 20;
64 else if (chipset >= 0x0a3)
65 return 12;
66 // GT200 is SM13
67 else if (chipset >= 0x0a0)
68 return 13;
69 else if (chipset >= 0x080)
70 return 11;
71 // this has to be == because 0x63 is older than 0x50 and has no compute
72 else if (chipset == 0x050)
73 return 10;
74 // no compute
75 return 0x00;
76 }
77
78 static uint8_t
max_warps_per_mp_for_sm(uint8_t sm)79 max_warps_per_mp_for_sm(uint8_t sm)
80 {
81 switch (sm) {
82 case 10:
83 case 11:
84 return 24;
85 case 12:
86 case 13:
87 case 75:
88 return 32;
89 case 20:
90 case 21:
91 case 86:
92 case 87:
93 case 89:
94 return 48;
95 case 30:
96 case 32:
97 case 35:
98 case 37:
99 case 50:
100 case 52:
101 case 53:
102 case 60:
103 case 61:
104 case 62:
105 case 70:
106 case 72:
107 case 80:
108 case 90:
109 return 64;
110 default:
111 assert(!"unkown SM version");
112 // return the biggest known value
113 return 64;
114 }
115 }
116
117 static uint8_t
mp_per_tpc_for_chipset(uint16_t chipset)118 mp_per_tpc_for_chipset(uint16_t chipset)
119 {
120 // GP100 is special and has two, otherwise it's a Volta and newer thing to have two
121 if (chipset == 0x130 || chipset >= 0x140)
122 return 2;
123 return 1;
124 }
125
126 static void
nouveau_ws_device_set_dbg_flags(struct nouveau_ws_device * dev)127 nouveau_ws_device_set_dbg_flags(struct nouveau_ws_device *dev)
128 {
129 const struct debug_control flags[] = {
130 { "push_dump", NVK_DEBUG_PUSH_DUMP },
131 { "push", NVK_DEBUG_PUSH_DUMP },
132 { "push_sync", NVK_DEBUG_PUSH_SYNC },
133 { "zero_memory", NVK_DEBUG_ZERO_MEMORY },
134 { "vm", NVK_DEBUG_VM },
135 { "no_cbuf", NVK_DEBUG_NO_CBUF },
136 { NULL, 0 },
137 };
138
139 dev->debug_flags = parse_debug_string(getenv("NVK_DEBUG"), flags);
140 }
141
142 static int
nouveau_ws_param(int fd,uint64_t param,uint64_t * value)143 nouveau_ws_param(int fd, uint64_t param, uint64_t *value)
144 {
145 struct drm_nouveau_getparam data = { .param = param };
146
147 int ret = drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &data, sizeof(data));
148 if (ret)
149 return ret;
150
151 *value = data.value;
152 return 0;
153 }
154
155 static int
nouveau_ws_device_alloc(int fd,struct nouveau_ws_device * dev)156 nouveau_ws_device_alloc(int fd, struct nouveau_ws_device *dev)
157 {
158 struct {
159 struct nvif_ioctl_v0 ioctl;
160 struct nvif_ioctl_new_v0 new;
161 struct nv_device_v0 dev;
162 } args = {
163 .ioctl = {
164 .object = 0,
165 .owner = NVIF_IOCTL_V0_OWNER_ANY,
166 .route = 0x00,
167 .type = NVIF_IOCTL_V0_NEW,
168 .version = 0,
169 },
170 .new = {
171 .handle = 0,
172 .object = (uintptr_t)dev,
173 .oclass = NV_DEVICE,
174 .route = NVIF_IOCTL_V0_ROUTE_NVIF,
175 .token = (uintptr_t)dev,
176 .version = 0,
177 },
178 .dev = {
179 .device = ~0ULL,
180 },
181 };
182
183 return drmCommandWrite(fd, DRM_NOUVEAU_NVIF, &args, sizeof(args));
184 }
185
186 static int
nouveau_ws_device_info(int fd,struct nouveau_ws_device * dev)187 nouveau_ws_device_info(int fd, struct nouveau_ws_device *dev)
188 {
189 struct {
190 struct nvif_ioctl_v0 ioctl;
191 struct nvif_ioctl_mthd_v0 mthd;
192 struct nv_device_info_v0 info;
193 } args = {
194 .ioctl = {
195 .object = (uintptr_t)dev,
196 .owner = NVIF_IOCTL_V0_OWNER_ANY,
197 .route = 0x00,
198 .type = NVIF_IOCTL_V0_MTHD,
199 .version = 0,
200 },
201 .mthd = {
202 .method = NV_DEVICE_V0_INFO,
203 .version = 0,
204 },
205 .info = {
206 .version = 0,
207 },
208 };
209
210 int ret = drmCommandWriteRead(fd, DRM_NOUVEAU_NVIF, &args, sizeof(args));
211 if (ret)
212 return ret;
213
214 dev->info.chipset = args.info.chipset;
215 dev->info.vram_size_B = args.info.ram_user;
216
217 switch (args.info.platform) {
218 case NV_DEVICE_INFO_V0_IGP:
219 dev->info.type = NV_DEVICE_TYPE_IGP;
220 break;
221 case NV_DEVICE_INFO_V0_SOC:
222 dev->info.type = NV_DEVICE_TYPE_SOC;
223 break;
224 case NV_DEVICE_INFO_V0_PCI:
225 case NV_DEVICE_INFO_V0_AGP:
226 case NV_DEVICE_INFO_V0_PCIE:
227 default:
228 dev->info.type = NV_DEVICE_TYPE_DIS;
229 break;
230 }
231
232 STATIC_ASSERT(sizeof(dev->info.device_name) >= sizeof(args.info.name));
233 memcpy(dev->info.device_name, args.info.name, sizeof(args.info.name));
234
235 STATIC_ASSERT(sizeof(dev->info.chipset_name) >= sizeof(args.info.chip));
236 memcpy(dev->info.chipset_name, args.info.chip, sizeof(args.info.chip));
237
238 return 0;
239 }
240
241 struct nouveau_ws_device *
nouveau_ws_device_new(drmDevicePtr drm_device)242 nouveau_ws_device_new(drmDevicePtr drm_device)
243 {
244 const char *path = drm_device->nodes[DRM_NODE_RENDER];
245 struct nouveau_ws_device *device = CALLOC_STRUCT(nouveau_ws_device);
246 uint64_t value = 0;
247 drmVersionPtr ver = NULL;
248
249 int fd = open(path, O_RDWR | O_CLOEXEC);
250 if (fd < 0)
251 goto out_open;
252
253 ver = drmGetVersion(fd);
254 if (!ver)
255 goto out_err;
256
257 if (strncmp("nouveau", ver->name, ver->name_len) != 0) {
258 fprintf(stderr,
259 "DRM kernel driver '%.*s' in use. NVK requires nouveau.\n",
260 ver->name_len, ver->name);
261 goto out_err;
262 }
263
264 uint32_t version =
265 ver->version_major << 24 |
266 ver->version_minor << 8 |
267 ver->version_patchlevel;
268 drmFreeVersion(ver);
269 ver = NULL;
270
271 if (version < 0x01000301)
272 goto out_err;
273
274 const uint64_t BDA = 1ull << 38;
275 const uint64_t KERN = 1ull << 39;
276 const uint64_t TOP = 1ull << 40;
277 struct drm_nouveau_vm_init vminit = { KERN, TOP-KERN };
278 int ret = drmCommandWrite(fd, DRM_NOUVEAU_VM_INIT, &vminit, sizeof(vminit));
279 if (ret == 0) {
280 device->has_vm_bind = true;
281 util_vma_heap_init(&device->vma_heap, 4096, BDA - 4096);
282 util_vma_heap_init(&device->bda_heap, BDA, KERN - BDA);
283 simple_mtx_init(&device->vma_mutex, mtx_plain);
284 }
285
286 if (nouveau_ws_device_alloc(fd, device))
287 goto out_err;
288
289 if (nouveau_ws_param(fd, NOUVEAU_GETPARAM_PCI_DEVICE, &value))
290 goto out_err;
291
292 device->info.device_id = value;
293
294 if (nouveau_ws_device_info(fd, device))
295 goto out_err;
296
297 if (drm_device->bustype == DRM_BUS_PCI) {
298 assert(device->info.type == NV_DEVICE_TYPE_DIS);
299 assert(device->info.device_id == drm_device->deviceinfo.pci->device_id);
300
301 device->info.pci.domain = drm_device->businfo.pci->domain;
302 device->info.pci.bus = drm_device->businfo.pci->bus;
303 device->info.pci.dev = drm_device->businfo.pci->dev;
304 device->info.pci.func = drm_device->businfo.pci->func;
305 device->info.pci.revision_id = drm_device->deviceinfo.pci->revision_id;
306 };
307
308 device->fd = fd;
309
310 if (nouveau_ws_param(fd, NOUVEAU_GETPARAM_EXEC_PUSH_MAX, &value))
311 device->max_push = NOUVEAU_GEM_MAX_PUSH;
312 else
313 device->max_push = value;
314
315 if (device->info.vram_size_B == 0)
316 device->local_mem_domain = NOUVEAU_GEM_DOMAIN_GART;
317 else
318 device->local_mem_domain = NOUVEAU_GEM_DOMAIN_VRAM;
319
320 if (drm_device->bustype == DRM_BUS_PCI &&
321 !nouveau_ws_param(fd, NOUVEAU_GETPARAM_VRAM_BAR_SIZE, &value))
322 device->info.bar_size_B = value;
323
324 if (nouveau_ws_param(fd, NOUVEAU_GETPARAM_GRAPH_UNITS, &value))
325 goto out_err;
326
327 device->info.gpc_count = (value >> 0) & 0x000000ff;
328 device->info.tpc_count = (value >> 8) & 0x0000ffff;
329
330 nouveau_ws_device_set_dbg_flags(device);
331
332 struct nouveau_ws_context *tmp_ctx;
333 if (nouveau_ws_context_create(device, ~0, &tmp_ctx))
334 goto out_err;
335
336 device->info.sm = sm_for_chipset(device->info.chipset);
337 device->info.cls_copy = tmp_ctx->copy.cls;
338 device->info.cls_eng2d = tmp_ctx->eng2d.cls;
339 device->info.cls_eng3d = tmp_ctx->eng3d.cls;
340 device->info.cls_m2mf = tmp_ctx->m2mf.cls;
341 device->info.cls_compute = tmp_ctx->compute.cls;
342
343 // for now we hardcode those values, but in the future Nouveau could provide that information to
344 // us instead.
345 device->info.max_warps_per_mp = max_warps_per_mp_for_sm(device->info.sm);
346 device->info.mp_per_tpc = mp_per_tpc_for_chipset(device->info.chipset);
347
348 nouveau_ws_context_destroy(tmp_ctx);
349
350 simple_mtx_init(&device->bos_lock, mtx_plain);
351 device->bos = _mesa_pointer_hash_table_create(NULL);
352
353 return device;
354
355 out_err:
356 if (device->has_vm_bind) {
357 util_vma_heap_finish(&device->vma_heap);
358 util_vma_heap_finish(&device->bda_heap);
359 simple_mtx_destroy(&device->vma_mutex);
360 }
361 if (ver)
362 drmFreeVersion(ver);
363 out_open:
364 FREE(device);
365 close(fd);
366 return NULL;
367 }
368
369 void
nouveau_ws_device_destroy(struct nouveau_ws_device * device)370 nouveau_ws_device_destroy(struct nouveau_ws_device *device)
371 {
372 if (!device)
373 return;
374
375 _mesa_hash_table_destroy(device->bos, NULL);
376 simple_mtx_destroy(&device->bos_lock);
377
378 if (device->has_vm_bind) {
379 util_vma_heap_finish(&device->vma_heap);
380 util_vma_heap_finish(&device->bda_heap);
381 simple_mtx_destroy(&device->vma_mutex);
382 }
383
384 close(device->fd);
385 FREE(device);
386 }
387
388 uint64_t
nouveau_ws_device_vram_used(struct nouveau_ws_device * device)389 nouveau_ws_device_vram_used(struct nouveau_ws_device *device)
390 {
391 uint64_t used = 0;
392 if (nouveau_ws_param(device->fd, NOUVEAU_GETPARAM_VRAM_USED, &used))
393 return 0;
394
395 /* Zero memory used would be very strange given that it includes kernel
396 * internal allocations.
397 */
398 assert(used > 0);
399
400 return used;
401 }
402