You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
drm/nouveau/core: pull in most of the new core infrastructure
This commit provides most of the infrastructure to support a major overhaul of Nouveau's internals coming in the following commits. This work aims to take all the things we've learned over the last several years, and turn that into a cleaner architecture that's more maintainable going forward. RAMHT and MM bits of the new core have been left out for the moment, and will be pulled in as I go through the process of porting the code to become either subdev or engine modules. There are several main goals I wanted to achieve through this work: -- Reduce complexity The goal here was to make each component of the driver as independent as possible, which will ease maintainability and readability, and provide a good base for resetting locked up GPU units in the future. -- Better tracking of GPU units that are required at any given time This is for future PM work, we'll be able to tell exactly what parts of the GPU we need powered at any given point (etc). -- Expose all available NVIDIA GPUs to the client In order to support things such as multi-GPU channels, we want to be able to expose all the NVIDIA GPUs to the client over a single file descriptor so it can send a single push buffer to multiple GPUs. -- Untangle the core hardware support code from the DRM implementation This happened initially as an unexpected side-effect of developing the initial core infrastructure in userspace, but it turned into a goal of the whole project. Initial benefits will be the availablility of a number of userspace tools and tests using the same code as the driver itself, but will also be important as I look into some virtualisation ideas. v2: Ben Skeggs <bskeggs@redhat.com> - fix duplicate assignments noticed by clang - implement some forgotten yelling in error path - ensure 64-bit engine mask is used everywhere v3: Marcin Slusarz <marcin.slusarz@gmail.com> - sparse fixes - inline nv_printk into nv_assert to prevent recursive inlining issues v4: Ben Skeggs <bskeggs@redhat.com> - fixed minor memory leak on gpuobj destruction Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
@@ -2,13 +2,31 @@
|
||||
# Makefile for the drm device driver. This driver provides support for the
|
||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
ccflags-y := -Iinclude/drm
|
||||
ccflags-y := -Iinclude/drm -DCONFIG_NOUVEAU_DEBUG=7 -DCONFIG_NOUVEAU_DEBUG_DEFAULT=3
|
||||
ccflags-y += -I$(src)/core/include
|
||||
ccflags-y += -I$(src)
|
||||
|
||||
nouveau-y := core/core/mm.o
|
||||
nouveau-y := core/core/client.o
|
||||
nouveau-y += core/core/engine.o
|
||||
nouveau-y += core/core/handle.o
|
||||
nouveau-y += core/core/mm.o
|
||||
nouveau-y += core/core/namedb.o
|
||||
nouveau-y += core/core/object.o
|
||||
nouveau-y += core/core/option.o
|
||||
nouveau-y += core/core/parent.o
|
||||
nouveau-y += core/core/printk.o
|
||||
nouveau-y += core/core/ramht.o
|
||||
nouveau-y += core/core/subdev.o
|
||||
|
||||
nouveau-y += core/subdev/device/base.o
|
||||
nouveau-y += core/subdev/device/nv04.o
|
||||
nouveau-y += core/subdev/device/nv10.o
|
||||
nouveau-y += core/subdev/device/nv20.o
|
||||
nouveau-y += core/subdev/device/nv30.o
|
||||
nouveau-y += core/subdev/device/nv40.o
|
||||
nouveau-y += core/subdev/device/nv50.o
|
||||
nouveau-y += core/subdev/device/nvc0.o
|
||||
nouveau-y += core/subdev/device/nve0.o
|
||||
nouveau-y += core/subdev/fb/nv04.o
|
||||
nouveau-y += core/subdev/fb/nv10.o
|
||||
nouveau-y += core/subdev/fb/nv20.o
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/client.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/option.h>
|
||||
|
||||
#include <subdev/device.h>
|
||||
|
||||
static void
|
||||
nouveau_client_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_client *client = (void *)object;
|
||||
nouveau_object_ref(NULL, &client->device);
|
||||
nouveau_handle_destroy(client->root);
|
||||
nouveau_namedb_destroy(&client->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nouveau_client_oclass = {
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.dtor = nouveau_client_dtor,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_client_create_(u32 name, u64 devname, const char *cfg, const char *dbg,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_object *device;
|
||||
struct nouveau_client *client;
|
||||
int ret;
|
||||
|
||||
device = (void *)nouveau_device_find(devname);
|
||||
if (!device)
|
||||
return -ENODEV;
|
||||
|
||||
ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass,
|
||||
NV_CLIENT_CLASS, nouveau_device_sclass,
|
||||
0, length, pobject);
|
||||
client = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_handle_create(nv_object(client), ~0, ~0,
|
||||
nv_object(client), &client->root);
|
||||
if (ret) {
|
||||
nouveau_namedb_destroy(&client->base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* prevent init/fini being called, os in in charge of this */
|
||||
atomic_set(&nv_object(client)->usecount, 2);
|
||||
|
||||
nouveau_object_ref(device, &client->device);
|
||||
client->handle = name;
|
||||
client->debug = nouveau_dbgopt(dbg, "CLIENT");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_client_init(struct nouveau_client *client)
|
||||
{
|
||||
int ret;
|
||||
nv_debug(client, "init running\n");
|
||||
ret = nouveau_handle_init(client->root);
|
||||
nv_debug(client, "init completed with %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_client_fini(struct nouveau_client *client, bool suspend)
|
||||
{
|
||||
const char *name[2] = { "fini", "suspend" };
|
||||
int ret;
|
||||
|
||||
nv_debug(client, "%s running\n", name[suspend]);
|
||||
ret = nouveau_handle_fini(client->root, suspend);
|
||||
nv_debug(client, "%s completed with %d\n", name[suspend], ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/client.h>
|
||||
#include <core/engctx.h>
|
||||
|
||||
#include <subdev/vm.h>
|
||||
|
||||
int
|
||||
nouveau_engctx_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engobj,
|
||||
struct nouveau_oclass *oclass,
|
||||
struct nouveau_object *pargpu,
|
||||
u32 size, u32 align, u32 flags,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_client *client = nouveau_client(parent);
|
||||
struct nouveau_engine *engine = nv_engine(engobj);
|
||||
struct nouveau_subdev *subdev = nv_subdev(engine);
|
||||
struct nouveau_engctx *engctx;
|
||||
struct nouveau_object *ctxpar;
|
||||
int ret;
|
||||
|
||||
/* use existing context for the engine if one is available */
|
||||
mutex_lock(&subdev->mutex);
|
||||
list_for_each_entry(engctx, &engine->contexts, head) {
|
||||
ctxpar = nv_pclass(nv_object(engctx), NV_PARENT_CLASS);
|
||||
if (ctxpar == parent) {
|
||||
atomic_inc(&nv_object(engctx)->refcount);
|
||||
*pobject = engctx;
|
||||
mutex_unlock(&subdev->mutex);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&subdev->mutex);
|
||||
|
||||
if (size) {
|
||||
ret = nouveau_gpuobj_create_(parent, engobj, oclass,
|
||||
NV_ENGCTX_CLASS,
|
||||
pargpu, size, align, flags,
|
||||
length, pobject);
|
||||
} else {
|
||||
ret = nouveau_object_create_(parent, engobj, oclass,
|
||||
NV_ENGCTX_CLASS, length, pobject);
|
||||
}
|
||||
|
||||
engctx = *pobject;
|
||||
if (engctx && client->vm)
|
||||
atomic_inc(&client->vm->engref[nv_engidx(engobj)]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_add(&engctx->head, &engine->contexts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_engctx_destroy(struct nouveau_engctx *engctx)
|
||||
{
|
||||
struct nouveau_object *engine = nv_object(engctx)->engine;
|
||||
struct nouveau_client *client = nouveau_client(engctx);
|
||||
|
||||
nouveau_gpuobj_unmap(&engctx->vma);
|
||||
list_del(&engctx->head);
|
||||
if (client->vm)
|
||||
atomic_dec(&client->vm->engref[nv_engidx(engine)]);
|
||||
|
||||
if (engctx->base.size)
|
||||
nouveau_gpuobj_destroy(&engctx->base);
|
||||
else
|
||||
nouveau_object_destroy(&engctx->base.base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_engctx_init(struct nouveau_engctx *engctx)
|
||||
{
|
||||
struct nouveau_object *object = nv_object(engctx);
|
||||
struct nouveau_subdev *subdev = nv_subdev(object->engine);
|
||||
struct nouveau_object *parent;
|
||||
struct nouveau_subdev *pardev;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpuobj_init(&engctx->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
parent = nv_pclass(object->parent, NV_PARENT_CLASS);
|
||||
pardev = nv_subdev(parent->engine);
|
||||
if (nv_parent(parent)->context_attach) {
|
||||
mutex_lock(&pardev->mutex);
|
||||
ret = nv_parent(parent)->context_attach(parent, object);
|
||||
mutex_unlock(&pardev->mutex);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
nv_error(parent, "failed to attach %s context, %d\n",
|
||||
subdev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nv_debug(parent, "attached %s context\n", subdev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_engctx_fini(struct nouveau_engctx *engctx, bool suspend)
|
||||
{
|
||||
struct nouveau_object *object = nv_object(engctx);
|
||||
struct nouveau_subdev *subdev = nv_subdev(object->engine);
|
||||
struct nouveau_object *parent;
|
||||
struct nouveau_subdev *pardev;
|
||||
int ret = 0;
|
||||
|
||||
parent = nv_pclass(object->parent, NV_PARENT_CLASS);
|
||||
pardev = nv_subdev(parent->engine);
|
||||
if (nv_parent(parent)->context_detach) {
|
||||
mutex_lock(&pardev->mutex);
|
||||
ret = nv_parent(parent)->context_detach(parent, suspend, object);
|
||||
mutex_unlock(&pardev->mutex);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
nv_error(parent, "failed to detach %s context, %d\n",
|
||||
subdev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nv_debug(parent, "detached %s context\n", subdev->name);
|
||||
return nouveau_gpuobj_fini(&engctx->base, suspend);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_engctx_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_engctx_destroy(nv_engctx(object));
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_engctx_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_engctx_init(nv_engctx(object));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_nouveau_engctx_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_engctx_fini(nv_engctx(object), suspend);
|
||||
}
|
||||
|
||||
struct nouveau_object *
|
||||
nouveau_engctx_lookup(struct nouveau_engine *engine, u64 addr)
|
||||
{
|
||||
struct nouveau_engctx *engctx;
|
||||
|
||||
list_for_each_entry(engctx, &engine->contexts, head) {
|
||||
if (engctx->base.size &&
|
||||
nv_gpuobj(engctx)->addr == addr)
|
||||
return nv_object(engctx);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_engctx_lookup_class(struct nouveau_engine *engine, u64 addr, u16 oclass)
|
||||
{
|
||||
struct nouveau_object *engctx = nouveau_engctx_lookup(engine, addr);
|
||||
struct nouveau_namedb *namedb;
|
||||
|
||||
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
|
||||
return nouveau_namedb_get_class(namedb, oclass);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_engctx_lookup_vinst(struct nouveau_engine *engine, u64 addr, u64 vinst)
|
||||
{
|
||||
struct nouveau_object *engctx = nouveau_engctx_lookup(engine, addr);
|
||||
struct nouveau_namedb *namedb;
|
||||
|
||||
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
|
||||
return nouveau_namedb_get_vinst(namedb, vinst);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_engctx_lookup_cinst(struct nouveau_engine *engine, u64 addr, u32 cinst)
|
||||
{
|
||||
struct nouveau_object *engctx = nouveau_engctx_lookup(engine, addr);
|
||||
struct nouveau_namedb *namedb;
|
||||
|
||||
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
|
||||
return nouveau_namedb_get_cinst(namedb, cinst);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_engctx_handle_put(struct nouveau_handle *handle)
|
||||
{
|
||||
if (handle)
|
||||
nouveau_namedb_put(handle);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <core/device.h>
|
||||
#include <core/engine.h>
|
||||
#include <core/option.h>
|
||||
|
||||
int
|
||||
nouveau_engine_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engobj,
|
||||
struct nouveau_oclass *oclass, bool enable,
|
||||
const char *iname, const char *fname,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(parent);
|
||||
struct nouveau_engine *engine;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
|
||||
iname, fname, length, pobject);
|
||||
engine = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!nouveau_boolopt(device->cfgopt, iname, enable)) {
|
||||
if (!enable)
|
||||
nv_warn(engine, "disabled, %s=1 to enable\n", iname);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&engine->contexts);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Nouveau Project
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, 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 (including the
|
||||
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
|
||||
const struct nouveau_enum *
|
||||
nouveau_enum_find(const struct nouveau_enum *en, u32 value)
|
||||
{
|
||||
while (en->name) {
|
||||
if (en->value == value)
|
||||
return en;
|
||||
en++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_enum_print(const struct nouveau_enum *en, u32 value)
|
||||
{
|
||||
en = nouveau_enum_find(en, value);
|
||||
if (en)
|
||||
printk("%s", en->name);
|
||||
else
|
||||
printk("(unknown enum 0x%08x)", value);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
|
||||
{
|
||||
while (bf->name) {
|
||||
if (value & bf->mask) {
|
||||
printk(" %s", bf->name);
|
||||
value &= ~bf->mask;
|
||||
}
|
||||
|
||||
bf++;
|
||||
}
|
||||
|
||||
if (value)
|
||||
printk(" (unknown bits 0x%08x)", value);
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
#include <subdev/instmem.h>
|
||||
#include <subdev/bar.h>
|
||||
#include <subdev/vm.h>
|
||||
|
||||
void
|
||||
nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
|
||||
for (i = 0; i < gpuobj->size; i += 4)
|
||||
nv_wo32(gpuobj, i, 0x00000000);
|
||||
}
|
||||
|
||||
if (gpuobj->heap.block_size)
|
||||
nouveau_mm_fini(&gpuobj->heap);
|
||||
|
||||
nouveau_object_destroy(&gpuobj->base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_gpuobj_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
struct nouveau_object *pargpu,
|
||||
u32 size, u32 align, u32 flags,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_instmem *imem = nouveau_instmem(parent);
|
||||
struct nouveau_bar *bar = nouveau_bar(parent);
|
||||
struct nouveau_gpuobj *gpuobj;
|
||||
struct nouveau_mm *heap = NULL;
|
||||
int ret, i;
|
||||
u64 addr;
|
||||
|
||||
*pobject = NULL;
|
||||
|
||||
if (pargpu) {
|
||||
while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
|
||||
if (nv_gpuobj(pargpu)->heap.block_size)
|
||||
break;
|
||||
pargpu = pargpu->parent;
|
||||
}
|
||||
|
||||
if (unlikely(pargpu == NULL)) {
|
||||
nv_error(parent, "no gpuobj heap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
addr = nv_gpuobj(pargpu)->addr;
|
||||
heap = &nv_gpuobj(pargpu)->heap;
|
||||
atomic_inc(&parent->refcount);
|
||||
} else {
|
||||
ret = imem->alloc(imem, parent, size, align, &parent);
|
||||
pargpu = parent;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = nv_memobj(pargpu)->addr;
|
||||
size = nv_memobj(pargpu)->size;
|
||||
|
||||
if (bar && bar->alloc) {
|
||||
struct nouveau_instobj *iobj = (void *)parent;
|
||||
struct nouveau_mem **mem = (void *)(iobj + 1);
|
||||
struct nouveau_mem *node = *mem;
|
||||
if (!bar->alloc(bar, parent, node, &pargpu)) {
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
parent = pargpu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, pclass |
|
||||
NV_GPUOBJ_CLASS, length, pobject);
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
gpuobj = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpuobj->parent = pargpu;
|
||||
gpuobj->flags = flags;
|
||||
gpuobj->addr = addr;
|
||||
gpuobj->size = size;
|
||||
|
||||
if (heap) {
|
||||
ret = nouveau_mm_head(heap, 1, size, size,
|
||||
max(align, (u32)1), &gpuobj->node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpuobj->addr += gpuobj->node->offset;
|
||||
}
|
||||
|
||||
if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
|
||||
ret = nouveau_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
|
||||
for (i = 0; i < gpuobj->size; i += 4)
|
||||
nv_wo32(gpuobj, i, 0x00000000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct nouveau_gpuobj_class {
|
||||
struct nouveau_object *pargpu;
|
||||
u64 size;
|
||||
u32 align;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
int
|
||||
_nouveau_gpuobj_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_gpuobj_class *args = data;
|
||||
struct nouveau_gpuobj *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
|
||||
args->size, args->align, args->flags,
|
||||
&object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_gpuobj_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_gpuobj_destroy(nv_gpuobj(object));
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_gpuobj_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_gpuobj_init(nv_gpuobj(object));
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_gpuobj_fini(nv_gpuobj(object), suspend);
|
||||
}
|
||||
|
||||
u32
|
||||
_nouveau_gpuobj_rd32(struct nouveau_object *object, u32 addr)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
|
||||
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
|
||||
if (gpuobj->node)
|
||||
addr += gpuobj->node->offset;
|
||||
return pfuncs->rd32(gpuobj->parent, addr);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_gpuobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
|
||||
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
|
||||
if (gpuobj->node)
|
||||
addr += gpuobj->node->offset;
|
||||
pfuncs->wr32(gpuobj->parent, addr, data);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
_nouveau_gpuobj_oclass = {
|
||||
.handle = 0x00000000,
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = _nouveau_gpuobj_ctor,
|
||||
.dtor = _nouveau_gpuobj_dtor,
|
||||
.init = _nouveau_gpuobj_init,
|
||||
.fini = _nouveau_gpuobj_fini,
|
||||
.rd32 = _nouveau_gpuobj_rd32,
|
||||
.wr32 = _nouveau_gpuobj_wr32,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_gpuobj_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
|
||||
u32 size, u32 align, u32 flags,
|
||||
struct nouveau_gpuobj **pgpuobj)
|
||||
{
|
||||
struct nouveau_object *engine = parent;
|
||||
struct nouveau_gpuobj_class args = {
|
||||
.pargpu = pargpu,
|
||||
.size = size,
|
||||
.align = align,
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
if (!nv_iclass(engine, NV_SUBDEV_CLASS))
|
||||
engine = engine->engine;
|
||||
BUG_ON(engine == NULL);
|
||||
|
||||
return nouveau_object_ctor(parent, engine, &_nouveau_gpuobj_oclass,
|
||||
&args, sizeof(args),
|
||||
(struct nouveau_object **)pgpuobj);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_gpuobj_map(struct nouveau_gpuobj *gpuobj, u32 access,
|
||||
struct nouveau_vma *vma)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(gpuobj);
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (bar && bar->umap) {
|
||||
struct nouveau_instobj *iobj = (void *)
|
||||
nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
|
||||
struct nouveau_mem **mem = (void *)(iobj + 1);
|
||||
ret = bar->umap(bar, *mem, access, vma);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm,
|
||||
u32 access, struct nouveau_vma *vma)
|
||||
{
|
||||
struct nouveau_instobj *iobj = (void *)
|
||||
nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
|
||||
struct nouveau_mem **mem = (void *)(iobj + 1);
|
||||
int ret;
|
||||
|
||||
ret = nouveau_vm_get(vm, gpuobj->size, 12, access, vma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_vm_map(vma, *mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_gpuobj_unmap(struct nouveau_vma *vma)
|
||||
{
|
||||
if (vma->node) {
|
||||
nouveau_vm_unmap(vma);
|
||||
nouveau_vm_put(vma);
|
||||
}
|
||||
}
|
||||
|
||||
/* the below is basically only here to support sharing the paged dma object
|
||||
* for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
|
||||
* anywhere else.
|
||||
*/
|
||||
|
||||
static void
|
||||
nouveau_gpudup_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj = (void *)object;
|
||||
nouveau_object_ref(NULL, &gpuobj->parent);
|
||||
nouveau_object_destroy(&gpuobj->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nouveau_gpudup_oclass = {
|
||||
.handle = NV_GPUOBJ_CLASS,
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.dtor = nouveau_gpudup_dtor,
|
||||
.init = nouveau_object_init,
|
||||
.fini = nouveau_object_fini,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_gpuobj_dup(struct nouveau_object *parent, struct nouveau_gpuobj *base,
|
||||
struct nouveau_gpuobj **pgpuobj)
|
||||
{
|
||||
struct nouveau_gpuobj *gpuobj;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create(parent, parent->engine,
|
||||
&nouveau_gpudup_oclass, 0, &gpuobj);
|
||||
*pgpuobj = gpuobj;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_object_ref(nv_object(base), &gpuobj->parent);
|
||||
gpuobj->addr = base->addr;
|
||||
gpuobj->size = base->size;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/client.h>
|
||||
|
||||
#define hprintk(h,l,f,a...) do { \
|
||||
struct nouveau_client *c = nouveau_client((h)->object); \
|
||||
struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \
|
||||
nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \
|
||||
} while(0)
|
||||
|
||||
int
|
||||
nouveau_handle_init(struct nouveau_handle *handle)
|
||||
{
|
||||
struct nouveau_handle *item;
|
||||
int ret;
|
||||
|
||||
hprintk(handle, TRACE, "init running\n");
|
||||
ret = nouveau_object_inc(handle->object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hprintk(handle, TRACE, "init children\n");
|
||||
list_for_each_entry(item, &handle->tree, head) {
|
||||
ret = nouveau_handle_init(item);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "init completed\n");
|
||||
return 0;
|
||||
fail:
|
||||
hprintk(handle, ERROR, "init failed with %d\n", ret);
|
||||
list_for_each_entry_continue_reverse(item, &handle->tree, head) {
|
||||
nouveau_handle_fini(item, false);
|
||||
}
|
||||
|
||||
nouveau_object_dec(handle->object, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_handle_fini(struct nouveau_handle *handle, bool suspend)
|
||||
{
|
||||
static char *name[2] = { "fini", "suspend" };
|
||||
struct nouveau_handle *item;
|
||||
int ret;
|
||||
|
||||
hprintk(handle, TRACE, "%s children\n", name[suspend]);
|
||||
list_for_each_entry(item, &handle->tree, head) {
|
||||
ret = nouveau_handle_fini(item, suspend);
|
||||
if (ret && suspend)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "%s running\n", name[suspend]);
|
||||
if (handle->object) {
|
||||
ret = nouveau_object_dec(handle->object, suspend);
|
||||
if (ret && suspend)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "%s completed\n", name[suspend]);
|
||||
return 0;
|
||||
fail:
|
||||
hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
|
||||
list_for_each_entry_continue_reverse(item, &handle->tree, head) {
|
||||
int rret = nouveau_handle_init(item);
|
||||
if (rret)
|
||||
hprintk(handle, FATAL, "failed to restart, %d\n", rret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
|
||||
struct nouveau_object *object,
|
||||
struct nouveau_handle **phandle)
|
||||
{
|
||||
struct nouveau_object *namedb;
|
||||
struct nouveau_handle *handle;
|
||||
int ret;
|
||||
|
||||
namedb = parent;
|
||||
while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
|
||||
namedb = namedb->parent;
|
||||
|
||||
handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||
if (!handle)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&handle->head);
|
||||
INIT_LIST_HEAD(&handle->tree);
|
||||
handle->name = _handle;
|
||||
handle->priv = ~0;
|
||||
|
||||
ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);
|
||||
if (ret) {
|
||||
kfree(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (nv_parent(parent)->object_attach) {
|
||||
ret = nv_parent(parent)->object_attach(parent, object, _handle);
|
||||
if (ret < 0) {
|
||||
nouveau_handle_destroy(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
handle->priv = ret;
|
||||
}
|
||||
|
||||
if (object != namedb) {
|
||||
while (!nv_iclass(namedb, NV_CLIENT_CLASS))
|
||||
namedb = namedb->parent;
|
||||
|
||||
handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);
|
||||
if (handle->parent) {
|
||||
list_add(&handle->head, &handle->parent->tree);
|
||||
nouveau_namedb_put(handle->parent);
|
||||
}
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "created\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_handle_destroy(struct nouveau_handle *handle)
|
||||
{
|
||||
struct nouveau_handle *item, *temp;
|
||||
|
||||
hprintk(handle, TRACE, "destroy running\n");
|
||||
list_for_each_entry_safe(item, temp, &handle->tree, head) {
|
||||
nouveau_handle_destroy(item);
|
||||
}
|
||||
list_del(&handle->head);
|
||||
|
||||
if (handle->priv != ~0) {
|
||||
struct nouveau_object *parent = handle->parent->object;
|
||||
nv_parent(parent)->object_detach(parent, handle->priv);
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "destroy completed\n");
|
||||
nouveau_namedb_remove(handle);
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
struct nouveau_object *
|
||||
nouveau_handle_ref(struct nouveau_object *parent, u32 name)
|
||||
{
|
||||
struct nouveau_object *object = NULL;
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
while (!nv_iclass(parent, NV_NAMEDB_CLASS))
|
||||
parent = parent->parent;
|
||||
|
||||
handle = nouveau_namedb_get(nv_namedb(parent), name);
|
||||
if (handle) {
|
||||
nouveau_object_ref(handle->object, &object);
|
||||
nouveau_namedb_put(handle);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
@@ -22,8 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "nouveau_drv.h"
|
||||
#include <core/os.h>
|
||||
#include <core/mm.h>
|
||||
|
||||
static inline void
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (handle->name == name)
|
||||
return handle;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup_class(struct nouveau_namedb *namedb, u16 oclass)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (nv_mclass(handle->object) == oclass)
|
||||
return handle;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup_vinst(struct nouveau_namedb *namedb, u64 vinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
|
||||
if (nv_gpuobj(handle->object)->addr == vinst)
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_handle *
|
||||
nouveau_namedb_lookup_cinst(struct nouveau_namedb *namedb, u32 cinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &namedb->list, node) {
|
||||
if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
|
||||
if (nv_gpuobj(handle->object)->node &&
|
||||
nv_gpuobj(handle->object)->node->offset == cinst)
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name,
|
||||
struct nouveau_object *object,
|
||||
struct nouveau_handle *handle)
|
||||
{
|
||||
int ret = -EEXIST;
|
||||
write_lock_irq(&namedb->lock);
|
||||
if (!nouveau_namedb_lookup(namedb, name)) {
|
||||
nouveau_object_ref(object, &handle->object);
|
||||
handle->namedb = namedb;
|
||||
list_add(&handle->node, &namedb->list);
|
||||
ret = 0;
|
||||
}
|
||||
write_unlock_irq(&namedb->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_namedb_remove(struct nouveau_handle *handle)
|
||||
{
|
||||
struct nouveau_namedb *namedb = handle->namedb;
|
||||
struct nouveau_object *object = handle->object;
|
||||
write_lock_irq(&namedb->lock);
|
||||
list_del(&handle->node);
|
||||
write_unlock_irq(&namedb->lock);
|
||||
nouveau_object_ref(NULL, &object);
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup(namedb, name);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get_class(struct nouveau_namedb *namedb, u16 oclass)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup_class(namedb, oclass);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get_vinst(struct nouveau_namedb *namedb, u64 vinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup_vinst(namedb, vinst);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_namedb_get_cinst(struct nouveau_namedb *namedb, u32 cinst)
|
||||
{
|
||||
struct nouveau_handle *handle;
|
||||
read_lock(&namedb->lock);
|
||||
handle = nouveau_namedb_lookup_cinst(namedb, cinst);
|
||||
if (handle == NULL)
|
||||
read_unlock(&namedb->lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_namedb_put(struct nouveau_handle *handle)
|
||||
{
|
||||
if (handle)
|
||||
read_unlock(&handle->namedb->lock);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_namedb_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
struct nouveau_oclass *sclass, u32 engcls,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_namedb *namedb;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_parent_create_(parent, engine, oclass, pclass |
|
||||
NV_NAMEDB_CLASS, sclass, engcls,
|
||||
length, pobject);
|
||||
namedb = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rwlock_init(&namedb->lock);
|
||||
INIT_LIST_HEAD(&namedb->list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_namedb_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_namedb *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/parent.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/engine.h>
|
||||
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
|
||||
static DEFINE_SPINLOCK(_objlist_lock);
|
||||
#endif
|
||||
|
||||
int
|
||||
nouveau_object_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
int size, void **pobject)
|
||||
{
|
||||
struct nouveau_object *object;
|
||||
|
||||
object = *pobject = kzalloc(size, GFP_KERNEL);
|
||||
if (!object)
|
||||
return -ENOMEM;
|
||||
|
||||
nouveau_object_ref(parent, &object->parent);
|
||||
nouveau_object_ref(engine, &object->engine);
|
||||
object->oclass = oclass;
|
||||
object->oclass->handle |= pclass;
|
||||
atomic_set(&object->refcount, 1);
|
||||
atomic_set(&object->usecount, 0);
|
||||
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
object->_magic = NOUVEAU_OBJECT_MAGIC;
|
||||
spin_lock(&_objlist_lock);
|
||||
list_add(&object->list, &_objlist);
|
||||
spin_unlock(&_objlist_lock);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_object_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_object *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create(parent, engine, oclass, 0, &object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_object_destroy(struct nouveau_object *object)
|
||||
{
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
spin_lock(&_objlist_lock);
|
||||
list_del(&object->list);
|
||||
spin_unlock(&_objlist_lock);
|
||||
#endif
|
||||
nouveau_object_ref(NULL, &object->engine);
|
||||
nouveau_object_ref(NULL, &object->parent);
|
||||
kfree(object);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_object_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_object_destroy(object);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_init(struct nouveau_object *object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_object_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_object_init(object);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_object_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_object_fini(object, suspend);
|
||||
}
|
||||
|
||||
struct nouveau_ofuncs
|
||||
nouveau_object_ofuncs = {
|
||||
.ctor = _nouveau_object_ctor,
|
||||
.dtor = _nouveau_object_dtor,
|
||||
.init = _nouveau_object_init,
|
||||
.fini = _nouveau_object_fini,
|
||||
};
|
||||
|
||||
int
|
||||
nouveau_object_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
|
||||
int ret;
|
||||
|
||||
*pobject = NULL;
|
||||
|
||||
ret = ofuncs->ctor(parent, engine, oclass, data, size, pobject);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENODEV) {
|
||||
nv_error(parent, "failed to create 0x%08x, %d\n",
|
||||
oclass->handle, ret);
|
||||
}
|
||||
|
||||
if (*pobject) {
|
||||
ofuncs->dtor(*pobject);
|
||||
*pobject = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
nv_debug(*pobject, "created\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_object_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nv_debug(object, "destroying\n");
|
||||
nv_ofuncs(object)->dtor(object);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
|
||||
{
|
||||
if (obj) {
|
||||
atomic_inc(&obj->refcount);
|
||||
nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
|
||||
}
|
||||
|
||||
if (*ref) {
|
||||
int dead = atomic_dec_and_test(&(*ref)->refcount);
|
||||
nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
|
||||
if (dead)
|
||||
nouveau_object_dtor(*ref);
|
||||
}
|
||||
|
||||
*ref = obj;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_new(struct nouveau_object *client, u32 _parent, u32 _handle,
|
||||
u16 _oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_object *parent = NULL;
|
||||
struct nouveau_object *engctx = NULL;
|
||||
struct nouveau_object *object = NULL;
|
||||
struct nouveau_object *engine;
|
||||
struct nouveau_oclass *oclass;
|
||||
struct nouveau_handle *handle;
|
||||
int ret;
|
||||
|
||||
/* lookup parent object and ensure it *is* a parent */
|
||||
parent = nouveau_handle_ref(client, _parent);
|
||||
if (!parent) {
|
||||
nv_error(client, "parent 0x%08x not found\n", _parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!nv_iclass(parent, NV_PARENT_CLASS)) {
|
||||
nv_error(parent, "cannot have children\n");
|
||||
ret = -EINVAL;
|
||||
goto fail_class;
|
||||
}
|
||||
|
||||
/* check that parent supports the requested subclass */
|
||||
ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
|
||||
if (ret) {
|
||||
nv_debug(parent, "illegal class 0x%04x\n", _oclass);
|
||||
goto fail_class;
|
||||
}
|
||||
|
||||
/* make sure engine init has been completed *before* any objects
|
||||
* it controls are created - the constructors may depend on
|
||||
* state calculated at init (ie. default context construction)
|
||||
*/
|
||||
if (engine) {
|
||||
ret = nouveau_object_inc(engine);
|
||||
if (ret)
|
||||
goto fail_class;
|
||||
}
|
||||
|
||||
/* if engine requires it, create a context object to insert
|
||||
* between the parent and its children (eg. PGRAPH context)
|
||||
*/
|
||||
if (engine && nv_engine(engine)->cclass) {
|
||||
ret = nouveau_object_ctor(parent, engine,
|
||||
nv_engine(engine)->cclass,
|
||||
data, size, &engctx);
|
||||
if (ret)
|
||||
goto fail_engctx;
|
||||
} else {
|
||||
nouveau_object_ref(parent, &engctx);
|
||||
}
|
||||
|
||||
/* finally, create new object and bind it to its handle */
|
||||
ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
|
||||
*pobject = object;
|
||||
if (ret)
|
||||
goto fail_ctor;
|
||||
|
||||
ret = nouveau_object_inc(object);
|
||||
if (ret)
|
||||
goto fail_init;
|
||||
|
||||
ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
|
||||
if (ret)
|
||||
goto fail_handle;
|
||||
|
||||
ret = nouveau_handle_init(handle);
|
||||
if (ret)
|
||||
nouveau_handle_destroy(handle);
|
||||
|
||||
fail_handle:
|
||||
nouveau_object_dec(object, false);
|
||||
fail_init:
|
||||
nouveau_object_ref(NULL, &object);
|
||||
fail_ctor:
|
||||
nouveau_object_ref(NULL, &engctx);
|
||||
fail_engctx:
|
||||
if (engine)
|
||||
nouveau_object_dec(engine, false);
|
||||
fail_class:
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle)
|
||||
{
|
||||
struct nouveau_object *parent = NULL;
|
||||
struct nouveau_object *namedb = NULL;
|
||||
struct nouveau_handle *handle = NULL;
|
||||
int ret = -EINVAL;
|
||||
|
||||
parent = nouveau_handle_ref(client, _parent);
|
||||
if (!parent)
|
||||
return -ENOENT;
|
||||
|
||||
namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
|
||||
if (namedb) {
|
||||
handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
|
||||
if (handle) {
|
||||
nouveau_namedb_put(handle);
|
||||
nouveau_handle_fini(handle, false);
|
||||
nouveau_handle_destroy(handle);
|
||||
}
|
||||
}
|
||||
|
||||
nouveau_object_ref(NULL, &parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_inc(struct nouveau_object *object)
|
||||
{
|
||||
int ref = atomic_add_return(1, &object->usecount);
|
||||
int ret;
|
||||
|
||||
nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
|
||||
if (ref != 1)
|
||||
return 0;
|
||||
|
||||
nv_trace(object, "initialising...\n");
|
||||
if (object->parent) {
|
||||
ret = nouveau_object_inc(object->parent);
|
||||
if (ret) {
|
||||
nv_error(object, "parent failed, %d\n", ret);
|
||||
goto fail_parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
ret = nouveau_object_inc(object->engine);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
if (ret) {
|
||||
nv_error(object, "engine failed, %d\n", ret);
|
||||
goto fail_engine;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nv_ofuncs(object)->init(object);
|
||||
if (ret) {
|
||||
nv_error(object, "init failed, %d\n", ret);
|
||||
goto fail_self;
|
||||
}
|
||||
|
||||
nv_debug(object, "initialised\n");
|
||||
return 0;
|
||||
|
||||
fail_self:
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
nouveau_object_dec(object->engine, false);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
}
|
||||
fail_engine:
|
||||
if (object->parent)
|
||||
nouveau_object_dec(object->parent, false);
|
||||
fail_parent:
|
||||
atomic_dec(&object->usecount);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_object_decf(struct nouveau_object *object)
|
||||
{
|
||||
int ret;
|
||||
|
||||
nv_trace(object, "stopping...\n");
|
||||
|
||||
ret = nv_ofuncs(object)->fini(object, false);
|
||||
if (ret)
|
||||
nv_warn(object, "failed fini, %d\n", ret);
|
||||
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
nouveau_object_dec(object->engine, false);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
}
|
||||
|
||||
if (object->parent)
|
||||
nouveau_object_dec(object->parent, false);
|
||||
|
||||
nv_debug(object, "stopped\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_object_decs(struct nouveau_object *object)
|
||||
{
|
||||
int ret, rret;
|
||||
|
||||
nv_trace(object, "suspending...\n");
|
||||
|
||||
ret = nv_ofuncs(object)->fini(object, true);
|
||||
if (ret) {
|
||||
nv_error(object, "failed suspend, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
ret = nouveau_object_dec(object->engine, true);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
if (ret) {
|
||||
nv_warn(object, "engine failed suspend, %d\n", ret);
|
||||
goto fail_engine;
|
||||
}
|
||||
}
|
||||
|
||||
if (object->parent) {
|
||||
ret = nouveau_object_dec(object->parent, true);
|
||||
if (ret) {
|
||||
nv_warn(object, "parent failed suspend, %d\n", ret);
|
||||
goto fail_parent;
|
||||
}
|
||||
}
|
||||
|
||||
nv_debug(object, "suspended\n");
|
||||
return 0;
|
||||
|
||||
fail_parent:
|
||||
if (object->engine) {
|
||||
mutex_lock(&nv_subdev(object->engine)->mutex);
|
||||
rret = nouveau_object_inc(object->engine);
|
||||
mutex_unlock(&nv_subdev(object->engine)->mutex);
|
||||
if (rret)
|
||||
nv_fatal(object, "engine failed to reinit, %d\n", rret);
|
||||
}
|
||||
|
||||
fail_engine:
|
||||
rret = nv_ofuncs(object)->init(object);
|
||||
if (rret)
|
||||
nv_fatal(object, "failed to reinit, %d\n", rret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_object_dec(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
int ref = atomic_add_return(-1, &object->usecount);
|
||||
int ret;
|
||||
|
||||
nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
|
||||
|
||||
if (ref == 0) {
|
||||
if (suspend)
|
||||
ret = nouveau_object_decs(object);
|
||||
else
|
||||
ret = nouveau_object_decf(object);
|
||||
|
||||
if (ret) {
|
||||
atomic_inc(&object->usecount);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_object_debug(void)
|
||||
{
|
||||
#ifdef NOUVEAU_OBJECT_MAGIC
|
||||
struct nouveau_object *object;
|
||||
if (!list_empty(&_objlist)) {
|
||||
nv_fatal(NULL, "*******************************************\n");
|
||||
nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
|
||||
nv_fatal(NULL, "*******************************************\n");
|
||||
list_for_each_entry(object, &_objlist, list) {
|
||||
nv_fatal(object, "%p/%p/%d/%d\n",
|
||||
object->parent, object->engine,
|
||||
atomic_read(&object->refcount),
|
||||
atomic_read(&object->usecount));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 <core/os.h>
|
||||
#include <core/debug.h>
|
||||
|
||||
/* compares unterminated string 'str' with zero-terminated string 'cmp' */
|
||||
static inline int
|
||||
strncasecmpz(const char *str, const char *cmp, size_t len)
|
||||
{
|
||||
if (strlen(cmp) != len)
|
||||
return len;
|
||||
return strncasecmp(str, cmp, len);
|
||||
}
|
||||
|
||||
const char *
|
||||
nouveau_stropt(const char *optstr, const char *opt, int *arglen)
|
||||
{
|
||||
while (optstr && *optstr != '\0') {
|
||||
int len = strcspn(optstr, ",=");
|
||||
switch (optstr[len]) {
|
||||
case '=':
|
||||
if (!strncasecmpz(optstr, opt, len)) {
|
||||
optstr += len + 1;
|
||||
*arglen = strcspn(optstr, ",=");
|
||||
return *arglen ? optstr : NULL;
|
||||
}
|
||||
optstr++;
|
||||
break;
|
||||
case ',':
|
||||
optstr++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
optstr += len;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
nouveau_boolopt(const char *optstr, const char *opt, bool value)
|
||||
{
|
||||
int arglen;
|
||||
|
||||
optstr = nouveau_stropt(optstr, opt, &arglen);
|
||||
if (optstr) {
|
||||
if (!strncasecmpz(optstr, "0", arglen) ||
|
||||
!strncasecmpz(optstr, "no", arglen) ||
|
||||
!strncasecmpz(optstr, "off", arglen) ||
|
||||
!strncasecmpz(optstr, "false", arglen))
|
||||
value = false;
|
||||
else
|
||||
if (!strncasecmpz(optstr, "1", arglen) ||
|
||||
!strncasecmpz(optstr, "yes", arglen) ||
|
||||
!strncasecmpz(optstr, "on", arglen) ||
|
||||
!strncasecmpz(optstr, "true", arglen))
|
||||
value = true;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_dbgopt(const char *optstr, const char *sub)
|
||||
{
|
||||
int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT;
|
||||
|
||||
while (optstr) {
|
||||
int len = strcspn(optstr, ",=");
|
||||
switch (optstr[len]) {
|
||||
case '=':
|
||||
if (strncasecmpz(optstr, sub, len))
|
||||
mode = 0;
|
||||
optstr++;
|
||||
break;
|
||||
default:
|
||||
if (mode) {
|
||||
if (!strncasecmpz(optstr, "fatal", len))
|
||||
level = NV_DBG_FATAL;
|
||||
else if (!strncasecmpz(optstr, "error", len))
|
||||
level = NV_DBG_ERROR;
|
||||
else if (!strncasecmpz(optstr, "warn", len))
|
||||
level = NV_DBG_WARN;
|
||||
else if (!strncasecmpz(optstr, "info", len))
|
||||
level = NV_DBG_INFO;
|
||||
else if (!strncasecmpz(optstr, "debug", len))
|
||||
level = NV_DBG_DEBUG;
|
||||
else if (!strncasecmpz(optstr, "trace", len))
|
||||
level = NV_DBG_TRACE;
|
||||
else if (!strncasecmpz(optstr, "paranoia", len))
|
||||
level = NV_DBG_PARANOIA;
|
||||
else if (!strncasecmpz(optstr, "spam", len))
|
||||
level = NV_DBG_SPAM;
|
||||
}
|
||||
|
||||
if (optstr[len] != '\0') {
|
||||
optstr++;
|
||||
mode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
optstr += len;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/parent.h>
|
||||
|
||||
int
|
||||
nouveau_parent_sclass(struct nouveau_object *parent, u16 handle,
|
||||
struct nouveau_object **pengine,
|
||||
struct nouveau_oclass **poclass)
|
||||
{
|
||||
struct nouveau_sclass *sclass;
|
||||
struct nouveau_engine *engine;
|
||||
struct nouveau_oclass *oclass;
|
||||
u64 mask;
|
||||
|
||||
sclass = nv_parent(parent)->sclass;
|
||||
while (sclass) {
|
||||
if ((sclass->oclass->handle & 0xffff) == handle) {
|
||||
*pengine = parent->engine;
|
||||
*poclass = sclass->oclass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sclass = sclass->sclass;
|
||||
}
|
||||
|
||||
mask = nv_parent(parent)->engine;
|
||||
while (mask) {
|
||||
int i = ffsll(mask) - 1;
|
||||
|
||||
if ((engine = nouveau_engine(parent, i))) {
|
||||
oclass = engine->sclass;
|
||||
while (oclass->ofuncs) {
|
||||
if ((oclass->handle & 0xffff) == handle) {
|
||||
*pengine = nv_object(engine);
|
||||
*poclass = oclass;
|
||||
return 0;
|
||||
}
|
||||
oclass++;
|
||||
}
|
||||
}
|
||||
|
||||
mask &= ~(1ULL << i);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_parent_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
struct nouveau_oclass *sclass, u64 engcls,
|
||||
int size, void **pobject)
|
||||
{
|
||||
struct nouveau_parent *object;
|
||||
struct nouveau_sclass *nclass;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, pclass |
|
||||
NV_PARENT_CLASS, size, pobject);
|
||||
object = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while (sclass && sclass->ofuncs) {
|
||||
nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);
|
||||
if (!nclass)
|
||||
return -ENOMEM;
|
||||
|
||||
nclass->sclass = object->sclass;
|
||||
object->sclass = nclass;
|
||||
nclass->engine = engine ? nv_engine(engine) : NULL;
|
||||
nclass->oclass = sclass;
|
||||
sclass++;
|
||||
}
|
||||
|
||||
object->engine = engcls;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_parent_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_parent *object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_parent_create(parent, engine, oclass, 0, NULL, 0, &object);
|
||||
*pobject = nv_object(object);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_parent_destroy(struct nouveau_parent *parent)
|
||||
{
|
||||
struct nouveau_sclass *sclass;
|
||||
|
||||
while ((sclass = parent->sclass)) {
|
||||
parent->sclass = sclass->sclass;
|
||||
kfree(sclass);
|
||||
}
|
||||
|
||||
nouveau_object_destroy(&parent->base);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_nouveau_parent_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_parent_destroy(nv_parent(object));
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/client.h>
|
||||
#include <core/subdev.h>
|
||||
#include <core/printk.h>
|
||||
|
||||
void
|
||||
nv_printk_(struct nouveau_object *object, const char *pfx, int level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' };
|
||||
char mfmt[256];
|
||||
va_list args;
|
||||
|
||||
if (object && !nv_iclass(object, NV_CLIENT_CLASS)) {
|
||||
struct nouveau_object *device = object;
|
||||
struct nouveau_object *subdev = object;
|
||||
char obuf[64], *ofmt = "";
|
||||
|
||||
if (object->engine) {
|
||||
snprintf(obuf, sizeof(obuf), "[0x%08x][%p]",
|
||||
nv_hclass(object), object);
|
||||
ofmt = obuf;
|
||||
subdev = object->engine;
|
||||
device = object->engine;
|
||||
}
|
||||
|
||||
if (subdev->parent)
|
||||
device = subdev->parent;
|
||||
|
||||
if (level > nv_subdev(subdev)->debug)
|
||||
return;
|
||||
|
||||
snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx,
|
||||
name[level], nv_subdev(subdev)->name,
|
||||
nv_device(device)->name, ofmt, fmt);
|
||||
} else
|
||||
if (object && nv_iclass(object, NV_CLIENT_CLASS)) {
|
||||
if (level > nv_client(object)->debug)
|
||||
return;
|
||||
|
||||
snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8d] %s", pfx,
|
||||
name[level], nv_client(object)->handle, fmt);
|
||||
} else {
|
||||
snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt);
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
vprintk(mfmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 <core/object.h>
|
||||
#include <core/subdev.h>
|
||||
#include <core/device.h>
|
||||
#include <core/option.h>
|
||||
|
||||
void
|
||||
nouveau_subdev_reset(struct nouveau_object *subdev)
|
||||
{
|
||||
nv_trace(subdev, "resetting...\n");
|
||||
nv_ofuncs(subdev)->fini(subdev, false);
|
||||
nv_debug(subdev, "reset\n");
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_subdev_init(struct nouveau_subdev *subdev)
|
||||
{
|
||||
int ret = nouveau_object_init(&subdev->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nouveau_subdev_reset(&subdev->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_subdev_init(struct nouveau_object *object)
|
||||
{
|
||||
return nouveau_subdev_init(nv_subdev(object));
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_subdev_fini(struct nouveau_subdev *subdev, bool suspend)
|
||||
{
|
||||
if (subdev->unit) {
|
||||
nv_mask(subdev, 0x000200, subdev->unit, 0x00000000);
|
||||
nv_mask(subdev, 0x000200, subdev->unit, subdev->unit);
|
||||
}
|
||||
|
||||
return nouveau_object_fini(&subdev->base, suspend);
|
||||
}
|
||||
|
||||
int
|
||||
_nouveau_subdev_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
return nouveau_subdev_fini(nv_subdev(object), suspend);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_subdev_destroy(struct nouveau_subdev *subdev)
|
||||
{
|
||||
int subidx = nv_hclass(subdev) & 0xff;
|
||||
nv_device(subdev)->subdev[subidx] = NULL;
|
||||
nouveau_object_destroy(&subdev->base);
|
||||
}
|
||||
|
||||
void
|
||||
_nouveau_subdev_dtor(struct nouveau_object *object)
|
||||
{
|
||||
nouveau_subdev_destroy(nv_subdev(object));
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_subdev_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u32 pclass,
|
||||
const char *subname, const char *sysname,
|
||||
int size, void **pobject)
|
||||
{
|
||||
struct nouveau_subdev *subdev;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, pclass |
|
||||
NV_SUBDEV_CLASS, size, pobject);
|
||||
subdev = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&subdev->mutex);
|
||||
subdev->name = subname;
|
||||
|
||||
if (parent) {
|
||||
struct nouveau_device *device = nv_device(parent);
|
||||
int subidx = nv_hclass(subdev) & 0xff;
|
||||
|
||||
subdev->debug = nouveau_dbgopt(device->dbgopt, subname);
|
||||
subdev->mmio = nv_subdev(device)->mmio;
|
||||
device->subdev[subidx] = *pobject;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifndef __NOUVEAU_CLASS_H__
|
||||
#define __NOUVEAU_CLASS_H__
|
||||
|
||||
/* 0080: NV_DEVICE
|
||||
*/
|
||||
|
||||
#define NV_DEVICE_DISABLE_IDENTIFY 0x0000000000000001ULL
|
||||
#define NV_DEVICE_DISABLE_MMIO 0x0000000000000002ULL
|
||||
#define NV_DEVICE_DISABLE_VBIOS 0x0000000000000004ULL
|
||||
#define NV_DEVICE_DISABLE_CORE 0x0000000000000008ULL
|
||||
#define NV_DEVICE_DISABLE_DISP 0x0000000000010000ULL
|
||||
#define NV_DEVICE_DISABLE_FIFO 0x0000000000020000ULL
|
||||
#define NV_DEVICE_DISABLE_GRAPH 0x0000000100000000ULL
|
||||
#define NV_DEVICE_DISABLE_MPEG 0x0000000200000000ULL
|
||||
#define NV_DEVICE_DISABLE_ME 0x0000000400000000ULL
|
||||
#define NV_DEVICE_DISABLE_VP 0x0000000800000000ULL
|
||||
#define NV_DEVICE_DISABLE_CRYPT 0x0000001000000000ULL
|
||||
#define NV_DEVICE_DISABLE_BSP 0x0000002000000000ULL
|
||||
#define NV_DEVICE_DISABLE_PPP 0x0000004000000000ULL
|
||||
#define NV_DEVICE_DISABLE_COPY0 0x0000008000000000ULL
|
||||
#define NV_DEVICE_DISABLE_COPY1 0x0000010000000000ULL
|
||||
#define NV_DEVICE_DISABLE_UNK1C1 0x0000020000000000ULL
|
||||
|
||||
struct nv_device_class {
|
||||
u64 device; /* device identifier, ~0 for client default */
|
||||
u64 disable; /* disable particular subsystems */
|
||||
u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */
|
||||
};
|
||||
|
||||
/* 0002: NV_DMA_FROM_MEMORY
|
||||
* 0003: NV_DMA_TO_MEMORY
|
||||
* 003d: NV_DMA_IN_MEMORY
|
||||
*/
|
||||
|
||||
#define NV_DMA_TARGET_MASK 0x000000ff
|
||||
#define NV_DMA_TARGET_VM 0x00000000
|
||||
#define NV_DMA_TARGET_VRAM 0x00000001
|
||||
#define NV_DMA_TARGET_PCI 0x00000002
|
||||
#define NV_DMA_TARGET_PCI_US 0x00000003
|
||||
#define NV_DMA_TARGET_AGP 0x00000004
|
||||
#define NV_DMA_ACCESS_MASK 0x00000f00
|
||||
#define NV_DMA_ACCESS_VM 0x00000000
|
||||
#define NV_DMA_ACCESS_RD 0x00000100
|
||||
#define NV_DMA_ACCESS_WR 0x00000200
|
||||
#define NV_DMA_ACCESS_RDWR 0x00000300
|
||||
|
||||
struct nv_dma_class {
|
||||
u32 flags;
|
||||
u32 pad0;
|
||||
u64 start;
|
||||
u64 limit;
|
||||
};
|
||||
|
||||
/* 006b: NV03_CHANNEL_DMA
|
||||
* 006e: NV10_CHANNEL_DMA
|
||||
* 406e: NV40_CHANNEL_DMA
|
||||
*/
|
||||
|
||||
struct nv_channel_dma_class {
|
||||
u32 pushbuf;
|
||||
u32 pad0;
|
||||
u64 offset;
|
||||
};
|
||||
|
||||
/* 506f: NV50_CHANNEL_IND
|
||||
* 826f: NV84_CHANNEL_IND
|
||||
* 906f: NVC0_CHANNEL_IND
|
||||
* a06f: NVE0_CHANNEL_IND
|
||||
*/
|
||||
|
||||
struct nv_channel_ind_class {
|
||||
u32 pushbuf;
|
||||
u32 ilength;
|
||||
u64 ioffset;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef __NOUVEAU_CLIENT_H__
|
||||
#define __NOUVEAU_CLIENT_H__
|
||||
|
||||
#include <core/namedb.h>
|
||||
|
||||
struct nouveau_client {
|
||||
struct nouveau_namedb base;
|
||||
struct nouveau_handle *root;
|
||||
struct nouveau_object *device;
|
||||
u32 handle;
|
||||
u32 debug;
|
||||
struct nouveau_vm *vm;
|
||||
};
|
||||
|
||||
static inline struct nouveau_client *
|
||||
nv_client(void *obj)
|
||||
{
|
||||
#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
|
||||
if (unlikely(!nv_iclass(obj, NV_CLIENT_CLASS)))
|
||||
nv_assert("BAD CAST -> NvClient, %08x", nv_hclass(obj));
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
static inline struct nouveau_client *
|
||||
nouveau_client(void *obj)
|
||||
{
|
||||
struct nouveau_object *client = nv_object(obj);
|
||||
while (client && !(nv_iclass(client, NV_CLIENT_CLASS)))
|
||||
client = client->parent;
|
||||
return (void *)client;
|
||||
}
|
||||
|
||||
#define nouveau_client_create(n,c,oc,od,d) \
|
||||
nouveau_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d)
|
||||
|
||||
int nouveau_client_create_(u32 name, u64 device, const char *cfg,
|
||||
const char *dbg, int, void **);
|
||||
int nouveau_client_init(struct nouveau_client *);
|
||||
int nouveau_client_fini(struct nouveau_client *, bool suspend);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef __NOUVEAU_DEBUG_H__
|
||||
#define __NOUVEAU_DEBUG_H__
|
||||
|
||||
#define NV_DBG_FATAL 0
|
||||
#define NV_DBG_ERROR 1
|
||||
#define NV_DBG_WARN 2
|
||||
#define NV_DBG_INFO 3
|
||||
#define NV_DBG_DEBUG 4
|
||||
#define NV_DBG_TRACE 5
|
||||
#define NV_DBG_PARANOIA 6
|
||||
#define NV_DBG_SPAM 7
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,122 @@
|
||||
#ifndef __NOUVEAU_DEVICE_H__
|
||||
#define __NOUVEAU_DEVICE_H__
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/subdev.h>
|
||||
#include <core/engine.h>
|
||||
|
||||
enum nv_subdev_type {
|
||||
NVDEV_SUBDEV_DEVICE,
|
||||
NVDEV_SUBDEV_VBIOS,
|
||||
NVDEV_SUBDEV_GPIO,
|
||||
NVDEV_SUBDEV_I2C,
|
||||
NVDEV_SUBDEV_CLOCK,
|
||||
NVDEV_SUBDEV_MXM,
|
||||
NVDEV_SUBDEV_DEVINIT,
|
||||
NVDEV_SUBDEV_MC,
|
||||
NVDEV_SUBDEV_TIMER,
|
||||
NVDEV_SUBDEV_FB,
|
||||
NVDEV_SUBDEV_LTCG,
|
||||
NVDEV_SUBDEV_INSTMEM,
|
||||
NVDEV_SUBDEV_VM,
|
||||
NVDEV_SUBDEV_BAR,
|
||||
NVDEV_SUBDEV_VOLT,
|
||||
NVDEV_SUBDEV_FAN0,
|
||||
NVDEV_SUBDEV_THERM,
|
||||
NVDEV_ENGINE_DMAOBJ,
|
||||
NVDEV_ENGINE_FIFO,
|
||||
NVDEV_ENGINE_SW,
|
||||
NVDEV_ENGINE_GR,
|
||||
NVDEV_ENGINE_MPEG,
|
||||
NVDEV_ENGINE_ME,
|
||||
NVDEV_ENGINE_VP,
|
||||
NVDEV_ENGINE_CRYPT,
|
||||
NVDEV_ENGINE_BSP,
|
||||
NVDEV_ENGINE_PPP,
|
||||
NVDEV_ENGINE_COPY0,
|
||||
NVDEV_ENGINE_COPY1,
|
||||
NVDEV_ENGINE_UNK1C1,
|
||||
NVDEV_ENGINE_FENCE,
|
||||
NVDEV_ENGINE_DISP,
|
||||
NVDEV_SUBDEV_NR,
|
||||
};
|
||||
|
||||
struct nouveau_device {
|
||||
struct nouveau_subdev base;
|
||||
struct list_head head;
|
||||
|
||||
struct pci_dev *pdev;
|
||||
u64 handle;
|
||||
|
||||
const char *cfgopt;
|
||||
const char *dbgopt;
|
||||
const char *name;
|
||||
const char *cname;
|
||||
|
||||
enum {
|
||||
NV_04 = 0x04,
|
||||
NV_10 = 0x10,
|
||||
NV_20 = 0x20,
|
||||
NV_30 = 0x30,
|
||||
NV_40 = 0x40,
|
||||
NV_50 = 0x50,
|
||||
NV_C0 = 0xc0,
|
||||
NV_D0 = 0xd0,
|
||||
NV_E0 = 0xe0,
|
||||
} card_type;
|
||||
u32 chipset;
|
||||
u32 crystal;
|
||||
|
||||
struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR];
|
||||
struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
|
||||
};
|
||||
|
||||
static inline struct nouveau_device *
|
||||
nv_device(void *obj)
|
||||
{
|
||||
struct nouveau_object *object = nv_object(obj);
|
||||
struct nouveau_object *device = object;
|
||||
|
||||
if (device->engine)
|
||||
device = device->engine;
|
||||
if (device->parent)
|
||||
device = device->parent;
|
||||
|
||||
#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
|
||||
if (unlikely(!nv_iclass(device, NV_SUBDEV_CLASS) ||
|
||||
(nv_hclass(device) & 0xff) != NVDEV_SUBDEV_DEVICE)) {
|
||||
nv_assert("BAD CAST -> NvDevice, 0x%08x 0x%08x",
|
||||
nv_hclass(object), nv_hclass(device));
|
||||
}
|
||||
#endif
|
||||
|
||||
return (void *)device;
|
||||
}
|
||||
|
||||
static inline struct nouveau_subdev *
|
||||
nouveau_subdev(void *obj, int sub)
|
||||
{
|
||||
if (nv_device(obj)->subdev[sub])
|
||||
return nv_subdev(nv_device(obj)->subdev[sub]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct nouveau_engine *
|
||||
nouveau_engine(void *obj, int sub)
|
||||
{
|
||||
struct nouveau_subdev *subdev = nouveau_subdev(obj, sub);
|
||||
if (subdev && nv_iclass(subdev, NV_ENGINE_CLASS))
|
||||
return nv_engine(subdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(object);
|
||||
return device->pdev->device == dev &&
|
||||
device->pdev->subsystem_vendor == ven &&
|
||||
device->pdev->subsystem_device == sub;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifndef __NOUVEAU_ENGCTX_H__
|
||||
#define __NOUVEAU_ENGCTX_H__
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/gpuobj.h>
|
||||
|
||||
#include <subdev/vm.h>
|
||||
|
||||
#define NV_ENGCTX_(eng,var) (NV_ENGCTX_CLASS | ((var) << 8) | (eng))
|
||||
#define NV_ENGCTX(name,var) NV_ENGCTX_(NVDEV_ENGINE_##name, (var))
|
||||
|
||||
struct nouveau_engctx {
|
||||
struct nouveau_gpuobj base;
|
||||
struct nouveau_vma vma;
|
||||
struct list_head head;
|
||||
};
|
||||
|
||||
static inline void *
|
||||
nv_engctx(void *obj)
|
||||
{
|
||||
#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
|
||||
if (unlikely(!nv_iclass(obj, NV_ENGCTX_CLASS)))
|
||||
nv_assert("BAD CAST -> NvEngCtx, %08x", nv_hclass(obj));
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
#define nouveau_engctx_create(p,e,c,g,s,a,f,d) \
|
||||
nouveau_engctx_create_((p), (e), (c), (g), (s), (a), (f), \
|
||||
sizeof(**d), (void **)d)
|
||||
|
||||
int nouveau_engctx_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, struct nouveau_object *,
|
||||
u32 size, u32 align, u32 flags,
|
||||
int length, void **data);
|
||||
void nouveau_engctx_destroy(struct nouveau_engctx *);
|
||||
int nouveau_engctx_init(struct nouveau_engctx *);
|
||||
int nouveau_engctx_fini(struct nouveau_engctx *, bool suspend);
|
||||
|
||||
void _nouveau_engctx_dtor(struct nouveau_object *);
|
||||
int _nouveau_engctx_init(struct nouveau_object *);
|
||||
int _nouveau_engctx_fini(struct nouveau_object *, bool suspend);
|
||||
#define _nouveau_engctx_rd32 _nouveau_gpuobj_rd32
|
||||
#define _nouveau_engctx_wr32 _nouveau_gpuobj_wr32
|
||||
|
||||
struct nouveau_object *
|
||||
nouveau_engctx_lookup(struct nouveau_engine *, u64 addr);
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_engctx_lookup_class(struct nouveau_engine *, u64, u16);
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_engctx_lookup_vinst(struct nouveau_engine *, u64, u64);
|
||||
|
||||
struct nouveau_handle *
|
||||
nouveau_engctx_lookup_cinst(struct nouveau_engine *, u64, u32);
|
||||
|
||||
void
|
||||
nouveau_engctx_handle_put(struct nouveau_handle *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef __NOUVEAU_ENGINE_H__
|
||||
#define __NOUVEAU_ENGINE_H__
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/subdev.h>
|
||||
|
||||
#define NV_ENGINE_(eng,var) (NV_ENGINE_CLASS | ((var) << 8) | (eng))
|
||||
#define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var))
|
||||
|
||||
struct nouveau_engine {
|
||||
struct nouveau_subdev base;
|
||||
struct nouveau_oclass *cclass;
|
||||
struct nouveau_oclass *sclass;
|
||||
struct list_head contexts;
|
||||
void (*tile_prog)(struct nouveau_engine *, int region);
|
||||
int (*tlb_flush)(struct nouveau_engine *);
|
||||
};
|
||||
|
||||
static inline struct nouveau_engine *
|
||||
nv_engine(void *obj)
|
||||
{
|
||||
#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
|
||||
if (unlikely(!nv_iclass(obj, NV_ENGINE_CLASS)))
|
||||
nv_assert("BAD CAST -> NvEngine, %08x", nv_hclass(obj));
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nv_engidx(struct nouveau_object *object)
|
||||
{
|
||||
return nv_subidx(object);
|
||||
}
|
||||
|
||||
#define nouveau_engine_create(p,e,c,d,i,f,r) \
|
||||
nouveau_engine_create_((p), (e), (c), (d), (i), (f), \
|
||||
sizeof(**r),(void **)r)
|
||||
|
||||
#define nouveau_engine_destroy(p) \
|
||||
nouveau_subdev_destroy(&(p)->base)
|
||||
#define nouveau_engine_init(p) \
|
||||
nouveau_subdev_init(&(p)->base)
|
||||
#define nouveau_engine_fini(p,s) \
|
||||
nouveau_subdev_fini(&(p)->base, (s))
|
||||
|
||||
int nouveau_engine_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, bool, const char *,
|
||||
const char *, int, void **);
|
||||
|
||||
#define _nouveau_engine_dtor _nouveau_subdev_dtor
|
||||
#define _nouveau_engine_init _nouveau_subdev_init
|
||||
#define _nouveau_engine_fini _nouveau_subdev_fini
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user