OSDN Git Service

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