ChangeLog | 195 ++ configure.ac | 2 debian/changelog | 9 debian/patches/02-drm-nouveau-newabi.patch | 2272 +++++++++++++++++++++++++++++ debian/patches/series | 1 src/Makefile.am | 4 src/drmmode_display.c | 30 src/nouveau_dri2.c | 32 src/nouveau_exa.c | 29 src/nouveau_local.h | 186 +- src/nouveau_wfb.c | 4 src/nouveau_xv.c | 69 src/nv04_accel.h | 83 + src/nv04_exa.c | 524 +++--- src/nv04_xv_blit.c | 262 +-- src/nv10_exa.c | 857 ++++------ src/nv30_exa.c | 975 ++++++------ src/nv30_shaders.c | 347 ---- src/nv30_shaders.h | 72 src/nv30_xv_tex.c | 302 +-- src/nv40_exa.c | 994 +++++++----- src/nv40_xv_tex.c | 293 +-- src/nv50_accel.c | 670 ++++---- src/nv50_accel.h | 66 src/nv50_exa.c | 895 +++++------ src/nv50_xv.c | 381 +--- src/nv_accel_common.c | 582 +++---- src/nv_dma.c | 77 src/nv_dma.h | 4 src/nv_driver.c | 43 src/nv_include.h | 11 src/nv_proto.h | 7 src/nv_shadow.c | 3 src/nv_type.h | 53 src/nvc0_accel.c | 841 ++-------- src/nvc0_accel.h | 120 - src/nvc0_exa.c | 974 +++++------- src/nvc0_shader.h | 444 +++++ src/nvc0_xv.c | 374 +--- src/nve0_shader.h | 460 +++++ 40 files changed, 8045 insertions(+), 5502 deletions(-)
New commits: commit c20b687c6f92abb63eb019c1778cb5b465ac1b57 Author: Maarten Lankhorst <[email protected]> Date: Wed May 23 10:08:34 2012 +0200 Add 02-drm-nouveau-newabi.patch to build with old libdrm Until mesa 8.1 is released, we cannot build with new libdrm yet diff --git a/debian/changelog b/debian/changelog index 55d53bb..e96e86b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ xserver-xorg-video-nouveau (1:0.0.16+git20120523+5815644-1) UNRELEASED; urgency= [ Maarten Lankhorst ] * New upstream snapshot. First one to have the new ABI. + * Add 02-drm-nouveau-newabi.patch to build with old libdrm + - Until mesa 8.1 is released, we cannot build with new libdrm yet -- Maarten Lankhorst <[email protected]> Wed, 23 May 2012 09:45:06 +0200 diff --git a/debian/patches/02-drm-nouveau-newabi.patch b/debian/patches/02-drm-nouveau-newabi.patch new file mode 100644 index 0000000..8179f9f --- /dev/null +++ b/debian/patches/02-drm-nouveau-newabi.patch @@ -0,0 +1,2272 @@ +commit d99486bda5601cb887ac898037a2dfad795aeb8f +Author: Maarten Lankhorst <[email protected]> +Date: Wed May 23 09:29:29 2012 +0200 + + awful hack to remove dependency on libdrm_nouveau + +diff --git a/configure.ac b/configure.ac +index afb6cde..7326144 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -67,7 +67,8 @@ XORG_DRIVER_CHECK_EXT(XV, videoproto) + XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto) + + # Checks for pkg-config packages +-PKG_CHECK_MODULES(LIBDRM_NOUVEAU, [libdrm_nouveau >= 2.4.25]) ++PKG_CHECK_MODULES(LIBDRM_NOUVEAU_DUMMY, [libdrm_nouveau = 0.6]) ++PKG_CHECK_MODULES(LIBDRM_NOUVEAU, [libdrm]) + AC_SUBST(LIBDRM_NOUVEAU_CFLAGS) + AC_SUBST(LIBDRM_NOUVEAU_LIBS) + +diff --git a/drm_nouveau/abi16.c b/drm_nouveau/abi16.c +new file mode 100644 +index 0000000..69a0a9b +--- /dev/null ++++ b/drm_nouveau/abi16.c +@@ -0,0 +1,198 @@ ++/* ++ * Copyright 2012 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include <stdlib.h> ++#include <stdint.h> ++ ++#include "private.h" ++ ++int ++abi16_chan_nv04(struct nouveau_object *obj) ++{ ++ struct nouveau_device *dev = (struct nouveau_device *)obj->parent; ++ struct drm_nouveau_channel_alloc req; ++ struct nv04_fifo *nv04 = obj->data; ++ int ret; ++ ++ req.fb_ctxdma_handle = nv04->vram; ++ req.tt_ctxdma_handle = nv04->gart; ++ ++ ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_CHANNEL_ALLOC, ++ &req, sizeof(req)); ++ if (ret) ++ return ret; ++ ++ nv04->base.channel = req.channel; ++ nv04->base.pushbuf = req.pushbuf_domains; ++ nv04->notify = req.notifier_handle; ++ nv04->base.object->handle = req.channel; ++ nv04->base.object->length = sizeof(*nv04); ++ return 0; ++} ++ ++int ++abi16_chan_nvc0(struct nouveau_object *obj) ++{ ++ struct nouveau_device *dev = (struct nouveau_device *)obj->parent; ++ struct drm_nouveau_channel_alloc req = {}; ++ struct nvc0_fifo *nvc0 = obj->data; ++ int ret; ++ ++ ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_CHANNEL_ALLOC, ++ &req, sizeof(req)); ++ if (ret) ++ return ret; ++ ++ nvc0->base.channel = req.channel; ++ nvc0->base.pushbuf = req.pushbuf_domains; ++ nvc0->notify = req.notifier_handle; ++ nvc0->base.object->handle = req.channel; ++ nvc0->base.object->length = sizeof(*nvc0); ++ return 0; ++} ++ ++int ++abi16_engobj(struct nouveau_object *obj) ++{ ++ struct drm_nouveau_grobj_alloc req = { ++ obj->parent->handle, obj->handle, obj->oclass ++ }; ++ struct nouveau_device *dev; ++ int ret; ++ ++ dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); ++ ret = drmCommandWrite(dev->fd, DRM_NOUVEAU_GROBJ_ALLOC, ++ &req, sizeof(req)); ++ if (ret) ++ return ret; ++ ++ obj->length = sizeof(struct nouveau_object *); ++ return 0; ++} ++ ++int ++abi16_ntfy(struct nouveau_object *obj) ++{ ++ struct nv04_notify *ntfy = obj->data; ++ struct drm_nouveau_notifierobj_alloc req = { ++ obj->parent->handle, ntfy->object->handle, ntfy->length ++ }; ++ struct nouveau_device *dev; ++ int ret; ++ ++ dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); ++ ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, ++ &req, sizeof(req)); ++ if (ret) ++ return ret; ++ ++ ntfy->offset = req.offset; ++ ntfy->object->length = sizeof(*ntfy); ++ return 0; ++} ++ ++void ++abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info) ++{ ++ struct nouveau_bo_priv *nvbo = nouveau_bo(bo); ++ ++ nvbo->map_handle = info->map_handle; ++ bo->handle = info->handle; ++ bo->size = info->size; ++ bo->offset = info->offset; ++ ++ bo->flags = 0; ++ if (info->domain & NOUVEAU_GEM_DOMAIN_VRAM) ++ bo->flags |= NOUVEAU_BO_VRAM; ++ if (info->domain & NOUVEAU_GEM_DOMAIN_GART) ++ bo->flags |= NOUVEAU_BO_GART; ++ if (!(info->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)) ++ bo->flags |= NOUVEAU_BO_CONTIG; ++ if (nvbo->map_handle) ++ bo->flags |= NOUVEAU_BO_MAP; ++ ++ if (bo->device->chipset >= 0xc0) { ++ bo->config.nvc0.memtype = (info->tile_flags & 0xff00) >> 8; ++ bo->config.nvc0.tile_mode = info->tile_mode; ++ } else ++ if (bo->device->chipset >= 0x80 || bo->device->chipset == 0x50) { ++ bo->config.nv50.memtype = (info->tile_flags & 0x07f00) >> 8 | ++ (info->tile_flags & 0x30000) >> 9; ++ bo->config.nv50.tile_mode = info->tile_mode << 4; ++ } else { ++ bo->config.nv04.surf_flags = info->tile_flags & 7; ++ bo->config.nv04.surf_pitch = info->tile_mode; ++ } ++} ++ ++int ++abi16_bo_init(struct nouveau_bo *bo, uint32_t alignment, ++ union nouveau_bo_config *config) ++{ ++ struct nouveau_device *dev = bo->device; ++ struct drm_nouveau_gem_new req = {}; ++ struct drm_nouveau_gem_info *info = &req.info; ++ int ret; ++ ++ if (bo->flags & NOUVEAU_BO_VRAM) ++ info->domain |= NOUVEAU_GEM_DOMAIN_VRAM; ++ if (bo->flags & NOUVEAU_BO_GART) ++ info->domain |= NOUVEAU_GEM_DOMAIN_GART; ++ if (!info->domain) ++ info->domain |= NOUVEAU_GEM_DOMAIN_VRAM | ++ NOUVEAU_GEM_DOMAIN_GART; ++ ++ if (bo->flags & NOUVEAU_BO_MAP) ++ info->domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE; ++ ++ if (!(bo->flags & NOUVEAU_BO_CONTIG)) ++ info->tile_flags = NOUVEAU_GEM_TILE_NONCONTIG; ++ ++ info->size = bo->size; ++ req.align = alignment; ++ ++ if (config) { ++ if (dev->chipset >= 0xc0) { ++ info->tile_flags = (config->nvc0.memtype & 0xff) << 8; ++ info->tile_mode = config->nvc0.tile_mode; ++ } else ++ if (dev->chipset >= 0x80 || dev->chipset == 0x50) { ++ info->tile_flags = (config->nv50.memtype & 0x07f) << 8 | ++ (config->nv50.memtype & 0x180) << 9; ++ info->tile_mode = config->nv50.tile_mode >> 4; ++ } else { ++ info->tile_flags = config->nv04.surf_flags & 7; ++ info->tile_mode = config->nv04.surf_pitch; ++ } ++ } ++ ++ if (!nouveau_device(dev)->have_bo_usage) ++ info->tile_flags &= 0x0000ff00; ++ ++ ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_NEW, ++ &req, sizeof(req)); ++ if (ret == 0) ++ abi16_bo_info(bo, &req.info); ++ return ret; ++} +diff --git a/drm_nouveau/bufctx.c b/drm_nouveau/bufctx.c +new file mode 100644 +index 0000000..23d6f09 +--- /dev/null ++++ b/drm_nouveau/bufctx.c +@@ -0,0 +1,170 @@ ++/* ++ * Copyright 2012 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdint.h> ++#include <stdbool.h> ++#include <assert.h> ++#include <errno.h> ++ ++#include "libdrm_lists.h" ++ ++#include "nouveau.h" ++#include "private.h" ++ ++struct nouveau_bufref_priv { ++ struct nouveau_bufref base; ++ struct nouveau_bufref_priv *next; ++ struct nouveau_bufctx *bufctx; ++}; ++ ++static inline struct nouveau_bufref_priv * ++nouveau_bufref(struct nouveau_bufref *bctx) ++{ ++ return (struct nouveau_bufref_priv *)bctx; ++} ++ ++struct nouveau_bufbin_priv { ++ struct nouveau_bufref_priv *list; ++ int relocs; ++}; ++ ++struct nouveau_bufctx_priv { ++ struct nouveau_bufctx base; ++ struct nouveau_bufref_priv *free; ++ int nr_bins; ++ struct nouveau_bufbin_priv bins[]; ++}; ++ ++static inline struct nouveau_bufctx_priv * ++nouveau_bufctx(struct nouveau_bufctx *bctx) ++{ ++ return (struct nouveau_bufctx_priv *)bctx; ++} ++ ++int ++nouveau_bufctx_new(struct nouveau_client *client, int bins, ++ struct nouveau_bufctx **pbctx) ++{ ++ struct nouveau_bufctx_priv *priv; ++ ++ priv = calloc(1, sizeof(*priv) + sizeof(priv->bins[0]) * bins); ++ if (priv) { ++ DRMINITLISTHEAD(&priv->base.head); ++ DRMINITLISTHEAD(&priv->base.pending); ++ DRMINITLISTHEAD(&priv->base.current); ++ priv->base.client = client; ++ priv->nr_bins = bins; ++ *pbctx = &priv->base; ++ return 0; ++ } ++ ++ return -ENOMEM; ++} ++ ++void ++nouveau_bufctx_del(struct nouveau_bufctx **pbctx) ++{ ++ struct nouveau_bufctx_priv *pctx = nouveau_bufctx(*pbctx); ++ struct nouveau_bufref_priv *pref; ++ if (pctx) { ++ while (pctx->nr_bins--) ++ nouveau_bufctx_reset(&pctx->base, pctx->nr_bins); ++ while ((pref = pctx->free)) { ++ pctx->free = pref->next; ++ free(pref); ++ } ++ free(pctx); ++ *pbctx = NULL; ++ } ++} ++ ++void ++nouveau_bufctx_reset(struct nouveau_bufctx *bctx, int bin) ++{ ++ struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); ++ struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; ++ struct nouveau_bufref_priv *pref; ++ ++ while ((pref = pbin->list)) { ++ DRMLISTDELINIT(&pref->base.thead); ++ pbin->list = pref->next; ++ pref->next = pctx->free; ++ pctx->free = pref; ++ } ++ ++ bctx->relocs -= pbin->relocs; ++ pbin->relocs = 0; ++} ++ ++struct nouveau_bufref * ++nouveau_bufctx_refn(struct nouveau_bufctx *bctx, int bin, ++ struct nouveau_bo *bo, uint32_t flags) ++{ ++ struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); ++ struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; ++ struct nouveau_bufref_priv *pref = pctx->free; ++ ++ if (!pref) ++ pref = malloc(sizeof(*pref)); ++ else ++ pctx->free = pref->next; ++ ++ if (pref) { ++ pref->base.bo = bo; ++ pref->base.flags = flags; ++ pref->base.packet = 0; ++ ++ DRMLISTADDTAIL(&pref->base.thead, &bctx->pending); ++ pref->bufctx = bctx; ++ pref->next = pbin->list; ++ pbin->list = pref; ++ } ++ ++ return &pref->base; ++} ++ ++struct nouveau_bufref * ++nouveau_bufctx_mthd(struct nouveau_bufctx *bctx, int bin, uint32_t packet, ++ struct nouveau_bo *bo, uint64_t data, uint32_t flags, ++ uint32_t vor, uint32_t tor) ++{ ++ struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); ++ struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; ++ struct nouveau_bufref *bref = nouveau_bufctx_refn(bctx, bin, bo, flags); ++ if (bref) { ++ bref->packet = packet; ++ bref->data = data; ++ bref->vor = vor; ++ bref->tor = tor; ++ pbin->relocs++; ++ bctx->relocs++; ++ } ++ return bref; ++} +diff --git a/drm_nouveau/libdrm_lists.h b/drm_nouveau/libdrm_lists.h +new file mode 100644 +index 0000000..8926d8d +--- /dev/null ++++ b/drm_nouveau/libdrm_lists.h +@@ -0,0 +1,118 @@ ++/************************************************************************** ++ * ++ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ */ ++ ++/* ++ * List macros heavily inspired by the Linux kernel ++ * list handling. No list looping yet. ++ */ ++ ++#include <stddef.h> ++ ++typedef struct _drmMMListHead ++{ ++ struct _drmMMListHead *prev; ++ struct _drmMMListHead *next; ++} drmMMListHead; ++ ++#define DRMINITLISTHEAD(__item) \ ++ do{ \ ++ (__item)->prev = (__item); \ ++ (__item)->next = (__item); \ ++ } while (0) ++ ++#define DRMLISTADD(__item, __list) \ ++ do { \ ++ (__item)->prev = (__list); \ ++ (__item)->next = (__list)->next; \ ++ (__list)->next->prev = (__item); \ ++ (__list)->next = (__item); \ ++ } while (0) ++ ++#define DRMLISTADDTAIL(__item, __list) \ ++ do { \ ++ (__item)->next = (__list); \ ++ (__item)->prev = (__list)->prev; \ ++ (__list)->prev->next = (__item); \ ++ (__list)->prev = (__item); \ ++ } while(0) ++ ++#define DRMLISTDEL(__item) \ ++ do { \ ++ (__item)->prev->next = (__item)->next; \ ++ (__item)->next->prev = (__item)->prev; \ ++ } while(0) ++ ++#define DRMLISTDELINIT(__item) \ ++ do { \ ++ (__item)->prev->next = (__item)->next; \ ++ (__item)->next->prev = (__item)->prev; \ ++ (__item)->next = (__item); \ ++ (__item)->prev = (__item); \ ++ } while(0) ++ ++#define DRMLISTENTRY(__type, __item, __field) \ ++ ((__type *)(((char *) (__item)) - offsetof(__type, __field))) ++ ++#define DRMLISTEMPTY(__item) ((__item)->next == (__item)) ++ ++#define DRMLISTSINGLE(__list) \ ++ (!DRMLISTEMPTY(__list) && ((__list)->next == (__list)->prev)) ++ ++#define DRMLISTFOREACH(__item, __list) \ ++ for ((__item) = (__list)->next; \ ++ (__item) != (__list); (__item) = (__item)->next) ++ ++#define DRMLISTFOREACHSAFE(__item, __temp, __list) \ ++ for ((__item) = (__list)->next, (__temp) = (__item)->next; \ ++ (__item) != (__list); \ ++ (__item) = (__temp), (__temp) = (__item)->next) ++ ++#define DRMLISTFOREACHSAFEREVERSE(__item, __temp, __list) \ ++ for ((__item) = (__list)->prev, (__temp) = (__item)->prev; \ ++ (__item) != (__list); \ ++ (__item) = (__temp), (__temp) = (__item)->prev) ++ ++#define DRMLISTFOREACHENTRY(__item, __list, __head) \ ++ for ((__item) = DRMLISTENTRY(typeof(*__item), (__list)->next, __head); \ ++ &(__item)->__head != (__list); \ ++ (__item) = DRMLISTENTRY(typeof(*__item), \ ++ (__item)->__head.next, __head)) ++ ++#define DRMLISTFOREACHENTRYSAFE(__item, __temp, __list, __head) \ ++ for ((__item) = DRMLISTENTRY(typeof(*__item), (__list)->next, __head), \ ++ (__temp) = DRMLISTENTRY(typeof(*__item), \ ++ (__item)->__head.next, __head); \ ++ &(__item)->__head != (__list); \ ++ (__item) = (__temp), \ ++ (__temp) = DRMLISTENTRY(typeof(*__item), \ ++ (__temp)->__head.next, __head)) ++ ++#define DRMLISTJOIN(__list, __join) if (!DRMLISTEMPTY(__list)) { \ ++ (__list)->next->prev = (__join); \ ++ (__list)->prev->next = (__join)->next; \ ++ (__join)->next->prev = (__list)->prev; \ ++ (__join)->next = (__list)->next; \ ++} +diff --git a/drm_nouveau/nouveau.c b/drm_nouveau/nouveau.c +new file mode 100644 +index 0000000..5aa4107 +--- /dev/null ++++ b/drm_nouveau/nouveau.c +@@ -0,0 +1,492 @@ ++/* ++ * Copyright 2012 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdint.h> ++#include <string.h> ++#include <stdbool.h> ++#include <assert.h> ++#include <errno.h> ++#include <sys/mman.h> ++ ++#include <xf86drm.h> ++#include <xf86atomic.h> ++#include "libdrm_lists.h" ++#include "nouveau_drm.h" ++ ++#include "nouveau.h" ++#include "private.h" ++ ++#ifdef DEBUG ++uint32_t nouveau_debug = 0; ++ ++static void ++debug_init(char *args) ++{ ++ if (args) { ++ int n = strtol(args, NULL, 0); ++ if (n >= 0) ++ nouveau_debug = n; ++ } ++} ++#endif ++ ++/* this is the old libdrm's version of nouveau_device_wrap(), the symbol ++ * is kept here to prevent AIGLX from crashing if the DDX is linked against ++ * the new libdrm, but the DRI driver against the old ++ */ ++int ++nouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd, ++ drm_context_t ctx) ++{ ++ return -EACCES; ++} ++ ++int ++nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev) ++{ ++ struct nouveau_device_priv *nvdev = calloc(1, sizeof(*nvdev)); ++ struct nouveau_device *dev = &nvdev->base; ++ uint64_t chipset, vram, gart, bousage; ++ drmVersionPtr ver; ++ int ret; ++ ++#ifdef DEBUG ++ debug_init(getenv("NOUVEAU_LIBDRM_DEBUG")); ++#endif ++ ++ if (!nvdev) ++ return -ENOMEM; ++ nvdev->base.fd = fd; ++ ++ ver = drmGetVersion(fd); ++ if (ver) dev->drm_version = (ver->version_major << 24) | ++ (ver->version_minor << 8) | ++ ver->version_patchlevel; ++ drmFreeVersion(ver); ++ ++ if ( dev->drm_version != 0x00000010 && ++ (dev->drm_version < 0x01000000 || ++ dev->drm_version >= 0x02000000)) { ++ nouveau_device_del(&dev); ++ return -EINVAL; ++ } ++ ++ ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &chipset); ++ if (ret == 0) ++ ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &vram); ++ if (ret == 0) ++ ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &gart); ++ if (ret) { ++ nouveau_device_del(&dev); ++ return ret; ++ } ++ ++ ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &bousage); ++ if (ret == 0) ++ nvdev->have_bo_usage = (bousage != 0); ++ ++ nvdev->close = close; ++ DRMINITLISTHEAD(&nvdev->bo_list); ++ nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS; ++ nvdev->base.lib_version = 0x01000000; ++ nvdev->base.chipset = chipset; ++ nvdev->base.vram_size = vram; ++ nvdev->base.gart_size = gart; ++ nvdev->base.vram_limit = (nvdev->base.vram_size * 80) / 100; ++ nvdev->base.gart_limit = (nvdev->base.gart_size * 80) / 100; ++ ++ *pdev = &nvdev->base; ++ return 0; ++} ++ ++int ++nouveau_device_open(const char *busid, struct nouveau_device **pdev) ++{ ++ int ret = -ENODEV, fd = drmOpen("nouveau", busid); ++ if (fd >= 0) { ++ ret = nouveau_device_wrap(fd, 1, pdev); ++ if (ret) ++ drmClose(fd); ++ } ++ return ret; ++} ++ ++void ++nouveau_device_del(struct nouveau_device **pdev) ++{ ++ struct nouveau_device_priv *nvdev = nouveau_device(*pdev); ++ if (nvdev) { ++ if (nvdev->close) ++ drmClose(nvdev->base.fd); ++ free(nvdev->client); ++ free(nvdev); ++ *pdev = NULL; ++ } ++} ++ ++int ++nouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value) ++{ ++ struct drm_nouveau_getparam r = { param, 0 }; ++ int fd = dev->fd, ret = ++ drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r)); ++ *value = r.value; ++ return ret; ++} ++ ++int ++nouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value) ++{ ++ struct drm_nouveau_setparam r = { param, value }; ++ return drmCommandWrite(dev->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r)); ++} ++ ++int ++nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient) ++{ ++ struct nouveau_device_priv *nvdev = nouveau_device(dev); ++ struct nouveau_client_priv *pcli; ++ int id = 0, i, ret = -ENOMEM; ++ uint32_t *clients; ++ ++ for (i = 0; i < nvdev->nr_client; i++) { ++ id = ffs(nvdev->client[i]) - 1; ++ if (id >= 0) ++ goto out; ++ } ++ ++ clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1)); ++ if (!clients) ++ return ret; ++ nvdev->client = clients; ++ nvdev->client[i] = 0; ++ nvdev->nr_client++; ++ ++out: ++ pcli = calloc(1, sizeof(*pcli)); ++ if (pcli) { ++ nvdev->client[i] |= (1 << id); ++ pcli->base.device = dev; ++ pcli->base.id = (i * 32) + id; ++ ret = 0; ++ } ++ ++ *pclient = &pcli->base; ++ return ret; ++} ++ ++void ++nouveau_client_del(struct nouveau_client **pclient) ++{ ++ struct nouveau_client_priv *pcli = nouveau_client(*pclient); ++ struct nouveau_device_priv *nvdev; ++ if (pcli) { ++ int id = pcli->base.id; ++ nvdev = nouveau_device(pcli->base.device); ++ nvdev->client[id / 32] &= ~(1 << (id % 32)); ++ free(pcli->kref); ++ free(pcli); ++ } ++} ++ ++int ++nouveau_object_new(struct nouveau_object *parent, uint64_t handle, ++ uint32_t oclass, void *data, uint32_t length, ++ struct nouveau_object **pobj) ++{ ++ struct nouveau_device *dev; ++ struct nouveau_object *obj; ++ int ret = -EINVAL; ++ ++ if (length == 0) ++ length = sizeof(struct nouveau_object *); ++ obj = malloc(sizeof(*obj) + length); ++ obj->parent = parent; ++ obj->handle = handle; ++ obj->oclass = oclass; ++ obj->length = length; ++ obj->data = obj + 1; ++ if (data) ++ memcpy(obj->data, data, length); ++ *(struct nouveau_object **)obj->data = obj; ++ ++ dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); ++ switch (parent->oclass) { ++ case NOUVEAU_DEVICE_CLASS: ++ switch (obj->oclass) { ++ case NOUVEAU_FIFO_CHANNEL_CLASS: ++ { ++ if (dev->chipset < 0xc0) ++ ret = abi16_chan_nv04(obj); ++ else ++ ret = abi16_chan_nvc0(obj); ++ } ++ break; ++ default: ++ break; ++ } ++ break; ++ case NOUVEAU_FIFO_CHANNEL_CLASS: ++ switch (obj->oclass) { ++ case NOUVEAU_NOTIFIER_CLASS: ++ ret = abi16_ntfy(obj); ++ break; ++ default: ++ ret = abi16_engobj(obj); ++ break; ++ } ++ default: ++ break; ++ } ++ ++ if (ret) { ++ free(obj); ++ return ret; ++ } ++ ++ *pobj = obj; ++ return 0; ++} ++ ++void ++nouveau_object_del(struct nouveau_object **pobj) ++{ ++ struct nouveau_object *obj = *pobj; ++ struct nouveau_device *dev; ++ if (obj) { ++ dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); ++ if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) { ++ struct drm_nouveau_channel_free req; ++ req.channel = obj->handle; ++ drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE, ++ &req, sizeof(req)); ++ } else { ++ struct drm_nouveau_gpuobj_free req; ++ req.channel = obj->parent->handle; ++ req.handle = obj->handle; ++ drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE, ++ &req, sizeof(req)); ++ } ++ } ++ free(obj); ++ *pobj = NULL; ++} ++ ++void * ++nouveau_object_find(struct nouveau_object *obj, uint32_t pclass) ++{ ++ while (obj && obj->oclass != pclass) { ++ obj = obj->parent; ++ if (pclass == NOUVEAU_PARENT_CLASS) ++ break; ++ } ++ return obj; ++} ++ ++static void ++nouveau_bo_del(struct nouveau_bo *bo) ++{ ++ struct nouveau_bo_priv *nvbo = nouveau_bo(bo); ++ struct drm_gem_close req = { bo->handle }; ++ DRMLISTDEL(&nvbo->head); ++ if (bo->map) ++ munmap(bo->map, bo->size); ++ drmIoctl(bo->device->fd, DRM_IOCTL_GEM_CLOSE, &req); ++ free(nvbo); ++} ++ ++int ++nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align, ++ uint64_t size, union nouveau_bo_config *config, ++ struct nouveau_bo **pbo) ++{ ++ struct nouveau_device_priv *nvdev = nouveau_device(dev); ++ struct nouveau_bo_priv *nvbo = calloc(1, sizeof(*nvbo)); ++ struct nouveau_bo *bo = &nvbo->base; ++ int ret; ++ ++ if (!nvbo) ++ return -ENOMEM; ++ atomic_set(&nvbo->refcnt, 1); ++ bo->device = dev; ++ bo->flags = flags; ++ bo->size = size; ++ ++ ret = abi16_bo_init(bo, align, config); ++ if (ret) { ++ free(nvbo); ++ return ret; ++ } ++ ++ DRMLISTADD(&nvbo->head, &nvdev->bo_list); ++ ++ *pbo = bo; ++ return 0; ++} ++ ++int ++nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle, ++ struct nouveau_bo **pbo) ++{ ++ struct nouveau_device_priv *nvdev = nouveau_device(dev); ++ struct drm_nouveau_gem_info req = { .handle = handle }; ++ struct nouveau_bo_priv *nvbo; ++ int ret; ++ ++ DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { ++ if (nvbo->base.handle == handle) { ++ *pbo = NULL; ++ nouveau_bo_ref(&nvbo->base, pbo); ++ return 0; ++ } ++ } ++ ++ ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_INFO, ++ &req, sizeof(req)); ++ if (ret) ++ return ret; ++ ++ nvbo = calloc(1, sizeof(*nvbo)); ++ if (nvbo) { ++ atomic_set(&nvbo->refcnt, 1); ++ nvbo->base.device = dev; ++ abi16_bo_info(&nvbo->base, &req); ++ DRMLISTADD(&nvbo->head, &nvdev->bo_list); ++ *pbo = &nvbo->base; ++ return 0; ++ } ++ ++ return -ENOMEM; ++} ++ ++int ++nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name, ++ struct nouveau_bo **pbo) ++{ ++ struct nouveau_device_priv *nvdev = nouveau_device(dev); ++ struct nouveau_bo_priv *nvbo; ++ struct drm_gem_open req = { .name = name }; ++ int ret; ++ ++ DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { ++ if (nvbo->name == name) { ++ *pbo = NULL; -- To UNSUBSCRIBE, email to [email protected] with a subject of "unsubscribe". Trouble? Contact [email protected] Archive: http://lists.debian.org/[email protected]

