• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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