OSDN Git Service

drmSL: Fix neighbor lookup
[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 <stdbool.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <fcntl.h>
37
38 #include <xf86drm.h>
39 #include <xf86atomic.h>
40 #include "libdrm.h"
41 #include "libdrm_lists.h"
42 #include "nouveau_drm.h"
43
44 #include "nouveau.h"
45 #include "private.h"
46
47 #ifdef DEBUG
48 uint32_t nouveau_debug = 0;
49
50 static void
51 debug_init(char *args)
52 {
53         if (args) {
54                 int n = strtol(args, NULL, 0);
55                 if (n >= 0)
56                         nouveau_debug = n;
57         }
58 }
59 #endif
60
61 /* this is the old libdrm's version of nouveau_device_wrap(), the symbol
62  * is kept here to prevent AIGLX from crashing if the DDX is linked against
63  * the new libdrm, but the DRI driver against the old
64  */
65 drm_public int
66 nouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd,
67                              drm_context_t ctx)
68 {
69         return -EACCES;
70 }
71
72 drm_public int
73 nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
74 {
75         struct nouveau_device_priv *nvdev = calloc(1, sizeof(*nvdev));
76         struct nouveau_device *dev = &nvdev->base;
77         uint64_t chipset, vram, gart, bousage;
78         drmVersionPtr ver;
79         int ret;
80         char *tmp;
81
82 #ifdef DEBUG
83         debug_init(getenv("NOUVEAU_LIBDRM_DEBUG"));
84 #endif
85
86         if (!nvdev)
87                 return -ENOMEM;
88         ret = pthread_mutex_init(&nvdev->lock, NULL);
89         if (ret) {
90                 free(nvdev);
91                 return ret;
92         }
93
94         nvdev->base.fd = fd;
95
96         ver = drmGetVersion(fd);
97         if (ver) dev->drm_version = (ver->version_major << 24) |
98                                     (ver->version_minor << 8) |
99                                      ver->version_patchlevel;
100         drmFreeVersion(ver);
101
102         if ( dev->drm_version != 0x00000010 &&
103             (dev->drm_version <  0x01000000 ||
104              dev->drm_version >= 0x02000000)) {
105                 nouveau_device_del(&dev);
106                 return -EINVAL;
107         }
108
109         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &chipset);
110         if (ret == 0)
111         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &vram);
112         if (ret == 0)
113         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &gart);
114         if (ret) {
115                 nouveau_device_del(&dev);
116                 return ret;
117         }
118
119         ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &bousage);
120         if (ret == 0)
121                 nvdev->have_bo_usage = (bousage != 0);
122
123         nvdev->close = close;
124
125         tmp = getenv("NOUVEAU_LIBDRM_VRAM_LIMIT_PERCENT");
126         if (tmp)
127                 nvdev->vram_limit_percent = atoi(tmp);
128         else
129                 nvdev->vram_limit_percent = 80;
130         tmp = getenv("NOUVEAU_LIBDRM_GART_LIMIT_PERCENT");
131         if (tmp)
132                 nvdev->gart_limit_percent = atoi(tmp);
133         else
134                 nvdev->gart_limit_percent = 80;
135         DRMINITLISTHEAD(&nvdev->bo_list);
136         nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
137         nvdev->base.lib_version = 0x01000000;
138         nvdev->base.chipset = chipset;
139         nvdev->base.vram_size = vram;
140         nvdev->base.gart_size = gart;
141         nvdev->base.vram_limit =
142                 (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100;
143         nvdev->base.gart_limit =
144                 (nvdev->base.gart_size * nvdev->gart_limit_percent) / 100;
145
146         *pdev = &nvdev->base;
147         return 0;
148 }
149
150 drm_public int
151 nouveau_device_open(const char *busid, struct nouveau_device **pdev)
152 {
153         int ret = -ENODEV, fd = drmOpen("nouveau", busid);
154         if (fd >= 0) {
155                 ret = nouveau_device_wrap(fd, 1, pdev);
156                 if (ret)
157                         drmClose(fd);
158         }
159         return ret;
160 }
161
162 drm_public void
163 nouveau_device_del(struct nouveau_device **pdev)
164 {
165         struct nouveau_device_priv *nvdev = nouveau_device(*pdev);
166         if (nvdev) {
167                 if (nvdev->close)
168                         drmClose(nvdev->base.fd);
169                 free(nvdev->client);
170                 pthread_mutex_destroy(&nvdev->lock);
171                 free(nvdev);
172                 *pdev = NULL;
173         }
174 }
175
176 drm_public int
177 nouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value)
178 {
179         struct drm_nouveau_getparam r = { param, 0 };
180         int fd = dev->fd, ret =
181                 drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r));
182         *value = r.value;
183         return ret;
184 }
185
186 drm_public int
187 nouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value)
188 {
189         struct drm_nouveau_setparam r = { param, value };
190         return drmCommandWrite(dev->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r));
191 }
192
193 drm_public int
194 nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient)
195 {
196         struct nouveau_device_priv *nvdev = nouveau_device(dev);
197         struct nouveau_client_priv *pcli;
198         int id = 0, i, ret = -ENOMEM;
199         uint32_t *clients;
200
201         pthread_mutex_lock(&nvdev->lock);
202
203         for (i = 0; i < nvdev->nr_client; i++) {
204                 id = ffs(nvdev->client[i]) - 1;
205                 if (id >= 0)
206                         goto out;
207         }
208
209         clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1));
210         if (!clients)
211                 goto unlock;
212         nvdev->client = clients;
213         nvdev->client[i] = 0;
214         nvdev->nr_client++;
215
216 out:
217         pcli = calloc(1, sizeof(*pcli));
218         if (pcli) {
219                 nvdev->client[i] |= (1 << id);
220                 pcli->base.device = dev;
221                 pcli->base.id = (i * 32) + id;
222                 ret = 0;
223         }
224
225         *pclient = &pcli->base;
226
227 unlock:
228         pthread_mutex_unlock(&nvdev->lock);
229         return ret;
230 }
231
232 drm_public void
233 nouveau_client_del(struct nouveau_client **pclient)
234 {
235         struct nouveau_client_priv *pcli = nouveau_client(*pclient);
236         struct nouveau_device_priv *nvdev;
237         if (pcli) {
238                 int id = pcli->base.id;
239                 nvdev = nouveau_device(pcli->base.device);
240                 pthread_mutex_lock(&nvdev->lock);
241                 nvdev->client[id / 32] &= ~(1 << (id % 32));
242                 pthread_mutex_unlock(&nvdev->lock);
243                 free(pcli->kref);
244                 free(pcli);
245         }
246 }
247
248 drm_public int
249 nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
250                    uint32_t oclass, void *data, uint32_t length,
251                    struct nouveau_object **pobj)
252 {
253         struct nouveau_device *dev;
254         struct nouveau_object *obj;
255         int ret = -EINVAL;
256
257         if (length == 0)
258                 length = sizeof(struct nouveau_object *);
259         obj = malloc(sizeof(*obj) + length);
260         obj->parent = parent;
261         obj->handle = handle;
262         obj->oclass = oclass;
263         obj->length = length;
264         obj->data = obj + 1;
265         if (data)
266                 memcpy(obj->data, data, length);
267         *(struct nouveau_object **)obj->data = obj;
268
269         dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
270         switch (parent->oclass) {
271         case NOUVEAU_DEVICE_CLASS:
272                 switch (obj->oclass) {
273                 case NOUVEAU_FIFO_CHANNEL_CLASS:
274                 {
275                         if (dev->chipset < 0xc0)
276                                 ret = abi16_chan_nv04(obj);
277                         else
278                         if (dev->chipset < 0xe0)
279                                 ret = abi16_chan_nvc0(obj);
280                         else
281                                 ret = abi16_chan_nve0(obj);
282                 }
283                         break;
284                 default:
285                         break;
286                 }
287                 break;
288         case NOUVEAU_FIFO_CHANNEL_CLASS:
289                 switch (obj->oclass) {
290                 case NOUVEAU_NOTIFIER_CLASS:
291                         ret = abi16_ntfy(obj);
292                         break;
293                 default:
294                         ret = abi16_engobj(obj);
295                         break;
296                 }
297         default:
298                 break;
299         }
300
301         if (ret) {
302                 free(obj);
303                 return ret;
304         }
305
306         *pobj = obj;
307         return 0;
308 }
309
310 drm_public void
311 nouveau_object_del(struct nouveau_object **pobj)
312 {
313         struct nouveau_object *obj = *pobj;
314         struct nouveau_device *dev;
315         if (obj) {
316                 dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
317                 if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) {
318                         struct drm_nouveau_channel_free req;
319                         req.channel = obj->handle;
320                         drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE,
321                                         &req, sizeof(req));
322                 } else {
323                         struct drm_nouveau_gpuobj_free req;
324                         req.channel = obj->parent->handle;
325                         req.handle  = obj->handle;
326                         drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
327                                         &req, sizeof(req));
328                 }
329         }
330         free(obj);
331         *pobj = NULL;
332 }
333
334 drm_public void *
335 nouveau_object_find(struct nouveau_object *obj, uint32_t pclass)
336 {
337         while (obj && obj->oclass != pclass) {
338                 obj = obj->parent;
339                 if (pclass == NOUVEAU_PARENT_CLASS)
340                         break;
341         }
342         return obj;
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 = { 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 drm_public 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 drm_public 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 drm_public 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 drm_gem_open req = { .name = name };
483         int ret;
484
485         pthread_mutex_lock(&nvdev->lock);
486         ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
487         if (ret == 0) {
488                 ret = nouveau_bo_wrap_locked(dev, req.handle, pbo, name);
489         }
490
491         pthread_mutex_unlock(&nvdev->lock);
492         return ret;
493 }
494
495 drm_public int
496 nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name)
497 {
498         struct drm_gem_flink req = { .handle = bo->handle };
499         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
500
501         *name = nvbo->name;
502         if (!*name) {
503                 int ret = drmIoctl(bo->device->fd, DRM_IOCTL_GEM_FLINK, &req);
504
505                 if (ret) {
506                         *name = 0;
507                         return ret;
508                 }
509                 nvbo->name = *name = req.name;
510
511                 nouveau_bo_make_global(nvbo);
512         }
513         return 0;
514 }
515
516 drm_public void
517 nouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref)
518 {
519         struct nouveau_bo *ref = *pref;
520         if (bo) {
521                 atomic_inc(&nouveau_bo(bo)->refcnt);
522         }
523         if (ref) {
524                 if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt))
525                         nouveau_bo_del(ref);
526         }
527         *pref = bo;
528 }
529
530 drm_public int
531 nouveau_bo_prime_handle_ref(struct nouveau_device *dev, int prime_fd,
532                             struct nouveau_bo **bo)
533 {
534         struct nouveau_device_priv *nvdev = nouveau_device(dev);
535         int ret;
536         unsigned int handle;
537
538         nouveau_bo_ref(NULL, bo);
539
540         pthread_mutex_lock(&nvdev->lock);
541         ret = drmPrimeFDToHandle(dev->fd, prime_fd, &handle);
542         if (ret == 0) {
543                 ret = nouveau_bo_wrap_locked(dev, handle, bo, 0);
544         }
545         pthread_mutex_unlock(&nvdev->lock);
546         return ret;
547 }
548
549 drm_public int
550 nouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd)
551 {
552         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
553         int ret;
554
555         ret = drmPrimeHandleToFD(bo->device->fd, nvbo->base.handle, DRM_CLOEXEC, prime_fd);
556         if (ret)
557                 return ret;
558
559         nouveau_bo_make_global(nvbo);
560         return 0;
561 }
562
563 drm_public int
564 nouveau_bo_wait(struct nouveau_bo *bo, uint32_t access,
565                 struct nouveau_client *client)
566 {
567         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
568         struct drm_nouveau_gem_cpu_prep req;
569         struct nouveau_pushbuf *push;
570         int ret = 0;
571
572         if (!(access & NOUVEAU_BO_RDWR))
573                 return 0;
574
575         push = cli_push_get(client, bo);
576         if (push && push->channel)
577                 nouveau_pushbuf_kick(push, push->channel);
578
579         if (!nvbo->head.next && !(nvbo->access & NOUVEAU_BO_WR) &&
580                                 !(access & NOUVEAU_BO_WR))
581                 return 0;
582
583         req.handle = bo->handle;
584         req.flags = 0;
585         if (access & NOUVEAU_BO_WR)
586                 req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
587         if (access & NOUVEAU_BO_NOBLOCK)
588                 req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
589
590         ret = drmCommandWrite(bo->device->fd, DRM_NOUVEAU_GEM_CPU_PREP,
591                               &req, sizeof(req));
592         if (ret == 0)
593                 nvbo->access = 0;
594         return ret;
595 }
596
597 drm_public int
598 nouveau_bo_map(struct nouveau_bo *bo, uint32_t access,
599                struct nouveau_client *client)
600 {
601         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
602         if (bo->map == NULL) {
603                 bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
604                                MAP_SHARED, bo->device->fd, nvbo->map_handle);
605                 if (bo->map == MAP_FAILED) {
606                         bo->map = NULL;
607                         return -errno;
608                 }
609         }
610         return nouveau_bo_wait(bo, access, client);
611 }