OSDN Git Service

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