OSDN Git Service

nouveau: add interface to call an object's methods
[android-x86/external-libdrm.git] / nouveau / nouveau.c
1 /*
2  * Copyright 2012 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  * Authors: Ben Skeggs
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdbool.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <fcntl.h>
38
39 #include <xf86drm.h>
40 #include <xf86atomic.h>
41 #include "libdrm_macros.h"
42 #include "libdrm_lists.h"
43 #include "nouveau_drm.h"
44
45 #include "nouveau.h"
46 #include "private.h"
47
48 #ifdef DEBUG
49 drm_private uint32_t nouveau_debug = 0;
50
51 static void
52 debug_init(char *args)
53 {
54         if (args) {
55                 int n = strtol(args, NULL, 0);
56                 if (n >= 0)
57                         nouveau_debug = n;
58         }
59 }
60 #endif
61
62 int
63 nouveau_object_mthd(struct nouveau_object *obj,
64                     uint32_t mthd, void *data, uint32_t size)
65 {
66         return -ENODEV;
67 }
68
69 static void
70 nouveau_object_fini(struct nouveau_object *obj)
71 {
72         if (obj->data) {
73                 abi16_delete(obj);
74                 free(obj->data);
75                 obj->data = NULL;
76                 return;
77         }
78 }
79
80 static int
81 nouveau_object_init(struct nouveau_object *parent, uint32_t handle,
82                     int32_t oclass, void *data, uint32_t size,
83                     struct nouveau_object *obj)
84 {
85         int (*func)(struct nouveau_object *);
86         int ret = -ENOSYS;
87
88         obj->parent = parent;
89         obj->handle = handle;
90         obj->oclass = oclass;
91         obj->length = 0;
92         obj->data = NULL;
93
94         abi16_object(obj, &func);
95         if (func) {
96                 obj->length = size ? size : sizeof(struct nouveau_object *);
97                 if (!(obj->data = malloc(obj->length)))
98                         return -ENOMEM;
99                 if (data)
100                         memcpy(obj->data, data, obj->length);
101                 *(struct nouveau_object **)obj->data = obj;
102
103                 ret = func(obj);
104         }
105
106         if (ret) {
107                 nouveau_object_fini(obj);
108                 return ret;
109         }
110
111         return 0;
112 }
113
114 int
115 nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
116                    uint32_t oclass, void *data, uint32_t length,
117                    struct nouveau_object **pobj)
118 {
119         struct nouveau_object *obj;
120         int ret;
121
122         if (!(obj = malloc(sizeof(*obj))))
123                 return -ENOMEM;
124
125         ret = nouveau_object_init(parent, handle, oclass, data, length, obj);
126         if (ret) {
127                 free(obj);
128                 return ret;
129         }
130
131         *pobj = obj;
132         return 0;
133 }
134
135 void
136 nouveau_object_del(struct nouveau_object **pobj)
137 {
138         struct nouveau_object *obj = *pobj;
139         if (obj) {
140                 nouveau_object_fini(obj);
141                 free(obj);
142                 *pobj = NULL;
143         }
144 }
145
146 void *
147 nouveau_object_find(struct nouveau_object *obj, uint32_t pclass)
148 {
149         while (obj && obj->oclass != pclass) {
150                 obj = obj->parent;
151                 if (pclass == NOUVEAU_PARENT_CLASS)
152                         break;
153         }
154         return obj;
155 }
156
157 /* this is the old libdrm's version of nouveau_device_wrap(), the symbol
158  * is kept here to prevent AIGLX from crashing if the DDX is linked against
159  * the new libdrm, but the DRI driver against the old
160  */
161 int
162 nouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd,
163                              drm_context_t ctx)
164 {
165         return -EACCES;
166 }
167
168 int
169 nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
170 {
171         struct nouveau_device_priv *nvdev = calloc(1, sizeof(*nvdev));
172         struct nouveau_device *dev = &nvdev->base;
173         uint64_t chipset, vram, gart, bousage;
174         drmVersionPtr ver;
175         int ret;
176         char *tmp;
177
178 #ifdef DEBUG
179         debug_init(getenv("NOUVEAU_LIBDRM_DEBUG"));
180 #endif
181
182         if (!nvdev)
183                 return -ENOMEM;
184         ret = pthread_mutex_init(&nvdev->lock, NULL);
185         if (ret) {
186                 free(nvdev);
187                 return ret;
188         }
189
190         nvdev->base.fd = fd;
191
192         ver = drmGetVersion(fd);
193         if (ver) dev->drm_version = (ver->version_major << 24) |
194                                     (ver->version_minor << 8) |
195                                      ver->version_patchlevel;
196         drmFreeVersion(ver);
197
198         if ( dev->drm_version != 0x00000010 &&
199             (dev->drm_version <  0x01000000 ||
200              dev->drm_version >= 0x02000000)) {
201                 nouveau_device_del(&dev);
202                 return -EINVAL;
203         }
204
205         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &chipset);
206         if (ret == 0)
207         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &vram);
208         if (ret == 0)
209         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &gart);
210         if (ret) {
211                 nouveau_device_del(&dev);
212                 return ret;
213         }
214
215         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &bousage);
216         if (ret == 0)
217                 nvdev->have_bo_usage = (bousage != 0);
218
219         nvdev->close = close;
220
221         tmp = getenv("NOUVEAU_LIBDRM_VRAM_LIMIT_PERCENT");
222         if (tmp)
223                 nvdev->vram_limit_percent = atoi(tmp);
224         else
225                 nvdev->vram_limit_percent = 80;
226         tmp = getenv("NOUVEAU_LIBDRM_GART_LIMIT_PERCENT");
227         if (tmp)
228                 nvdev->gart_limit_percent = atoi(tmp);
229         else
230                 nvdev->gart_limit_percent = 80;
231         DRMINITLISTHEAD(&nvdev->bo_list);
232         nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
233         nvdev->base.object.length = ~0;
234         nvdev->base.lib_version = 0x01000000;
235         nvdev->base.chipset = chipset;
236         nvdev->base.vram_size = vram;
237         nvdev->base.gart_size = gart;
238         nvdev->base.vram_limit =
239                 (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100;
240         nvdev->base.gart_limit =
241                 (nvdev->base.gart_size * nvdev->gart_limit_percent) / 100;
242
243         *pdev = &nvdev->base;
244         return 0;
245 }
246
247 int
248 nouveau_device_open(const char *busid, struct nouveau_device **pdev)
249 {
250         int ret = -ENODEV, fd = drmOpen("nouveau", busid);
251         if (fd >= 0) {
252                 ret = nouveau_device_wrap(fd, 1, pdev);
253                 if (ret)
254                         drmClose(fd);
255         }
256         return ret;
257 }
258
259 void
260 nouveau_device_del(struct nouveau_device **pdev)
261 {
262         struct nouveau_device_priv *nvdev = nouveau_device(*pdev);
263         if (nvdev) {
264                 if (nvdev->close)
265                         drmClose(nvdev->base.fd);
266                 free(nvdev->client);
267                 pthread_mutex_destroy(&nvdev->lock);
268                 free(nvdev);
269                 *pdev = NULL;
270         }
271 }
272
273 int
274 nouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value)
275 {
276         struct drm_nouveau_getparam r = { .param = param };
277         int fd = dev->fd, ret =
278                 drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r));
279         *value = r.value;
280         return ret;
281 }
282
283 int
284 nouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value)
285 {
286         struct drm_nouveau_setparam r = { .param = param, .value = value };
287         return drmCommandWrite(dev->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r));
288 }
289
290 int
291 nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient)
292 {
293         struct nouveau_device_priv *nvdev = nouveau_device(dev);
294         struct nouveau_client_priv *pcli;
295         int id = 0, i, ret = -ENOMEM;
296         uint32_t *clients;
297
298         pthread_mutex_lock(&nvdev->lock);
299
300         for (i = 0; i < nvdev->nr_client; i++) {
301                 id = ffs(nvdev->client[i]) - 1;
302                 if (id >= 0)
303                         goto out;
304         }
305
306         clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1));
307         if (!clients)
308                 goto unlock;
309         nvdev->client = clients;
310         nvdev->client[i] = 0;
311         nvdev->nr_client++;
312
313 out:
314         pcli = calloc(1, sizeof(*pcli));
315         if (pcli) {
316                 nvdev->client[i] |= (1 << id);
317                 pcli->base.device = dev;
318                 pcli->base.id = (i * 32) + id;
319                 ret = 0;
320         }
321
322         *pclient = &pcli->base;
323
324 unlock:
325         pthread_mutex_unlock(&nvdev->lock);
326         return ret;
327 }
328
329 void
330 nouveau_client_del(struct nouveau_client **pclient)
331 {
332         struct nouveau_client_priv *pcli = nouveau_client(*pclient);
333         struct nouveau_device_priv *nvdev;
334         if (pcli) {
335                 int id = pcli->base.id;
336                 nvdev = nouveau_device(pcli->base.device);
337                 pthread_mutex_lock(&nvdev->lock);
338                 nvdev->client[id / 32] &= ~(1 << (id % 32));
339                 pthread_mutex_unlock(&nvdev->lock);
340                 free(pcli->kref);
341                 free(pcli);
342         }
343 }
344
345 static void
346 nouveau_bo_del(struct nouveau_bo *bo)
347 {
348         struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
349         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
350         struct drm_gem_close req = { .handle = bo->handle };
351
352         if (nvbo->head.next) {
353                 pthread_mutex_lock(&nvdev->lock);
354                 if (atomic_read(&nvbo->refcnt) == 0) {
355                         DRMLISTDEL(&nvbo->head);
356                         /*
357                          * This bo has to be closed with the lock held because
358                          * gem handles are not refcounted. If a shared bo is
359                          * closed and re-opened in another thread a race
360                          * against DRM_IOCTL_GEM_OPEN or drmPrimeFDToHandle
361                          * might cause the bo to be closed accidentally while
362                          * re-importing.
363                          */
364                         drmIoctl(bo->device->fd, DRM_IOCTL_GEM_CLOSE, &req);
365                 }
366                 pthread_mutex_unlock(&nvdev->lock);
367         } else {
368                 drmIoctl(bo->device->fd, DRM_IOCTL_GEM_CLOSE, &req);
369         }
370         if (bo->map)
371                 drm_munmap(bo->map, bo->size);
372         free(nvbo);
373 }
374
375 int
376 nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align,
377                uint64_t size, union nouveau_bo_config *config,
378                struct nouveau_bo **pbo)
379 {
380         struct nouveau_bo_priv *nvbo = calloc(1, sizeof(*nvbo));
381         struct nouveau_bo *bo = &nvbo->base;
382         int ret;
383
384         if (!nvbo)
385                 return -ENOMEM;
386         atomic_set(&nvbo->refcnt, 1);
387         bo->device = dev;
388         bo->flags = flags;
389         bo->size = size;
390
391         ret = abi16_bo_init(bo, align, config);
392         if (ret) {
393                 free(nvbo);
394                 return ret;
395         }
396
397         *pbo = bo;
398         return 0;
399 }
400
401 static int
402 nouveau_bo_wrap_locked(struct nouveau_device *dev, uint32_t handle,
403                        struct nouveau_bo **pbo, int name)
404 {
405         struct nouveau_device_priv *nvdev = nouveau_device(dev);
406         struct drm_nouveau_gem_info req = { .handle = handle };
407         struct nouveau_bo_priv *nvbo;
408         int ret;
409
410         DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) {
411                 if (nvbo->base.handle == handle) {
412                         if (atomic_inc_return(&nvbo->refcnt) == 1) {
413                                 /*
414                                  * Uh oh, this bo is dead and someone else
415                                  * will free it, but because refcnt is
416                                  * now non-zero fortunately they won't
417                                  * call the ioctl to close the bo.
418                                  *
419                                  * Remove this bo from the list so other
420                                  * calls to nouveau_bo_wrap_locked will
421                                  * see our replacement nvbo.
422                                  */
423                                 DRMLISTDEL(&nvbo->head);
424                                 if (!name)
425                                         name = nvbo->name;
426                                 break;
427                         }
428
429                         *pbo = &nvbo->base;
430                         return 0;
431                 }
432         }
433
434         ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_INFO,
435                                   &req, sizeof(req));
436         if (ret)
437                 return ret;
438
439         nvbo = calloc(1, sizeof(*nvbo));
440         if (nvbo) {
441                 atomic_set(&nvbo->refcnt, 1);
442                 nvbo->base.device = dev;
443                 abi16_bo_info(&nvbo->base, &req);
444                 nvbo->name = name;
445                 DRMLISTADD(&nvbo->head, &nvdev->bo_list);
446                 *pbo = &nvbo->base;
447                 return 0;
448         }
449
450         return -ENOMEM;
451 }
452
453 static void
454 nouveau_bo_make_global(struct nouveau_bo_priv *nvbo)
455 {
456         if (!nvbo->head.next) {
457                 struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
458                 pthread_mutex_lock(&nvdev->lock);
459                 if (!nvbo->head.next)
460                         DRMLISTADD(&nvbo->head, &nvdev->bo_list);
461                 pthread_mutex_unlock(&nvdev->lock);
462         }
463 }
464
465 int
466 nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
467                 struct nouveau_bo **pbo)
468 {
469         struct nouveau_device_priv *nvdev = nouveau_device(dev);
470         int ret;
471         pthread_mutex_lock(&nvdev->lock);
472         ret = nouveau_bo_wrap_locked(dev, handle, pbo, 0);
473         pthread_mutex_unlock(&nvdev->lock);
474         return ret;
475 }
476
477 int
478 nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name,
479                     struct nouveau_bo **pbo)
480 {
481         struct nouveau_device_priv *nvdev = nouveau_device(dev);
482         struct nouveau_bo_priv *nvbo;
483         struct drm_gem_open req = { .name = name };
484         int ret;
485
486         pthread_mutex_lock(&nvdev->lock);
487         DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) {
488                 if (nvbo->name == name) {
489                         ret = nouveau_bo_wrap_locked(dev, nvbo->base.handle,
490                                                      pbo, name);
491                         pthread_mutex_unlock(&nvdev->lock);
492                         return ret;
493                 }
494         }
495
496         ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
497         if (ret == 0) {
498                 ret = nouveau_bo_wrap_locked(dev, req.handle, pbo, name);
499         }
500
501         pthread_mutex_unlock(&nvdev->lock);
502         return ret;
503 }
504
505 int
506 nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name)
507 {
508         struct drm_gem_flink req = { .handle = bo->handle };
509         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
510
511         *name = nvbo->name;
512         if (!*name) {
513                 int ret = drmIoctl(bo->device->fd, DRM_IOCTL_GEM_FLINK, &req);
514
515                 if (ret) {
516                         *name = 0;
517                         return ret;
518                 }
519                 nvbo->name = *name = req.name;
520
521                 nouveau_bo_make_global(nvbo);
522         }
523         return 0;
524 }
525
526 void
527 nouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref)
528 {
529         struct nouveau_bo *ref = *pref;
530         if (bo) {
531                 atomic_inc(&nouveau_bo(bo)->refcnt);
532         }
533         if (ref) {
534                 if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt))
535                         nouveau_bo_del(ref);
536         }
537         *pref = bo;
538 }
539
540 int
541 nouveau_bo_prime_handle_ref(struct nouveau_device *dev, int prime_fd,
542                             struct nouveau_bo **bo)
543 {
544         struct nouveau_device_priv *nvdev = nouveau_device(dev);
545         int ret;
546         unsigned int handle;
547
548         nouveau_bo_ref(NULL, bo);
549
550         pthread_mutex_lock(&nvdev->lock);
551         ret = drmPrimeFDToHandle(dev->fd, prime_fd, &handle);
552         if (ret == 0) {
553                 ret = nouveau_bo_wrap_locked(dev, handle, bo, 0);
554         }
555         pthread_mutex_unlock(&nvdev->lock);
556         return ret;
557 }
558
559 int
560 nouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd)
561 {
562         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
563         int ret;
564
565         ret = drmPrimeHandleToFD(bo->device->fd, nvbo->base.handle, DRM_CLOEXEC, prime_fd);
566         if (ret)
567                 return ret;
568
569         nouveau_bo_make_global(nvbo);
570         return 0;
571 }
572
573 int
574 nouveau_bo_wait(struct nouveau_bo *bo, uint32_t access,
575                 struct nouveau_client *client)
576 {
577         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
578         struct drm_nouveau_gem_cpu_prep req;
579         struct nouveau_pushbuf *push;
580         int ret = 0;
581
582         if (!(access & NOUVEAU_BO_RDWR))
583                 return 0;
584
585         push = cli_push_get(client, bo);
586         if (push && push->channel)
587                 nouveau_pushbuf_kick(push, push->channel);
588
589         if (!nvbo->head.next && !(nvbo->access & NOUVEAU_BO_WR) &&
590                                 !(access & NOUVEAU_BO_WR))
591                 return 0;
592
593         req.handle = bo->handle;
594         req.flags = 0;
595         if (access & NOUVEAU_BO_WR)
596                 req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
597         if (access & NOUVEAU_BO_NOBLOCK)
598                 req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
599
600         ret = drmCommandWrite(bo->device->fd, DRM_NOUVEAU_GEM_CPU_PREP,
601                               &req, sizeof(req));
602         if (ret == 0)
603                 nvbo->access = 0;
604         return ret;
605 }
606
607 int
608 nouveau_bo_map(struct nouveau_bo *bo, uint32_t access,
609                struct nouveau_client *client)
610 {
611         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
612         if (bo->map == NULL) {
613                 bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
614                                MAP_SHARED, bo->device->fd, nvbo->map_handle);
615                 if (bo->map == MAP_FAILED) {
616                         bo->map = NULL;
617                         return -errno;
618                 }
619         }
620         return nouveau_bo_wait(bo, access, client);
621 }