# 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
* Authors: Ben Skeggs
*/
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include <core/os.h>
#include <core/mm.h>
static inline void
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#ifndef __NOUVEAU_ENUM_H__
+#define __NOUVEAU_ENUM_H__
+
+struct nouveau_enum {
+ u32 value;
+ const char *name;
+ void *data;
+};
+
+const struct nouveau_enum *
+nouveau_enum_find(const struct nouveau_enum *, u32 value);
+
+void
+nouveau_enum_print(const struct nouveau_enum *en, u32 value);
+
+struct nouveau_bitfield {
+ u32 mask;
+ const char *name;
+};
+
+void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value);
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_GPUOBJ_H__
+#define __NOUVEAU_GPUOBJ_H__
+
+#include <core/object.h>
+#ifndef XXX_THIS_IS_A_HACK
+#include <core/device.h>
+#include <core/parent.h>
+#include <core/mm.h>
+#endif
+
+struct nouveau_vma;
+struct nouveau_vm;
+
+#define NVOBJ_FLAG_ZERO_ALLOC 0x00000001
+#define NVOBJ_FLAG_ZERO_FREE 0x00000002
+#define NVOBJ_FLAG_HEAP 0x00000004
+
+struct nouveau_gpuobj {
+ struct nouveau_object base;
+ struct nouveau_object *parent;
+ struct nouveau_mm_node *node;
+ struct nouveau_mm heap;
+
+ u32 flags;
+ u64 addr;
+ u32 size;
+
+ /*XXX*/
+ struct drm_device *dev;
+ u32 engine;
+ u32 class;
+};
+
+#ifndef XXX_THIS_IS_A_HACK
+static inline struct nouveau_gpuobj *
+nv_gpuobj(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_GPUOBJ_CLASS)))
+ nv_assert("BAD CAST -> NvGpuObj, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+#define nouveau_gpuobj_create(p,e,c,v,g,s,a,f,d) \
+ nouveau_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f), \
+ sizeof(**d), (void **)d)
+#define nouveau_gpuobj_init(p) nouveau_object_init(&(p)->base)
+#define nouveau_gpuobj_fini(p,s) nouveau_object_fini(&(p)->base, (s))
+int nouveau_gpuobj_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, u32 pclass,
+ struct nouveau_object *, u32 size, u32 align,
+ u32 flags, int length, void **);
+void nouveau_gpuobj_destroy(struct nouveau_gpuobj *);
+
+int nouveau_gpuobj_new(struct nouveau_object *, struct nouveau_object *,
+ u32 size, u32 align, u32 flags,
+ struct nouveau_gpuobj **);
+int nouveau_gpuobj_dup(struct nouveau_object *, struct nouveau_gpuobj *,
+ struct nouveau_gpuobj **);
+
+int nouveau_gpuobj_map(struct nouveau_gpuobj *, u32 acc, struct nouveau_vma *);
+int nouveau_gpuobj_map_vm(struct nouveau_gpuobj *, struct nouveau_vm *,
+ u32 access, struct nouveau_vma *);
+void nouveau_gpuobj_unmap(struct nouveau_vma *);
+#endif
+
+static inline void
+nouveau_gpuobj_ref(struct nouveau_gpuobj *obj, struct nouveau_gpuobj **ref)
+{
+ nouveau_object_ref(&obj->base, (struct nouveau_object **)ref);
+}
+
+#ifndef XXX_THIS_IS_A_HACK
+void _nouveau_gpuobj_dtor(struct nouveau_object *);
+int _nouveau_gpuobj_init(struct nouveau_object *);
+int _nouveau_gpuobj_fini(struct nouveau_object *, bool);
+u32 _nouveau_gpuobj_rd32(struct nouveau_object *, u32);
+void _nouveau_gpuobj_wr32(struct nouveau_object *, u32, u32);
+#endif
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_HANDLE_H__
+#define __NOUVEAU_HANDLE_H__
+
+struct nouveau_handle {
+ struct nouveau_namedb *namedb;
+ struct list_head node;
+
+ struct list_head head;
+ struct list_head tree;
+ u32 name;
+ u32 priv;
+
+ struct nouveau_handle *parent;
+ struct nouveau_object *object;
+};
+
+int nouveau_handle_create(struct nouveau_object *, u32 parent, u32 handle,
+ struct nouveau_object *, struct nouveau_handle **);
+void nouveau_handle_destroy(struct nouveau_handle *);
+int nouveau_handle_init(struct nouveau_handle *);
+int nouveau_handle_fini(struct nouveau_handle *, bool suspend);
+
+struct nouveau_object *
+nouveau_handle_ref(struct nouveau_object *, u32 name);
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_MATH_H__
+#define __NOUVEAU_MATH_H__
+
+static inline int
+log2i(u64 base)
+{
+ u64 temp = base >> 1;
+ int log2;
+
+ for (log2 = 0; temp; log2++, temp >>= 1) {
+ }
+
+ return (base & (base - 1)) ? log2 + 1: log2;
+}
+
+#endif
* Authors: Ben Skeggs
*/
-#ifndef __NOUVEAU_REGION_H__
-#define __NOUVEAU_REGION_H__
+#ifndef __NOUVEAU_MM_H__
+#define __NOUVEAU_MM_H__
struct nouveau_mm_node {
struct list_head nl_entry;
--- /dev/null
+#ifndef __NOUVEAU_NAMEDB_H__
+#define __NOUVEAU_NAMEDB_H__
+
+#include <core/parent.h>
+
+struct nouveau_handle;
+
+struct nouveau_namedb {
+ struct nouveau_parent base;
+ rwlock_t lock;
+ struct list_head list;
+};
+
+static inline struct nouveau_namedb *
+nv_namedb(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_NAMEDB_CLASS)))
+ nv_assert("BAD CAST -> NvNameDB, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+#define nouveau_namedb_create(p,e,c,v,s,m,d) \
+ nouveau_namedb_create_((p), (e), (c), (v), (s), (m), \
+ sizeof(**d), (void **)d)
+#define nouveau_namedb_init(p) \
+ nouveau_parent_init(&(p)->base)
+#define nouveau_namedb_fini(p,s) \
+ nouveau_parent_fini(&(p)->base, (s))
+#define nouveau_namedb_destroy(p) \
+ nouveau_parent_destroy(&(p)->base)
+
+int nouveau_namedb_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, u32 pclass,
+ struct nouveau_oclass *, u32 engcls,
+ int size, void **);
+
+int _nouveau_namedb_ctor(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, void *, u32,
+ struct nouveau_object **);
+#define _nouveau_namedb_dtor _nouveau_parent_dtor
+#define _nouveau_namedb_init _nouveau_parent_init
+#define _nouveau_namedb_fini _nouveau_parent_fini
+
+int nouveau_namedb_insert(struct nouveau_namedb *, u32 name,
+ struct nouveau_object *, struct nouveau_handle *);
+void nouveau_namedb_remove(struct nouveau_handle *);
+
+struct nouveau_handle *nouveau_namedb_get(struct nouveau_namedb *, u32);
+struct nouveau_handle *nouveau_namedb_get_class(struct nouveau_namedb *, u16);
+struct nouveau_handle *nouveau_namedb_get_vinst(struct nouveau_namedb *, u64);
+struct nouveau_handle *nouveau_namedb_get_cinst(struct nouveau_namedb *, u32);
+void nouveau_namedb_put(struct nouveau_handle *);
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_OBJECT_H__
+#define __NOUVEAU_OBJECT_H__
+
+#include <core/os.h>
+#include <core/printk.h>
+
+#define NV_PARENT_CLASS 0x80000000
+#define NV_NAMEDB_CLASS 0x40000000
+#define NV_CLIENT_CLASS 0x20000000
+#define NV_SUBDEV_CLASS 0x10000000
+#define NV_ENGINE_CLASS 0x08000000
+#define NV_MEMOBJ_CLASS 0x04000000
+#define NV_GPUOBJ_CLASS 0x02000000
+#define NV_ENGCTX_CLASS 0x01000000
+#define NV_OBJECT_CLASS 0x0000ffff
+
+struct nouveau_object {
+ struct nouveau_oclass *oclass;
+ struct nouveau_object *parent;
+ struct nouveau_object *engine;
+ atomic_t refcount;
+ atomic_t usecount;
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+#define NOUVEAU_OBJECT_MAGIC 0x75ef0bad
+ struct list_head list;
+ u32 _magic;
+#endif
+};
+
+static inline struct nouveau_object *
+nv_object(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (likely(obj)) {
+ struct nouveau_object *object = obj;
+ if (unlikely(object->_magic != NOUVEAU_OBJECT_MAGIC))
+ nv_assert("BAD CAST -> NvObject, invalid magic");
+ }
+#endif
+ return obj;
+}
+
+#define nouveau_object_create(p,e,c,s,d) \
+ nouveau_object_create_((p), (e), (c), (s), sizeof(**d), (void **)d)
+int nouveau_object_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, u32, int size, void **);
+void nouveau_object_destroy(struct nouveau_object *);
+int nouveau_object_init(struct nouveau_object *);
+int nouveau_object_fini(struct nouveau_object *, bool suspend);
+
+extern struct nouveau_ofuncs nouveau_object_ofuncs;
+
+struct nouveau_oclass {
+ u32 handle;
+ struct nouveau_ofuncs *ofuncs;
+ struct nouveau_omthds *omthds;
+};
+
+#define nv_oclass(o) nv_object(o)->oclass
+#define nv_hclass(o) nv_oclass(o)->handle
+#define nv_iclass(o,i) (nv_hclass(o) & (i))
+#define nv_mclass(o) nv_iclass(o, NV_OBJECT_CLASS)
+
+static inline struct nouveau_object *
+nv_pclass(struct nouveau_object *parent, u32 oclass)
+{
+ while (parent && !nv_iclass(parent, oclass))
+ parent = parent->parent;
+ return parent;
+}
+
+struct nouveau_omthds {
+ u32 method;
+ int (*call)(struct nouveau_object *, u32, void *, u32);
+};
+
+struct nouveau_ofuncs {
+ int (*ctor)(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, void *data, u32 size,
+ struct nouveau_object **);
+ void (*dtor)(struct nouveau_object *);
+ int (*init)(struct nouveau_object *);
+ int (*fini)(struct nouveau_object *, bool suspend);
+ u8 (*rd08)(struct nouveau_object *, u32 offset);
+ u16 (*rd16)(struct nouveau_object *, u32 offset);
+ u32 (*rd32)(struct nouveau_object *, u32 offset);
+ void (*wr08)(struct nouveau_object *, u32 offset, u8 data);
+ void (*wr16)(struct nouveau_object *, u32 offset, u16 data);
+ void (*wr32)(struct nouveau_object *, u32 offset, u32 data);
+};
+
+static inline struct nouveau_ofuncs *
+nv_ofuncs(void *obj)
+{
+ return nv_oclass(obj)->ofuncs;
+}
+
+int nouveau_object_ctor(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, void *, u32,
+ struct nouveau_object **);
+void nouveau_object_ref(struct nouveau_object *, struct nouveau_object **);
+int nouveau_object_inc(struct nouveau_object *);
+int nouveau_object_dec(struct nouveau_object *, bool suspend);
+
+int nouveau_object_new(struct nouveau_object *, u32 parent, u32 handle,
+ u16 oclass, void *data, u32 size,
+ struct nouveau_object **);
+int nouveau_object_del(struct nouveau_object *, u32 parent, u32 handle);
+void nouveau_object_debug(void);
+
+static inline int
+nv_call(void *obj, u32 mthd, u32 data)
+{
+ struct nouveau_omthds *method = nv_oclass(obj)->omthds;
+
+ while (method && method->call) {
+ if (method->method == mthd)
+ return method->call(obj, mthd, &data, sizeof(data));
+ method++;
+ }
+
+ return -EINVAL;
+}
+
+static inline u8
+nv_ro08(void *obj, u32 addr)
+{
+ u8 data = nv_ofuncs(obj)->rd08(obj, addr);
+ nv_spam(obj, "nv_ro08 0x%08x 0x%02x\n", addr, data);
+ return data;
+}
+
+static inline u16
+nv_ro16(void *obj, u32 addr)
+{
+ u16 data = nv_ofuncs(obj)->rd16(obj, addr);
+ nv_spam(obj, "nv_ro16 0x%08x 0x%04x\n", addr, data);
+ return data;
+}
+
+static inline u32
+nv_ro32(void *obj, u32 addr)
+{
+ u32 data = nv_ofuncs(obj)->rd32(obj, addr);
+ nv_spam(obj, "nv_ro32 0x%08x 0x%08x\n", addr, data);
+ return data;
+}
+
+static inline void
+nv_wo08(void *obj, u32 addr, u8 data)
+{
+ nv_spam(obj, "nv_wo08 0x%08x 0x%02x\n", addr, data);
+ nv_ofuncs(obj)->wr08(obj, addr, data);
+}
+
+static inline void
+nv_wo16(void *obj, u32 addr, u16 data)
+{
+ nv_spam(obj, "nv_wo16 0x%08x 0x%04x\n", addr, data);
+ nv_ofuncs(obj)->wr16(obj, addr, data);
+}
+
+static inline void
+nv_wo32(void *obj, u32 addr, u32 data)
+{
+ nv_spam(obj, "nv_wo32 0x%08x 0x%08x\n", addr, data);
+ nv_ofuncs(obj)->wr32(obj, addr, data);
+}
+
+static inline u32
+nv_mo32(void *obj, u32 addr, u32 mask, u32 data)
+{
+ u32 temp = nv_ro32(obj, addr);
+ nv_wo32(obj, addr, (temp & ~mask) | data);
+ return temp;
+}
+
+static inline bool
+nv_strncmp(void *obj, u32 addr, u32 len, const char *str)
+{
+ while (len--) {
+ if (nv_ro08(obj, addr++) != *(str++))
+ return false;
+ }
+ return true;
+}
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_OPTION_H__
+#define __NOUVEAU_OPTION_H__
+
+#include <core/os.h>
+
+const char *nouveau_stropt(const char *optstr, const char *opt, int *len);
+bool nouveau_boolopt(const char *optstr, const char *opt, bool value);
+
+int nouveau_dbgopt(const char *optstr, const char *sub);
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_PARENT_H__
+#define __NOUVEAU_PARENT_H__
+
+#include <core/device.h>
+#include <core/object.h>
+
+struct nouveau_sclass {
+ struct nouveau_sclass *sclass;
+ struct nouveau_engine *engine;
+ struct nouveau_oclass *oclass;
+};
+
+struct nouveau_parent {
+ struct nouveau_object base;
+
+ struct nouveau_sclass *sclass;
+ u32 engine;
+
+ int (*context_attach)(struct nouveau_object *,
+ struct nouveau_object *);
+ int (*context_detach)(struct nouveau_object *, bool suspend,
+ struct nouveau_object *);
+
+ int (*object_attach)(struct nouveau_object *parent,
+ struct nouveau_object *object, u32 name);
+ void (*object_detach)(struct nouveau_object *parent, int cookie);
+};
+
+static inline struct nouveau_parent *
+nv_parent(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!(nv_iclass(obj, NV_PARENT_CLASS))))
+ nv_assert("BAD CAST -> NvParent, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+#define nouveau_parent_create(p,e,c,v,s,m,d) \
+ nouveau_parent_create_((p), (e), (c), (v), (s), (m), \
+ sizeof(**d), (void **)d)
+#define nouveau_parent_init(p) \
+ nouveau_object_init(&(p)->base)
+#define nouveau_parent_fini(p,s) \
+ nouveau_object_fini(&(p)->base, (s))
+
+int nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, u32 pclass,
+ struct nouveau_oclass *, u64 engcls,
+ int size, void **);
+void nouveau_parent_destroy(struct nouveau_parent *);
+
+int _nouveau_parent_ctor(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, void *, u32,
+ struct nouveau_object **);
+void _nouveau_parent_dtor(struct nouveau_object *);
+#define _nouveau_parent_init _nouveau_object_init
+#define _nouveau_parent_fini _nouveau_object_fini
+
+int nouveau_parent_sclass(struct nouveau_object *, u16 handle,
+ struct nouveau_object **pengine,
+ struct nouveau_oclass **poclass);
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_PRINTK_H__
+#define __NOUVEAU_PRINTK_H__
+
+#include <core/os.h>
+#include <core/debug.h>
+
+struct nouveau_object;
+
+#define NV_PRINTK_FATAL KERN_CRIT
+#define NV_PRINTK_ERROR KERN_ERR
+#define NV_PRINTK_WARN KERN_WARNING
+#define NV_PRINTK_INFO KERN_INFO
+#define NV_PRINTK_DEBUG KERN_DEBUG
+#define NV_PRINTK_PARANOIA KERN_DEBUG
+#define NV_PRINTK_TRACE KERN_DEBUG
+#define NV_PRINTK_SPAM KERN_DEBUG
+
+void nv_printk_(struct nouveau_object *, const char *, int, const char *, ...);
+
+#define nv_printk(o,l,f,a...) do { \
+ if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \
+ nv_printk_(nv_object(o), NV_PRINTK_##l, NV_DBG_##l, f, ##a); \
+} while(0)
+
+#define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a)
+#define nv_error(o,f,a...) nv_printk((o), ERROR, f, ##a)
+#define nv_warn(o,f,a...) nv_printk((o), WARN, f, ##a)
+#define nv_info(o,f,a...) nv_printk((o), INFO, f, ##a)
+#define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a)
+#define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a)
+#define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a)
+
+#define nv_assert(f,a...) do { \
+ if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG) \
+ nv_printk_(NULL, NV_PRINTK_FATAL, NV_DBG_FATAL, f "\n", ##a); \
+ BUG_ON(1); \
+} while(0)
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_SUBDEV_H__
+#define __NOUVEAU_SUBDEV_H__
+
+#include <core/object.h>
+
+#define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub))
+#define NV_SUBDEV(name,var) NV_SUBDEV_(NVDEV_SUBDEV_##name, (var))
+
+struct nouveau_subdev {
+ struct nouveau_object base;
+ struct mutex mutex;
+ const char *name;
+ void __iomem *mmio;
+ u32 debug;
+ u32 unit;
+
+ void (*intr)(struct nouveau_subdev *);
+};
+
+static inline struct nouveau_subdev *
+nv_subdev(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_SUBDEV_CLASS)))
+ nv_assert("BAD CAST -> NvSubDev, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+static inline int
+nv_subidx(struct nouveau_object *object)
+{
+ return nv_hclass(nv_subdev(object)) & 0xff;
+}
+
+#define nouveau_subdev_create(p,e,o,v,s,f,d) \
+ nouveau_subdev_create_((p), (e), (o), (v), (s), (f), \
+ sizeof(**d),(void **)d)
+
+int nouveau_subdev_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, u32 pclass,
+ const char *sname, const char *fname,
+ int size, void **);
+void nouveau_subdev_destroy(struct nouveau_subdev *);
+int nouveau_subdev_init(struct nouveau_subdev *);
+int nouveau_subdev_fini(struct nouveau_subdev *, bool suspend);
+void nouveau_subdev_reset(struct nouveau_object *);
+
+void _nouveau_subdev_dtor(struct nouveau_object *);
+int _nouveau_subdev_init(struct nouveau_object *);
+int _nouveau_subdev_fini(struct nouveau_object *, bool suspend);
+
+#define s_printk(s,l,f,a...) do { \
+ if ((s)->debug >= OS_DBG_##l) { \
+ nv_printk((s)->base.parent, (s)->name, l, f, ##a); \
+ } \
+} while(0)
+
+static inline u8
+nv_rd08(void *obj, u32 addr)
+{
+ struct nouveau_subdev *subdev = nv_subdev(obj);
+ u8 data = ioread8(subdev->mmio + addr);
+ nv_spam(subdev, "nv_rd08 0x%06x 0x%02x\n", addr, data);
+ return data;
+}
+
+static inline u16
+nv_rd16(void *obj, u32 addr)
+{
+ struct nouveau_subdev *subdev = nv_subdev(obj);
+ u16 data = ioread16_native(subdev->mmio + addr);
+ nv_spam(subdev, "nv_rd16 0x%06x 0x%04x\n", addr, data);
+ return data;
+}
+
+static inline u32
+nv_rd32(void *obj, u32 addr)
+{
+ struct nouveau_subdev *subdev = nv_subdev(obj);
+ u32 data = ioread32_native(subdev->mmio + addr);
+ nv_spam(subdev, "nv_rd32 0x%06x 0x%08x\n", addr, data);
+ return data;
+}
+
+static inline void
+nv_wr08(void *obj, u32 addr, u8 data)
+{
+ struct nouveau_subdev *subdev = nv_subdev(obj);
+ nv_spam(subdev, "nv_wr08 0x%06x 0x%02x\n", addr, data);
+ iowrite8(data, subdev->mmio + addr);
+}
+
+static inline void
+nv_wr16(void *obj, u32 addr, u16 data)
+{
+ struct nouveau_subdev *subdev = nv_subdev(obj);
+ nv_spam(subdev, "nv_wr16 0x%06x 0x%04x\n", addr, data);
+ iowrite16_native(data, subdev->mmio + addr);
+}
+
+static inline void
+nv_wr32(void *obj, u32 addr, u32 data)
+{
+ struct nouveau_subdev *subdev = nv_subdev(obj);
+ nv_spam(subdev, "nv_wr32 0x%06x 0x%08x\n", addr, data);
+ iowrite32_native(data, subdev->mmio + addr);
+}
+
+static inline u32
+nv_mask(void *obj, u32 addr, u32 mask, u32 data)
+{
+ u32 temp = nv_rd32(obj, addr);
+ nv_wr32(obj, addr, (temp & ~mask) | data);
+ return temp;
+}
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_SUBDEV_DEVICE_H__
+#define __NOUVEAU_SUBDEV_DEVICE_H__
+
+#include <core/device.h>
+
+#define nouveau_device_create(p,n,s,c,d,u) \
+ nouveau_device_create_((p), (n), (s), (c), (d), sizeof(**u), (void **)u)
+
+int nouveau_device_create_(struct pci_dev *, u64 name, const char *sname,
+ const char *cfg, const char *dbg, int, void **);
+void nouveau_device_destroy(struct nouveau_device **);
+
+int nv04_identify(struct nouveau_device *);
+int nv10_identify(struct nouveau_device *);
+int nv20_identify(struct nouveau_device *);
+int nv30_identify(struct nouveau_device *);
+int nv40_identify(struct nouveau_device *);
+int nv50_identify(struct nouveau_device *);
+int nvc0_identify(struct nouveau_device *);
+int nve0_identify(struct nouveau_device *);
+
+extern struct nouveau_oclass nouveau_device_sclass[];
+struct nouveau_device *nouveau_device_find(u64 name);
+
+#endif
--- /dev/null
+#ifndef __NOUVEAU_OS_H__
+#define __NOUVEAU_OS_H__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/delay.h>
+#include <linux/io-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/acpi.h>
+
+#include <asm/unaligned.h>
+
+static inline int
+ffsll(u64 mask)
+{
+ int i;
+ for (i = 0; i < 64; i++) {
+ if (mask & (1ULL << i))
+ return i + 1;
+ }
+ return 0;
+}
+
+#ifndef ioread32_native
+#ifdef __BIG_ENDIAN
+#define ioread16_native ioread16be
+#define iowrite16_native iowrite16be
+#define ioread32_native ioread32be
+#define iowrite32_native iowrite32be
+#else /* def __BIG_ENDIAN */
+#define ioread16_native ioread16
+#define iowrite16_native iowrite16
+#define ioread32_native ioread32
+#define iowrite32_native iowrite32
+#endif /* def __BIG_ENDIAN else */
+#endif /* !ioread32_native */
+
+#endif
--- /dev/null
+/*
+ * 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/device.h>
+#include <core/client.h>
+#include <core/device.h>
+#include <core/option.h>
+
+#include <core/class.h>
+
+#include <subdev/device.h>
+
+static DEFINE_MUTEX(nv_devices_mutex);
+static LIST_HEAD(nv_devices);
+
+struct nouveau_device *
+nouveau_device_find(u64 name)
+{
+ struct nouveau_device *device, *match = NULL;
+ mutex_lock(&nv_devices_mutex);
+ list_for_each_entry(device, &nv_devices, head) {
+ if (device->handle == name) {
+ match = device;
+ break;
+ }
+ }
+ mutex_unlock(&nv_devices_mutex);
+ return match;
+}
+
+/******************************************************************************
+ * nouveau_devobj (0x0080): class implementation
+ *****************************************************************************/
+struct nouveau_devobj {
+ struct nouveau_parent base;
+ struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
+ bool created;
+};
+
+static const u64 disable_map[] = {
+ [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_DISABLE_VBIOS,
+ [NVDEV_SUBDEV_GPIO] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_I2C] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_VM] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_FAN0] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_ENGINE_GR] = NV_DEVICE_DISABLE_GRAPH,
+ [NVDEV_ENGINE_MPEG] = NV_DEVICE_DISABLE_MPEG,
+ [NVDEV_ENGINE_ME] = NV_DEVICE_DISABLE_ME,
+ [NVDEV_ENGINE_VP] = NV_DEVICE_DISABLE_VP,
+ [NVDEV_ENGINE_CRYPT] = NV_DEVICE_DISABLE_CRYPT,
+ [NVDEV_ENGINE_BSP] = NV_DEVICE_DISABLE_BSP,
+ [NVDEV_ENGINE_PPP] = NV_DEVICE_DISABLE_PPP,
+ [NVDEV_ENGINE_COPY0] = NV_DEVICE_DISABLE_COPY0,
+ [NVDEV_ENGINE_COPY1] = NV_DEVICE_DISABLE_COPY1,
+ [NVDEV_ENGINE_UNK1C1] = NV_DEVICE_DISABLE_UNK1C1,
+ [NVDEV_ENGINE_FIFO] = NV_DEVICE_DISABLE_FIFO,
+ [NVDEV_ENGINE_DISP] = NV_DEVICE_DISABLE_DISP,
+ [NVDEV_SUBDEV_NR] = 0,
+};
+
+static int
+nouveau_devobj_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_client *client = nv_client(parent);
+ struct nouveau_object *subdev = NULL;
+ struct nouveau_device *device;
+ struct nouveau_devobj *devobj;
+ struct nv_device_class *args = data;
+ u64 disable, boot0, strap;
+ u64 mmio_base, mmio_size;
+ void __iomem *map;
+ int ret, i;
+
+ if (size < sizeof(struct nv_device_class))
+ return -EINVAL;
+
+ /* find the device subdev that matches what the client requested */
+ device = nv_device(client->device);
+ if (args->device != ~0) {
+ device = nouveau_device_find(args->device);
+ if (!device)
+ return -ENODEV;
+ }
+
+ ret = nouveau_parent_create(parent, nv_object(device), oclass, 0, NULL,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_FIFO) |
+ (1ULL << NVDEV_ENGINE_DISP), &devobj);
+ *pobject = nv_object(devobj);
+ if (ret)
+ return ret;
+
+ mmio_base = pci_resource_start(device->pdev, 0);
+ mmio_size = pci_resource_len(device->pdev, 0);
+
+ /* translate api disable mask into internal mapping */
+ disable = args->debug0;
+ for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+ if (args->disable & disable_map[i])
+ disable |= (1ULL << i);
+ }
+
+ /* identify the chipset, and determine classes of subdev/engines */
+ if (!(args->disable & NV_DEVICE_DISABLE_IDENTIFY) &&
+ !device->card_type) {
+ map = ioremap(mmio_base, 0x102000);
+ if (map == NULL) {
+ }
+
+ /* switch mmio to cpu's native endianness */
+#ifndef __BIG_ENDIAN
+ if (ioread32_native(map + 0x000004) != 0x00000000)
+#else
+ if (ioread32_native(map + 0x000004) == 0x00000000)
+#endif
+ iowrite32_native(0x01000001, map + 0x000004);
+
+ /* read boot0 and strapping information */
+ boot0 = ioread32_native(map + 0x000000);
+ strap = ioread32_native(map + 0x101000);
+ iounmap(map);
+
+ /* determine chipset and derive architecture from it */
+ if ((boot0 & 0x0f000000) > 0) {
+ device->chipset = (boot0 & 0xff00000) >> 20;
+ switch (device->chipset & 0xf0) {
+ case 0x10: device->card_type = NV_10; break;
+ case 0x20: device->card_type = NV_20; break;
+ case 0x30: device->card_type = NV_30; break;
+ case 0x40:
+ case 0x60: device->card_type = NV_40; break;
+ case 0x50:
+ case 0x80:
+ case 0x90:
+ case 0xa0: device->card_type = NV_50; break;
+ case 0xc0: device->card_type = NV_C0; break;
+ case 0xd0: device->card_type = NV_D0; break;
+ case 0xe0: device->card_type = NV_E0; break;
+ default:
+ break;
+ }
+ } else
+ if ((boot0 & 0xff00fff0) == 0x20004000) {
+ if (boot0 & 0x00f00000)
+ device->chipset = 0x05;
+ else
+ device->chipset = 0x04;
+ device->card_type = NV_04;
+ }
+
+ switch (device->card_type) {
+ case NV_04: ret = nv04_identify(device); break;
+ case NV_10: ret = nv10_identify(device); break;
+ case NV_20: ret = nv20_identify(device); break;
+ case NV_30: ret = nv30_identify(device); break;
+ case NV_40: ret = nv40_identify(device); break;
+ case NV_50: ret = nv50_identify(device); break;
+ case NV_C0:
+ case NV_D0: ret = nvc0_identify(device); break;
+ case NV_E0: ret = nve0_identify(device); break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ nv_error(device, "unknown chipset, 0x%08x\n", boot0);
+ return ret;
+ }
+
+ nv_info(device, "BOOT0 : 0x%08x\n", boot0);
+ nv_info(device, "Chipset: NV%02X\n", device->chipset);
+ nv_info(device, "Family : NV%02X\n", device->card_type);
+
+ /* determine frequency of timing crystal */
+ if ( device->chipset < 0x17 ||
+ (device->chipset >= 0x20 && device->chipset <= 0x25))
+ strap &= 0x00000040;
+ else
+ strap &= 0x00400040;
+
+ switch (strap) {
+ case 0x00000000: device->crystal = 13500; break;
+ case 0x00000040: device->crystal = 14318; break;
+ case 0x00400000: device->crystal = 27000; break;
+ case 0x00400040: device->crystal = 25000; break;
+ }
+
+ nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
+ }
+
+ if (!(args->disable & NV_DEVICE_DISABLE_MMIO) &&
+ !nv_subdev(device)->mmio) {
+ nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size);
+ if (!nv_subdev(device)->mmio) {
+ nv_error(device, "unable to map device registers\n");
+ return ret;
+ }
+ }
+
+ /* ensure requested subsystems are available for use */
+ for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+ if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
+ continue;
+
+ if (!device->subdev[i]) {
+ ret = nouveau_object_ctor(nv_object(device), NULL,
+ oclass, NULL, i, &subdev);
+ if (ret)
+ return ret;
+
+ if (nv_iclass(subdev, NV_ENGINE_CLASS))
+ nouveau_subdev_reset(subdev);
+ } else {
+ nouveau_object_ref(device->subdev[i], &subdev);
+ }
+
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nouveau_object_inc(subdev);
+ if (ret) {
+ nouveau_object_ref(NULL, &subdev);
+ return ret;
+ }
+ }
+
+ nouveau_object_ref(subdev, &devobj->subdev[i]);
+ nouveau_object_ref(NULL, &subdev);
+ }
+
+ return 0;
+}
+
+static void
+nouveau_devobj_dtor(struct nouveau_object *object)
+{
+ struct nouveau_devobj *devobj = (void *)object;
+ int i;
+
+ for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
+ nouveau_object_ref(NULL, &devobj->subdev[i]);
+
+ nouveau_parent_destroy(&devobj->base);
+}
+
+static int
+nouveau_devobj_init(struct nouveau_object *object)
+{
+ struct nouveau_devobj *devobj = (void *)object;
+ struct nouveau_object *subdev;
+ int ret, i;
+
+ ret = nouveau_parent_init(&devobj->base);
+ if (ret)
+ return ret;
+
+ for (i = 0; devobj->created && i < NVDEV_SUBDEV_NR; i++) {
+ if ((subdev = devobj->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nouveau_object_inc(subdev);
+ if (ret)
+ goto fail;
+ }
+ }
+ }
+
+ devobj->created = true;
+ return 0;
+
+fail:
+ for (--i; i >= 0; i--) {
+ if ((subdev = devobj->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS))
+ nouveau_object_dec(subdev, false);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nouveau_devobj_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nouveau_devobj *devobj = (void *)object;
+ struct nouveau_object *subdev;
+ int ret, i;
+
+ for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
+ if ((subdev = devobj->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nouveau_object_dec(subdev, suspend);
+ if (ret && suspend)
+ goto fail;
+ }
+ }
+ }
+
+ ret = nouveau_parent_fini(&devobj->base, suspend);
+fail:
+ for (; ret && suspend && i < NVDEV_SUBDEV_NR; i++) {
+ if ((subdev = devobj->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nouveau_object_inc(subdev);
+ if (ret) {
+ /* XXX */
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+static u8
+nouveau_devobj_rd08(struct nouveau_object *object, u32 addr)
+{
+ return nv_rd08(object->engine, addr);
+}
+
+static u16
+nouveau_devobj_rd16(struct nouveau_object *object, u32 addr)
+{
+ return nv_rd16(object->engine, addr);
+}
+
+static u32
+nouveau_devobj_rd32(struct nouveau_object *object, u32 addr)
+{
+ return nv_rd32(object->engine, addr);
+}
+
+static void
+nouveau_devobj_wr08(struct nouveau_object *object, u32 addr, u8 data)
+{
+ nv_wr08(object->engine, addr, data);
+}
+
+static void
+nouveau_devobj_wr16(struct nouveau_object *object, u32 addr, u16 data)
+{
+ nv_wr16(object->engine, addr, data);
+}
+
+static void
+nouveau_devobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
+{
+ nv_wr32(object->engine, addr, data);
+}
+
+static struct nouveau_ofuncs
+nouveau_devobj_ofuncs = {
+ .ctor = nouveau_devobj_ctor,
+ .dtor = nouveau_devobj_dtor,
+ .init = nouveau_devobj_init,
+ .fini = nouveau_devobj_fini,
+ .rd08 = nouveau_devobj_rd08,
+ .rd16 = nouveau_devobj_rd16,
+ .rd32 = nouveau_devobj_rd32,
+ .wr08 = nouveau_devobj_wr08,
+ .wr16 = nouveau_devobj_wr16,
+ .wr32 = nouveau_devobj_wr32,
+};
+
+/******************************************************************************
+ * nouveau_device: engine functions
+ *****************************************************************************/
+struct nouveau_oclass
+nouveau_device_sclass[] = {
+ { 0x0080, &nouveau_devobj_ofuncs },
+ {}
+};
+
+static struct nouveau_oclass
+nouveau_device_oclass = {
+ .handle = NV_SUBDEV(DEVICE, 0x00),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ },
+};
+
+int
+nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname,
+ const char *cfg, const char *dbg,
+ int length, void **pobject)
+{
+ struct nouveau_device *device;
+ int ret = -EEXIST;
+
+ mutex_lock(&nv_devices_mutex);
+ list_for_each_entry(device, &nv_devices, head) {
+ if (device->handle == name)
+ goto done;
+ }
+
+ ret = nouveau_subdev_create_(NULL, NULL, &nouveau_device_oclass, 0,
+ "DEVICE", "device", length, pobject);
+ device = *pobject;
+ if (ret)
+ goto done;
+
+ atomic_set(&nv_object(device)->usecount, 2);
+ device->pdev = pdev;
+ device->handle = name;
+ device->cfgopt = cfg;
+ device->dbgopt = dbg;
+ device->name = sname;
+
+ nv_subdev(device)->debug = nouveau_dbgopt(device->dbgopt, "DEVICE");
+ list_add(&device->head, &nv_devices);
+done:
+ mutex_unlock(&nv_devices_mutex);
+ return ret;
+}
+
+void
+nouveau_device_destroy(struct nouveau_device **pdevice)
+{
+ struct nouveau_device *device = *pdevice;
+ if (device) {
+ mutex_lock(&nv_devices_mutex);
+ list_del(&device->head);
+ mutex_unlock(&nv_devices_mutex);
+ if (device->base.mmio)
+ iounmap(device->base.mmio);
+ nouveau_subdev_destroy(&device->base);
+ }
+ *pdevice = NULL;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nv04_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0x04:
+ break;
+ case 0x05:
+ break;
+ default:
+ nv_fatal(device, "unknown RIVA chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nv10_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0x10:
+ break;
+ case 0x15:
+ break;
+ case 0x16:
+ break;
+ case 0x1a:
+ break;
+ case 0x11:
+ break;
+ case 0x17:
+ break;
+ case 0x1f:
+ break;
+ case 0x18:
+ break;
+ default:
+ nv_fatal(device, "unknown Celsius chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nv20_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0x20:
+ break;
+ case 0x25:
+ break;
+ case 0x28:
+ break;
+ case 0x2a:
+ break;
+ default:
+ nv_fatal(device, "unknown Kelvin chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nv30_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0x30:
+ break;
+ case 0x35:
+ break;
+ case 0x31:
+ break;
+ case 0x36:
+ break;
+ case 0x34:
+ break;
+ default:
+ nv_fatal(device, "unknown Rankine chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nv40_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0x40:
+ break;
+ case 0x41:
+ break;
+ case 0x42:
+ break;
+ case 0x43:
+ break;
+ case 0x45:
+ break;
+ case 0x47:
+ break;
+ case 0x49:
+ break;
+ case 0x4b:
+ break;
+ case 0x44:
+ break;
+ case 0x46:
+ break;
+ case 0x4a:
+ break;
+ case 0x4c:
+ break;
+ case 0x4e:
+ break;
+ case 0x63:
+ break;
+ case 0x67:
+ break;
+ case 0x68:
+ break;
+ default:
+ nv_fatal(device, "unknown Curie chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nv50_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0x50:
+ break;
+ case 0x84:
+ break;
+ case 0x86:
+ break;
+ case 0x92:
+ break;
+ case 0x94:
+ break;
+ case 0x96:
+ break;
+ case 0x98:
+ break;
+ case 0xa0:
+ break;
+ case 0xaa:
+ break;
+ case 0xac:
+ break;
+ case 0xa3:
+ break;
+ case 0xa5:
+ break;
+ case 0xa8:
+ break;
+ case 0xaf:
+ break;
+ default:
+ nv_fatal(device, "unknown Tesla chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nvc0_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0xc0:
+ break;
+ case 0xc4:
+ break;
+ case 0xc3:
+ break;
+ case 0xce:
+ break;
+ case 0xcf:
+ break;
+ case 0xc1:
+ break;
+ case 0xc8:
+ break;
+ case 0xd9:
+ break;
+ default:
+ nv_fatal(device, "unknown Fermi chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <subdev/device.h>
+
+int
+nve0_identify(struct nouveau_device *device)
+{
+ switch (device->chipset) {
+ case 0xe4:
+ break;
+ case 0xe7:
+ break;
+ default:
+ nv_fatal(device, "unknown Kepler chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}