nouveau.c revision 857b0bc6
1e88f27b3Smrg/* 2e88f27b3Smrg * Copyright 2012 Red Hat Inc. 3e88f27b3Smrg * 4e88f27b3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5e88f27b3Smrg * copy of this software and associated documentation files (the "Software"), 6e88f27b3Smrg * to deal in the Software without restriction, including without limitation 7e88f27b3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8e88f27b3Smrg * and/or sell copies of the Software, and to permit persons to whom the 9e88f27b3Smrg * Software is furnished to do so, subject to the following conditions: 10e88f27b3Smrg * 11e88f27b3Smrg * The above copyright notice and this permission notice shall be included in 12e88f27b3Smrg * all copies or substantial portions of the Software. 13e88f27b3Smrg * 14e88f27b3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15e88f27b3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16e88f27b3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17e88f27b3Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18e88f27b3Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19e88f27b3Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20e88f27b3Smrg * OTHER DEALINGS IN THE SOFTWARE. 21e88f27b3Smrg * 22e88f27b3Smrg * Authors: Ben Skeggs 23e88f27b3Smrg */ 24e88f27b3Smrg 25e88f27b3Smrg#ifdef HAVE_CONFIG_H 26e88f27b3Smrg#include <config.h> 27e88f27b3Smrg#endif 28e88f27b3Smrg 29e88f27b3Smrg#include <stdio.h> 30e88f27b3Smrg#include <stdlib.h> 31e88f27b3Smrg#include <stdint.h> 32e88f27b3Smrg#include <string.h> 33e88f27b3Smrg#include <stdbool.h> 34e88f27b3Smrg#include <assert.h> 35e88f27b3Smrg#include <errno.h> 36e88f27b3Smrg#include <sys/mman.h> 37e88f27b3Smrg#include <fcntl.h> 38e88f27b3Smrg 39e88f27b3Smrg#include <xf86drm.h> 40e88f27b3Smrg#include <xf86atomic.h> 41e88f27b3Smrg#include "libdrm_lists.h" 42e88f27b3Smrg#include "nouveau_drm.h" 43e88f27b3Smrg 44e88f27b3Smrg#include "nouveau.h" 45e88f27b3Smrg#include "private.h" 46e88f27b3Smrg 47e88f27b3Smrg#ifdef DEBUG 48e88f27b3Smrguint32_t nouveau_debug = 0; 49e88f27b3Smrg 50e88f27b3Smrgstatic void 51e88f27b3Smrgdebug_init(char *args) 52e88f27b3Smrg{ 53e88f27b3Smrg if (args) { 54e88f27b3Smrg int n = strtol(args, NULL, 0); 55e88f27b3Smrg if (n >= 0) 56e88f27b3Smrg nouveau_debug = n; 57e88f27b3Smrg } 58e88f27b3Smrg} 59e88f27b3Smrg#endif 60e88f27b3Smrg 61e88f27b3Smrg/* this is the old libdrm's version of nouveau_device_wrap(), the symbol 62e88f27b3Smrg * is kept here to prevent AIGLX from crashing if the DDX is linked against 63e88f27b3Smrg * the new libdrm, but the DRI driver against the old 64e88f27b3Smrg */ 65e88f27b3Smrgint 66e88f27b3Smrgnouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd, 67e88f27b3Smrg drm_context_t ctx) 68e88f27b3Smrg{ 69e88f27b3Smrg return -EACCES; 70e88f27b3Smrg} 71e88f27b3Smrg 72e88f27b3Smrgint 73e88f27b3Smrgnouveau_device_wrap(int fd, int close, struct nouveau_device **pdev) 74e88f27b3Smrg{ 75e88f27b3Smrg struct nouveau_device_priv *nvdev = calloc(1, sizeof(*nvdev)); 76e88f27b3Smrg struct nouveau_device *dev = &nvdev->base; 77e88f27b3Smrg uint64_t chipset, vram, gart, bousage; 78e88f27b3Smrg drmVersionPtr ver; 79e88f27b3Smrg int ret; 80e88f27b3Smrg char *tmp; 81e88f27b3Smrg 82e88f27b3Smrg#ifdef DEBUG 83e88f27b3Smrg debug_init(getenv("NOUVEAU_LIBDRM_DEBUG")); 84e88f27b3Smrg#endif 85e88f27b3Smrg 86e88f27b3Smrg if (!nvdev) 87e88f27b3Smrg return -ENOMEM; 88857b0bc6Smrg ret = pthread_mutex_init(&nvdev->lock, NULL); 89857b0bc6Smrg if (ret) { 90857b0bc6Smrg free(nvdev); 91857b0bc6Smrg return ret; 92857b0bc6Smrg } 93857b0bc6Smrg 94e88f27b3Smrg nvdev->base.fd = fd; 95e88f27b3Smrg 96e88f27b3Smrg ver = drmGetVersion(fd); 97e88f27b3Smrg if (ver) dev->drm_version = (ver->version_major << 24) | 98e88f27b3Smrg (ver->version_minor << 8) | 99e88f27b3Smrg ver->version_patchlevel; 100e88f27b3Smrg drmFreeVersion(ver); 101e88f27b3Smrg 102e88f27b3Smrg if ( dev->drm_version != 0x00000010 && 103e88f27b3Smrg (dev->drm_version < 0x01000000 || 104e88f27b3Smrg dev->drm_version >= 0x02000000)) { 105e88f27b3Smrg nouveau_device_del(&dev); 106e88f27b3Smrg return -EINVAL; 107e88f27b3Smrg } 108e88f27b3Smrg 109e88f27b3Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &chipset); 110e88f27b3Smrg if (ret == 0) 111e88f27b3Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &vram); 112e88f27b3Smrg if (ret == 0) 113e88f27b3Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &gart); 114e88f27b3Smrg if (ret) { 115e88f27b3Smrg nouveau_device_del(&dev); 116e88f27b3Smrg return ret; 117e88f27b3Smrg } 118e88f27b3Smrg 119e88f27b3Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &bousage); 120e88f27b3Smrg if (ret == 0) 121e88f27b3Smrg nvdev->have_bo_usage = (bousage != 0); 122e88f27b3Smrg 123e88f27b3Smrg nvdev->close = close; 124e88f27b3Smrg 125e88f27b3Smrg tmp = getenv("NOUVEAU_LIBDRM_VRAM_LIMIT_PERCENT"); 126e88f27b3Smrg if (tmp) 127e88f27b3Smrg nvdev->vram_limit_percent = atoi(tmp); 128e88f27b3Smrg else 129e88f27b3Smrg nvdev->vram_limit_percent = 80; 130e88f27b3Smrg tmp = getenv("NOUVEAU_LIBDRM_GART_LIMIT_PERCENT"); 131e88f27b3Smrg if (tmp) 132e88f27b3Smrg nvdev->gart_limit_percent = atoi(tmp); 133e88f27b3Smrg else 134e88f27b3Smrg nvdev->gart_limit_percent = 80; 135e88f27b3Smrg DRMINITLISTHEAD(&nvdev->bo_list); 136e88f27b3Smrg nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS; 137e88f27b3Smrg nvdev->base.lib_version = 0x01000000; 138e88f27b3Smrg nvdev->base.chipset = chipset; 139e88f27b3Smrg nvdev->base.vram_size = vram; 140e88f27b3Smrg nvdev->base.gart_size = gart; 141e88f27b3Smrg nvdev->base.vram_limit = 142e88f27b3Smrg (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100; 143e88f27b3Smrg nvdev->base.gart_limit = 144e88f27b3Smrg (nvdev->base.gart_size * nvdev->gart_limit_percent) / 100; 145e88f27b3Smrg 146e88f27b3Smrg *pdev = &nvdev->base; 147e88f27b3Smrg return 0; 148e88f27b3Smrg} 149e88f27b3Smrg 150e88f27b3Smrgint 151e88f27b3Smrgnouveau_device_open(const char *busid, struct nouveau_device **pdev) 152e88f27b3Smrg{ 153e88f27b3Smrg int ret = -ENODEV, fd = drmOpen("nouveau", busid); 154e88f27b3Smrg if (fd >= 0) { 155e88f27b3Smrg ret = nouveau_device_wrap(fd, 1, pdev); 156e88f27b3Smrg if (ret) 157e88f27b3Smrg drmClose(fd); 158e88f27b3Smrg } 159e88f27b3Smrg return ret; 160e88f27b3Smrg} 161e88f27b3Smrg 162e88f27b3Smrgvoid 163e88f27b3Smrgnouveau_device_del(struct nouveau_device **pdev) 164e88f27b3Smrg{ 165e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(*pdev); 166e88f27b3Smrg if (nvdev) { 167e88f27b3Smrg if (nvdev->close) 168e88f27b3Smrg drmClose(nvdev->base.fd); 169e88f27b3Smrg free(nvdev->client); 170857b0bc6Smrg pthread_mutex_destroy(&nvdev->lock); 171e88f27b3Smrg free(nvdev); 172e88f27b3Smrg *pdev = NULL; 173e88f27b3Smrg } 174e88f27b3Smrg} 175e88f27b3Smrg 176e88f27b3Smrgint 177e88f27b3Smrgnouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value) 178e88f27b3Smrg{ 179e88f27b3Smrg struct drm_nouveau_getparam r = { param, 0 }; 180e88f27b3Smrg int fd = dev->fd, ret = 181e88f27b3Smrg drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r)); 182e88f27b3Smrg *value = r.value; 183e88f27b3Smrg return ret; 184e88f27b3Smrg} 185e88f27b3Smrg 186e88f27b3Smrgint 187e88f27b3Smrgnouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value) 188e88f27b3Smrg{ 189e88f27b3Smrg struct drm_nouveau_setparam r = { param, value }; 190e88f27b3Smrg return drmCommandWrite(dev->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r)); 191e88f27b3Smrg} 192e88f27b3Smrg 193e88f27b3Smrgint 194e88f27b3Smrgnouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient) 195e88f27b3Smrg{ 196e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 197e88f27b3Smrg struct nouveau_client_priv *pcli; 198e88f27b3Smrg int id = 0, i, ret = -ENOMEM; 199e88f27b3Smrg uint32_t *clients; 200e88f27b3Smrg 201857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 202857b0bc6Smrg 203e88f27b3Smrg for (i = 0; i < nvdev->nr_client; i++) { 204e88f27b3Smrg id = ffs(nvdev->client[i]) - 1; 205e88f27b3Smrg if (id >= 0) 206e88f27b3Smrg goto out; 207e88f27b3Smrg } 208e88f27b3Smrg 209e88f27b3Smrg clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1)); 210e88f27b3Smrg if (!clients) 211857b0bc6Smrg goto unlock; 212e88f27b3Smrg nvdev->client = clients; 213e88f27b3Smrg nvdev->client[i] = 0; 214e88f27b3Smrg nvdev->nr_client++; 215e88f27b3Smrg 216e88f27b3Smrgout: 217e88f27b3Smrg pcli = calloc(1, sizeof(*pcli)); 218e88f27b3Smrg if (pcli) { 219e88f27b3Smrg nvdev->client[i] |= (1 << id); 220e88f27b3Smrg pcli->base.device = dev; 221e88f27b3Smrg pcli->base.id = (i * 32) + id; 222e88f27b3Smrg ret = 0; 223e88f27b3Smrg } 224e88f27b3Smrg 225e88f27b3Smrg *pclient = &pcli->base; 226857b0bc6Smrg 227857b0bc6Smrgunlock: 228857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 229e88f27b3Smrg return ret; 230e88f27b3Smrg} 231e88f27b3Smrg 232e88f27b3Smrgvoid 233e88f27b3Smrgnouveau_client_del(struct nouveau_client **pclient) 234e88f27b3Smrg{ 235e88f27b3Smrg struct nouveau_client_priv *pcli = nouveau_client(*pclient); 236e88f27b3Smrg struct nouveau_device_priv *nvdev; 237e88f27b3Smrg if (pcli) { 238e88f27b3Smrg int id = pcli->base.id; 239e88f27b3Smrg nvdev = nouveau_device(pcli->base.device); 240857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 241e88f27b3Smrg nvdev->client[id / 32] &= ~(1 << (id % 32)); 242857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 243e88f27b3Smrg free(pcli->kref); 244e88f27b3Smrg free(pcli); 245e88f27b3Smrg } 246e88f27b3Smrg} 247e88f27b3Smrg 248e88f27b3Smrgint 249e88f27b3Smrgnouveau_object_new(struct nouveau_object *parent, uint64_t handle, 250e88f27b3Smrg uint32_t oclass, void *data, uint32_t length, 251e88f27b3Smrg struct nouveau_object **pobj) 252e88f27b3Smrg{ 253e88f27b3Smrg struct nouveau_device *dev; 254e88f27b3Smrg struct nouveau_object *obj; 255e88f27b3Smrg int ret = -EINVAL; 256e88f27b3Smrg 257e88f27b3Smrg if (length == 0) 258e88f27b3Smrg length = sizeof(struct nouveau_object *); 259e88f27b3Smrg obj = malloc(sizeof(*obj) + length); 260e88f27b3Smrg obj->parent = parent; 261e88f27b3Smrg obj->handle = handle; 262e88f27b3Smrg obj->oclass = oclass; 263e88f27b3Smrg obj->length = length; 264e88f27b3Smrg obj->data = obj + 1; 265e88f27b3Smrg if (data) 266e88f27b3Smrg memcpy(obj->data, data, length); 267e88f27b3Smrg *(struct nouveau_object **)obj->data = obj; 268e88f27b3Smrg 269e88f27b3Smrg dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); 270e88f27b3Smrg switch (parent->oclass) { 271e88f27b3Smrg case NOUVEAU_DEVICE_CLASS: 272e88f27b3Smrg switch (obj->oclass) { 273e88f27b3Smrg case NOUVEAU_FIFO_CHANNEL_CLASS: 274e88f27b3Smrg { 275e88f27b3Smrg if (dev->chipset < 0xc0) 276e88f27b3Smrg ret = abi16_chan_nv04(obj); 277e88f27b3Smrg else 278e88f27b3Smrg if (dev->chipset < 0xe0) 279e88f27b3Smrg ret = abi16_chan_nvc0(obj); 280e88f27b3Smrg else 281e88f27b3Smrg ret = abi16_chan_nve0(obj); 282e88f27b3Smrg } 283e88f27b3Smrg break; 284e88f27b3Smrg default: 285e88f27b3Smrg break; 286e88f27b3Smrg } 287e88f27b3Smrg break; 288e88f27b3Smrg case NOUVEAU_FIFO_CHANNEL_CLASS: 289e88f27b3Smrg switch (obj->oclass) { 290e88f27b3Smrg case NOUVEAU_NOTIFIER_CLASS: 291e88f27b3Smrg ret = abi16_ntfy(obj); 292e88f27b3Smrg break; 293e88f27b3Smrg default: 294e88f27b3Smrg ret = abi16_engobj(obj); 295e88f27b3Smrg break; 296e88f27b3Smrg } 297e88f27b3Smrg default: 298e88f27b3Smrg break; 299e88f27b3Smrg } 300e88f27b3Smrg 301e88f27b3Smrg if (ret) { 302e88f27b3Smrg free(obj); 303e88f27b3Smrg return ret; 304e88f27b3Smrg } 305e88f27b3Smrg 306e88f27b3Smrg *pobj = obj; 307e88f27b3Smrg return 0; 308e88f27b3Smrg} 309e88f27b3Smrg 310e88f27b3Smrgvoid 311e88f27b3Smrgnouveau_object_del(struct nouveau_object **pobj) 312e88f27b3Smrg{ 313e88f27b3Smrg struct nouveau_object *obj = *pobj; 314e88f27b3Smrg struct nouveau_device *dev; 315e88f27b3Smrg if (obj) { 316e88f27b3Smrg dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); 317e88f27b3Smrg if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) { 318e88f27b3Smrg struct drm_nouveau_channel_free req; 319e88f27b3Smrg req.channel = obj->handle; 320e88f27b3Smrg drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE, 321e88f27b3Smrg &req, sizeof(req)); 322e88f27b3Smrg } else { 323e88f27b3Smrg struct drm_nouveau_gpuobj_free req; 324e88f27b3Smrg req.channel = obj->parent->handle; 325e88f27b3Smrg req.handle = obj->handle; 326e88f27b3Smrg drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE, 327e88f27b3Smrg &req, sizeof(req)); 328e88f27b3Smrg } 329e88f27b3Smrg } 330e88f27b3Smrg free(obj); 331e88f27b3Smrg *pobj = NULL; 332e88f27b3Smrg} 333e88f27b3Smrg 334e88f27b3Smrgvoid * 335e88f27b3Smrgnouveau_object_find(struct nouveau_object *obj, uint32_t pclass) 336e88f27b3Smrg{ 337e88f27b3Smrg while (obj && obj->oclass != pclass) { 338e88f27b3Smrg obj = obj->parent; 339e88f27b3Smrg if (pclass == NOUVEAU_PARENT_CLASS) 340e88f27b3Smrg break; 341e88f27b3Smrg } 342e88f27b3Smrg return obj; 343e88f27b3Smrg} 344e88f27b3Smrg 345e88f27b3Smrgstatic void 346e88f27b3Smrgnouveau_bo_del(struct nouveau_bo *bo) 347e88f27b3Smrg{ 348857b0bc6Smrg struct nouveau_device_priv *nvdev = nouveau_device(bo->device); 349e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 350e88f27b3Smrg struct drm_gem_close req = { bo->handle }; 351857b0bc6Smrg 352857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 353857b0bc6Smrg if (nvbo->name) { 354857b0bc6Smrg if (atomic_read(&nvbo->refcnt)) { 355857b0bc6Smrg /* 356857b0bc6Smrg * bo has been revived by a race with 357857b0bc6Smrg * nouveau_bo_prime_handle_ref, or nouveau_bo_name_ref. 358857b0bc6Smrg * 359857b0bc6Smrg * In theory there's still a race possible with 360857b0bc6Smrg * nouveau_bo_wrap, but when using this function 361857b0bc6Smrg * the lifetime of the handle is probably already 362857b0bc6Smrg * handled in another way. If there are races 363857b0bc6Smrg * you're probably using nouveau_bo_wrap wrong. 364857b0bc6Smrg */ 365857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 366857b0bc6Smrg return; 367857b0bc6Smrg } 368857b0bc6Smrg DRMLISTDEL(&nvbo->head); 369857b0bc6Smrg /* 370857b0bc6Smrg * This bo has to be closed with the lock held because gem 371857b0bc6Smrg * handles are not refcounted. If a shared bo is closed and 372857b0bc6Smrg * re-opened in another thread a race against 373857b0bc6Smrg * DRM_IOCTL_GEM_OPEN or drmPrimeFDToHandle might cause the 374857b0bc6Smrg * bo to be closed accidentally while re-importing. 375857b0bc6Smrg */ 376857b0bc6Smrg drmIoctl(bo->device->fd, DRM_IOCTL_GEM_CLOSE, &req); 377857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 378857b0bc6Smrg } else { 379857b0bc6Smrg DRMLISTDEL(&nvbo->head); 380857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 381857b0bc6Smrg drmIoctl(bo->device->fd, DRM_IOCTL_GEM_CLOSE, &req); 382857b0bc6Smrg } 383e88f27b3Smrg if (bo->map) 384e88f27b3Smrg munmap(bo->map, bo->size); 385e88f27b3Smrg free(nvbo); 386e88f27b3Smrg} 387e88f27b3Smrg 388e88f27b3Smrgint 389e88f27b3Smrgnouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align, 390e88f27b3Smrg uint64_t size, union nouveau_bo_config *config, 391e88f27b3Smrg struct nouveau_bo **pbo) 392e88f27b3Smrg{ 393e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 394e88f27b3Smrg struct nouveau_bo_priv *nvbo = calloc(1, sizeof(*nvbo)); 395e88f27b3Smrg struct nouveau_bo *bo = &nvbo->base; 396e88f27b3Smrg int ret; 397e88f27b3Smrg 398e88f27b3Smrg if (!nvbo) 399e88f27b3Smrg return -ENOMEM; 400e88f27b3Smrg atomic_set(&nvbo->refcnt, 1); 401e88f27b3Smrg bo->device = dev; 402e88f27b3Smrg bo->flags = flags; 403e88f27b3Smrg bo->size = size; 404e88f27b3Smrg 405e88f27b3Smrg ret = abi16_bo_init(bo, align, config); 406e88f27b3Smrg if (ret) { 407e88f27b3Smrg free(nvbo); 408e88f27b3Smrg return ret; 409e88f27b3Smrg } 410e88f27b3Smrg 411857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 412e88f27b3Smrg DRMLISTADD(&nvbo->head, &nvdev->bo_list); 413857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 414e88f27b3Smrg 415e88f27b3Smrg *pbo = bo; 416e88f27b3Smrg return 0; 417e88f27b3Smrg} 418e88f27b3Smrg 419857b0bc6Smrgstatic int 420857b0bc6Smrgnouveau_bo_wrap_locked(struct nouveau_device *dev, uint32_t handle, 421857b0bc6Smrg struct nouveau_bo **pbo) 422e88f27b3Smrg{ 423e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 424e88f27b3Smrg struct drm_nouveau_gem_info req = { .handle = handle }; 425e88f27b3Smrg struct nouveau_bo_priv *nvbo; 426e88f27b3Smrg int ret; 427e88f27b3Smrg 428e88f27b3Smrg DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { 429e88f27b3Smrg if (nvbo->base.handle == handle) { 430e88f27b3Smrg *pbo = NULL; 431e88f27b3Smrg nouveau_bo_ref(&nvbo->base, pbo); 432e88f27b3Smrg return 0; 433e88f27b3Smrg } 434e88f27b3Smrg } 435e88f27b3Smrg 436e88f27b3Smrg ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_INFO, 437e88f27b3Smrg &req, sizeof(req)); 438e88f27b3Smrg if (ret) 439e88f27b3Smrg return ret; 440e88f27b3Smrg 441e88f27b3Smrg nvbo = calloc(1, sizeof(*nvbo)); 442e88f27b3Smrg if (nvbo) { 443e88f27b3Smrg atomic_set(&nvbo->refcnt, 1); 444e88f27b3Smrg nvbo->base.device = dev; 445e88f27b3Smrg abi16_bo_info(&nvbo->base, &req); 446e88f27b3Smrg DRMLISTADD(&nvbo->head, &nvdev->bo_list); 447e88f27b3Smrg *pbo = &nvbo->base; 448e88f27b3Smrg return 0; 449e88f27b3Smrg } 450e88f27b3Smrg 451e88f27b3Smrg return -ENOMEM; 452e88f27b3Smrg} 453e88f27b3Smrg 454857b0bc6Smrgint 455857b0bc6Smrgnouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle, 456857b0bc6Smrg struct nouveau_bo **pbo) 457857b0bc6Smrg{ 458857b0bc6Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 459857b0bc6Smrg int ret; 460857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 461857b0bc6Smrg ret = nouveau_bo_wrap_locked(dev, handle, pbo); 462857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 463857b0bc6Smrg return ret; 464857b0bc6Smrg} 465857b0bc6Smrg 466e88f27b3Smrgint 467e88f27b3Smrgnouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name, 468e88f27b3Smrg struct nouveau_bo **pbo) 469e88f27b3Smrg{ 470e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 471e88f27b3Smrg struct nouveau_bo_priv *nvbo; 472e88f27b3Smrg struct drm_gem_open req = { .name = name }; 473e88f27b3Smrg int ret; 474e88f27b3Smrg 475857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 476e88f27b3Smrg DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { 477e88f27b3Smrg if (nvbo->name == name) { 478e88f27b3Smrg *pbo = NULL; 479e88f27b3Smrg nouveau_bo_ref(&nvbo->base, pbo); 480857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 481e88f27b3Smrg return 0; 482e88f27b3Smrg } 483e88f27b3Smrg } 484e88f27b3Smrg 485e88f27b3Smrg ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req); 486e88f27b3Smrg if (ret == 0) { 487857b0bc6Smrg ret = nouveau_bo_wrap_locked(dev, req.handle, pbo); 488e88f27b3Smrg nouveau_bo((*pbo))->name = name; 489857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 490e88f27b3Smrg } 491e88f27b3Smrg 492e88f27b3Smrg return ret; 493e88f27b3Smrg} 494e88f27b3Smrg 495e88f27b3Smrgint 496e88f27b3Smrgnouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name) 497e88f27b3Smrg{ 498e88f27b3Smrg struct drm_gem_flink req = { .handle = bo->handle }; 499e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 500857b0bc6Smrg 501857b0bc6Smrg *name = nvbo->name; 502857b0bc6Smrg if (!*name || *name == ~0U) { 503e88f27b3Smrg int ret = drmIoctl(bo->device->fd, DRM_IOCTL_GEM_FLINK, &req); 504857b0bc6Smrg if (ret) { 505857b0bc6Smrg *name = 0; 506e88f27b3Smrg return ret; 507857b0bc6Smrg } 508857b0bc6Smrg nvbo->name = *name = req.name; 509e88f27b3Smrg } 510e88f27b3Smrg return 0; 511e88f27b3Smrg} 512e88f27b3Smrg 513e88f27b3Smrgvoid 514e88f27b3Smrgnouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref) 515e88f27b3Smrg{ 516e88f27b3Smrg struct nouveau_bo *ref = *pref; 517e88f27b3Smrg if (bo) { 518e88f27b3Smrg atomic_inc(&nouveau_bo(bo)->refcnt); 519e88f27b3Smrg } 520e88f27b3Smrg if (ref) { 521e88f27b3Smrg if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt)) 522e88f27b3Smrg nouveau_bo_del(ref); 523e88f27b3Smrg } 524e88f27b3Smrg *pref = bo; 525e88f27b3Smrg} 526e88f27b3Smrg 527e88f27b3Smrgint 528e88f27b3Smrgnouveau_bo_prime_handle_ref(struct nouveau_device *dev, int prime_fd, 529e88f27b3Smrg struct nouveau_bo **bo) 530e88f27b3Smrg{ 531857b0bc6Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 532e88f27b3Smrg int ret; 533e88f27b3Smrg unsigned int handle; 534e88f27b3Smrg 535857b0bc6Smrg nouveau_bo_ref(NULL, bo); 536e88f27b3Smrg 537857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 538857b0bc6Smrg ret = drmPrimeFDToHandle(dev->fd, prime_fd, &handle); 539857b0bc6Smrg if (ret == 0) { 540857b0bc6Smrg ret = nouveau_bo_wrap_locked(dev, handle, bo); 541857b0bc6Smrg if (!ret) { 542857b0bc6Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(*bo); 543857b0bc6Smrg if (!nvbo->name) { 544857b0bc6Smrg /* 545857b0bc6Smrg * XXX: Force locked DRM_IOCTL_GEM_CLOSE 546857b0bc6Smrg * to rule out race conditions 547857b0bc6Smrg */ 548857b0bc6Smrg nvbo->name = ~0; 549857b0bc6Smrg } 550857b0bc6Smrg } 551e88f27b3Smrg } 552857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 553857b0bc6Smrg return ret; 554e88f27b3Smrg} 555e88f27b3Smrg 556e88f27b3Smrgint 557e88f27b3Smrgnouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd) 558e88f27b3Smrg{ 559e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 560e88f27b3Smrg int ret; 561e88f27b3Smrg 562e88f27b3Smrg ret = drmPrimeHandleToFD(bo->device->fd, nvbo->base.handle, DRM_CLOEXEC, prime_fd); 563e88f27b3Smrg if (ret) 564e88f27b3Smrg return ret; 565857b0bc6Smrg if (!nvbo->name) 566857b0bc6Smrg nvbo->name = ~0; 567e88f27b3Smrg return 0; 568e88f27b3Smrg} 569e88f27b3Smrg 570e88f27b3Smrgint 571e88f27b3Smrgnouveau_bo_wait(struct nouveau_bo *bo, uint32_t access, 572e88f27b3Smrg struct nouveau_client *client) 573e88f27b3Smrg{ 574e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 575e88f27b3Smrg struct drm_nouveau_gem_cpu_prep req; 576e88f27b3Smrg struct nouveau_pushbuf *push; 577e88f27b3Smrg int ret = 0; 578e88f27b3Smrg 579e88f27b3Smrg if (!(access & NOUVEAU_BO_RDWR)) 580e88f27b3Smrg return 0; 581e88f27b3Smrg 582e88f27b3Smrg push = cli_push_get(client, bo); 583e88f27b3Smrg if (push && push->channel) 584e88f27b3Smrg nouveau_pushbuf_kick(push, push->channel); 585e88f27b3Smrg 586e88f27b3Smrg if (!nvbo->name && !(nvbo->access & NOUVEAU_BO_WR) && 587e88f27b3Smrg !( access & NOUVEAU_BO_WR)) 588e88f27b3Smrg return 0; 589e88f27b3Smrg 590e88f27b3Smrg req.handle = bo->handle; 591e88f27b3Smrg req.flags = 0; 592e88f27b3Smrg if (access & NOUVEAU_BO_WR) 593e88f27b3Smrg req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE; 594e88f27b3Smrg if (access & NOUVEAU_BO_NOBLOCK) 595e88f27b3Smrg req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT; 596e88f27b3Smrg 597e88f27b3Smrg ret = drmCommandWrite(bo->device->fd, DRM_NOUVEAU_GEM_CPU_PREP, 598e88f27b3Smrg &req, sizeof(req)); 599e88f27b3Smrg if (ret == 0) 600e88f27b3Smrg nvbo->access = 0; 601e88f27b3Smrg return ret; 602e88f27b3Smrg} 603e88f27b3Smrg 604e88f27b3Smrgint 605e88f27b3Smrgnouveau_bo_map(struct nouveau_bo *bo, uint32_t access, 606e88f27b3Smrg struct nouveau_client *client) 607e88f27b3Smrg{ 608e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 609e88f27b3Smrg if (bo->map == NULL) { 610e88f27b3Smrg bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, 611e88f27b3Smrg MAP_SHARED, bo->device->fd, nvbo->map_handle); 612e88f27b3Smrg if (bo->map == MAP_FAILED) { 613e88f27b3Smrg bo->map = NULL; 614e88f27b3Smrg return -errno; 615e88f27b3Smrg } 616e88f27b3Smrg } 617e88f27b3Smrg return nouveau_bo_wait(bo, access, client); 618e88f27b3Smrg} 619