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