nouveau.c revision bbff01ce
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#include <stdio.h> 26e88f27b3Smrg#include <stdlib.h> 27e88f27b3Smrg#include <stdint.h> 28e88f27b3Smrg#include <string.h> 29e6188e58Smrg#include <strings.h> 30e88f27b3Smrg#include <stdbool.h> 31e88f27b3Smrg#include <assert.h> 32e88f27b3Smrg#include <errno.h> 33e88f27b3Smrg#include <fcntl.h> 34e88f27b3Smrg 35e88f27b3Smrg#include <xf86drm.h> 36e88f27b3Smrg#include <xf86atomic.h> 37e6188e58Smrg#include "libdrm_macros.h" 38e88f27b3Smrg#include "libdrm_lists.h" 39e88f27b3Smrg#include "nouveau_drm.h" 40e88f27b3Smrg 41e88f27b3Smrg#include "nouveau.h" 42e88f27b3Smrg#include "private.h" 43e88f27b3Smrg 443f012e29Smrg#include "nvif/class.h" 453f012e29Smrg#include "nvif/cl0080.h" 463f012e29Smrg#include "nvif/ioctl.h" 473f012e29Smrg#include "nvif/unpack.h" 483f012e29Smrg 494babd585Smrgdrm_private FILE *nouveau_out = NULL; 50e6188e58Smrgdrm_private uint32_t nouveau_debug = 0; 51e88f27b3Smrg 52e88f27b3Smrgstatic void 534babd585Smrgdebug_init(void) 54e88f27b3Smrg{ 554babd585Smrg static bool once = false; 564babd585Smrg char *debug, *out; 574babd585Smrg 584babd585Smrg if (once) 594babd585Smrg return; 604babd585Smrg once = true; 614babd585Smrg 624babd585Smrg debug = getenv("NOUVEAU_LIBDRM_DEBUG"); 634babd585Smrg if (debug) { 644babd585Smrg int n = strtol(debug, NULL, 0); 65e88f27b3Smrg if (n >= 0) 66e88f27b3Smrg nouveau_debug = n; 674babd585Smrg 684babd585Smrg } 694babd585Smrg 704babd585Smrg nouveau_out = stderr; 714babd585Smrg out = getenv("NOUVEAU_LIBDRM_OUT"); 724babd585Smrg if (out) { 734babd585Smrg FILE *fout = fopen(out, "w"); 744babd585Smrg if (fout) 754babd585Smrg nouveau_out = fout; 76e88f27b3Smrg } 77e88f27b3Smrg} 78e88f27b3Smrg 793f012e29Smrgstatic int 803f012e29Smrgnouveau_object_ioctl(struct nouveau_object *obj, void *data, uint32_t size) 813f012e29Smrg{ 823f012e29Smrg struct nouveau_drm *drm = nouveau_drm(obj); 833f012e29Smrg union { 843f012e29Smrg struct nvif_ioctl_v0 v0; 853f012e29Smrg } *args = data; 863f012e29Smrg uint32_t argc = size; 873f012e29Smrg int ret = -ENOSYS; 883f012e29Smrg 893f012e29Smrg if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { 903f012e29Smrg if (!obj->length) { 913f012e29Smrg if (obj != &drm->client) 923f012e29Smrg args->v0.object = (unsigned long)(void *)obj; 933f012e29Smrg else 943f012e29Smrg args->v0.object = 0; 953f012e29Smrg args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; 963f012e29Smrg args->v0.route = 0x00; 973f012e29Smrg } else { 983f012e29Smrg args->v0.route = 0xff; 993f012e29Smrg args->v0.token = obj->handle; 1003f012e29Smrg } 1013f012e29Smrg } else 1023f012e29Smrg return ret; 1033f012e29Smrg 1043f012e29Smrg return drmCommandWriteRead(drm->fd, DRM_NOUVEAU_NVIF, args, argc); 1053f012e29Smrg} 1063f012e29Smrg 1077cdc0497Smrgdrm_public int 1083f012e29Smrgnouveau_object_mthd(struct nouveau_object *obj, 1093f012e29Smrg uint32_t mthd, void *data, uint32_t size) 1103f012e29Smrg{ 1113f012e29Smrg struct nouveau_drm *drm = nouveau_drm(obj); 1123f012e29Smrg struct { 1133f012e29Smrg struct nvif_ioctl_v0 ioctl; 1143f012e29Smrg struct nvif_ioctl_mthd_v0 mthd; 1153f012e29Smrg } *args; 1163f012e29Smrg uint32_t argc = sizeof(*args) + size; 1173f012e29Smrg uint8_t stack[128]; 1183f012e29Smrg int ret; 1193f012e29Smrg 1203f012e29Smrg if (!drm->nvif) 1213f012e29Smrg return -ENOSYS; 1223f012e29Smrg 1233f012e29Smrg if (argc > sizeof(stack)) { 1243f012e29Smrg if (!(args = malloc(argc))) 1253f012e29Smrg return -ENOMEM; 1263f012e29Smrg } else { 1273f012e29Smrg args = (void *)stack; 1283f012e29Smrg } 1293f012e29Smrg args->ioctl.version = 0; 1303f012e29Smrg args->ioctl.type = NVIF_IOCTL_V0_MTHD; 1313f012e29Smrg args->mthd.version = 0; 1323f012e29Smrg args->mthd.method = mthd; 1333f012e29Smrg 1343f012e29Smrg memcpy(args->mthd.data, data, size); 1353f012e29Smrg ret = nouveau_object_ioctl(obj, args, argc); 1363f012e29Smrg memcpy(data, args->mthd.data, size); 1373f012e29Smrg if (args != (void *)stack) 1383f012e29Smrg free(args); 1393f012e29Smrg return ret; 1403f012e29Smrg} 1413f012e29Smrg 1427cdc0497Smrgdrm_public void 1433f012e29Smrgnouveau_object_sclass_put(struct nouveau_sclass **psclass) 1443f012e29Smrg{ 1453f012e29Smrg free(*psclass); 1463f012e29Smrg *psclass = NULL; 1473f012e29Smrg} 1483f012e29Smrg 1497cdc0497Smrgdrm_public int 1503f012e29Smrgnouveau_object_sclass_get(struct nouveau_object *obj, 1513f012e29Smrg struct nouveau_sclass **psclass) 1523f012e29Smrg{ 1533f012e29Smrg struct nouveau_drm *drm = nouveau_drm(obj); 1543f012e29Smrg struct { 1553f012e29Smrg struct nvif_ioctl_v0 ioctl; 1563f012e29Smrg struct nvif_ioctl_sclass_v0 sclass; 1573f012e29Smrg } *args = NULL; 1583f012e29Smrg struct nouveau_sclass *sclass; 1593f012e29Smrg int ret, cnt = 0, i; 1603f012e29Smrg uint32_t size; 1613f012e29Smrg 1623f012e29Smrg if (!drm->nvif) 1633f012e29Smrg return abi16_sclass(obj, psclass); 1643f012e29Smrg 1653f012e29Smrg while (1) { 1663f012e29Smrg size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]); 1673f012e29Smrg if (!(args = malloc(size))) 1683f012e29Smrg return -ENOMEM; 1693f012e29Smrg args->ioctl.version = 0; 1703f012e29Smrg args->ioctl.type = NVIF_IOCTL_V0_SCLASS; 1713f012e29Smrg args->sclass.version = 0; 1723f012e29Smrg args->sclass.count = cnt; 1733f012e29Smrg 1743f012e29Smrg ret = nouveau_object_ioctl(obj, args, size); 1753f012e29Smrg if (ret == 0 && args->sclass.count <= cnt) 1763f012e29Smrg break; 1773f012e29Smrg cnt = args->sclass.count; 1783f012e29Smrg free(args); 1793f012e29Smrg if (ret != 0) 1803f012e29Smrg return ret; 1813f012e29Smrg } 1823f012e29Smrg 1833f012e29Smrg if ((sclass = calloc(args->sclass.count, sizeof(*sclass)))) { 1843f012e29Smrg for (i = 0; i < args->sclass.count; i++) { 1853f012e29Smrg sclass[i].oclass = args->sclass.oclass[i].oclass; 1863f012e29Smrg sclass[i].minver = args->sclass.oclass[i].minver; 1873f012e29Smrg sclass[i].maxver = args->sclass.oclass[i].maxver; 1883f012e29Smrg } 1893f012e29Smrg *psclass = sclass; 1903f012e29Smrg ret = args->sclass.count; 1913f012e29Smrg } else { 1923f012e29Smrg ret = -ENOMEM; 1933f012e29Smrg } 1943f012e29Smrg 1953f012e29Smrg free(args); 1963f012e29Smrg return ret; 1973f012e29Smrg} 1983f012e29Smrg 1997cdc0497Smrgdrm_public int 2003f012e29Smrgnouveau_object_mclass(struct nouveau_object *obj, 2013f012e29Smrg const struct nouveau_mclass *mclass) 2023f012e29Smrg{ 2033f012e29Smrg struct nouveau_sclass *sclass; 2043f012e29Smrg int ret = -ENODEV; 2053f012e29Smrg int cnt, i, j; 2063f012e29Smrg 2073f012e29Smrg cnt = nouveau_object_sclass_get(obj, &sclass); 2083f012e29Smrg if (cnt < 0) 2093f012e29Smrg return cnt; 2103f012e29Smrg 2113f012e29Smrg for (i = 0; ret < 0 && mclass[i].oclass; i++) { 2123f012e29Smrg for (j = 0; j < cnt; j++) { 2133f012e29Smrg if (mclass[i].oclass == sclass[j].oclass && 2143f012e29Smrg mclass[i].version >= sclass[j].minver && 2153f012e29Smrg mclass[i].version <= sclass[j].maxver) { 2163f012e29Smrg ret = i; 2173f012e29Smrg break; 2183f012e29Smrg } 2193f012e29Smrg } 2203f012e29Smrg } 2213f012e29Smrg 2223f012e29Smrg nouveau_object_sclass_put(&sclass); 2233f012e29Smrg return ret; 2243f012e29Smrg} 2253f012e29Smrg 2263f012e29Smrgstatic void 2273f012e29Smrgnouveau_object_fini(struct nouveau_object *obj) 2283f012e29Smrg{ 2293f012e29Smrg struct { 2303f012e29Smrg struct nvif_ioctl_v0 ioctl; 2313f012e29Smrg struct nvif_ioctl_del del; 2323f012e29Smrg } args = { 2333f012e29Smrg .ioctl.type = NVIF_IOCTL_V0_DEL, 2343f012e29Smrg }; 2353f012e29Smrg 2363f012e29Smrg if (obj->data) { 2373f012e29Smrg abi16_delete(obj); 2383f012e29Smrg free(obj->data); 2393f012e29Smrg obj->data = NULL; 2403f012e29Smrg return; 2413f012e29Smrg } 2423f012e29Smrg 2433f012e29Smrg nouveau_object_ioctl(obj, &args, sizeof(args)); 2443f012e29Smrg} 2453f012e29Smrg 2463f012e29Smrgstatic int 2473f012e29Smrgnouveau_object_init(struct nouveau_object *parent, uint32_t handle, 2483f012e29Smrg int32_t oclass, void *data, uint32_t size, 2493f012e29Smrg struct nouveau_object *obj) 2503f012e29Smrg{ 2513f012e29Smrg struct nouveau_drm *drm = nouveau_drm(parent); 2523f012e29Smrg struct { 2533f012e29Smrg struct nvif_ioctl_v0 ioctl; 2543f012e29Smrg struct nvif_ioctl_new_v0 new; 2553f012e29Smrg } *args; 2563f012e29Smrg uint32_t argc = sizeof(*args) + size; 2573f012e29Smrg int (*func)(struct nouveau_object *); 2583f012e29Smrg int ret = -ENOSYS; 2593f012e29Smrg 2603f012e29Smrg obj->parent = parent; 2613f012e29Smrg obj->handle = handle; 2623f012e29Smrg obj->oclass = oclass; 2633f012e29Smrg obj->length = 0; 2643f012e29Smrg obj->data = NULL; 2653f012e29Smrg 2663f012e29Smrg if (!abi16_object(obj, &func) && drm->nvif) { 2673f012e29Smrg if (!(args = malloc(argc))) 2683f012e29Smrg return -ENOMEM; 2693f012e29Smrg args->ioctl.version = 0; 2703f012e29Smrg args->ioctl.type = NVIF_IOCTL_V0_NEW; 2713f012e29Smrg args->new.version = 0; 2723f012e29Smrg args->new.route = NVIF_IOCTL_V0_ROUTE_NVIF; 2733f012e29Smrg args->new.token = (unsigned long)(void *)obj; 2743f012e29Smrg args->new.object = (unsigned long)(void *)obj; 2753f012e29Smrg args->new.handle = handle; 2763f012e29Smrg args->new.oclass = oclass; 2773f012e29Smrg memcpy(args->new.data, data, size); 2783f012e29Smrg ret = nouveau_object_ioctl(parent, args, argc); 2793f012e29Smrg memcpy(data, args->new.data, size); 2803f012e29Smrg free(args); 2813f012e29Smrg } else 2823f012e29Smrg if (func) { 2833f012e29Smrg obj->length = size ? size : sizeof(struct nouveau_object *); 2843f012e29Smrg if (!(obj->data = malloc(obj->length))) 2853f012e29Smrg return -ENOMEM; 2863f012e29Smrg if (data) 2873f012e29Smrg memcpy(obj->data, data, obj->length); 2883f012e29Smrg *(struct nouveau_object **)obj->data = obj; 2893f012e29Smrg 2903f012e29Smrg ret = func(obj); 2913f012e29Smrg } 2923f012e29Smrg 2933f012e29Smrg if (ret) { 2943f012e29Smrg nouveau_object_fini(obj); 2953f012e29Smrg return ret; 2963f012e29Smrg } 2973f012e29Smrg 2983f012e29Smrg return 0; 2993f012e29Smrg} 3003f012e29Smrg 3017cdc0497Smrgdrm_public int 3023f012e29Smrgnouveau_object_new(struct nouveau_object *parent, uint64_t handle, 3033f012e29Smrg uint32_t oclass, void *data, uint32_t length, 3043f012e29Smrg struct nouveau_object **pobj) 3053f012e29Smrg{ 3063f012e29Smrg struct nouveau_object *obj; 3073f012e29Smrg int ret; 3083f012e29Smrg 3093f012e29Smrg if (!(obj = malloc(sizeof(*obj)))) 3103f012e29Smrg return -ENOMEM; 3113f012e29Smrg 3123f012e29Smrg ret = nouveau_object_init(parent, handle, oclass, data, length, obj); 3133f012e29Smrg if (ret) { 3143f012e29Smrg free(obj); 3153f012e29Smrg return ret; 3163f012e29Smrg } 3173f012e29Smrg 3183f012e29Smrg *pobj = obj; 3193f012e29Smrg return 0; 3203f012e29Smrg} 3213f012e29Smrg 3227cdc0497Smrgdrm_public void 3233f012e29Smrgnouveau_object_del(struct nouveau_object **pobj) 3243f012e29Smrg{ 3253f012e29Smrg struct nouveau_object *obj = *pobj; 3263f012e29Smrg if (obj) { 3273f012e29Smrg nouveau_object_fini(obj); 3283f012e29Smrg free(obj); 3293f012e29Smrg *pobj = NULL; 3303f012e29Smrg } 3313f012e29Smrg} 3323f012e29Smrg 3337cdc0497Smrgdrm_public void 3343f012e29Smrgnouveau_drm_del(struct nouveau_drm **pdrm) 3353f012e29Smrg{ 3363f012e29Smrg free(*pdrm); 3373f012e29Smrg *pdrm = NULL; 3383f012e29Smrg} 3393f012e29Smrg 3407cdc0497Smrgdrm_public int 3413f012e29Smrgnouveau_drm_new(int fd, struct nouveau_drm **pdrm) 3423f012e29Smrg{ 3433f012e29Smrg struct nouveau_drm *drm; 3443f012e29Smrg drmVersionPtr ver; 3453f012e29Smrg 3464babd585Smrg debug_init(); 3473f012e29Smrg 3483f012e29Smrg if (!(drm = calloc(1, sizeof(*drm)))) 3493f012e29Smrg return -ENOMEM; 3503f012e29Smrg drm->fd = fd; 3513f012e29Smrg 3523f012e29Smrg if (!(ver = drmGetVersion(fd))) { 3533f012e29Smrg nouveau_drm_del(&drm); 3543f012e29Smrg return -EINVAL; 3553f012e29Smrg } 3563f012e29Smrg *pdrm = drm; 3573f012e29Smrg 3583f012e29Smrg drm->version = (ver->version_major << 24) | 3593f012e29Smrg (ver->version_minor << 8) | 3603f012e29Smrg ver->version_patchlevel; 3613f012e29Smrg drm->nvif = (drm->version >= 0x01000301); 3623f012e29Smrg drmFreeVersion(ver); 3633f012e29Smrg return 0; 3643f012e29Smrg} 3653f012e29Smrg 366e88f27b3Smrg/* this is the old libdrm's version of nouveau_device_wrap(), the symbol 367e88f27b3Smrg * is kept here to prevent AIGLX from crashing if the DDX is linked against 368e88f27b3Smrg * the new libdrm, but the DRI driver against the old 369e88f27b3Smrg */ 3707cdc0497Smrgdrm_public int 371e88f27b3Smrgnouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd, 372e88f27b3Smrg drm_context_t ctx) 373e88f27b3Smrg{ 374e88f27b3Smrg return -EACCES; 375e88f27b3Smrg} 376e88f27b3Smrg 3777cdc0497Smrgdrm_public int 3783f012e29Smrgnouveau_device_new(struct nouveau_object *parent, int32_t oclass, 3793f012e29Smrg void *data, uint32_t size, struct nouveau_device **pdev) 380e88f27b3Smrg{ 3813f012e29Smrg struct nv_device_info_v0 info = {}; 3823f012e29Smrg union { 3833f012e29Smrg struct nv_device_v0 v0; 3843f012e29Smrg } *args = data; 3853f012e29Smrg uint32_t argc = size; 3863f012e29Smrg struct nouveau_drm *drm = nouveau_drm(parent); 3873f012e29Smrg struct nouveau_device_priv *nvdev; 3883f012e29Smrg struct nouveau_device *dev; 3893f012e29Smrg uint64_t v; 390e88f27b3Smrg char *tmp; 3913f012e29Smrg int ret = -ENOSYS; 392e88f27b3Smrg 3933f012e29Smrg if (oclass != NV_DEVICE || 3943f012e29Smrg nvif_unpack(ret, &data, &size, args->v0, 0, 0, false)) 3953f012e29Smrg return ret; 396e88f27b3Smrg 3973f012e29Smrg if (!(nvdev = calloc(1, sizeof(*nvdev)))) 398e88f27b3Smrg return -ENOMEM; 3993f012e29Smrg dev = *pdev = &nvdev->base; 4003f012e29Smrg dev->fd = -1; 401857b0bc6Smrg 4023f012e29Smrg if (drm->nvif) { 4033f012e29Smrg ret = nouveau_object_init(parent, 0, oclass, args, argc, 4043f012e29Smrg &dev->object); 4053f012e29Smrg if (ret) 4063f012e29Smrg goto done; 407e88f27b3Smrg 4083f012e29Smrg info.version = 0; 409e88f27b3Smrg 4103f012e29Smrg ret = nouveau_object_mthd(&dev->object, NV_DEVICE_V0_INFO, 4113f012e29Smrg &info, sizeof(info)); 4123f012e29Smrg if (ret) 4133f012e29Smrg goto done; 4143f012e29Smrg 4153f012e29Smrg nvdev->base.chipset = info.chipset; 4163f012e29Smrg nvdev->have_bo_usage = true; 4173f012e29Smrg } else 4183f012e29Smrg if (args->v0.device == ~0ULL) { 4193f012e29Smrg nvdev->base.object.parent = &drm->client; 4203f012e29Smrg nvdev->base.object.handle = ~0ULL; 4213f012e29Smrg nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS; 4223f012e29Smrg nvdev->base.object.length = ~0; 4233f012e29Smrg 4243f012e29Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &v); 4253f012e29Smrg if (ret) 4263f012e29Smrg goto done; 4273f012e29Smrg nvdev->base.chipset = v; 428e88f27b3Smrg 4293f012e29Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &v); 4303f012e29Smrg if (ret == 0) 4313f012e29Smrg nvdev->have_bo_usage = (v != 0); 4323f012e29Smrg } else 4333f012e29Smrg return -ENOSYS; 434e88f27b3Smrg 4353f012e29Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &v); 4363f012e29Smrg if (ret) 4373f012e29Smrg goto done; 4383f012e29Smrg nvdev->base.vram_size = v; 439e88f27b3Smrg 4403f012e29Smrg ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &v); 4413f012e29Smrg if (ret) 4423f012e29Smrg goto done; 4433f012e29Smrg nvdev->base.gart_size = v; 444e88f27b3Smrg 445e88f27b3Smrg tmp = getenv("NOUVEAU_LIBDRM_VRAM_LIMIT_PERCENT"); 446e88f27b3Smrg if (tmp) 447e88f27b3Smrg nvdev->vram_limit_percent = atoi(tmp); 448e88f27b3Smrg else 449e88f27b3Smrg nvdev->vram_limit_percent = 80; 4503f012e29Smrg 4513f012e29Smrg nvdev->base.vram_limit = 4523f012e29Smrg (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100; 4533f012e29Smrg 454e88f27b3Smrg tmp = getenv("NOUVEAU_LIBDRM_GART_LIMIT_PERCENT"); 455e88f27b3Smrg if (tmp) 456e88f27b3Smrg nvdev->gart_limit_percent = atoi(tmp); 457e88f27b3Smrg else 458e88f27b3Smrg nvdev->gart_limit_percent = 80; 4593f012e29Smrg 460e88f27b3Smrg nvdev->base.gart_limit = 461e88f27b3Smrg (nvdev->base.gart_size * nvdev->gart_limit_percent) / 100; 462e88f27b3Smrg 4633f012e29Smrg ret = pthread_mutex_init(&nvdev->lock, NULL); 4643f012e29Smrg DRMINITLISTHEAD(&nvdev->bo_list); 4653f012e29Smrgdone: 4663f012e29Smrg if (ret) 4673f012e29Smrg nouveau_device_del(pdev); 4683f012e29Smrg return ret; 4693f012e29Smrg} 4703f012e29Smrg 4717cdc0497Smrgdrm_public int 4723f012e29Smrgnouveau_device_wrap(int fd, int close, struct nouveau_device **pdev) 4733f012e29Smrg{ 4743f012e29Smrg struct nouveau_drm *drm; 4753f012e29Smrg struct nouveau_device_priv *nvdev; 4763f012e29Smrg int ret; 4773f012e29Smrg 4783f012e29Smrg ret = nouveau_drm_new(fd, &drm); 4793f012e29Smrg if (ret) 4803f012e29Smrg return ret; 4813f012e29Smrg drm->nvif = false; 4823f012e29Smrg 4833f012e29Smrg ret = nouveau_device_new(&drm->client, NV_DEVICE, 4843f012e29Smrg &(struct nv_device_v0) { 4853f012e29Smrg .device = ~0ULL, 4863f012e29Smrg }, sizeof(struct nv_device_v0), pdev); 4873f012e29Smrg if (ret) { 4883f012e29Smrg nouveau_drm_del(&drm); 4893f012e29Smrg return ret; 4903f012e29Smrg } 4913f012e29Smrg 4923f012e29Smrg nvdev = nouveau_device(*pdev); 4933f012e29Smrg nvdev->base.fd = drm->fd; 4943f012e29Smrg nvdev->base.drm_version = drm->version; 4953f012e29Smrg nvdev->close = close; 496e88f27b3Smrg return 0; 497e88f27b3Smrg} 498e88f27b3Smrg 4997cdc0497Smrgdrm_public int 500e88f27b3Smrgnouveau_device_open(const char *busid, struct nouveau_device **pdev) 501e88f27b3Smrg{ 502e88f27b3Smrg int ret = -ENODEV, fd = drmOpen("nouveau", busid); 503e88f27b3Smrg if (fd >= 0) { 504e88f27b3Smrg ret = nouveau_device_wrap(fd, 1, pdev); 505e88f27b3Smrg if (ret) 506e88f27b3Smrg drmClose(fd); 507e88f27b3Smrg } 508e88f27b3Smrg return ret; 509e88f27b3Smrg} 510e88f27b3Smrg 5117cdc0497Smrgdrm_public void 512e88f27b3Smrgnouveau_device_del(struct nouveau_device **pdev) 513e88f27b3Smrg{ 514e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(*pdev); 515e88f27b3Smrg if (nvdev) { 516e88f27b3Smrg free(nvdev->client); 517857b0bc6Smrg pthread_mutex_destroy(&nvdev->lock); 5183f012e29Smrg if (nvdev->base.fd >= 0) { 5193f012e29Smrg struct nouveau_drm *drm = 5203f012e29Smrg nouveau_drm(&nvdev->base.object); 5213f012e29Smrg nouveau_drm_del(&drm); 5223f012e29Smrg if (nvdev->close) 5233f012e29Smrg drmClose(nvdev->base.fd); 5243f012e29Smrg } 525e88f27b3Smrg free(nvdev); 526e88f27b3Smrg *pdev = NULL; 527e88f27b3Smrg } 528e88f27b3Smrg} 529e88f27b3Smrg 5307cdc0497Smrgdrm_public int 531e88f27b3Smrgnouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value) 532e88f27b3Smrg{ 5333f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&dev->object); 5343f012e29Smrg struct drm_nouveau_getparam r = { .param = param }; 5353f012e29Smrg int fd = drm->fd, ret = 536e88f27b3Smrg drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r)); 537e88f27b3Smrg *value = r.value; 538e88f27b3Smrg return ret; 539e88f27b3Smrg} 540e88f27b3Smrg 5417cdc0497Smrgdrm_public int 542e88f27b3Smrgnouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value) 543e88f27b3Smrg{ 5443f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&dev->object); 5453f012e29Smrg struct drm_nouveau_setparam r = { .param = param, .value = value }; 5463f012e29Smrg return drmCommandWrite(drm->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r)); 547e88f27b3Smrg} 548e88f27b3Smrg 5497cdc0497Smrgdrm_public int 550e88f27b3Smrgnouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient) 551e88f27b3Smrg{ 552e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 553e88f27b3Smrg struct nouveau_client_priv *pcli; 554e88f27b3Smrg int id = 0, i, ret = -ENOMEM; 555e88f27b3Smrg uint32_t *clients; 556e88f27b3Smrg 557857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 558857b0bc6Smrg 559e88f27b3Smrg for (i = 0; i < nvdev->nr_client; i++) { 560e88f27b3Smrg id = ffs(nvdev->client[i]) - 1; 561e88f27b3Smrg if (id >= 0) 562e88f27b3Smrg goto out; 563e88f27b3Smrg } 564e88f27b3Smrg 565e88f27b3Smrg clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1)); 566e88f27b3Smrg if (!clients) 567857b0bc6Smrg goto unlock; 568e88f27b3Smrg nvdev->client = clients; 569e88f27b3Smrg nvdev->client[i] = 0; 570e88f27b3Smrg nvdev->nr_client++; 571e88f27b3Smrg 572e88f27b3Smrgout: 573e88f27b3Smrg pcli = calloc(1, sizeof(*pcli)); 574e88f27b3Smrg if (pcli) { 575e88f27b3Smrg nvdev->client[i] |= (1 << id); 576e88f27b3Smrg pcli->base.device = dev; 577e88f27b3Smrg pcli->base.id = (i * 32) + id; 578e88f27b3Smrg ret = 0; 579e88f27b3Smrg } 580e88f27b3Smrg 581e88f27b3Smrg *pclient = &pcli->base; 582857b0bc6Smrg 583857b0bc6Smrgunlock: 584857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 585e88f27b3Smrg return ret; 586e88f27b3Smrg} 587e88f27b3Smrg 5887cdc0497Smrgdrm_public void 589e88f27b3Smrgnouveau_client_del(struct nouveau_client **pclient) 590e88f27b3Smrg{ 591e88f27b3Smrg struct nouveau_client_priv *pcli = nouveau_client(*pclient); 592e88f27b3Smrg struct nouveau_device_priv *nvdev; 593e88f27b3Smrg if (pcli) { 594e88f27b3Smrg int id = pcli->base.id; 595e88f27b3Smrg nvdev = nouveau_device(pcli->base.device); 596857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 597e88f27b3Smrg nvdev->client[id / 32] &= ~(1 << (id % 32)); 598857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 599e88f27b3Smrg free(pcli->kref); 600e88f27b3Smrg free(pcli); 601e88f27b3Smrg } 602e88f27b3Smrg} 603e88f27b3Smrg 604e88f27b3Smrgstatic void 605e88f27b3Smrgnouveau_bo_del(struct nouveau_bo *bo) 606e88f27b3Smrg{ 6073f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&bo->device->object); 608857b0bc6Smrg struct nouveau_device_priv *nvdev = nouveau_device(bo->device); 609e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 610857b0bc6Smrg 611e6188e58Smrg if (nvbo->head.next) { 612e6188e58Smrg pthread_mutex_lock(&nvdev->lock); 613e6188e58Smrg if (atomic_read(&nvbo->refcnt) == 0) { 614e6188e58Smrg DRMLISTDEL(&nvbo->head); 615857b0bc6Smrg /* 616e6188e58Smrg * This bo has to be closed with the lock held because 617e6188e58Smrg * gem handles are not refcounted. If a shared bo is 618e6188e58Smrg * closed and re-opened in another thread a race 619e6188e58Smrg * against DRM_IOCTL_GEM_OPEN or drmPrimeFDToHandle 620e6188e58Smrg * might cause the bo to be closed accidentally while 621e6188e58Smrg * re-importing. 622857b0bc6Smrg */ 62349ef06a4Smrg drmCloseBufferHandle(drm->fd, bo->handle); 624857b0bc6Smrg } 625857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 626857b0bc6Smrg } else { 62749ef06a4Smrg drmCloseBufferHandle(drm->fd, bo->handle); 628857b0bc6Smrg } 629e88f27b3Smrg if (bo->map) 630baaff307Smrg drm_munmap(bo->map, bo->size); 631e88f27b3Smrg free(nvbo); 632e88f27b3Smrg} 633e88f27b3Smrg 6347cdc0497Smrgdrm_public int 635e88f27b3Smrgnouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align, 636e88f27b3Smrg uint64_t size, union nouveau_bo_config *config, 637e88f27b3Smrg struct nouveau_bo **pbo) 638e88f27b3Smrg{ 639e88f27b3Smrg struct nouveau_bo_priv *nvbo = calloc(1, sizeof(*nvbo)); 640e88f27b3Smrg struct nouveau_bo *bo = &nvbo->base; 641e88f27b3Smrg int ret; 642e88f27b3Smrg 643e88f27b3Smrg if (!nvbo) 644e88f27b3Smrg return -ENOMEM; 645e88f27b3Smrg atomic_set(&nvbo->refcnt, 1); 646e88f27b3Smrg bo->device = dev; 647e88f27b3Smrg bo->flags = flags; 648e88f27b3Smrg bo->size = size; 649e88f27b3Smrg 650e88f27b3Smrg ret = abi16_bo_init(bo, align, config); 651e88f27b3Smrg if (ret) { 652e88f27b3Smrg free(nvbo); 653e88f27b3Smrg return ret; 654e88f27b3Smrg } 655e88f27b3Smrg 656e88f27b3Smrg *pbo = bo; 657e88f27b3Smrg return 0; 658e88f27b3Smrg} 659e88f27b3Smrg 660857b0bc6Smrgstatic int 661857b0bc6Smrgnouveau_bo_wrap_locked(struct nouveau_device *dev, uint32_t handle, 662e6188e58Smrg struct nouveau_bo **pbo, int name) 663e88f27b3Smrg{ 6643f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&dev->object); 665e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 666e88f27b3Smrg struct drm_nouveau_gem_info req = { .handle = handle }; 667e88f27b3Smrg struct nouveau_bo_priv *nvbo; 668e88f27b3Smrg int ret; 669e88f27b3Smrg 670e88f27b3Smrg DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { 671e88f27b3Smrg if (nvbo->base.handle == handle) { 672e6188e58Smrg if (atomic_inc_return(&nvbo->refcnt) == 1) { 673e6188e58Smrg /* 674e6188e58Smrg * Uh oh, this bo is dead and someone else 675e6188e58Smrg * will free it, but because refcnt is 676e6188e58Smrg * now non-zero fortunately they won't 677e6188e58Smrg * call the ioctl to close the bo. 678e6188e58Smrg * 679e6188e58Smrg * Remove this bo from the list so other 680e6188e58Smrg * calls to nouveau_bo_wrap_locked will 681e6188e58Smrg * see our replacement nvbo. 682e6188e58Smrg */ 683e6188e58Smrg DRMLISTDEL(&nvbo->head); 684e6188e58Smrg if (!name) 685e6188e58Smrg name = nvbo->name; 686e6188e58Smrg break; 687e6188e58Smrg } 688e6188e58Smrg 689e6188e58Smrg *pbo = &nvbo->base; 690e88f27b3Smrg return 0; 691e88f27b3Smrg } 692e88f27b3Smrg } 693e88f27b3Smrg 6943f012e29Smrg ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_INFO, 695e88f27b3Smrg &req, sizeof(req)); 696e88f27b3Smrg if (ret) 697e88f27b3Smrg return ret; 698e88f27b3Smrg 699e88f27b3Smrg nvbo = calloc(1, sizeof(*nvbo)); 700e88f27b3Smrg if (nvbo) { 701e88f27b3Smrg atomic_set(&nvbo->refcnt, 1); 702e88f27b3Smrg nvbo->base.device = dev; 703e88f27b3Smrg abi16_bo_info(&nvbo->base, &req); 704e6188e58Smrg nvbo->name = name; 705e88f27b3Smrg DRMLISTADD(&nvbo->head, &nvdev->bo_list); 706e88f27b3Smrg *pbo = &nvbo->base; 707e88f27b3Smrg return 0; 708e88f27b3Smrg } 709e88f27b3Smrg 710e88f27b3Smrg return -ENOMEM; 711e88f27b3Smrg} 712e88f27b3Smrg 713e6188e58Smrgstatic void 714bbff01ceSmrgnouveau_nvbo_make_global(struct nouveau_bo_priv *nvbo) 715e6188e58Smrg{ 716e6188e58Smrg if (!nvbo->head.next) { 717e6188e58Smrg struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device); 718e6188e58Smrg pthread_mutex_lock(&nvdev->lock); 719e6188e58Smrg if (!nvbo->head.next) 720e6188e58Smrg DRMLISTADD(&nvbo->head, &nvdev->bo_list); 721e6188e58Smrg pthread_mutex_unlock(&nvdev->lock); 722e6188e58Smrg } 723e6188e58Smrg} 724e6188e58Smrg 725bbff01ceSmrgdrm_public void 726bbff01ceSmrgnouveau_bo_make_global(struct nouveau_bo *bo) 727bbff01ceSmrg{ 728bbff01ceSmrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 729bbff01ceSmrg 730bbff01ceSmrg nouveau_nvbo_make_global(nvbo); 731bbff01ceSmrg} 732bbff01ceSmrg 7337cdc0497Smrgdrm_public int 734857b0bc6Smrgnouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle, 735857b0bc6Smrg struct nouveau_bo **pbo) 736857b0bc6Smrg{ 737857b0bc6Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 738857b0bc6Smrg int ret; 739857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 740e6188e58Smrg ret = nouveau_bo_wrap_locked(dev, handle, pbo, 0); 741857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 742857b0bc6Smrg return ret; 743857b0bc6Smrg} 744857b0bc6Smrg 7457cdc0497Smrgdrm_public int 746e88f27b3Smrgnouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name, 747e88f27b3Smrg struct nouveau_bo **pbo) 748e88f27b3Smrg{ 7493f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&dev->object); 750e88f27b3Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 751e88f27b3Smrg struct nouveau_bo_priv *nvbo; 752e88f27b3Smrg struct drm_gem_open req = { .name = name }; 753e88f27b3Smrg int ret; 754e88f27b3Smrg 755857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 756e88f27b3Smrg DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { 757e88f27b3Smrg if (nvbo->name == name) { 758e6188e58Smrg ret = nouveau_bo_wrap_locked(dev, nvbo->base.handle, 759e6188e58Smrg pbo, name); 760857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 761e6188e58Smrg return ret; 762e88f27b3Smrg } 763e88f27b3Smrg } 764e88f27b3Smrg 7653f012e29Smrg ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &req); 766e88f27b3Smrg if (ret == 0) { 767e6188e58Smrg ret = nouveau_bo_wrap_locked(dev, req.handle, pbo, name); 768e88f27b3Smrg } 769e88f27b3Smrg 770e6188e58Smrg pthread_mutex_unlock(&nvdev->lock); 771e88f27b3Smrg return ret; 772e88f27b3Smrg} 773e88f27b3Smrg 7747cdc0497Smrgdrm_public int 775e88f27b3Smrgnouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name) 776e88f27b3Smrg{ 777e88f27b3Smrg struct drm_gem_flink req = { .handle = bo->handle }; 7783f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&bo->device->object); 779e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 780857b0bc6Smrg 781857b0bc6Smrg *name = nvbo->name; 782e6188e58Smrg if (!*name) { 7833f012e29Smrg int ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_FLINK, &req); 784e6188e58Smrg 785857b0bc6Smrg if (ret) { 786857b0bc6Smrg *name = 0; 787e88f27b3Smrg return ret; 788857b0bc6Smrg } 789857b0bc6Smrg nvbo->name = *name = req.name; 790e6188e58Smrg 791bbff01ceSmrg nouveau_nvbo_make_global(nvbo); 792e88f27b3Smrg } 793e88f27b3Smrg return 0; 794e88f27b3Smrg} 795e88f27b3Smrg 7967cdc0497Smrgdrm_public void 797e88f27b3Smrgnouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref) 798e88f27b3Smrg{ 799e88f27b3Smrg struct nouveau_bo *ref = *pref; 800e88f27b3Smrg if (bo) { 801e88f27b3Smrg atomic_inc(&nouveau_bo(bo)->refcnt); 802e88f27b3Smrg } 803e88f27b3Smrg if (ref) { 804e88f27b3Smrg if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt)) 805e88f27b3Smrg nouveau_bo_del(ref); 806e88f27b3Smrg } 807e88f27b3Smrg *pref = bo; 808e88f27b3Smrg} 809e88f27b3Smrg 8107cdc0497Smrgdrm_public int 811e88f27b3Smrgnouveau_bo_prime_handle_ref(struct nouveau_device *dev, int prime_fd, 812e88f27b3Smrg struct nouveau_bo **bo) 813e88f27b3Smrg{ 8143f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&dev->object); 815857b0bc6Smrg struct nouveau_device_priv *nvdev = nouveau_device(dev); 816e88f27b3Smrg int ret; 817e88f27b3Smrg unsigned int handle; 818e88f27b3Smrg 819857b0bc6Smrg nouveau_bo_ref(NULL, bo); 820e88f27b3Smrg 821857b0bc6Smrg pthread_mutex_lock(&nvdev->lock); 8223f012e29Smrg ret = drmPrimeFDToHandle(drm->fd, prime_fd, &handle); 823857b0bc6Smrg if (ret == 0) { 824e6188e58Smrg ret = nouveau_bo_wrap_locked(dev, handle, bo, 0); 825e88f27b3Smrg } 826857b0bc6Smrg pthread_mutex_unlock(&nvdev->lock); 827857b0bc6Smrg return ret; 828e88f27b3Smrg} 829e88f27b3Smrg 8307cdc0497Smrgdrm_public int 831e88f27b3Smrgnouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd) 832e88f27b3Smrg{ 8333f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&bo->device->object); 834e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 835e88f27b3Smrg int ret; 836e88f27b3Smrg 8373f012e29Smrg ret = drmPrimeHandleToFD(drm->fd, nvbo->base.handle, DRM_CLOEXEC, prime_fd); 838e88f27b3Smrg if (ret) 839e88f27b3Smrg return ret; 840e6188e58Smrg 841bbff01ceSmrg nouveau_nvbo_make_global(nvbo); 842e88f27b3Smrg return 0; 843e88f27b3Smrg} 844e88f27b3Smrg 8457cdc0497Smrgdrm_public int 846e88f27b3Smrgnouveau_bo_wait(struct nouveau_bo *bo, uint32_t access, 847e88f27b3Smrg struct nouveau_client *client) 848e88f27b3Smrg{ 8493f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&bo->device->object); 850e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 851e88f27b3Smrg struct drm_nouveau_gem_cpu_prep req; 852e88f27b3Smrg struct nouveau_pushbuf *push; 853e88f27b3Smrg int ret = 0; 854e88f27b3Smrg 855e88f27b3Smrg if (!(access & NOUVEAU_BO_RDWR)) 856e88f27b3Smrg return 0; 857e88f27b3Smrg 858e88f27b3Smrg push = cli_push_get(client, bo); 859e88f27b3Smrg if (push && push->channel) 860e88f27b3Smrg nouveau_pushbuf_kick(push, push->channel); 861e88f27b3Smrg 862e6188e58Smrg if (!nvbo->head.next && !(nvbo->access & NOUVEAU_BO_WR) && 863e6188e58Smrg !(access & NOUVEAU_BO_WR)) 864e88f27b3Smrg return 0; 865e88f27b3Smrg 866e88f27b3Smrg req.handle = bo->handle; 867e88f27b3Smrg req.flags = 0; 868e88f27b3Smrg if (access & NOUVEAU_BO_WR) 869e88f27b3Smrg req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE; 870e88f27b3Smrg if (access & NOUVEAU_BO_NOBLOCK) 871e88f27b3Smrg req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT; 872e88f27b3Smrg 8733f012e29Smrg ret = drmCommandWrite(drm->fd, DRM_NOUVEAU_GEM_CPU_PREP, 874e88f27b3Smrg &req, sizeof(req)); 875e88f27b3Smrg if (ret == 0) 876e88f27b3Smrg nvbo->access = 0; 877e88f27b3Smrg return ret; 878e88f27b3Smrg} 879e88f27b3Smrg 8807cdc0497Smrgdrm_public int 881e88f27b3Smrgnouveau_bo_map(struct nouveau_bo *bo, uint32_t access, 882e88f27b3Smrg struct nouveau_client *client) 883e88f27b3Smrg{ 8843f012e29Smrg struct nouveau_drm *drm = nouveau_drm(&bo->device->object); 885e88f27b3Smrg struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 886e88f27b3Smrg if (bo->map == NULL) { 887baaff307Smrg bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, 8883f012e29Smrg MAP_SHARED, drm->fd, nvbo->map_handle); 889e88f27b3Smrg if (bo->map == MAP_FAILED) { 890e88f27b3Smrg bo->map = NULL; 891e88f27b3Smrg return -errno; 892e88f27b3Smrg } 893e88f27b3Smrg } 894e88f27b3Smrg return nouveau_bo_wait(bo, access, client); 895e88f27b3Smrg} 896