nouveau: pull in major libdrm rewrite
Redesigned primarily to allow us to better take advantage of BO's having fixed GPU virtual addresses on GeForce 8 and up, and to reduce the overhead of handling relocations on earlier chipsets. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Christoph Bumiller <e0425955@student.tuwien.ac.at>main
parent
0d6350002d
commit
292da616fe
25
configure.ac
25
configure.ac
|
@ -73,16 +73,16 @@ AC_ARG_ENABLE(radeon,
|
||||||
[Enable support for radeon's KMS API (default: auto)]),
|
[Enable support for radeon's KMS API (default: auto)]),
|
||||||
[RADEON=$enableval], [RADEON=auto])
|
[RADEON=$enableval], [RADEON=auto])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(nouveau,
|
||||||
|
AS_HELP_STRING([--disable-nouveau],
|
||||||
|
[Enable support for nouveau's KMS API (default: auto)]),
|
||||||
|
[NOUVEAU=$enableval], [NOUVEAU=auto])
|
||||||
|
|
||||||
AC_ARG_ENABLE(vmwgfx-experimental-api,
|
AC_ARG_ENABLE(vmwgfx-experimental-api,
|
||||||
AS_HELP_STRING([--enable-vmwgfx-experimental-api],
|
AS_HELP_STRING([--enable-vmwgfx-experimental-api],
|
||||||
[Install vmwgfx's experimental kernel API header (default: disabled)]),
|
[Install vmwgfx's experimental kernel API header (default: disabled)]),
|
||||||
[VMWGFX=$enableval], [VMWGFX=no])
|
[VMWGFX=$enableval], [VMWGFX=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(nouveau-experimental-api,
|
|
||||||
AS_HELP_STRING([--enable-nouveau-experimental-api],
|
|
||||||
[Enable support for nouveau's experimental API (default: disabled)]),
|
|
||||||
[NOUVEAU=$enableval], [NOUVEAU=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(omap-experimental-api,
|
AC_ARG_ENABLE(omap-experimental-api,
|
||||||
AS_HELP_STRING([--enable-omap-experimental-api],
|
AS_HELP_STRING([--enable-omap-experimental-api],
|
||||||
[Enable support for OMAP's experimental API (default: disabled)]),
|
[Enable support for OMAP's experimental API (default: disabled)]),
|
||||||
|
@ -204,7 +204,7 @@ if test "x$HAVE_LIBUDEV" = xyes; then
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(HAVE_LIBUDEV, [test "x$HAVE_LIBUDEV" = xyes])
|
AM_CONDITIONAL(HAVE_LIBUDEV, [test "x$HAVE_LIBUDEV" = xyes])
|
||||||
|
|
||||||
if test "x$INTEL" != "xno" -o "x$RADEON" != "xno"; then
|
if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno"; then
|
||||||
# Check for atomic intrinsics
|
# Check for atomic intrinsics
|
||||||
AC_CACHE_CHECK([for native atomic primitives], drm_cv_atomic_primitives,
|
AC_CACHE_CHECK([for native atomic primitives], drm_cv_atomic_primitives,
|
||||||
[
|
[
|
||||||
|
@ -252,7 +252,14 @@ if test "x$INTEL" != "xno" -o "x$RADEON" != "xno"; then
|
||||||
AC_MSG_WARN([Disabling libdrm_radeon. It depends on atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package.])
|
AC_MSG_WARN([Disabling libdrm_radeon. It depends on atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package.])
|
||||||
RADEON=no
|
RADEON=no
|
||||||
fi
|
fi
|
||||||
|
if test "x$NOUVEAU" != "xauto"; then
|
||||||
|
if test "x$NOUVEAU" != "xno"; then
|
||||||
|
AC_MSG_ERROR([libdrm_nouveau depends upon atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package, or, failing both of those, disable support for NVIDIA GPUs by passing --disable-nouveau to ./configure])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([Disabling libdrm_nouveau. It depends on atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package.])
|
||||||
|
NOUVEAU=no
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
if test "x$INTEL" != "xno"; then
|
if test "x$INTEL" != "xno"; then
|
||||||
case $host_cpu in
|
case $host_cpu in
|
||||||
|
@ -263,6 +270,9 @@ if test "x$INTEL" != "xno" -o "x$RADEON" != "xno"; then
|
||||||
if test "x$RADEON" != "xno"; then
|
if test "x$RADEON" != "xno"; then
|
||||||
RADEON=yes
|
RADEON=yes
|
||||||
fi
|
fi
|
||||||
|
if test "x$NOUVEAU" != "xno"; then
|
||||||
|
NOUVEAU=yes
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -279,6 +289,7 @@ fi
|
||||||
|
|
||||||
AM_CONDITIONAL(HAVE_INTEL, [test "x$INTEL" != "xno"])
|
AM_CONDITIONAL(HAVE_INTEL, [test "x$INTEL" != "xno"])
|
||||||
AM_CONDITIONAL(HAVE_RADEON, [test "x$RADEON" != "xno"])
|
AM_CONDITIONAL(HAVE_RADEON, [test "x$RADEON" != "xno"])
|
||||||
|
AM_CONDITIONAL(HAVE_NOUVEAU, [test "x$NOUVEAU" != "xno"])
|
||||||
if test "x$RADEON" = xyes; then
|
if test "x$RADEON" = xyes; then
|
||||||
AC_DEFINE(HAVE_RADEON, 1, [Have radeon support])
|
AC_DEFINE(HAVE_RADEON, 1, [Have radeon support])
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -3,41 +3,23 @@ AM_CFLAGS = \
|
||||||
-I$(top_srcdir) \
|
-I$(top_srcdir) \
|
||||||
-I$(top_srcdir)/nouveau \
|
-I$(top_srcdir)/nouveau \
|
||||||
$(PTHREADSTUBS_CFLAGS) \
|
$(PTHREADSTUBS_CFLAGS) \
|
||||||
-I$(top_srcdir)/include/drm
|
-I$(top_srcdir)/include/drm \
|
||||||
|
-DDEBUG
|
||||||
|
|
||||||
libdrm_nouveau_la_LTLIBRARIES = libdrm_nouveau.la
|
libdrm_nouveau_la_LTLIBRARIES = libdrm_nouveau.la
|
||||||
libdrm_nouveau_ladir = $(libdir)
|
libdrm_nouveau_ladir = $(libdir)
|
||||||
libdrm_nouveau_la_LDFLAGS = -version-number 1:0:0 -no-undefined
|
libdrm_nouveau_la_LDFLAGS = -version-number 2:0:0 -no-undefined
|
||||||
libdrm_nouveau_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
|
libdrm_nouveau_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
|
||||||
|
|
||||||
libdrm_nouveau_la_SOURCES = \
|
libdrm_nouveau_la_SOURCES = nouveau.c \
|
||||||
nouveau_device.c \
|
pushbuf.c \
|
||||||
nouveau_channel.c \
|
bufctx.c \
|
||||||
nouveau_pushbuf.c \
|
abi16.c \
|
||||||
nouveau_grobj.c \
|
private.h
|
||||||
nouveau_notifier.c \
|
|
||||||
nouveau_bo.c \
|
|
||||||
nouveau_resource.c \
|
|
||||||
nouveau_private.h \
|
|
||||||
nouveau_reloc.c
|
|
||||||
|
|
||||||
libdrm_nouveaucommonincludedir = ${includedir}/nouveau
|
|
||||||
libdrm_nouveaucommoninclude_HEADERS = \
|
|
||||||
nouveau_device.h \
|
|
||||||
nouveau_channel.h \
|
|
||||||
nouveau_grobj.h \
|
|
||||||
nouveau_notifier.h \
|
|
||||||
nouveau_pushbuf.h \
|
|
||||||
nv04_pushbuf.h \
|
|
||||||
nvc0_pushbuf.h \
|
|
||||||
nouveau_bo.h \
|
|
||||||
nouveau_resource.h \
|
|
||||||
nouveau_reloc.h
|
|
||||||
|
|
||||||
|
|
||||||
libdrm_nouveauincludedir = ${includedir}/libdrm
|
libdrm_nouveauincludedir = ${includedir}/libdrm
|
||||||
libdrm_nouveauinclude_HEADERS = \
|
libdrm_nouveauinclude_HEADERS = nouveau.h
|
||||||
nouveau_drmif.h
|
|
||||||
|
|
||||||
pkgconfigdir = @pkgconfigdir@
|
pkgconfigdir = @pkgconfigdir@
|
||||||
pkgconfig_DATA = libdrm_nouveau.pc
|
pkgconfig_DATA = libdrm_nouveau.pc
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* 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->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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ includedir=@includedir@
|
||||||
|
|
||||||
Name: libdrm_nouveau
|
Name: libdrm_nouveau
|
||||||
Description: Userspace interface to nouveau kernel DRM services
|
Description: Userspace interface to nouveau kernel DRM services
|
||||||
Version: 0.6
|
Version: 2.4.33
|
||||||
Libs: -L${libdir} -ldrm_nouveau
|
Libs: -L${libdir} -ldrm_nouveau
|
||||||
Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/nouveau
|
Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/nouveau
|
||||||
Requires.private: libdrm
|
Requires.private: libdrm
|
||||||
|
|
|
@ -0,0 +1,489 @@
|
||||||
|
/*
|
||||||
|
* 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 drm_nouveau_gpuobj_free req;
|
||||||
|
struct nouveau_object *obj = *pobj;
|
||||||
|
struct nouveau_device *dev;
|
||||||
|
if (obj) {
|
||||||
|
dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
|
||||||
|
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;
|
||||||
|
nouveau_bo_ref(&nvbo->base, pbo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = nouveau_bo_wrap(dev, req.handle, pbo);
|
||||||
|
nouveau_bo((*pbo))->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name)
|
||||||
|
{
|
||||||
|
struct drm_gem_flink req = { .handle = bo->handle };
|
||||||
|
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
||||||
|
if (!nvbo->name) {
|
||||||
|
int ret = drmIoctl(bo->device->fd, DRM_IOCTL_GEM_FLINK, &req);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
nvbo->name = req.name;
|
||||||
|
}
|
||||||
|
*name = nvbo->name;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref)
|
||||||
|
{
|
||||||
|
struct nouveau_bo *ref = *pref;
|
||||||
|
if (bo) {
|
||||||
|
atomic_inc(&nouveau_bo(bo)->refcnt);
|
||||||
|
}
|
||||||
|
if (ref) {
|
||||||
|
if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt))
|
||||||
|
nouveau_bo_del(ref);
|
||||||
|
}
|
||||||
|
*pref = bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_bo_wait(struct nouveau_bo *bo, uint32_t access,
|
||||||
|
struct nouveau_client *client)
|
||||||
|
{
|
||||||
|
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
||||||
|
struct drm_nouveau_gem_cpu_prep req;
|
||||||
|
struct nouveau_pushbuf *push;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!(access & NOUVEAU_BO_RDWR))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
push = cli_push_get(client, bo);
|
||||||
|
if (push && push->channel)
|
||||||
|
nouveau_pushbuf_kick(push, push->channel);
|
||||||
|
|
||||||
|
if (!nvbo->name && !(nvbo->access & NOUVEAU_BO_WR) &&
|
||||||
|
!( access & NOUVEAU_BO_WR))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
req.handle = bo->handle;
|
||||||
|
req.flags = 0;
|
||||||
|
if (access & NOUVEAU_BO_WR)
|
||||||
|
req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
|
||||||
|
if (access & NOUVEAU_BO_NOBLOCK)
|
||||||
|
req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = drmCommandWrite(bo->device->fd,
|
||||||
|
DRM_NOUVEAU_GEM_CPU_PREP,
|
||||||
|
&req, sizeof(req));
|
||||||
|
} while (ret == -EAGAIN);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
nvbo->access = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_bo_map(struct nouveau_bo *bo, uint32_t access,
|
||||||
|
struct nouveau_client *client)
|
||||||
|
{
|
||||||
|
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
||||||
|
if (bo->map == NULL) {
|
||||||
|
bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED, bo->device->fd, nvbo->map_handle);
|
||||||
|
if (bo->map == MAP_FAILED) {
|
||||||
|
bo->map = NULL;
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nouveau_bo_wait(bo, access, client);
|
||||||
|
}
|
|
@ -0,0 +1,211 @@
|
||||||
|
#ifndef __NOUVEAU_H__
|
||||||
|
#define __NOUVEAU_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define NOUVEAU_DEVICE_CLASS 0x80000000
|
||||||
|
#define NOUVEAU_FIFO_CHANNEL_CLASS 0x80000001
|
||||||
|
#define NOUVEAU_NOTIFIER_CLASS 0x80000002
|
||||||
|
#define NOUVEAU_PARENT_CLASS 0xffffffff
|
||||||
|
|
||||||
|
struct nouveau_list {
|
||||||
|
struct nouveau_list *prev;
|
||||||
|
struct nouveau_list *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nouveau_object {
|
||||||
|
struct nouveau_object *parent;
|
||||||
|
uint64_t handle;
|
||||||
|
uint32_t oclass;
|
||||||
|
uint32_t length;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nouveau_fifo {
|
||||||
|
struct nouveau_object *object;
|
||||||
|
uint32_t channel;
|
||||||
|
uint32_t pushbuf;
|
||||||
|
uint64_t unused1[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nv04_fifo {
|
||||||
|
struct nouveau_fifo base;
|
||||||
|
uint32_t vram;
|
||||||
|
uint32_t gart;
|
||||||
|
uint32_t notify;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nvc0_fifo {
|
||||||
|
struct nouveau_fifo base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nv04_notify {
|
||||||
|
struct nouveau_object *object;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
int nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
|
||||||
|
uint32_t oclass, void *data, uint32_t length,
|
||||||
|
struct nouveau_object **);
|
||||||
|
void nouveau_object_del(struct nouveau_object **);
|
||||||
|
void *nouveau_object_find(struct nouveau_object *, uint32_t parent_class);
|
||||||
|
|
||||||
|
struct nouveau_device {
|
||||||
|
struct nouveau_object object;
|
||||||
|
int fd;
|
||||||
|
uint32_t lib_version;
|
||||||
|
uint32_t drm_version;
|
||||||
|
uint32_t chipset;
|
||||||
|
uint64_t vram_size;
|
||||||
|
uint64_t gart_size;
|
||||||
|
uint64_t vram_limit;
|
||||||
|
uint64_t gart_limit;
|
||||||
|
};
|
||||||
|
|
||||||
|
int nouveau_device_wrap(int fd, int close, struct nouveau_device **);
|
||||||
|
int nouveau_device_open(const char *busid, struct nouveau_device **);
|
||||||
|
void nouveau_device_del(struct nouveau_device **);
|
||||||
|
int nouveau_getparam(struct nouveau_device *, uint64_t param, uint64_t *value);
|
||||||
|
int nouveau_setparam(struct nouveau_device *, uint64_t param, uint64_t value);
|
||||||
|
|
||||||
|
struct nouveau_client {
|
||||||
|
struct nouveau_device *device;
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
|
||||||
|
int nouveau_client_new(struct nouveau_device *, struct nouveau_client **);
|
||||||
|
void nouveau_client_del(struct nouveau_client **);
|
||||||
|
|
||||||
|
union nouveau_bo_config {
|
||||||
|
struct {
|
||||||
|
#define NV04_BO_16BPP 0x00000001
|
||||||
|
#define NV04_BO_32BPP 0x00000002
|
||||||
|
#define NV04_BO_ZETA 0x00000004
|
||||||
|
uint32_t surf_flags;
|
||||||
|
uint32_t surf_pitch;
|
||||||
|
} nv04;
|
||||||
|
struct {
|
||||||
|
uint32_t memtype;
|
||||||
|
uint32_t tile_mode;
|
||||||
|
} nv50;
|
||||||
|
struct {
|
||||||
|
uint32_t memtype;
|
||||||
|
uint32_t tile_mode;
|
||||||
|
} nvc0;
|
||||||
|
uint32_t data[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NOUVEAU_BO_VRAM 0x00000001
|
||||||
|
#define NOUVEAU_BO_GART 0x00000002
|
||||||
|
#define NOUVEAU_BO_APER (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)
|
||||||
|
#define NOUVEAU_BO_RD 0x00000100
|
||||||
|
#define NOUVEAU_BO_WR 0x00000200
|
||||||
|
#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR)
|
||||||
|
#define NOUVEAU_BO_NOBLOCK 0x00000400
|
||||||
|
#define NOUVEAU_BO_LOW 0x00001000
|
||||||
|
#define NOUVEAU_BO_HIGH 0x00002000
|
||||||
|
#define NOUVEAU_BO_OR 0x00004000
|
||||||
|
#define NOUVEAU_BO_MAP 0x80000000
|
||||||
|
#define NOUVEAU_BO_CONTIG 0x40000000
|
||||||
|
#define NOUVEAU_BO_NOSNOOP 0x20000000
|
||||||
|
|
||||||
|
struct nouveau_bo {
|
||||||
|
struct nouveau_device *device;
|
||||||
|
uint32_t handle;
|
||||||
|
uint64_t size;
|
||||||
|
uint32_t flags;
|
||||||
|
uint64_t offset;
|
||||||
|
void *map;
|
||||||
|
union nouveau_bo_config config;
|
||||||
|
};
|
||||||
|
|
||||||
|
int nouveau_bo_new(struct nouveau_device *, uint32_t flags, uint32_t align,
|
||||||
|
uint64_t size, union nouveau_bo_config *,
|
||||||
|
struct nouveau_bo **);
|
||||||
|
int nouveau_bo_wrap(struct nouveau_device *, uint32_t handle,
|
||||||
|
struct nouveau_bo **);
|
||||||
|
int nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name,
|
||||||
|
struct nouveau_bo **);
|
||||||
|
int nouveau_bo_name_get(struct nouveau_bo *, uint32_t *name);
|
||||||
|
void nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **);
|
||||||
|
int nouveau_bo_map(struct nouveau_bo *, uint32_t access,
|
||||||
|
struct nouveau_client *);
|
||||||
|
int nouveau_bo_wait(struct nouveau_bo *, uint32_t access,
|
||||||
|
struct nouveau_client *);
|
||||||
|
|
||||||
|
struct nouveau_bufref {
|
||||||
|
struct nouveau_list thead;
|
||||||
|
struct nouveau_bo *bo;
|
||||||
|
uint32_t packet;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t vor;
|
||||||
|
uint32_t tor;
|
||||||
|
uint32_t priv_data;
|
||||||
|
void *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nouveau_bufctx {
|
||||||
|
struct nouveau_client *client;
|
||||||
|
struct nouveau_list head;
|
||||||
|
struct nouveau_list pending;
|
||||||
|
struct nouveau_list current;
|
||||||
|
int relocs;
|
||||||
|
};
|
||||||
|
|
||||||
|
int nouveau_bufctx_new(struct nouveau_client *, int bins,
|
||||||
|
struct nouveau_bufctx **);
|
||||||
|
void nouveau_bufctx_del(struct nouveau_bufctx **);
|
||||||
|
struct nouveau_bufref *
|
||||||
|
nouveau_bufctx_refn(struct nouveau_bufctx *, int bin,
|
||||||
|
struct nouveau_bo *, uint32_t flags);
|
||||||
|
struct nouveau_bufref *
|
||||||
|
nouveau_bufctx_mthd(struct nouveau_bufctx *, int bin, uint32_t packet,
|
||||||
|
struct nouveau_bo *, uint64_t data, uint32_t flags,
|
||||||
|
uint32_t vor, uint32_t tor);
|
||||||
|
void nouveau_bufctx_reset(struct nouveau_bufctx *, int bin);
|
||||||
|
|
||||||
|
struct nouveau_pushbuf_krec;
|
||||||
|
struct nouveau_pushbuf {
|
||||||
|
struct nouveau_client *client;
|
||||||
|
struct nouveau_object *channel;
|
||||||
|
struct nouveau_bufctx *bufctx;
|
||||||
|
void (*kick_notify)(struct nouveau_pushbuf *);
|
||||||
|
void *user_priv;
|
||||||
|
uint32_t rsvd_kick;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t *cur;
|
||||||
|
uint32_t *end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nouveau_pushbuf_refn {
|
||||||
|
struct nouveau_bo *bo;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
int nouveau_pushbuf_new(struct nouveau_client *, struct nouveau_object *channel,
|
||||||
|
int nr, uint32_t size, bool immediate,
|
||||||
|
struct nouveau_pushbuf **);
|
||||||
|
void nouveau_pushbuf_del(struct nouveau_pushbuf **);
|
||||||
|
int nouveau_pushbuf_space(struct nouveau_pushbuf *, uint32_t dwords,
|
||||||
|
uint32_t relocs, uint32_t pushes);
|
||||||
|
void nouveau_pushbuf_data(struct nouveau_pushbuf *, struct nouveau_bo *,
|
||||||
|
uint64_t offset, uint64_t length);
|
||||||
|
int nouveau_pushbuf_refn(struct nouveau_pushbuf *,
|
||||||
|
struct nouveau_pushbuf_refn *, int nr);
|
||||||
|
/* Emits a reloc into the push buffer at the current position, you *must*
|
||||||
|
* have previously added the referenced buffer to a buffer context, and
|
||||||
|
* validated it against the current push buffer.
|
||||||
|
*/
|
||||||
|
void nouveau_pushbuf_reloc(struct nouveau_pushbuf *, struct nouveau_bo *,
|
||||||
|
uint32_t data, uint32_t flags,
|
||||||
|
uint32_t vor, uint32_t tor);
|
||||||
|
int nouveau_pushbuf_validate(struct nouveau_pushbuf *);
|
||||||
|
uint32_t nouveau_pushbuf_refd(struct nouveau_pushbuf *, struct nouveau_bo *);
|
||||||
|
int nouveau_pushbuf_kick(struct nouveau_pushbuf *, struct nouveau_object *channel);
|
||||||
|
struct nouveau_bufctx *
|
||||||
|
nouveau_pushbuf_bufctx(struct nouveau_pushbuf *, struct nouveau_bufctx *);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,549 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_init(struct nouveau_device *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_bo_takedown(struct nouveau_device *dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_bo_info(struct nouveau_bo_priv *nvbo, struct drm_nouveau_gem_info *arg)
|
|
||||||
{
|
|
||||||
nvbo->handle = nvbo->base.handle = arg->handle;
|
|
||||||
nvbo->domain = arg->domain;
|
|
||||||
nvbo->size = arg->size;
|
|
||||||
nvbo->offset = arg->offset;
|
|
||||||
nvbo->map_handle = arg->map_handle;
|
|
||||||
nvbo->base.tile_mode = arg->tile_mode;
|
|
||||||
/* XXX - flag inverted for backwards compatibility */
|
|
||||||
nvbo->base.tile_flags = arg->tile_flags ^ NOUVEAU_GEM_TILE_NONCONTIG;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_bo_allocated(struct nouveau_bo_priv *nvbo)
|
|
||||||
{
|
|
||||||
if (nvbo->sysmem || nvbo->handle)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_bo_ualloc(struct nouveau_bo_priv *nvbo)
|
|
||||||
{
|
|
||||||
if (nvbo->user || nvbo->sysmem) {
|
|
||||||
assert(nvbo->sysmem);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvbo->sysmem = malloc(nvbo->size);
|
|
||||||
if (!nvbo->sysmem)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nouveau_bo_ufree(struct nouveau_bo_priv *nvbo)
|
|
||||||
{
|
|
||||||
if (nvbo->sysmem) {
|
|
||||||
if (!nvbo->user)
|
|
||||||
free(nvbo->sysmem);
|
|
||||||
nvbo->sysmem = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nouveau_bo_kfree(struct nouveau_bo_priv *nvbo)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
|
|
||||||
struct drm_gem_close req;
|
|
||||||
|
|
||||||
if (!nvbo->handle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (nvbo->map) {
|
|
||||||
munmap(nvbo->map, nvbo->size);
|
|
||||||
nvbo->map = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
req.handle = nvbo->handle;
|
|
||||||
nvbo->handle = 0;
|
|
||||||
drmIoctl(nvdev->fd, DRM_IOCTL_GEM_CLOSE, &req);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_bo_kalloc(struct nouveau_bo_priv *nvbo, struct nouveau_channel *chan)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
|
|
||||||
struct drm_nouveau_gem_new req;
|
|
||||||
struct drm_nouveau_gem_info *info = &req.info;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (nvbo->handle)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
req.channel_hint = chan ? chan->id : 0;
|
|
||||||
req.align = nvbo->align;
|
|
||||||
|
|
||||||
|
|
||||||
info->size = nvbo->size;
|
|
||||||
info->domain = 0;
|
|
||||||
|
|
||||||
if (nvbo->flags & NOUVEAU_BO_VRAM)
|
|
||||||
info->domain |= NOUVEAU_GEM_DOMAIN_VRAM;
|
|
||||||
if (nvbo->flags & NOUVEAU_BO_GART)
|
|
||||||
info->domain |= NOUVEAU_GEM_DOMAIN_GART;
|
|
||||||
if (!info->domain) {
|
|
||||||
info->domain |= (NOUVEAU_GEM_DOMAIN_VRAM |
|
|
||||||
NOUVEAU_GEM_DOMAIN_GART);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvbo->flags & NOUVEAU_BO_MAP)
|
|
||||||
info->domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE;
|
|
||||||
|
|
||||||
info->tile_mode = nvbo->base.tile_mode;
|
|
||||||
info->tile_flags = nvbo->base.tile_flags;
|
|
||||||
/* XXX - flag inverted for backwards compatibility */
|
|
||||||
info->tile_flags ^= NOUVEAU_GEM_TILE_NONCONTIG;
|
|
||||||
if (!nvdev->has_bo_usage)
|
|
||||||
info->tile_flags &= NOUVEAU_GEM_TILE_LAYOUT_MASK;
|
|
||||||
|
|
||||||
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_NEW,
|
|
||||||
&req, sizeof(req));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
nouveau_bo_info(nvbo, &req.info);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_bo_kmap(struct nouveau_bo_priv *nvbo)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
|
|
||||||
|
|
||||||
if (nvbo->map)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!nvbo->map_handle)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
nvbo->map = mmap(0, nvbo->size, PROT_READ | PROT_WRITE,
|
|
||||||
MAP_SHARED, nvdev->fd, nvbo->map_handle);
|
|
||||||
if (nvbo->map == MAP_FAILED) {
|
|
||||||
nvbo->map = NULL;
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_new_tile(struct nouveau_device *dev, uint32_t flags, int align,
|
|
||||||
int size, uint32_t tile_mode, uint32_t tile_flags,
|
|
||||||
struct nouveau_bo **bo)
|
|
||||||
{
|
|
||||||
struct nouveau_bo_priv *nvbo;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!dev || !bo || *bo)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
nvbo = calloc(1, sizeof(struct nouveau_bo_priv));
|
|
||||||
if (!nvbo)
|
|
||||||
return -ENOMEM;
|
|
||||||
nvbo->base.device = dev;
|
|
||||||
nvbo->base.size = size;
|
|
||||||
nvbo->base.tile_mode = tile_mode;
|
|
||||||
nvbo->base.tile_flags = tile_flags;
|
|
||||||
|
|
||||||
nvbo->refcount = 1;
|
|
||||||
nvbo->flags = flags;
|
|
||||||
nvbo->size = size;
|
|
||||||
nvbo->align = align;
|
|
||||||
|
|
||||||
if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
|
|
||||||
ret = nouveau_bo_kalloc(nvbo, NULL);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_bo_ref(NULL, (void *)&nvbo);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*bo = &nvbo->base;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align,
|
|
||||||
int size, struct nouveau_bo **bo)
|
|
||||||
{
|
|
||||||
return nouveau_bo_new_tile(dev, flags, align, size, 0, 0, bo);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_user(struct nouveau_device *dev, void *ptr, int size,
|
|
||||||
struct nouveau_bo **bo)
|
|
||||||
{
|
|
||||||
struct nouveau_bo_priv *nvbo;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = nouveau_bo_new(dev, NOUVEAU_BO_MAP, 0, size, bo);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
nvbo = nouveau_bo(*bo);
|
|
||||||
|
|
||||||
nvbo->sysmem = ptr;
|
|
||||||
nvbo->user = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
|
|
||||||
struct nouveau_bo **bo)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(dev);
|
|
||||||
struct drm_nouveau_gem_info req;
|
|
||||||
struct nouveau_bo_priv *nvbo;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = nouveau_bo_new(dev, 0, 0, 0, bo);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
nvbo = nouveau_bo(*bo);
|
|
||||||
|
|
||||||
req.handle = handle;
|
|
||||||
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_INFO,
|
|
||||||
&req, sizeof(req));
|
|
||||||
if (ret) {
|
|
||||||
nouveau_bo_ref(NULL, bo);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
nouveau_bo_info(nvbo, &req);
|
|
||||||
nvbo->base.size = nvbo->size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_handle_get(struct nouveau_bo *bo, uint32_t *handle)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!bo || !handle)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!nvbo->global_handle) {
|
|
||||||
struct drm_gem_flink req;
|
|
||||||
|
|
||||||
ret = nouveau_bo_kalloc(nvbo, NULL);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
req.handle = nvbo->handle;
|
|
||||||
ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_FLINK, &req);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_bo_kfree(nvbo);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvbo->global_handle = req.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
*handle = nvbo->global_handle;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_handle_ref(struct nouveau_device *dev, uint32_t handle,
|
|
||||||
struct nouveau_bo **bo)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(dev);
|
|
||||||
struct nouveau_bo_priv *nvbo;
|
|
||||||
struct drm_gem_open req;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
req.name = handle;
|
|
||||||
ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_OPEN, &req);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_bo_ref(NULL, bo);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nouveau_bo_wrap(dev, req.handle, bo);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_bo_ref(NULL, bo);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvbo = nouveau_bo(*bo);
|
|
||||||
nvbo->base.handle = nvbo->handle;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nouveau_bo_del(struct nouveau_bo **bo)
|
|
||||||
{
|
|
||||||
struct nouveau_bo_priv *nvbo;
|
|
||||||
|
|
||||||
if (!bo || !*bo)
|
|
||||||
return;
|
|
||||||
nvbo = nouveau_bo(*bo);
|
|
||||||
*bo = NULL;
|
|
||||||
|
|
||||||
if (--nvbo->refcount)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (nvbo->pending) {
|
|
||||||
nvbo->pending = NULL;
|
|
||||||
nouveau_pushbuf_flush(nvbo->pending_channel, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
nouveau_bo_ufree(nvbo);
|
|
||||||
nouveau_bo_kfree(nvbo);
|
|
||||||
free(nvbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pbo)
|
|
||||||
{
|
|
||||||
if (!pbo)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (ref)
|
|
||||||
nouveau_bo(ref)->refcount++;
|
|
||||||
|
|
||||||
if (*pbo)
|
|
||||||
nouveau_bo_del(pbo);
|
|
||||||
|
|
||||||
*pbo = ref;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_bo_wait(struct nouveau_bo *bo, int cpu_write, int no_wait, int no_block)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
struct drm_nouveau_gem_cpu_prep req;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!nvbo->global_handle && !nvbo->write_marker && !cpu_write)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (nvbo->pending &&
|
|
||||||
(nvbo->pending->write_domains || cpu_write)) {
|
|
||||||
nvbo->pending = NULL;
|
|
||||||
nouveau_pushbuf_flush(nvbo->pending_channel, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
req.handle = nvbo->handle;
|
|
||||||
req.flags = 0;
|
|
||||||
if (cpu_write)
|
|
||||||
req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
|
|
||||||
if (no_wait)
|
|
||||||
req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
|
|
||||||
if (no_block)
|
|
||||||
req.flags |= NOUVEAU_GEM_CPU_PREP_NOBLOCK;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_PREP,
|
|
||||||
&req, sizeof(req));
|
|
||||||
} while (ret == -EAGAIN);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (ret == 0)
|
|
||||||
nvbo->write_marker = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_map_range(struct nouveau_bo *bo, uint32_t delta, uint32_t size,
|
|
||||||
uint32_t flags)
|
|
||||||
{
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!nvbo || bo->map)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!nouveau_bo_allocated(nvbo)) {
|
|
||||||
if (nvbo->flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
|
|
||||||
ret = nouveau_bo_kalloc(nvbo, NULL);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nouveau_bo_allocated(nvbo)) {
|
|
||||||
ret = nouveau_bo_ualloc(nvbo);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvbo->sysmem) {
|
|
||||||
bo->map = (char *)nvbo->sysmem + delta;
|
|
||||||
} else {
|
|
||||||
ret = nouveau_bo_kmap(nvbo);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (!(flags & NOUVEAU_BO_NOSYNC)) {
|
|
||||||
ret = nouveau_bo_wait(bo, (flags & NOUVEAU_BO_WR),
|
|
||||||
(flags & NOUVEAU_BO_NOWAIT), 0);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
nvbo->map_refcnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bo->map = (char *)nvbo->map + delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_bo_map_flush(struct nouveau_bo *bo, uint32_t delta, uint32_t size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_map(struct nouveau_bo *bo, uint32_t flags)
|
|
||||||
{
|
|
||||||
return nouveau_bo_map_range(bo, 0, bo->size, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_bo_unmap(struct nouveau_bo *bo)
|
|
||||||
{
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
|
|
||||||
if (bo->map && !nvbo->sysmem && nvbo->map_refcnt) {
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
|
|
||||||
struct drm_nouveau_gem_cpu_fini req;
|
|
||||||
|
|
||||||
req.handle = nvbo->handle;
|
|
||||||
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_FINI,
|
|
||||||
&req, sizeof(req));
|
|
||||||
nvbo->map_refcnt--;
|
|
||||||
}
|
|
||||||
|
|
||||||
bo->map = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access)
|
|
||||||
{
|
|
||||||
return nouveau_bo_wait(bo, (access & NOUVEAU_BO_WR), 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
nouveau_bo_pending(struct nouveau_bo *bo)
|
|
||||||
{
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
uint32_t flags;
|
|
||||||
|
|
||||||
if (!nvbo->pending)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
flags = 0;
|
|
||||||
if (nvbo->pending->read_domains)
|
|
||||||
flags |= NOUVEAU_BO_RD;
|
|
||||||
if (nvbo->pending->write_domains)
|
|
||||||
flags |= NOUVEAU_BO_WR;
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *
|
|
||||||
nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
|
|
||||||
{
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *pbbo;
|
|
||||||
struct nouveau_bo *ref = NULL;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (nvbo->pending)
|
|
||||||
return nvbo->pending;
|
|
||||||
|
|
||||||
if (!nvbo->handle) {
|
|
||||||
ret = nouveau_bo_kalloc(nvbo, chan);
|
|
||||||
if (ret)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (nvbo->sysmem) {
|
|
||||||
void *sysmem_tmp = nvbo->sysmem;
|
|
||||||
|
|
||||||
nvbo->sysmem = NULL;
|
|
||||||
ret = nouveau_bo_map(bo, NOUVEAU_BO_WR);
|
|
||||||
if (ret)
|
|
||||||
return NULL;
|
|
||||||
nvbo->sysmem = sysmem_tmp;
|
|
||||||
|
|
||||||
memcpy(bo->map, nvbo->sysmem, nvbo->base.size);
|
|
||||||
nouveau_bo_ufree(nvbo);
|
|
||||||
nouveau_bo_unmap(bo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvpb->nr_buffers >= NOUVEAU_GEM_MAX_BUFFERS)
|
|
||||||
return NULL;
|
|
||||||
pbbo = nvpb->buffers + nvpb->nr_buffers++;
|
|
||||||
nvbo->pending = pbbo;
|
|
||||||
nvbo->pending_channel = chan;
|
|
||||||
nvbo->pending_refcnt = 0;
|
|
||||||
|
|
||||||
nouveau_bo_ref(bo, &ref);
|
|
||||||
pbbo->user_priv = (uint64_t)(unsigned long)ref;
|
|
||||||
pbbo->handle = nvbo->handle;
|
|
||||||
pbbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART;
|
|
||||||
pbbo->read_domains = 0;
|
|
||||||
pbbo->write_domains = 0;
|
|
||||||
pbbo->presumed.domain = nvbo->domain;
|
|
||||||
pbbo->presumed.offset = nvbo->offset;
|
|
||||||
pbbo->presumed.valid = 1;
|
|
||||||
return pbbo;
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_BO_H__
|
|
||||||
#define __NOUVEAU_BO_H__
|
|
||||||
|
|
||||||
/* Relocation/Buffer type flags */
|
|
||||||
#define NOUVEAU_BO_VRAM (1 << 0)
|
|
||||||
#define NOUVEAU_BO_GART (1 << 1)
|
|
||||||
#define NOUVEAU_BO_RD (1 << 2)
|
|
||||||
#define NOUVEAU_BO_WR (1 << 3)
|
|
||||||
#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR)
|
|
||||||
#define NOUVEAU_BO_MAP (1 << 4)
|
|
||||||
#define NOUVEAU_BO_LOW (1 << 6)
|
|
||||||
#define NOUVEAU_BO_HIGH (1 << 7)
|
|
||||||
#define NOUVEAU_BO_OR (1 << 8)
|
|
||||||
#define NOUVEAU_BO_INVAL (1 << 12)
|
|
||||||
#define NOUVEAU_BO_NOSYNC (1 << 13)
|
|
||||||
#define NOUVEAU_BO_NOWAIT (1 << 14)
|
|
||||||
#define NOUVEAU_BO_IFLUSH (1 << 15)
|
|
||||||
#define NOUVEAU_BO_DUMMY (1 << 31)
|
|
||||||
|
|
||||||
#define NOUVEAU_BO_TILE_LAYOUT_MASK 0x0000ff00
|
|
||||||
#define NOUVEAU_BO_TILE_16BPP 0x00000001
|
|
||||||
#define NOUVEAU_BO_TILE_32BPP 0x00000002
|
|
||||||
#define NOUVEAU_BO_TILE_ZETA 0x00000004
|
|
||||||
#define NOUVEAU_BO_TILE_SCANOUT 0x00000008
|
|
||||||
|
|
||||||
struct nouveau_bo {
|
|
||||||
struct nouveau_device *device;
|
|
||||||
uint32_t handle;
|
|
||||||
|
|
||||||
uint64_t size;
|
|
||||||
void *map;
|
|
||||||
|
|
||||||
uint32_t tile_mode;
|
|
||||||
uint32_t tile_flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_new(struct nouveau_device *, uint32_t flags, int align, int size,
|
|
||||||
struct nouveau_bo **);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_new_tile(struct nouveau_device *, uint32_t flags, int align,
|
|
||||||
int size, uint32_t tile_mode, uint32_t tile_flags,
|
|
||||||
struct nouveau_bo **);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_user(struct nouveau_device *, void *ptr, int size,
|
|
||||||
struct nouveau_bo **);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_wrap(struct nouveau_device *, uint32_t handle, struct nouveau_bo **);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_handle_get(struct nouveau_bo *, uint32_t *);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_handle_ref(struct nouveau_device *, uint32_t handle,
|
|
||||||
struct nouveau_bo **);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_map_range(struct nouveau_bo *, uint32_t delta, uint32_t size,
|
|
||||||
uint32_t flags);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_bo_map_flush(struct nouveau_bo *, uint32_t delta, uint32_t size);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_map(struct nouveau_bo *, uint32_t flags);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_bo_unmap(struct nouveau_bo *);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_busy(struct nouveau_bo *, uint32_t access);
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
nouveau_bo_pending(struct nouveau_bo *);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,142 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_channel_alloc(struct nouveau_device *dev, uint32_t fb_ctxdma,
|
|
||||||
uint32_t tt_ctxdma, int pushbuf_size,
|
|
||||||
struct nouveau_channel **chan)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(dev);
|
|
||||||
struct nouveau_channel_priv *nvchan;
|
|
||||||
unsigned i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!nvdev || !chan || *chan)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
nvchan = calloc(1, sizeof(struct nouveau_channel_priv));
|
|
||||||
if (!nvchan)
|
|
||||||
return -ENOMEM;
|
|
||||||
nvchan->base.device = dev;
|
|
||||||
|
|
||||||
nvchan->drm.fb_ctxdma_handle = fb_ctxdma;
|
|
||||||
nvchan->drm.tt_ctxdma_handle = tt_ctxdma;
|
|
||||||
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_CHANNEL_ALLOC,
|
|
||||||
&nvchan->drm, sizeof(nvchan->drm));
|
|
||||||
if (ret) {
|
|
||||||
free(nvchan);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvchan->base.id = nvchan->drm.channel;
|
|
||||||
if (nouveau_grobj_ref(&nvchan->base, nvchan->drm.fb_ctxdma_handle,
|
|
||||||
&nvchan->base.vram) ||
|
|
||||||
nouveau_grobj_ref(&nvchan->base, nvchan->drm.tt_ctxdma_handle,
|
|
||||||
&nvchan->base.gart)) {
|
|
||||||
nouveau_channel_free((void *)&nvchan);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark all DRM-assigned subchannels as in-use */
|
|
||||||
for (i = 0; i < nvchan->drm.nr_subchan; i++) {
|
|
||||||
struct nouveau_grobj_priv *gr = calloc(1, sizeof(*gr));
|
|
||||||
|
|
||||||
gr->base.bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
|
|
||||||
gr->base.subc = i;
|
|
||||||
gr->base.handle = nvchan->drm.subchan[i].handle;
|
|
||||||
gr->base.grclass = nvchan->drm.subchan[i].grclass;
|
|
||||||
gr->base.channel = &nvchan->base;
|
|
||||||
|
|
||||||
nvchan->base.subc[i].gr = &gr->base;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->chipset < 0xc0) {
|
|
||||||
ret = nouveau_bo_wrap(dev, nvchan->drm.notifier_handle,
|
|
||||||
&nvchan->notifier_bo);
|
|
||||||
if (!ret)
|
|
||||||
ret = nouveau_bo_map(nvchan->notifier_bo,
|
|
||||||
NOUVEAU_BO_RDWR);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_channel_free((void *)&nvchan);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nouveau_grobj_alloc(&nvchan->base, 0x00000000, 0x0030,
|
|
||||||
&nvchan->base.nullobj);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_channel_free((void *)&nvchan);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nouveau_pushbuf_init(&nvchan->base, pushbuf_size);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_channel_free((void *)&nvchan);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
*chan = &nvchan->base;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_channel_free(struct nouveau_channel **chan)
|
|
||||||
{
|
|
||||||
struct nouveau_channel_priv *nvchan;
|
|
||||||
struct nouveau_device_priv *nvdev;
|
|
||||||
struct drm_nouveau_channel_free cf;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
if (!chan || !*chan)
|
|
||||||
return;
|
|
||||||
nvchan = nouveau_channel(*chan);
|
|
||||||
(*chan)->flush_notify = NULL;
|
|
||||||
*chan = NULL;
|
|
||||||
nvdev = nouveau_device(nvchan->base.device);
|
|
||||||
|
|
||||||
FIRE_RING(&nvchan->base);
|
|
||||||
|
|
||||||
nouveau_pushbuf_fini(&nvchan->base);
|
|
||||||
if (nvchan->notifier_bo) {
|
|
||||||
nouveau_bo_unmap(nvchan->notifier_bo);
|
|
||||||
nouveau_bo_ref(NULL, &nvchan->notifier_bo);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nvchan->drm.nr_subchan; i++)
|
|
||||||
free(nvchan->base.subc[i].gr);
|
|
||||||
|
|
||||||
nouveau_grobj_free(&nvchan->base.vram);
|
|
||||||
nouveau_grobj_free(&nvchan->base.gart);
|
|
||||||
nouveau_grobj_free(&nvchan->base.nullobj);
|
|
||||||
|
|
||||||
cf.channel = nvchan->drm.channel;
|
|
||||||
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_CHANNEL_FREE, &cf, sizeof(cf));
|
|
||||||
free(nvchan);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_CHANNEL_H__
|
|
||||||
#define __NOUVEAU_CHANNEL_H__
|
|
||||||
|
|
||||||
struct nouveau_subchannel {
|
|
||||||
struct nouveau_grobj *gr;
|
|
||||||
unsigned sequence;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nouveau_channel {
|
|
||||||
uint32_t *cur;
|
|
||||||
uint32_t *end;
|
|
||||||
|
|
||||||
struct nouveau_device *device;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
struct nouveau_grobj *nullobj;
|
|
||||||
struct nouveau_grobj *vram;
|
|
||||||
struct nouveau_grobj *gart;
|
|
||||||
|
|
||||||
void *user_private;
|
|
||||||
void (*hang_notify)(struct nouveau_channel *);
|
|
||||||
void (*flush_notify)(struct nouveau_channel *);
|
|
||||||
|
|
||||||
struct nouveau_subchannel subc[8];
|
|
||||||
unsigned subc_sequence;
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_channel_alloc(struct nouveau_device *, uint32_t fb, uint32_t tt,
|
|
||||||
int pushbuf_size, struct nouveau_channel **);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_channel_free(struct nouveau_channel **);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,198 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_open_existing(struct nouveau_device **dev, int close,
|
|
||||||
int fd, drm_context_t ctx)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev;
|
|
||||||
drmVersionPtr ver;
|
|
||||||
uint64_t value;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!dev || *dev)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
nvdev = calloc(1, sizeof(*nvdev));
|
|
||||||
if (!nvdev)
|
|
||||||
return -ENOMEM;
|
|
||||||
nvdev->fd = fd;
|
|
||||||
nvdev->ctx = ctx;
|
|
||||||
nvdev->needs_close = close;
|
|
||||||
|
|
||||||
ver = drmGetVersion(fd);
|
|
||||||
if (!ver) {
|
|
||||||
nouveau_device_close((void *)&nvdev);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ver->version_major == 0 && ver->version_patchlevel != 16) ||
|
|
||||||
ver->version_major > 1) {
|
|
||||||
nouveau_device_close((void *)&nvdev);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
drmFreeVersion(ver);
|
|
||||||
|
|
||||||
ret = nouveau_device_get_param(&nvdev->base,
|
|
||||||
NOUVEAU_GETPARAM_VM_VRAM_BASE, &value);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_device_close((void *)&nvdev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
nvdev->base.vm_vram_base = value;
|
|
||||||
|
|
||||||
ret = nouveau_device_get_param(&nvdev->base,
|
|
||||||
NOUVEAU_GETPARAM_FB_SIZE, &value);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_device_close((void *)&nvdev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
nvdev->base.vm_vram_size = value;
|
|
||||||
|
|
||||||
ret = nouveau_device_get_param(&nvdev->base,
|
|
||||||
NOUVEAU_GETPARAM_AGP_SIZE, &value);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_device_close((void *)&nvdev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
nvdev->base.vm_gart_size = value;
|
|
||||||
|
|
||||||
ret = nouveau_bo_init(&nvdev->base);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_device_close((void *)&nvdev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nouveau_device_get_param(&nvdev->base,
|
|
||||||
NOUVEAU_GETPARAM_CHIPSET_ID, &value);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_device_close((void *)&nvdev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
nvdev->base.chipset = value;
|
|
||||||
|
|
||||||
ret = nouveau_device_get_param(&nvdev->base,
|
|
||||||
NOUVEAU_GETPARAM_HAS_BO_USAGE, &value);
|
|
||||||
if (!ret)
|
|
||||||
nvdev->has_bo_usage = value;
|
|
||||||
|
|
||||||
*dev = &nvdev->base;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_open(struct nouveau_device **dev, const char *busid)
|
|
||||||
{
|
|
||||||
drm_context_t ctx;
|
|
||||||
int fd, ret;
|
|
||||||
|
|
||||||
if (!dev || *dev)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
fd = drmOpen("nouveau", busid);
|
|
||||||
if (fd < 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ret = drmCreateContext(fd, &ctx);
|
|
||||||
if (ret) {
|
|
||||||
drmClose(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nouveau_device_open_existing(dev, 1, fd, ctx);
|
|
||||||
if (ret) {
|
|
||||||
drmDestroyContext(fd, ctx);
|
|
||||||
drmClose(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_device_close(struct nouveau_device **dev)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev;
|
|
||||||
|
|
||||||
if (!dev || !*dev)
|
|
||||||
return;
|
|
||||||
nvdev = nouveau_device(*dev);
|
|
||||||
*dev = NULL;
|
|
||||||
|
|
||||||
nouveau_bo_takedown(&nvdev->base);
|
|
||||||
|
|
||||||
if (nvdev->needs_close) {
|
|
||||||
drmDestroyContext(nvdev->fd, nvdev->ctx);
|
|
||||||
drmClose(nvdev->fd);
|
|
||||||
}
|
|
||||||
free(nvdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_get_param(struct nouveau_device *dev,
|
|
||||||
uint64_t param, uint64_t *value)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(dev);
|
|
||||||
struct drm_nouveau_getparam g;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!nvdev || !value)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
g.param = param;
|
|
||||||
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GETPARAM,
|
|
||||||
&g, sizeof(g));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
*value = g.value;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_set_param(struct nouveau_device *dev,
|
|
||||||
uint64_t param, uint64_t value)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(dev);
|
|
||||||
struct drm_nouveau_setparam s;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!nvdev)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
s.param = param;
|
|
||||||
s.value = value;
|
|
||||||
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_SETPARAM,
|
|
||||||
&s, sizeof(s));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_DEVICE_H__
|
|
||||||
#define __NOUVEAU_DEVICE_H__
|
|
||||||
|
|
||||||
struct nouveau_device {
|
|
||||||
unsigned chipset;
|
|
||||||
uint64_t vm_vram_base;
|
|
||||||
uint64_t vm_vram_size;
|
|
||||||
uint64_t vm_gart_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2008 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_DRMIF_H__
|
|
||||||
#define __NOUVEAU_DRMIF_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <xf86drm.h>
|
|
||||||
|
|
||||||
#include "nouveau_device.h"
|
|
||||||
|
|
||||||
struct nouveau_device_priv {
|
|
||||||
struct nouveau_device base;
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
drm_context_t ctx;
|
|
||||||
drmLock *lock;
|
|
||||||
int needs_close;
|
|
||||||
int has_bo_usage;
|
|
||||||
};
|
|
||||||
#define nouveau_device(n) ((struct nouveau_device_priv *)(n))
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_open_existing(struct nouveau_device **, int close,
|
|
||||||
int fd, drm_context_t ctx);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_open(struct nouveau_device **, const char *busid);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_device_close(struct nouveau_device **);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,148 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_grobj_alloc(struct nouveau_channel *chan, uint32_t handle,
|
|
||||||
int class, struct nouveau_grobj **grobj)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
|
|
||||||
struct nouveau_grobj_priv *nvgrobj;
|
|
||||||
struct drm_nouveau_grobj_alloc g;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!nvdev || !grobj || *grobj)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
nvgrobj = calloc(1, sizeof(*nvgrobj));
|
|
||||||
if (!nvgrobj)
|
|
||||||
return -ENOMEM;
|
|
||||||
nvgrobj->base.channel = chan;
|
|
||||||
nvgrobj->base.handle = handle;
|
|
||||||
nvgrobj->base.grclass = class;
|
|
||||||
nvgrobj->base.bound = NOUVEAU_GROBJ_UNBOUND;
|
|
||||||
nvgrobj->base.subc = -1;
|
|
||||||
|
|
||||||
g.channel = chan->id;
|
|
||||||
g.handle = handle;
|
|
||||||
g.class = class;
|
|
||||||
ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
|
|
||||||
&g, sizeof(g));
|
|
||||||
if (ret) {
|
|
||||||
nouveau_grobj_free((void *)&nvgrobj);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
*grobj = &nvgrobj->base;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_grobj_ref(struct nouveau_channel *chan, uint32_t handle,
|
|
||||||
struct nouveau_grobj **grobj)
|
|
||||||
{
|
|
||||||
struct nouveau_grobj_priv *nvgrobj;
|
|
||||||
|
|
||||||
if (!chan || !grobj || *grobj)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
nvgrobj = calloc(1, sizeof(struct nouveau_grobj_priv));
|
|
||||||
if (!nvgrobj)
|
|
||||||
return -ENOMEM;
|
|
||||||
nvgrobj->base.channel = chan;
|
|
||||||
nvgrobj->base.handle = handle;
|
|
||||||
nvgrobj->base.grclass = 0;
|
|
||||||
|
|
||||||
*grobj = &nvgrobj->base;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_grobj_free(struct nouveau_grobj **grobj)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev;
|
|
||||||
struct nouveau_channel_priv *chan;
|
|
||||||
struct nouveau_grobj_priv *nvgrobj;
|
|
||||||
|
|
||||||
if (!grobj || !*grobj)
|
|
||||||
return;
|
|
||||||
nvgrobj = nouveau_grobj(*grobj);
|
|
||||||
*grobj = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
chan = nouveau_channel(nvgrobj->base.channel);
|
|
||||||
nvdev = nouveau_device(chan->base.device);
|
|
||||||
|
|
||||||
if (nvgrobj->base.grclass) {
|
|
||||||
struct drm_nouveau_gpuobj_free f;
|
|
||||||
|
|
||||||
FIRE_RING(&chan->base);
|
|
||||||
f.channel = chan->drm.channel;
|
|
||||||
f.handle = nvgrobj->base.handle;
|
|
||||||
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
|
|
||||||
&f, sizeof(f));
|
|
||||||
}
|
|
||||||
if (nvgrobj->base.bound != NOUVEAU_GROBJ_UNBOUND)
|
|
||||||
chan->base.subc[nvgrobj->base.subc].gr = NULL;
|
|
||||||
free(nvgrobj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_grobj_autobind(struct nouveau_grobj *grobj)
|
|
||||||
{
|
|
||||||
struct nouveau_channel *chan = grobj->channel;
|
|
||||||
struct nouveau_subchannel *subc = NULL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
struct nouveau_subchannel *scc = &grobj->channel->subc[i];
|
|
||||||
|
|
||||||
if (scc->gr && scc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!subc || scc->sequence < subc->sequence)
|
|
||||||
subc = scc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subc->gr) {
|
|
||||||
subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
|
|
||||||
subc->gr->subc = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
subc->gr = grobj;
|
|
||||||
subc->gr->bound = NOUVEAU_GROBJ_BOUND;
|
|
||||||
subc->gr->subc = subc - &grobj->channel->subc[0];
|
|
||||||
|
|
||||||
WAIT_RING(chan, 2);
|
|
||||||
if (chan->device->chipset < 0xc0) {
|
|
||||||
OUT_RING (chan, (1 << 18) | (grobj->subc << 13));
|
|
||||||
OUT_RING (chan, grobj->handle);
|
|
||||||
} else {
|
|
||||||
OUT_RING (chan, (2 << 28) | (1 << 16) | (grobj->subc << 13));
|
|
||||||
OUT_RING (chan, grobj->grclass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_GROBJ_H__
|
|
||||||
#define __NOUVEAU_GROBJ_H__
|
|
||||||
|
|
||||||
#include "nouveau_channel.h"
|
|
||||||
|
|
||||||
struct nouveau_grobj {
|
|
||||||
struct nouveau_channel *channel;
|
|
||||||
int grclass;
|
|
||||||
uint32_t handle;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
NOUVEAU_GROBJ_UNBOUND = 0,
|
|
||||||
NOUVEAU_GROBJ_BOUND = 1,
|
|
||||||
NOUVEAU_GROBJ_BOUND_EXPLICIT = 2
|
|
||||||
} bound;
|
|
||||||
int subc;
|
|
||||||
};
|
|
||||||
|
|
||||||
int nouveau_grobj_alloc(struct nouveau_channel *, uint32_t handle,
|
|
||||||
int class, struct nouveau_grobj **);
|
|
||||||
int nouveau_grobj_ref(struct nouveau_channel *, uint32_t handle,
|
|
||||||
struct nouveau_grobj **);
|
|
||||||
void nouveau_grobj_free(struct nouveau_grobj **);
|
|
||||||
void nouveau_grobj_autobind(struct nouveau_grobj *);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,148 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
#define NOTIFIER(__v) \
|
|
||||||
struct nouveau_notifier_priv *nvnotify = nouveau_notifier(notifier); \
|
|
||||||
volatile uint32_t *__v = (uint32_t *)((char *)nvnotify->map + (id * 32))
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
|
|
||||||
int count, struct nouveau_notifier **notifier)
|
|
||||||
{
|
|
||||||
struct nouveau_notifier_priv *nvnotify;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!chan || !notifier || *notifier)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
nvnotify = calloc(1, sizeof(struct nouveau_notifier_priv));
|
|
||||||
if (!nvnotify)
|
|
||||||
return -ENOMEM;
|
|
||||||
nvnotify->base.channel = chan;
|
|
||||||
nvnotify->base.handle = handle;
|
|
||||||
|
|
||||||
nvnotify->drm.channel = chan->id;
|
|
||||||
nvnotify->drm.handle = handle;
|
|
||||||
nvnotify->drm.size = (count * 32);
|
|
||||||
if ((ret = drmCommandWriteRead(nouveau_device(chan->device)->fd,
|
|
||||||
DRM_NOUVEAU_NOTIFIEROBJ_ALLOC,
|
|
||||||
&nvnotify->drm,
|
|
||||||
sizeof(nvnotify->drm)))) {
|
|
||||||
nouveau_notifier_free((void *)&nvnotify);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvnotify->map = (char *)nouveau_channel(chan)->notifier_bo->map +
|
|
||||||
nvnotify->drm.offset;
|
|
||||||
*notifier = &nvnotify->base;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_notifier_free(struct nouveau_notifier **notifier)
|
|
||||||
{
|
|
||||||
|
|
||||||
struct nouveau_notifier_priv *nvnotify;
|
|
||||||
struct nouveau_channel_priv *nvchan;
|
|
||||||
struct nouveau_device_priv *nvdev;
|
|
||||||
struct drm_nouveau_gpuobj_free f;
|
|
||||||
|
|
||||||
if (!notifier || !*notifier)
|
|
||||||
return;
|
|
||||||
nvnotify = nouveau_notifier(*notifier);
|
|
||||||
*notifier = NULL;
|
|
||||||
|
|
||||||
nvchan = nouveau_channel(nvnotify->base.channel);
|
|
||||||
nvdev = nouveau_device(nvchan->base.device);
|
|
||||||
|
|
||||||
FIRE_RING(&nvchan->base);
|
|
||||||
|
|
||||||
f.channel = nvchan->drm.channel;
|
|
||||||
f.handle = nvnotify->base.handle;
|
|
||||||
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f));
|
|
||||||
free(nvnotify);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_notifier_reset(struct nouveau_notifier *notifier, int id)
|
|
||||||
{
|
|
||||||
NOTIFIER(n);
|
|
||||||
|
|
||||||
n[NV_NOTIFY_TIME_0 /4] = 0x00000000;
|
|
||||||
n[NV_NOTIFY_TIME_1 /4] = 0x00000000;
|
|
||||||
n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
|
|
||||||
n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
|
|
||||||
NV_NOTIFY_STATE_STATUS_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
nouveau_notifier_status(struct nouveau_notifier *notifier, int id)
|
|
||||||
{
|
|
||||||
NOTIFIER(n);
|
|
||||||
|
|
||||||
return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
nouveau_notifier_return_val(struct nouveau_notifier *notifier, int id)
|
|
||||||
{
|
|
||||||
NOTIFIER(n);
|
|
||||||
|
|
||||||
return n[NV_NOTIFY_RETURN_VALUE/4];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double
|
|
||||||
gettime(void)
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
return (double)tv.tv_sec + tv.tv_usec / 1000000.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_notifier_wait_status(struct nouveau_notifier *notifier, int id,
|
|
||||||
uint32_t status, double timeout)
|
|
||||||
{
|
|
||||||
NOTIFIER(n);
|
|
||||||
double time = 0, t_start = gettime();
|
|
||||||
|
|
||||||
while (time <= timeout) {
|
|
||||||
uint32_t v;
|
|
||||||
|
|
||||||
v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
|
|
||||||
if (v == status)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (timeout)
|
|
||||||
time = gettime() - t_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_NOTIFIER_H__
|
|
||||||
#define __NOUVEAU_NOTIFIER_H__
|
|
||||||
|
|
||||||
#define NV_NOTIFIER_SIZE 32
|
|
||||||
#define NV_NOTIFY_TIME_0 0x00000000
|
|
||||||
#define NV_NOTIFY_TIME_1 0x00000004
|
|
||||||
#define NV_NOTIFY_RETURN_VALUE 0x00000008
|
|
||||||
#define NV_NOTIFY_STATE 0x0000000C
|
|
||||||
#define NV_NOTIFY_STATE_STATUS_MASK 0xFF000000
|
|
||||||
#define NV_NOTIFY_STATE_STATUS_SHIFT 24
|
|
||||||
#define NV_NOTIFY_STATE_STATUS_COMPLETED 0x00
|
|
||||||
#define NV_NOTIFY_STATE_STATUS_IN_PROCESS 0x01
|
|
||||||
#define NV_NOTIFY_STATE_ERROR_CODE_MASK 0x0000FFFF
|
|
||||||
#define NV_NOTIFY_STATE_ERROR_CODE_SHIFT 0
|
|
||||||
|
|
||||||
struct nouveau_notifier {
|
|
||||||
struct nouveau_channel *channel;
|
|
||||||
uint32_t handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int count,
|
|
||||||
struct nouveau_notifier **);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_notifier_free(struct nouveau_notifier **);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_notifier_reset(struct nouveau_notifier *, int id);
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
nouveau_notifier_status(struct nouveau_notifier *, int id);
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
nouveau_notifier_return_val(struct nouveau_notifier *, int id);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_notifier_wait_status(struct nouveau_notifier *, int id, uint32_t status,
|
|
||||||
double timeout);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_PRIVATE_H__
|
|
||||||
#define __NOUVEAU_PRIVATE_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <xf86drm.h>
|
|
||||||
#include <nouveau_drm.h>
|
|
||||||
|
|
||||||
#include "nouveau_drmif.h"
|
|
||||||
#include "nouveau_device.h"
|
|
||||||
#include "nouveau_channel.h"
|
|
||||||
#include "nouveau_grobj.h"
|
|
||||||
#include "nouveau_notifier.h"
|
|
||||||
#include "nouveau_bo.h"
|
|
||||||
#include "nouveau_resource.h"
|
|
||||||
#include "nouveau_pushbuf.h"
|
|
||||||
#include "nouveau_reloc.h"
|
|
||||||
|
|
||||||
#define CALPB_BUFFERS 3
|
|
||||||
|
|
||||||
struct nouveau_pushbuf_priv {
|
|
||||||
uint32_t cal_suffix0;
|
|
||||||
uint32_t cal_suffix1;
|
|
||||||
struct nouveau_bo *buffer[CALPB_BUFFERS];
|
|
||||||
int current;
|
|
||||||
int current_offset;
|
|
||||||
|
|
||||||
unsigned *pushbuf;
|
|
||||||
unsigned size;
|
|
||||||
|
|
||||||
uint32_t *marker;
|
|
||||||
unsigned marker_offset;
|
|
||||||
unsigned marker_relocs;
|
|
||||||
unsigned marker_push;
|
|
||||||
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *buffers;
|
|
||||||
unsigned nr_buffers;
|
|
||||||
struct drm_nouveau_gem_pushbuf_reloc *relocs;
|
|
||||||
unsigned nr_relocs;
|
|
||||||
struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH];
|
|
||||||
unsigned nr_push;
|
|
||||||
};
|
|
||||||
#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_init(struct nouveau_channel *, int buf_size);
|
|
||||||
void
|
|
||||||
nouveau_pushbuf_fini(struct nouveau_channel *);
|
|
||||||
|
|
||||||
struct nouveau_channel_priv {
|
|
||||||
struct nouveau_channel base;
|
|
||||||
|
|
||||||
struct drm_nouveau_channel_alloc drm;
|
|
||||||
|
|
||||||
struct nouveau_bo *notifier_bo;
|
|
||||||
|
|
||||||
struct nouveau_pushbuf_priv pb;
|
|
||||||
};
|
|
||||||
#define nouveau_channel(n) ((struct nouveau_channel_priv *)(n))
|
|
||||||
|
|
||||||
struct nouveau_grobj_priv {
|
|
||||||
struct nouveau_grobj base;
|
|
||||||
};
|
|
||||||
#define nouveau_grobj(n) ((struct nouveau_grobj_priv *)(n))
|
|
||||||
|
|
||||||
struct nouveau_notifier_priv {
|
|
||||||
struct nouveau_notifier base;
|
|
||||||
|
|
||||||
struct drm_nouveau_notifierobj_alloc drm;
|
|
||||||
volatile void *map;
|
|
||||||
};
|
|
||||||
#define nouveau_notifier(n) ((struct nouveau_notifier_priv *)(n))
|
|
||||||
|
|
||||||
struct nouveau_bo_priv {
|
|
||||||
struct nouveau_bo base;
|
|
||||||
int refcount;
|
|
||||||
|
|
||||||
/* Buffer configuration + usage hints */
|
|
||||||
unsigned flags;
|
|
||||||
unsigned size;
|
|
||||||
unsigned align;
|
|
||||||
int user;
|
|
||||||
|
|
||||||
/* Tracking */
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *pending;
|
|
||||||
struct nouveau_channel *pending_channel;
|
|
||||||
int pending_refcnt;
|
|
||||||
int write_marker;
|
|
||||||
|
|
||||||
/* Userspace object */
|
|
||||||
void *sysmem;
|
|
||||||
|
|
||||||
/* Kernel object */
|
|
||||||
uint32_t global_handle;
|
|
||||||
drm_handle_t handle;
|
|
||||||
uint64_t map_handle;
|
|
||||||
int map_refcnt;
|
|
||||||
void *map;
|
|
||||||
|
|
||||||
/* Last known information from kernel on buffer status */
|
|
||||||
uint64_t offset;
|
|
||||||
uint32_t domain;
|
|
||||||
};
|
|
||||||
#define nouveau_bo(n) ((struct nouveau_bo_priv *)(n))
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_bo_init(struct nouveau_device *);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_bo_takedown(struct nouveau_device *);
|
|
||||||
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *
|
|
||||||
nouveau_bo_emit_buffer(struct nouveau_channel *, struct nouveau_bo *);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,344 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
#define PB_BUFMGR_DWORDS (4096 / 2)
|
|
||||||
#define PB_MIN_USER_DWORDS 2048
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
|
|
||||||
{
|
|
||||||
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
|
|
||||||
struct nouveau_bo *bo;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (min < PB_MIN_USER_DWORDS)
|
|
||||||
min = PB_MIN_USER_DWORDS;
|
|
||||||
|
|
||||||
nvpb->current_offset = chan->cur - nvpb->pushbuf;
|
|
||||||
if (chan->cur + min + 2 <= chan->end)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
nvpb->current++;
|
|
||||||
if (nvpb->current == CALPB_BUFFERS)
|
|
||||||
nvpb->current = 0;
|
|
||||||
bo = nvpb->buffer[nvpb->current];
|
|
||||||
|
|
||||||
ret = nouveau_bo_map(bo, NOUVEAU_BO_WR);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
nvpb->size = (bo->size - 8) / 4;
|
|
||||||
nvpb->pushbuf = bo->map;
|
|
||||||
nvpb->current_offset = 0;
|
|
||||||
|
|
||||||
chan->cur = nvpb->pushbuf;
|
|
||||||
chan->end = nvpb->pushbuf + nvpb->size;
|
|
||||||
|
|
||||||
nouveau_bo_unmap(bo);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nouveau_pushbuf_fini_call(struct nouveau_channel *chan)
|
|
||||||
{
|
|
||||||
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < CALPB_BUFFERS; i++)
|
|
||||||
nouveau_bo_ref(NULL, &nvpb->buffer[i]);
|
|
||||||
nvpb->pushbuf = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_pushbuf_init_call(struct nouveau_channel *chan, int buf_size)
|
|
||||||
{
|
|
||||||
struct drm_nouveau_gem_pushbuf req;
|
|
||||||
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
|
|
||||||
struct nouveau_device *dev = chan->device;
|
|
||||||
uint32_t flags = 0;
|
|
||||||
int i, ret;
|
|
||||||
|
|
||||||
if (nvchan->drm.pushbuf_domains & NOUVEAU_GEM_DOMAIN_GART)
|
|
||||||
flags |= NOUVEAU_BO_GART;
|
|
||||||
else
|
|
||||||
flags |= NOUVEAU_BO_VRAM;
|
|
||||||
|
|
||||||
req.channel = chan->id;
|
|
||||||
req.nr_push = 0;
|
|
||||||
ret = drmCommandWriteRead(nouveau_device(dev)->fd,
|
|
||||||
DRM_NOUVEAU_GEM_PUSHBUF, &req, sizeof(req));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (i = 0; i < CALPB_BUFFERS; i++) {
|
|
||||||
ret = nouveau_bo_new(dev, flags | NOUVEAU_BO_MAP,
|
|
||||||
0, buf_size, &nvpb->buffer[i]);
|
|
||||||
if (ret) {
|
|
||||||
nouveau_pushbuf_fini_call(chan);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nvpb->cal_suffix0 = req.suffix0;
|
|
||||||
nvpb->cal_suffix1 = req.suffix1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_init(struct nouveau_channel *chan, int buf_size)
|
|
||||||
{
|
|
||||||
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = nouveau_pushbuf_init_call(chan, buf_size);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = nouveau_pushbuf_space(chan, 0);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
nvpb->buffers = calloc(NOUVEAU_GEM_MAX_BUFFERS,
|
|
||||||
sizeof(struct drm_nouveau_gem_pushbuf_bo));
|
|
||||||
nvpb->relocs = calloc(NOUVEAU_GEM_MAX_RELOCS,
|
|
||||||
sizeof(struct drm_nouveau_gem_pushbuf_reloc));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_pushbuf_fini(struct nouveau_channel *chan)
|
|
||||||
{
|
|
||||||
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
|
|
||||||
nouveau_pushbuf_fini_call(chan);
|
|
||||||
free(nvpb->buffers);
|
|
||||||
free(nvpb->relocs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nouveau_pushbuf_bo_add(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned offset, unsigned length)
|
|
||||||
{
|
|
||||||
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
|
|
||||||
struct drm_nouveau_gem_pushbuf_push *p = &nvpb->push[nvpb->nr_push++];
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *pbbo;
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
|
|
||||||
pbbo = nouveau_bo_emit_buffer(chan, bo);
|
|
||||||
if (!pbbo)
|
|
||||||
return -ENOMEM;
|
|
||||||
pbbo->valid_domains &= nvchan->drm.pushbuf_domains;
|
|
||||||
pbbo->read_domains |= nvchan->drm.pushbuf_domains;
|
|
||||||
nvbo->pending_refcnt++;
|
|
||||||
|
|
||||||
p->bo_index = pbbo - nvpb->buffers;
|
|
||||||
p->offset = offset;
|
|
||||||
p->length = length;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned offset, unsigned length)
|
|
||||||
{
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
|
|
||||||
int ret, len;
|
|
||||||
|
|
||||||
if ((AVAIL_RING(chan) + nvpb->current_offset) != nvpb->size) {
|
|
||||||
if (nvpb->cal_suffix0 || nvpb->cal_suffix1) {
|
|
||||||
*(chan->cur++) = nvpb->cal_suffix0;
|
|
||||||
*(chan->cur++) = nvpb->cal_suffix1;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = (chan->cur - nvpb->pushbuf) - nvpb->current_offset;
|
|
||||||
|
|
||||||
ret = nouveau_pushbuf_bo_add(chan, nvpb->buffer[nvpb->current],
|
|
||||||
nvpb->current_offset * 4, len * 4);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
nvpb->current_offset += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bo ? nouveau_pushbuf_bo_add(chan, bo, offset, length) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nouveau_pushbuf_bo_unref(struct nouveau_pushbuf_priv *nvpb, int index)
|
|
||||||
{
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *pbbo = &nvpb->buffers[index];
|
|
||||||
struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
|
|
||||||
if (--nvbo->pending_refcnt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pbbo->presumed.valid == 0) {
|
|
||||||
nvbo->domain = pbbo->presumed.domain;
|
|
||||||
nvbo->offset = pbbo->presumed.offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvbo->pending = NULL;
|
|
||||||
nouveau_bo_ref(NULL, &bo);
|
|
||||||
|
|
||||||
/* we only ever remove from the tail of the pending lists,
|
|
||||||
* so this is safe.
|
|
||||||
*/
|
|
||||||
nvpb->nr_buffers--;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
|
|
||||||
{
|
|
||||||
struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
|
|
||||||
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
|
|
||||||
struct drm_nouveau_gem_pushbuf req;
|
|
||||||
unsigned i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = nouveau_pushbuf_submit(chan, NULL, 0, 0);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (!nvpb->nr_push)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
req.channel = chan->id;
|
|
||||||
req.nr_push = nvpb->nr_push;
|
|
||||||
req.push = (uint64_t)(unsigned long)nvpb->push;
|
|
||||||
req.nr_buffers = nvpb->nr_buffers;
|
|
||||||
req.buffers = (uint64_t)(unsigned long)nvpb->buffers;
|
|
||||||
req.nr_relocs = nvpb->nr_relocs;
|
|
||||||
req.relocs = (uint64_t)(unsigned long)nvpb->relocs;
|
|
||||||
req.suffix0 = nvpb->cal_suffix0;
|
|
||||||
req.suffix1 = nvpb->cal_suffix1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
|
|
||||||
&req, sizeof(req));
|
|
||||||
} while (ret == -EAGAIN);
|
|
||||||
nvpb->cal_suffix0 = req.suffix0;
|
|
||||||
nvpb->cal_suffix1 = req.suffix1;
|
|
||||||
nvdev->base.vm_vram_size = req.vram_available;
|
|
||||||
nvdev->base.vm_gart_size = req.gart_available;
|
|
||||||
|
|
||||||
/* Update presumed offset/domain for any buffers that moved.
|
|
||||||
* Dereference all buffers on validate list
|
|
||||||
*/
|
|
||||||
for (i = 0; i < nvpb->nr_relocs; i++) {
|
|
||||||
nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
|
|
||||||
nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nvpb->nr_push; i++)
|
|
||||||
nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
|
|
||||||
|
|
||||||
nvpb->nr_buffers = 0;
|
|
||||||
nvpb->nr_relocs = 0;
|
|
||||||
nvpb->nr_push = 0;
|
|
||||||
|
|
||||||
/* Allocate space for next push buffer */
|
|
||||||
if (nouveau_pushbuf_space(chan, min))
|
|
||||||
assert(0);
|
|
||||||
|
|
||||||
if (chan->flush_notify)
|
|
||||||
chan->flush_notify(chan);
|
|
||||||
|
|
||||||
nvpb->marker = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
|
|
||||||
unsigned wait_dwords, unsigned wait_relocs)
|
|
||||||
{
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
|
|
||||||
|
|
||||||
if (AVAIL_RING(chan) < wait_dwords)
|
|
||||||
return nouveau_pushbuf_flush(chan, wait_dwords);
|
|
||||||
|
|
||||||
if (nvpb->nr_relocs + wait_relocs >= NOUVEAU_GEM_MAX_RELOCS)
|
|
||||||
return nouveau_pushbuf_flush(chan, wait_dwords);
|
|
||||||
|
|
||||||
nvpb->marker = chan->cur;
|
|
||||||
nvpb->marker_offset = nvpb->current_offset;
|
|
||||||
nvpb->marker_push = nvpb->nr_push;
|
|
||||||
nvpb->marker_relocs = nvpb->nr_relocs;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_pushbuf_marker_undo(struct nouveau_channel *chan)
|
|
||||||
{
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
if (!nvpb->marker)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* undo any relocs/buffers added to the list since last marker */
|
|
||||||
for (i = nvpb->marker_relocs; i < nvpb->nr_relocs; i++) {
|
|
||||||
nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
|
|
||||||
nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
|
|
||||||
}
|
|
||||||
nvpb->nr_relocs = nvpb->marker_relocs;
|
|
||||||
|
|
||||||
for (i = nvpb->marker_push; i < nvpb->nr_push; i++)
|
|
||||||
nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
|
|
||||||
nvpb->nr_push = nvpb->marker_push;
|
|
||||||
|
|
||||||
/* reset pushbuf back to last marker */
|
|
||||||
chan->cur = nvpb->marker;
|
|
||||||
nvpb->current_offset = nvpb->marker_offset;
|
|
||||||
nvpb->marker = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
|
|
||||||
struct nouveau_bo *bo, uint32_t data, uint32_t data2,
|
|
||||||
uint32_t flags, uint32_t vor, uint32_t tor)
|
|
||||||
{
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = nouveau_reloc_emit(chan, nvpb->buffer[nvpb->current],
|
|
||||||
(char *)ptr - (char *)nvpb->pushbuf, ptr,
|
|
||||||
bo, data, data2, flags, vor, tor);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_PUSHBUF_H__
|
|
||||||
#define __NOUVEAU_PUSHBUF_H__
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "nouveau_bo.h"
|
|
||||||
#include "nouveau_grobj.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
|
|
||||||
unsigned wait_dwords, unsigned wait_relocs);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_pushbuf_marker_undo(struct nouveau_channel *chan);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr,
|
|
||||||
struct nouveau_bo *, uint32_t data, uint32_t data2,
|
|
||||||
uint32_t flags, uint32_t vor, uint32_t tor);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned offset, unsigned length);
|
|
||||||
|
|
||||||
/* Push buffer access macros */
|
|
||||||
static __inline__ int
|
|
||||||
MARK_RING(struct nouveau_channel *chan, unsigned dwords, unsigned relocs)
|
|
||||||
{
|
|
||||||
return nouveau_pushbuf_marker_emit(chan, dwords, relocs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
MARK_UNDO(struct nouveau_channel *chan)
|
|
||||||
{
|
|
||||||
nouveau_pushbuf_marker_undo(chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
OUT_RING(struct nouveau_channel *chan, unsigned data)
|
|
||||||
{
|
|
||||||
*(chan->cur++) = (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned size)
|
|
||||||
{
|
|
||||||
memcpy(chan->cur, data, size * 4);
|
|
||||||
chan->cur += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
OUT_RINGf(struct nouveau_channel *chan, float f)
|
|
||||||
{
|
|
||||||
union { uint32_t i; float f; } c;
|
|
||||||
c.f = f;
|
|
||||||
OUT_RING(chan, c.i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ unsigned
|
|
||||||
AVAIL_RING(struct nouveau_channel *chan)
|
|
||||||
{
|
|
||||||
return chan->end - chan->cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
WAIT_RING(struct nouveau_channel *chan, unsigned size)
|
|
||||||
{
|
|
||||||
if (chan->cur + size > chan->end)
|
|
||||||
nouveau_pushbuf_flush(chan, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
FIRE_RING(struct nouveau_channel *chan)
|
|
||||||
{
|
|
||||||
nouveau_pushbuf_flush(chan, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ int
|
|
||||||
OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned data, unsigned flags, unsigned vor, unsigned tor)
|
|
||||||
{
|
|
||||||
return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
|
|
||||||
data, 0, flags, vor, tor);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ int
|
|
||||||
OUT_RELOC2(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned data, unsigned data2, unsigned flags,
|
|
||||||
unsigned vor, unsigned tor)
|
|
||||||
{
|
|
||||||
return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
|
|
||||||
data, data2, flags, vor, tor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Raw data + flags depending on FB/TT buffer */
|
|
||||||
static __inline__ int
|
|
||||||
OUT_RELOCd(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned data, unsigned flags, unsigned vor, unsigned tor)
|
|
||||||
{
|
|
||||||
return OUT_RELOC(chan, bo, data, flags | NOUVEAU_BO_OR, vor, tor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FB/TT object handle */
|
|
||||||
static __inline__ int
|
|
||||||
OUT_RELOCo(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned flags)
|
|
||||||
{
|
|
||||||
return OUT_RELOC(chan, bo, 0, flags | NOUVEAU_BO_OR,
|
|
||||||
chan->vram->handle, chan->gart->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Low 32-bits of offset */
|
|
||||||
static __inline__ int
|
|
||||||
OUT_RELOCl(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned delta, unsigned flags)
|
|
||||||
{
|
|
||||||
return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_LOW, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Low 32-bits of offset + GPU linear access range info */
|
|
||||||
static __inline__ int
|
|
||||||
OUT_RELOCr(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned delta, unsigned size, unsigned flags)
|
|
||||||
{
|
|
||||||
return OUT_RELOC2(chan, bo, delta, size, flags | NOUVEAU_BO_LOW, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* High 32-bits of offset */
|
|
||||||
static __inline__ int
|
|
||||||
OUT_RELOCh(struct nouveau_channel *chan, struct nouveau_bo *bo,
|
|
||||||
unsigned delta, unsigned flags)
|
|
||||||
{
|
|
||||||
return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_HIGH, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,154 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2010 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
nouveau_reloc_calc(struct drm_nouveau_gem_pushbuf_bo *pbbo,
|
|
||||||
struct drm_nouveau_gem_pushbuf_reloc *r)
|
|
||||||
{
|
|
||||||
uint32_t push = 0;
|
|
||||||
|
|
||||||
if (r->flags & NOUVEAU_GEM_RELOC_LOW)
|
|
||||||
push = (pbbo->presumed.offset + r->data);
|
|
||||||
else
|
|
||||||
if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
|
|
||||||
push = (pbbo->presumed.offset + r->data) >> 32;
|
|
||||||
else
|
|
||||||
push = r->data;
|
|
||||||
|
|
||||||
if (r->flags & NOUVEAU_GEM_RELOC_OR) {
|
|
||||||
if (pbbo->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM)
|
|
||||||
push |= r->vor;
|
|
||||||
else
|
|
||||||
push |= r->tor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return push;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
|
|
||||||
uint32_t reloc_offset, uint32_t *reloc_ptr,
|
|
||||||
struct nouveau_bo *bo, uint32_t data, uint32_t data2,
|
|
||||||
uint32_t flags, uint32_t vor, uint32_t tor)
|
|
||||||
{
|
|
||||||
struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
|
|
||||||
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
|
|
||||||
struct drm_nouveau_gem_pushbuf_reloc *r;
|
|
||||||
struct drm_nouveau_gem_pushbuf_bo *pbbo, *rpbbo;
|
|
||||||
uint32_t domains = 0;
|
|
||||||
|
|
||||||
if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) {
|
|
||||||
fprintf(stderr, "too many relocs!!\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvbo->user && (flags & NOUVEAU_BO_WR)) {
|
|
||||||
fprintf(stderr, "write to user buffer!!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We're about to reloc a user buffer, better make sure we don't cause
|
|
||||||
* a double migration.
|
|
||||||
*/
|
|
||||||
if (!(nvbo->flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM)))
|
|
||||||
nvbo->flags |= (flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM));
|
|
||||||
|
|
||||||
/* add buffer to validation list */
|
|
||||||
pbbo = nouveau_bo_emit_buffer(chan, bo);
|
|
||||||
if (!pbbo) {
|
|
||||||
fprintf(stderr, "buffer emit fail :(\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
nouveau_bo(bo)->pending_refcnt++;
|
|
||||||
|
|
||||||
if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
|
|
||||||
if (flags & NOUVEAU_BO_VRAM)
|
|
||||||
domains |= NOUVEAU_GEM_DOMAIN_VRAM;
|
|
||||||
if (flags & NOUVEAU_BO_GART)
|
|
||||||
domains |= NOUVEAU_GEM_DOMAIN_GART;
|
|
||||||
} else
|
|
||||||
domains |= nvbo->domain;
|
|
||||||
|
|
||||||
if (!(pbbo->valid_domains & domains)) {
|
|
||||||
fprintf(stderr, "no valid domains remain!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
pbbo->valid_domains &= domains;
|
|
||||||
|
|
||||||
assert(flags & NOUVEAU_BO_RDWR);
|
|
||||||
if (flags & NOUVEAU_BO_RD) {
|
|
||||||
pbbo->read_domains |= domains;
|
|
||||||
}
|
|
||||||
if (flags & NOUVEAU_BO_WR) {
|
|
||||||
pbbo->write_domains |= domains;
|
|
||||||
nvbo->write_marker = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* nvc0 gallium driver uses reloc_emit() with NULL target buffer
|
|
||||||
* to inform bufmgr of a buffer's use - however, we need something
|
|
||||||
* to track, so create a reloc for now, and hope it never triggers
|
|
||||||
* (it shouldn't, constant virtual address..)..
|
|
||||||
*/
|
|
||||||
if (!reloc_bo) {
|
|
||||||
reloc_bo = nvpb->buffer[nvpb->current];
|
|
||||||
reloc_offset = 0;
|
|
||||||
reloc_ptr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add reloc target bo to validation list, and create the reloc */
|
|
||||||
rpbbo = nouveau_bo_emit_buffer(chan, reloc_bo);
|
|
||||||
if (!rpbbo)
|
|
||||||
return -ENOMEM;
|
|
||||||
nouveau_bo(reloc_bo)->pending_refcnt++;
|
|
||||||
|
|
||||||
r = nvpb->relocs + nvpb->nr_relocs++;
|
|
||||||
r->reloc_bo_index = rpbbo - nvpb->buffers;
|
|
||||||
r->reloc_bo_offset = reloc_offset;
|
|
||||||
r->bo_index = pbbo - nvpb->buffers;
|
|
||||||
r->flags = 0;
|
|
||||||
if (flags & NOUVEAU_BO_LOW)
|
|
||||||
r->flags |= NOUVEAU_GEM_RELOC_LOW;
|
|
||||||
if (flags & NOUVEAU_BO_HIGH)
|
|
||||||
r->flags |= NOUVEAU_GEM_RELOC_HIGH;
|
|
||||||
if (flags & NOUVEAU_BO_OR)
|
|
||||||
r->flags |= NOUVEAU_GEM_RELOC_OR;
|
|
||||||
r->data = data;
|
|
||||||
r->vor = vor;
|
|
||||||
r->tor = tor;
|
|
||||||
|
|
||||||
if (reloc_ptr) {
|
|
||||||
if (flags & NOUVEAU_BO_DUMMY)
|
|
||||||
*reloc_ptr = 0;
|
|
||||||
else
|
|
||||||
*reloc_ptr = nouveau_reloc_calc(pbbo, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2010 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_RELOC_H__
|
|
||||||
#define __NOUVEAU_RELOC_H__
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
|
|
||||||
uint32_t reloc_offset, uint32_t *reloc_ptr,
|
|
||||||
struct nouveau_bo *bo, uint32_t data, uint32_t data2,
|
|
||||||
uint32_t flags, uint32_t vor, uint32_t tor);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,124 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "nouveau_private.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_resource_init(struct nouveau_resource **heap,
|
|
||||||
unsigned start, unsigned size)
|
|
||||||
{
|
|
||||||
struct nouveau_resource *r;
|
|
||||||
|
|
||||||
r = calloc(1, sizeof(struct nouveau_resource));
|
|
||||||
if (!r)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
r->start = start;
|
|
||||||
r->size = size;
|
|
||||||
*heap = r;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_resource_destroy(struct nouveau_resource **heap)
|
|
||||||
{
|
|
||||||
if (!*heap)
|
|
||||||
return;
|
|
||||||
free(*heap);
|
|
||||||
*heap = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
|
|
||||||
struct nouveau_resource **res)
|
|
||||||
{
|
|
||||||
struct nouveau_resource *r;
|
|
||||||
|
|
||||||
if (!heap || !size || !res || *res)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
while (heap) {
|
|
||||||
if (!heap->in_use && heap->size >= size) {
|
|
||||||
r = calloc(1, sizeof(struct nouveau_resource));
|
|
||||||
if (!r)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
r->start = (heap->start + heap->size) - size;
|
|
||||||
r->size = size;
|
|
||||||
r->in_use = 1;
|
|
||||||
r->priv = priv;
|
|
||||||
|
|
||||||
heap->size -= size;
|
|
||||||
|
|
||||||
r->next = heap->next;
|
|
||||||
if (heap->next)
|
|
||||||
heap->next->prev = r;
|
|
||||||
r->prev = heap;
|
|
||||||
heap->next = r;
|
|
||||||
|
|
||||||
*res = r;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap = heap->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_resource_free(struct nouveau_resource **res)
|
|
||||||
{
|
|
||||||
struct nouveau_resource *r;
|
|
||||||
|
|
||||||
if (!res || !*res)
|
|
||||||
return;
|
|
||||||
r = *res;
|
|
||||||
*res = NULL;
|
|
||||||
|
|
||||||
r->in_use = 0;
|
|
||||||
|
|
||||||
if (r->next && !r->next->in_use) {
|
|
||||||
struct nouveau_resource *new = r->next;
|
|
||||||
|
|
||||||
new->prev = r->prev;
|
|
||||||
if (r->prev)
|
|
||||||
r->prev->next = new;
|
|
||||||
new->size += r->size;
|
|
||||||
new->start = r->start;
|
|
||||||
|
|
||||||
free(r);
|
|
||||||
r = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r->prev && !r->prev->in_use) {
|
|
||||||
r->prev->next = r->next;
|
|
||||||
if (r->next)
|
|
||||||
r->next->prev = r->prev;
|
|
||||||
r->prev->size += r->size;
|
|
||||||
free(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NOUVEAU_RESOURCE_H__
|
|
||||||
#define __NOUVEAU_RESOURCE_H__
|
|
||||||
|
|
||||||
struct nouveau_resource {
|
|
||||||
struct nouveau_resource *prev;
|
|
||||||
struct nouveau_resource *next;
|
|
||||||
|
|
||||||
int in_use;
|
|
||||||
void *priv;
|
|
||||||
|
|
||||||
unsigned int start;
|
|
||||||
unsigned int size;
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_resource_init(struct nouveau_resource **heap, unsigned start,
|
|
||||||
unsigned size);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_resource_destroy(struct nouveau_resource **heap);
|
|
||||||
|
|
||||||
int
|
|
||||||
nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
|
|
||||||
struct nouveau_resource **);
|
|
||||||
|
|
||||||
void
|
|
||||||
nouveau_resource_free(struct nouveau_resource **);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NV04_PUSHBUF_H__
|
|
||||||
#define __NV04_PUSHBUF_H__
|
|
||||||
|
|
||||||
#include "nouveau_pushbuf.h"
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
|
|
||||||
unsigned mthd, unsigned size)
|
|
||||||
{
|
|
||||||
if (gr->bound == NOUVEAU_GROBJ_UNBOUND)
|
|
||||||
nouveau_grobj_autobind(gr);
|
|
||||||
chan->subc[gr->subc].sequence = chan->subc_sequence++;
|
|
||||||
|
|
||||||
WAIT_RING(chan, size + 1);
|
|
||||||
OUT_RING(chan, (gr->subc << 13) | (size << 18) | mthd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* non-incrementing BEGIN_RING */
|
|
||||||
static __inline__ void
|
|
||||||
BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr,
|
|
||||||
unsigned mthd, unsigned size)
|
|
||||||
{
|
|
||||||
BEGIN_RING(chan, gr, mthd | 0x40000000, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc)
|
|
||||||
{
|
|
||||||
struct nouveau_subchannel *subc = &gr->channel->subc[sc];
|
|
||||||
|
|
||||||
if (subc->gr) {
|
|
||||||
if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
|
|
||||||
assert(0);
|
|
||||||
subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
|
|
||||||
}
|
|
||||||
subc->gr = gr;
|
|
||||||
subc->gr->subc = sc;
|
|
||||||
subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
|
|
||||||
|
|
||||||
BEGIN_RING(chan, gr, 0x0000, 1);
|
|
||||||
OUT_RING (chan, gr->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,92 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2010 Nouveau Project
|
|
||||||
*
|
|
||||||
* 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 AUTHORS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NVC0_PUSHBUF_H__
|
|
||||||
#define __NVC0_PUSHBUF_H__
|
|
||||||
|
|
||||||
#include "nouveau_pushbuf.h"
|
|
||||||
|
|
||||||
#define SUBC_BIND(chan, gr) do { \
|
|
||||||
if (gr->bound == NOUVEAU_GROBJ_UNBOUND) \
|
|
||||||
nouveau_grobj_autobind(gr); \
|
|
||||||
chan->subc[gr->subc].sequence = chan->subc_sequence++; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* incremental methods */
|
|
||||||
static __inline__ void
|
|
||||||
BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
|
|
||||||
unsigned mthd, unsigned size)
|
|
||||||
{
|
|
||||||
SUBC_BIND(chan, gr);
|
|
||||||
WAIT_RING(chan, size + 1);
|
|
||||||
OUT_RING (chan, (0x2 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* non-incremental */
|
|
||||||
static __inline__ void
|
|
||||||
BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr,
|
|
||||||
unsigned mthd, unsigned size)
|
|
||||||
{
|
|
||||||
SUBC_BIND(chan, gr);
|
|
||||||
WAIT_RING(chan, size + 1);
|
|
||||||
OUT_RING (chan, (0x6 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* increment-once */
|
|
||||||
static __inline__ void
|
|
||||||
BEGIN_RING_1I(struct nouveau_channel *chan, struct nouveau_grobj *gr,
|
|
||||||
unsigned mthd, unsigned size)
|
|
||||||
{
|
|
||||||
SUBC_BIND(chan, gr);
|
|
||||||
WAIT_RING(chan, size + 1);
|
|
||||||
OUT_RING (chan, (0xa << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* inline-data */
|
|
||||||
static __inline__ void
|
|
||||||
IMMED_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
|
|
||||||
unsigned mthd, unsigned data)
|
|
||||||
{
|
|
||||||
SUBC_BIND(chan, gr);
|
|
||||||
WAIT_RING(chan, 1);
|
|
||||||
OUT_RING (chan, (0x8 << 28) | (data << 16) | (gr->subc << 13) | (mthd >> 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void
|
|
||||||
BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc)
|
|
||||||
{
|
|
||||||
struct nouveau_subchannel *subc = &gr->channel->subc[sc];
|
|
||||||
|
|
||||||
if (subc->gr) {
|
|
||||||
if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
|
|
||||||
assert(0);
|
|
||||||
subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
|
|
||||||
}
|
|
||||||
subc->gr = gr;
|
|
||||||
subc->gr->subc = sc;
|
|
||||||
subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
|
|
||||||
|
|
||||||
BEGIN_RING(chan, gr, 0x0000, 1);
|
|
||||||
OUT_RING (chan, gr->grclass);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
#ifndef __NOUVEAU_LIBDRM_PRIVATE_H__
|
||||||
|
#define __NOUVEAU_LIBDRM_PRIVATE_H__
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86atomic.h>
|
||||||
|
#include "nouveau_drm.h"
|
||||||
|
|
||||||
|
#include "nouveau.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
uint32_t nouveau_debug;
|
||||||
|
#define dbg_on(lvl) (nouveau_debug & (1 << lvl))
|
||||||
|
#define dbg(lvl, fmt, args...) do { \
|
||||||
|
if (dbg_on((lvl))) \
|
||||||
|
fprintf(stderr, "nouveau: "fmt, ##args); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define dbg_on(lvl) (0)
|
||||||
|
#define dbg(lvl, fmt, args...)
|
||||||
|
#endif
|
||||||
|
#define err(fmt, args...) fprintf(stderr, "nouveau: "fmt, ##args)
|
||||||
|
|
||||||
|
struct nouveau_client_kref {
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
struct nouveau_pushbuf *push;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nouveau_client_priv {
|
||||||
|
struct nouveau_client base;
|
||||||
|
struct nouveau_client_kref *kref;
|
||||||
|
unsigned kref_nr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct nouveau_client_priv *
|
||||||
|
nouveau_client(struct nouveau_client *client)
|
||||||
|
{
|
||||||
|
return (struct nouveau_client_priv *)client;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct drm_nouveau_gem_pushbuf_bo *
|
||||||
|
cli_kref_get(struct nouveau_client *client, struct nouveau_bo *bo)
|
||||||
|
{
|
||||||
|
struct nouveau_client_priv *pcli = nouveau_client(client);
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref = NULL;
|
||||||
|
if (pcli->kref_nr > bo->handle)
|
||||||
|
kref = pcli->kref[bo->handle].kref;
|
||||||
|
return kref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct nouveau_pushbuf *
|
||||||
|
cli_push_get(struct nouveau_client *client, struct nouveau_bo *bo)
|
||||||
|
{
|
||||||
|
struct nouveau_client_priv *pcli = nouveau_client(client);
|
||||||
|
struct nouveau_pushbuf *push = NULL;
|
||||||
|
if (pcli->kref_nr > bo->handle)
|
||||||
|
push = pcli->kref[bo->handle].push;
|
||||||
|
return push;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
cli_kref_set(struct nouveau_client *client, struct nouveau_bo *bo,
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref,
|
||||||
|
struct nouveau_pushbuf *push)
|
||||||
|
{
|
||||||
|
struct nouveau_client_priv *pcli = nouveau_client(client);
|
||||||
|
if (pcli->kref_nr <= bo->handle) {
|
||||||
|
pcli->kref = realloc(pcli->kref,
|
||||||
|
sizeof(*pcli->kref) * bo->handle * 2);
|
||||||
|
while (pcli->kref_nr < bo->handle * 2) {
|
||||||
|
pcli->kref[pcli->kref_nr].kref = NULL;
|
||||||
|
pcli->kref[pcli->kref_nr].push = NULL;
|
||||||
|
pcli->kref_nr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pcli->kref[bo->handle].kref = kref;
|
||||||
|
pcli->kref[bo->handle].push = push;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nouveau_bo_priv {
|
||||||
|
struct nouveau_bo base;
|
||||||
|
struct nouveau_list head;
|
||||||
|
atomic_t refcnt;
|
||||||
|
uint64_t map_handle;
|
||||||
|
uint32_t name;
|
||||||
|
uint32_t access;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct nouveau_bo_priv *
|
||||||
|
nouveau_bo(struct nouveau_bo *bo)
|
||||||
|
{
|
||||||
|
return (struct nouveau_bo_priv *)bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nouveau_device_priv {
|
||||||
|
struct nouveau_device base;
|
||||||
|
int close;
|
||||||
|
atomic_t lock;
|
||||||
|
struct nouveau_list bo_list;
|
||||||
|
uint32_t *client;
|
||||||
|
int nr_client;
|
||||||
|
bool have_bo_usage;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct nouveau_device_priv *
|
||||||
|
nouveau_device(struct nouveau_device *dev)
|
||||||
|
{
|
||||||
|
return (struct nouveau_device_priv *)dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t);
|
||||||
|
|
||||||
|
/* abi16.c */
|
||||||
|
int abi16_chan_nv04(struct nouveau_object *);
|
||||||
|
int abi16_chan_nvc0(struct nouveau_object *);
|
||||||
|
int abi16_engobj(struct nouveau_object *);
|
||||||
|
int abi16_ntfy(struct nouveau_object *);
|
||||||
|
void abi16_bo_info(struct nouveau_bo *, struct drm_nouveau_gem_info *);
|
||||||
|
int abi16_bo_init(struct nouveau_bo *, uint32_t alignment,
|
||||||
|
union nouveau_bo_config *);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,774 @@
|
||||||
|
/*
|
||||||
|
* 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 <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86atomic.h>
|
||||||
|
#include "libdrm_lists.h"
|
||||||
|
#include "nouveau_drm.h"
|
||||||
|
|
||||||
|
#include "nouveau.h"
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
struct nouveau_pushbuf_krec {
|
||||||
|
struct nouveau_pushbuf_krec *next;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo buffer[NOUVEAU_GEM_MAX_BUFFERS];
|
||||||
|
struct drm_nouveau_gem_pushbuf_reloc reloc[NOUVEAU_GEM_MAX_RELOCS];
|
||||||
|
struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH];
|
||||||
|
int nr_buffer;
|
||||||
|
int nr_reloc;
|
||||||
|
int nr_push;
|
||||||
|
uint64_t vram_used;
|
||||||
|
uint64_t gart_used;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nouveau_pushbuf_priv {
|
||||||
|
struct nouveau_pushbuf base;
|
||||||
|
struct nouveau_pushbuf_krec *list;
|
||||||
|
struct nouveau_pushbuf_krec *krec;
|
||||||
|
struct nouveau_list bctx_list;
|
||||||
|
struct nouveau_bo *bo;
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t suffix0;
|
||||||
|
uint32_t suffix1;
|
||||||
|
uint32_t *ptr;
|
||||||
|
uint32_t *bgn;
|
||||||
|
int bo_next;
|
||||||
|
int bo_nr;
|
||||||
|
struct nouveau_bo *bos[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct nouveau_pushbuf_priv *
|
||||||
|
nouveau_pushbuf(struct nouveau_pushbuf *push)
|
||||||
|
{
|
||||||
|
return (struct nouveau_pushbuf_priv *)push;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pushbuf_validate(struct nouveau_pushbuf *, bool);
|
||||||
|
static int pushbuf_flush(struct nouveau_pushbuf *);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
pushbuf_kref_fits(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
|
||||||
|
uint32_t *domains)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct nouveau_device *dev = push->client->device;
|
||||||
|
struct nouveau_bo *kbo;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* VRAM is the only valid domain. GART and VRAM|GART buffers
|
||||||
|
* are all accounted to GART, so if this doesn't fit in VRAM
|
||||||
|
* straight up, a flush is needed.
|
||||||
|
*/
|
||||||
|
if (*domains == NOUVEAU_GEM_DOMAIN_VRAM) {
|
||||||
|
if (krec->vram_used + bo->size > dev->vram_limit)
|
||||||
|
return false;
|
||||||
|
krec->vram_used += bo->size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GART or VRAM|GART buffer. Account both of these buffer types
|
||||||
|
* to GART only for the moment, which simplifies things. If the
|
||||||
|
* buffer can fit already, we're done here.
|
||||||
|
*/
|
||||||
|
if (krec->gart_used + bo->size <= dev->gart_limit) {
|
||||||
|
krec->gart_used += bo->size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ran out of GART space, if it's a VRAM|GART buffer and it'll
|
||||||
|
* fit into available VRAM, turn it into a VRAM buffer
|
||||||
|
*/
|
||||||
|
if ((*domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
|
||||||
|
krec->vram_used + bo->size <= dev->vram_limit) {
|
||||||
|
*domains &= NOUVEAU_GEM_DOMAIN_VRAM;
|
||||||
|
krec->vram_used += bo->size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Still couldn't fit the buffer in anywhere, so as a last resort;
|
||||||
|
* scan the buffer list for VRAM|GART buffers and turn them into
|
||||||
|
* VRAM buffers until we have enough space in GART for this one
|
||||||
|
*/
|
||||||
|
kref = krec->buffer;
|
||||||
|
for (i = 0; i < krec->nr_buffer; i++, kref++) {
|
||||||
|
if (!(kref->valid_domains & NOUVEAU_GEM_DOMAIN_GART))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
kbo = (void *)(unsigned long)kref->user_priv;
|
||||||
|
if (!(kref->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) ||
|
||||||
|
krec->vram_used + kbo->size > dev->vram_limit)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
kref->valid_domains &= NOUVEAU_GEM_DOMAIN_VRAM;
|
||||||
|
krec->gart_used -= kbo->size;
|
||||||
|
krec->vram_used += kbo->size;
|
||||||
|
if (krec->gart_used + bo->size <= dev->gart_limit) {
|
||||||
|
krec->gart_used += bo->size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Couldn't resolve a placement, need to force a flush */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct drm_nouveau_gem_pushbuf_bo *
|
||||||
|
pushbuf_kref(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
struct nouveau_device *dev = push->client->device;
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct nouveau_pushbuf *fpush;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
uint32_t domains, domains_wr, domains_rd;
|
||||||
|
|
||||||
|
domains = 0;
|
||||||
|
if (flags & NOUVEAU_BO_VRAM)
|
||||||
|
domains |= NOUVEAU_GEM_DOMAIN_VRAM;
|
||||||
|
if (flags & NOUVEAU_BO_GART)
|
||||||
|
domains |= NOUVEAU_GEM_DOMAIN_GART;
|
||||||
|
domains_wr = domains * !!(flags & NOUVEAU_BO_WR);
|
||||||
|
domains_rd = domains * !!(flags & NOUVEAU_BO_RD);
|
||||||
|
|
||||||
|
/* if buffer is referenced on another pushbuf that is owned by the
|
||||||
|
* same client, we need to flush the other pushbuf first to ensure
|
||||||
|
* the correct ordering of commands
|
||||||
|
*/
|
||||||
|
fpush = cli_push_get(push->client, bo);
|
||||||
|
if (fpush && fpush != push)
|
||||||
|
pushbuf_flush(fpush);
|
||||||
|
|
||||||
|
kref = cli_kref_get(push->client, bo);
|
||||||
|
if (kref) {
|
||||||
|
/* possible conflict in memory types - flush and retry */
|
||||||
|
if (!(kref->valid_domains & domains))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* VRAM|GART buffer turning into a VRAM buffer. Make sure
|
||||||
|
* it'll fit in VRAM and force a flush if not.
|
||||||
|
*/
|
||||||
|
if ((kref->valid_domains & NOUVEAU_GEM_DOMAIN_GART) &&
|
||||||
|
( domains == NOUVEAU_GEM_DOMAIN_VRAM)) {
|
||||||
|
if (krec->vram_used + bo->size > dev->vram_limit)
|
||||||
|
return NULL;
|
||||||
|
krec->vram_used += bo->size;
|
||||||
|
krec->gart_used -= bo->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
kref->valid_domains &= domains;
|
||||||
|
kref->write_domains |= domains_wr;
|
||||||
|
kref->read_domains |= domains_rd;
|
||||||
|
} else {
|
||||||
|
if (krec->nr_buffer == NOUVEAU_GEM_MAX_BUFFERS ||
|
||||||
|
!pushbuf_kref_fits(push, bo, &domains))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
kref = &krec->buffer[krec->nr_buffer++];
|
||||||
|
kref->user_priv = (unsigned long)bo;
|
||||||
|
kref->handle = bo->handle;
|
||||||
|
kref->valid_domains = domains;
|
||||||
|
kref->write_domains = domains_wr;
|
||||||
|
kref->read_domains = domains_rd;
|
||||||
|
kref->presumed.valid = 1;
|
||||||
|
kref->presumed.offset = bo->offset;
|
||||||
|
if (bo->flags & NOUVEAU_BO_VRAM)
|
||||||
|
kref->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM;
|
||||||
|
else
|
||||||
|
kref->presumed.domain = NOUVEAU_GEM_DOMAIN_GART;
|
||||||
|
|
||||||
|
cli_kref_set(push->client, bo, kref, push);
|
||||||
|
atomic_inc(&nouveau_bo(bo)->refcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return kref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
pushbuf_krel(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
|
||||||
|
uint32_t data, uint32_t flags, uint32_t vor, uint32_t tor)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct drm_nouveau_gem_pushbuf_reloc *krel;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *pkref;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *bkref;
|
||||||
|
uint32_t reloc = data;
|
||||||
|
|
||||||
|
pkref = cli_kref_get(push->client, nvpb->bo);
|
||||||
|
bkref = cli_kref_get(push->client, bo);
|
||||||
|
krel = &krec->reloc[krec->nr_reloc++];
|
||||||
|
|
||||||
|
krel->reloc_bo_index = pkref - krec->buffer;
|
||||||
|
krel->reloc_bo_offset = (push->cur - nvpb->ptr) * 4;
|
||||||
|
krel->bo_index = bkref - krec->buffer;
|
||||||
|
krel->flags = 0;
|
||||||
|
krel->data = data;
|
||||||
|
krel->vor = vor;
|
||||||
|
krel->tor = tor;
|
||||||
|
|
||||||
|
if (flags & NOUVEAU_BO_LOW) {
|
||||||
|
reloc = (bkref->presumed.offset + data);
|
||||||
|
krel->flags |= NOUVEAU_GEM_RELOC_LOW;
|
||||||
|
} else
|
||||||
|
if (flags & NOUVEAU_BO_HIGH) {
|
||||||
|
reloc = (bkref->presumed.offset + data) >> 32;
|
||||||
|
krel->flags |= NOUVEAU_GEM_RELOC_HIGH;
|
||||||
|
}
|
||||||
|
if (flags & NOUVEAU_BO_OR) {
|
||||||
|
if (bkref->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM)
|
||||||
|
reloc |= vor;
|
||||||
|
else
|
||||||
|
reloc |= tor;
|
||||||
|
krel->flags |= NOUVEAU_GEM_RELOC_OR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pushbuf_dump(struct nouveau_pushbuf_krec *krec, int krec_id, int chid)
|
||||||
|
{
|
||||||
|
struct drm_nouveau_gem_pushbuf_reloc *krel;
|
||||||
|
struct drm_nouveau_gem_pushbuf_push *kpsh;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
struct nouveau_bo *bo;
|
||||||
|
uint32_t *bgn, *end;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
err("ch%d: krec %d pushes %d bufs %d relocs %d\n", chid,
|
||||||
|
krec_id, krec->nr_push, krec->nr_buffer, krec->nr_reloc);
|
||||||
|
|
||||||
|
kref = krec->buffer;
|
||||||
|
for (i = 0; i < krec->nr_buffer; i++, kref++) {
|
||||||
|
err("ch%d: buf %08x %08x %08x %08x %08x\n", chid, i,
|
||||||
|
kref->handle, kref->valid_domains,
|
||||||
|
kref->read_domains, kref->write_domains);
|
||||||
|
}
|
||||||
|
|
||||||
|
krel = krec->reloc;
|
||||||
|
for (i = 0; i < krec->nr_reloc; i++, krel++) {
|
||||||
|
err("ch%d: rel %08x %08x %08x %08x %08x %08x %08x\n",
|
||||||
|
chid, krel->reloc_bo_index, krel->reloc_bo_offset,
|
||||||
|
krel->bo_index, krel->flags, krel->data,
|
||||||
|
krel->vor, krel->tor);
|
||||||
|
}
|
||||||
|
|
||||||
|
kpsh = krec->push;
|
||||||
|
for (i = 0; i < krec->nr_push; i++, kpsh++) {
|
||||||
|
kref = krec->buffer + kpsh->bo_index;
|
||||||
|
bo = (void *)(unsigned long)kref->user_priv;
|
||||||
|
bgn = (uint32_t *)((char *)bo->map + kpsh->offset);
|
||||||
|
end = bgn + (kpsh->length /4);
|
||||||
|
|
||||||
|
err("ch%d: psh %08x %010llx %010llx\n", chid, kpsh->bo_index,
|
||||||
|
(unsigned long long)kpsh->offset,
|
||||||
|
(unsigned long long)(kpsh->offset + kpsh->length));
|
||||||
|
while (bgn < end)
|
||||||
|
err("\t0x%08x\n", *bgn++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->list;
|
||||||
|
struct nouveau_device *dev = push->client->device;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo_presumed *info;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
struct drm_nouveau_gem_pushbuf req;
|
||||||
|
struct nouveau_fifo *fifo = chan->data;
|
||||||
|
struct nouveau_bo *bo;
|
||||||
|
int krec_id = 0;
|
||||||
|
int ret = 0, i;
|
||||||
|
|
||||||
|
if (chan->oclass != NOUVEAU_FIFO_CHANNEL_CLASS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (push->kick_notify)
|
||||||
|
push->kick_notify(push);
|
||||||
|
|
||||||
|
nouveau_pushbuf_data(push, NULL, 0, 0);
|
||||||
|
|
||||||
|
while (krec && krec->nr_push) {
|
||||||
|
req.channel = fifo->channel;
|
||||||
|
req.nr_buffers = krec->nr_buffer;
|
||||||
|
req.buffers = (uint64_t)(unsigned long)krec->buffer;
|
||||||
|
req.nr_relocs = krec->nr_reloc;
|
||||||
|
req.nr_push = krec->nr_push;
|
||||||
|
req.relocs = (uint64_t)(unsigned long)krec->reloc;
|
||||||
|
req.push = (uint64_t)(unsigned long)krec->push;
|
||||||
|
req.suffix0 = nvpb->suffix0;
|
||||||
|
req.suffix1 = nvpb->suffix1;
|
||||||
|
|
||||||
|
if (dbg_on(0))
|
||||||
|
pushbuf_dump(krec, krec_id++, fifo->channel);
|
||||||
|
|
||||||
|
#ifndef SIMULATE
|
||||||
|
do {
|
||||||
|
ret = drmCommandWriteRead(dev->fd,
|
||||||
|
DRM_NOUVEAU_GEM_PUSHBUF,
|
||||||
|
&req, sizeof(req));
|
||||||
|
} while (ret == -EAGAIN);
|
||||||
|
nvpb->suffix0 = req.suffix0;
|
||||||
|
nvpb->suffix1 = req.suffix1;
|
||||||
|
dev->vram_limit = (req.vram_available * 80) / 100;
|
||||||
|
dev->gart_limit = (req.gart_available * 80) / 100;
|
||||||
|
#else
|
||||||
|
if (dbg_on(31))
|
||||||
|
ret = -EINVAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
err("kernel rejected pushbuf: %s\n", strerror(-ret));
|
||||||
|
pushbuf_dump(krec, krec_id++, fifo->channel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
kref = krec->buffer;
|
||||||
|
for (i = 0; i < krec->nr_buffer; i++, kref++) {
|
||||||
|
bo = (void *)(unsigned long)kref->user_priv;
|
||||||
|
|
||||||
|
info = &kref->presumed;
|
||||||
|
if (!info->valid) {
|
||||||
|
bo->flags &= ~NOUVEAU_BO_APER;
|
||||||
|
if (info->domain == NOUVEAU_GEM_DOMAIN_VRAM)
|
||||||
|
bo->flags |= NOUVEAU_BO_VRAM;
|
||||||
|
else
|
||||||
|
bo->flags |= NOUVEAU_BO_GART;
|
||||||
|
bo->offset = info->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kref->write_domains)
|
||||||
|
nouveau_bo(bo)->access |= NOUVEAU_BO_WR;
|
||||||
|
if (kref->read_domains)
|
||||||
|
nouveau_bo(bo)->access |= NOUVEAU_BO_RD;
|
||||||
|
}
|
||||||
|
|
||||||
|
krec = krec->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pushbuf_flush(struct nouveau_pushbuf *push)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
struct nouveau_bufctx *bctx, *btmp;
|
||||||
|
struct nouveau_bo *bo;
|
||||||
|
int ret = 0, i;
|
||||||
|
|
||||||
|
if (push->channel) {
|
||||||
|
ret = pushbuf_submit(push, push->channel);
|
||||||
|
} else {
|
||||||
|
nouveau_pushbuf_data(push, NULL, 0, 0);
|
||||||
|
krec->next = malloc(sizeof(*krec));
|
||||||
|
nvpb->krec = krec->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
kref = krec->buffer;
|
||||||
|
for (i = 0; i < krec->nr_buffer; i++, kref++) {
|
||||||
|
bo = (void *)(unsigned long)kref->user_priv;
|
||||||
|
cli_kref_set(push->client, bo, NULL, NULL);
|
||||||
|
if (push->channel)
|
||||||
|
nouveau_bo_ref(NULL, &bo);
|
||||||
|
}
|
||||||
|
|
||||||
|
krec = nvpb->krec;
|
||||||
|
krec->vram_used = 0;
|
||||||
|
krec->gart_used = 0;
|
||||||
|
krec->nr_buffer = 0;
|
||||||
|
krec->nr_reloc = 0;
|
||||||
|
krec->nr_push = 0;
|
||||||
|
|
||||||
|
DRMLISTFOREACHENTRYSAFE(bctx, btmp, &nvpb->bctx_list, head) {
|
||||||
|
DRMLISTJOIN(&bctx->current, &bctx->pending);
|
||||||
|
DRMINITLISTHEAD(&bctx->current);
|
||||||
|
DRMLISTDELINIT(&bctx->head);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pushbuf_refn_fail(struct nouveau_pushbuf *push, int sref, int srel)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
|
||||||
|
kref = krec->buffer + sref;
|
||||||
|
while (krec->nr_buffer-- > sref) {
|
||||||
|
struct nouveau_bo *bo = (void *)(unsigned long)kref->user_priv;
|
||||||
|
cli_kref_set(push->client, bo, NULL, NULL);
|
||||||
|
nouveau_bo_ref(NULL, &bo);
|
||||||
|
kref++;
|
||||||
|
}
|
||||||
|
krec->nr_buffer = sref;
|
||||||
|
krec->nr_reloc = srel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pushbuf_refn(struct nouveau_pushbuf *push, bool retry,
|
||||||
|
struct nouveau_pushbuf_refn *refs, int nr)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
int sref = krec->nr_buffer;
|
||||||
|
int ret = 0, i;
|
||||||
|
|
||||||
|
for (i = 0; i < nr; i++) {
|
||||||
|
kref = pushbuf_kref(push, refs[i].bo, refs[i].flags);
|
||||||
|
if (!kref) {
|
||||||
|
ret = -ENOSPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pushbuf_refn_fail(push, sref, krec->nr_reloc);
|
||||||
|
if (retry) {
|
||||||
|
pushbuf_flush(push);
|
||||||
|
nouveau_pushbuf_space(push, 0, 0, 0);
|
||||||
|
return pushbuf_refn(push, false, refs, nr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pushbuf_validate(struct nouveau_pushbuf *push, bool retry)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
struct nouveau_bufctx *bctx = push->bufctx;
|
||||||
|
struct nouveau_bufref *bref;
|
||||||
|
int relocs = bctx ? bctx->relocs * 2: 0;
|
||||||
|
int sref, srel, ret;
|
||||||
|
|
||||||
|
ret = nouveau_pushbuf_space(push, relocs, relocs, 0);
|
||||||
|
if (ret || bctx == NULL)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
sref = krec->nr_buffer;
|
||||||
|
srel = krec->nr_reloc;
|
||||||
|
|
||||||
|
DRMLISTDEL(&bctx->head);
|
||||||
|
DRMLISTADD(&bctx->head, &nvpb->bctx_list);
|
||||||
|
|
||||||
|
DRMLISTFOREACHENTRY(bref, &bctx->pending, thead) {
|
||||||
|
kref = pushbuf_kref(push, bref->bo, bref->flags);
|
||||||
|
if (!kref) {
|
||||||
|
ret = -ENOSPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bref->packet) {
|
||||||
|
pushbuf_krel(push, bref->bo, bref->packet, 0, 0, 0);
|
||||||
|
*push->cur++ = 0;
|
||||||
|
pushbuf_krel(push, bref->bo, bref->data, bref->flags,
|
||||||
|
bref->vor, bref->tor);
|
||||||
|
*push->cur++ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRMLISTJOIN(&bctx->pending, &bctx->current);
|
||||||
|
DRMINITLISTHEAD(&bctx->pending);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pushbuf_refn_fail(push, sref, srel);
|
||||||
|
if (retry) {
|
||||||
|
pushbuf_flush(push);
|
||||||
|
return pushbuf_validate(push, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_pushbuf_new(struct nouveau_client *client, struct nouveau_object *chan,
|
||||||
|
int nr, uint32_t size, bool immediate,
|
||||||
|
struct nouveau_pushbuf **ppush)
|
||||||
|
{
|
||||||
|
struct nouveau_device *dev = client->device;
|
||||||
|
struct nouveau_fifo *fifo = chan->data;
|
||||||
|
struct nouveau_pushbuf_priv *nvpb;
|
||||||
|
struct nouveau_pushbuf *push;
|
||||||
|
struct drm_nouveau_gem_pushbuf req;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (chan->oclass != NOUVEAU_FIFO_CHANNEL_CLASS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* nop pushbuf call, to get the current "return to main" sequence
|
||||||
|
* we need to append to the pushbuf on early chipsets
|
||||||
|
*/
|
||||||
|
req.channel = fifo->channel;
|
||||||
|
req.nr_push = 0;
|
||||||
|
ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
|
||||||
|
&req, sizeof(req));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
nvpb = calloc(1, sizeof(*nvpb) + nr * sizeof(*nvpb->bos));
|
||||||
|
if (!nvpb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
#ifndef SIMULATE
|
||||||
|
nvpb->suffix0 = req.suffix0;
|
||||||
|
nvpb->suffix1 = req.suffix1;
|
||||||
|
#else
|
||||||
|
nvpb->suffix0 = 0xffffffff;
|
||||||
|
nvpb->suffix1 = 0xffffffff;
|
||||||
|
#endif
|
||||||
|
nvpb->krec = calloc(1, sizeof(*nvpb->krec));
|
||||||
|
nvpb->list = nvpb->krec;
|
||||||
|
if (!nvpb->krec) {
|
||||||
|
free(nvpb);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
push = &nvpb->base;
|
||||||
|
push->client = client;
|
||||||
|
push->channel = immediate ? chan : NULL;
|
||||||
|
push->flags = NOUVEAU_BO_RD;
|
||||||
|
if (fifo->pushbuf & NOUVEAU_GEM_DOMAIN_VRAM) {
|
||||||
|
push->flags |= NOUVEAU_BO_VRAM;
|
||||||
|
nvpb->type = NOUVEAU_BO_VRAM;
|
||||||
|
}
|
||||||
|
if (fifo->pushbuf & NOUVEAU_GEM_DOMAIN_GART) {
|
||||||
|
push->flags |= NOUVEAU_BO_GART;
|
||||||
|
nvpb->type = NOUVEAU_BO_GART;
|
||||||
|
}
|
||||||
|
nvpb->type |= NOUVEAU_BO_MAP;
|
||||||
|
|
||||||
|
for (nvpb->bo_nr = 0; nvpb->bo_nr < nr; nvpb->bo_nr++) {
|
||||||
|
ret = nouveau_bo_new(client->device, nvpb->type, 0, size,
|
||||||
|
NULL, &nvpb->bos[nvpb->bo_nr]);
|
||||||
|
if (ret) {
|
||||||
|
nouveau_pushbuf_del(&push);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRMINITLISTHEAD(&nvpb->bctx_list);
|
||||||
|
*ppush = push;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nouveau_pushbuf_del(struct nouveau_pushbuf **ppush)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(*ppush);
|
||||||
|
if (nvpb) {
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
struct nouveau_pushbuf_krec *krec;
|
||||||
|
while ((krec = nvpb->list)) {
|
||||||
|
kref = krec->buffer;
|
||||||
|
while (krec->nr_buffer--) {
|
||||||
|
unsigned long priv = kref++->user_priv;
|
||||||
|
struct nouveau_bo *bo = (void *)priv;
|
||||||
|
cli_kref_set(nvpb->base.client, bo, NULL, NULL);
|
||||||
|
nouveau_bo_ref(NULL, &bo);
|
||||||
|
}
|
||||||
|
nvpb->list = krec->next;
|
||||||
|
free(krec);
|
||||||
|
}
|
||||||
|
while (nvpb->bo_nr--)
|
||||||
|
nouveau_bo_ref(NULL, &nvpb->bos[nvpb->bo_nr]);
|
||||||
|
nouveau_bo_ref(NULL, &nvpb->bo);
|
||||||
|
free(nvpb);
|
||||||
|
}
|
||||||
|
*ppush = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nouveau_bufctx *
|
||||||
|
nouveau_pushbuf_bufctx(struct nouveau_pushbuf *push, struct nouveau_bufctx *ctx)
|
||||||
|
{
|
||||||
|
struct nouveau_bufctx *prev = push->bufctx;
|
||||||
|
push->bufctx = ctx;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_pushbuf_space(struct nouveau_pushbuf *push,
|
||||||
|
uint32_t dwords, uint32_t relocs, uint32_t pushes)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct nouveau_client *client = push->client;
|
||||||
|
struct nouveau_bo *bo = NULL;
|
||||||
|
bool flushed = false;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* switch to next buffer if insufficient space in the current one */
|
||||||
|
if (push->cur + dwords >= push->end) {
|
||||||
|
if (nvpb->bo_next < nvpb->bo_nr) {
|
||||||
|
nouveau_bo_ref(nvpb->bos[nvpb->bo_next++], &bo);
|
||||||
|
if (nvpb->bo_next == nvpb->bo_nr && push->channel)
|
||||||
|
nvpb->bo_next = 0;
|
||||||
|
} else {
|
||||||
|
ret = nouveau_bo_new(client->device, nvpb->type, 0,
|
||||||
|
nvpb->bos[0]->size, NULL, &bo);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure there's always enough space to queue up the pending
|
||||||
|
* data in the pushbuf proper
|
||||||
|
*/
|
||||||
|
pushes++;
|
||||||
|
|
||||||
|
/* need to flush if we've run out of space on an immediate pushbuf,
|
||||||
|
* if the new buffer won't fit, or if the kernel push/reloc limits
|
||||||
|
* have been hit
|
||||||
|
*/
|
||||||
|
if ((bo && ( push->channel ||
|
||||||
|
!pushbuf_kref(push, bo, push->flags))) ||
|
||||||
|
krec->nr_reloc + relocs >= NOUVEAU_GEM_MAX_RELOCS ||
|
||||||
|
krec->nr_push + pushes >= NOUVEAU_GEM_MAX_PUSH) {
|
||||||
|
if (nvpb->bo && krec->nr_buffer)
|
||||||
|
pushbuf_flush(push);
|
||||||
|
flushed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if necessary, switch to new buffer */
|
||||||
|
if (bo) {
|
||||||
|
ret = nouveau_bo_map(bo, NOUVEAU_BO_WR, push->client);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
nouveau_pushbuf_data(push, NULL, 0, 0);
|
||||||
|
nouveau_bo_ref(bo, &nvpb->bo);
|
||||||
|
nouveau_bo_ref(NULL, &bo);
|
||||||
|
|
||||||
|
nvpb->bgn = nvpb->bo->map;
|
||||||
|
nvpb->ptr = nvpb->bgn;
|
||||||
|
push->cur = nvpb->bgn;
|
||||||
|
push->end = push->cur + (nvpb->bo->size / 4);
|
||||||
|
push->end -= 2 + push->rsvd_kick; /* space for suffix */
|
||||||
|
}
|
||||||
|
|
||||||
|
pushbuf_kref(push, nvpb->bo, push->flags);
|
||||||
|
return flushed ? pushbuf_validate(push, false) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nouveau_pushbuf_data(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
|
||||||
|
uint64_t offset, uint64_t length)
|
||||||
|
{
|
||||||
|
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
|
||||||
|
struct nouveau_pushbuf_krec *krec = nvpb->krec;
|
||||||
|
struct drm_nouveau_gem_pushbuf_push *kpsh;
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
|
||||||
|
if (bo != nvpb->bo && nvpb->bgn != push->cur) {
|
||||||
|
if (nvpb->suffix0 || nvpb->suffix1) {
|
||||||
|
*push->cur++ = nvpb->suffix0;
|
||||||
|
*push->cur++ = nvpb->suffix1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nouveau_pushbuf_data(push, nvpb->bo,
|
||||||
|
(nvpb->bgn - nvpb->ptr) * 4,
|
||||||
|
(push->cur - nvpb->bgn) * 4);
|
||||||
|
nvpb->bgn = push->cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bo) {
|
||||||
|
kref = cli_kref_get(push->client, bo);
|
||||||
|
kpsh = &krec->push[krec->nr_push++];
|
||||||
|
kpsh->bo_index = kref - krec->buffer;
|
||||||
|
kpsh->offset = offset;
|
||||||
|
kpsh->length = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_pushbuf_refn(struct nouveau_pushbuf *push,
|
||||||
|
struct nouveau_pushbuf_refn *refs, int nr)
|
||||||
|
{
|
||||||
|
return pushbuf_refn(push, true, refs, nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nouveau_pushbuf_reloc(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
|
||||||
|
uint32_t data, uint32_t flags, uint32_t vor, uint32_t tor)
|
||||||
|
{
|
||||||
|
*push->cur++ = pushbuf_krel(push, bo, data, flags, vor, tor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_pushbuf_validate(struct nouveau_pushbuf *push)
|
||||||
|
{
|
||||||
|
return pushbuf_validate(push, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
nouveau_pushbuf_refd(struct nouveau_pushbuf *push, struct nouveau_bo *bo)
|
||||||
|
{
|
||||||
|
struct drm_nouveau_gem_pushbuf_bo *kref;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
|
||||||
|
if (cli_push_get(push->client, bo) == push) {
|
||||||
|
kref = cli_kref_get(push->client, bo);
|
||||||
|
if (kref->read_domains)
|
||||||
|
flags |= NOUVEAU_BO_RD;
|
||||||
|
if (kref->write_domains)
|
||||||
|
flags |= NOUVEAU_BO_WR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_pushbuf_kick(struct nouveau_pushbuf *push, struct nouveau_object *chan)
|
||||||
|
{
|
||||||
|
if (!push->channel)
|
||||||
|
return pushbuf_submit(push, chan);
|
||||||
|
pushbuf_flush(push);
|
||||||
|
return pushbuf_validate(push, false);
|
||||||
|
}
|
Loading…
Reference in New Issue