drm/nouveau/nvif: import library functions for the ioctl/event interfaces
authorBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 18:10:21 +0000 (04:10 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 19:13:09 +0000 (05:13 +1000)
This is a wrapper around the interfaces defined in an earlier commit,
and is also used by various userspace (either by a libdrm backend, or
libpciaccess) tools/tests.

In the future this will be extended to handle channels, replacing some
long-unloved code we currently use, and allow fifo/display/mpeg (hi
Ilia ;)) engines to all be exposed in the same way.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
14 files changed:
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/handle.c
drivers/gpu/drm/nouveau/core/include/core/class.h
drivers/gpu/drm/nouveau/nvif/client.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/client.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/device.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/device.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/driver.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/list.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/notify.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/notify.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/object.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/object.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/os.h [new symlink]

index dfab376466a1e64cb3720f6a3a25d3b8b3b3c412..3cddb955aad3d7b933375f4c7b1471af903daa9e 100644 (file)
@@ -327,6 +327,12 @@ nouveau-y += core/engine/vp/nv98.o
 nouveau-y += core/engine/vp/nvc0.o
 nouveau-y += core/engine/vp/nve0.o
 
+# nvif
+nouveau-y += nvif/object.o
+nouveau-y += nvif/client.o
+nouveau-y += nvif/device.o
+nouveau-y += nvif/notify.o
+
 # drm/core
 nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
 nouveau-y += nouveau_vga.o nouveau_agp.o
index 734777ce43f4d9f45b375b0bf1b237bcc8a0c93c..a490b805d7e321e0db2715ed979388e657b9f0e5 100644 (file)
@@ -146,9 +146,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
        }
 
        hprintk(handle, TRACE, "created\n");
-
        *phandle = handle;
-
        return 0;
 }
 
index d6fd2cbe43334e5c27574cb6c01b955489d43322..37d47cb44a7b07551567bbad7b66bd5c4f82f4c6 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __NOUVEAU_CLASS_H__
 #define __NOUVEAU_CLASS_H__
 
+#include <nvif/class.h>
+
 /* Device class
  *
  * 0080: NV_DEVICE
diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c
new file mode 100644 (file)
index 0000000..7048fd9
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2013 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 <bskeggs@redhat.com>
+ */
+
+#include "client.h"
+#include "driver.h"
+#include "ioctl.h"
+
+int
+nvif_client_ioctl(struct nvif_client *client, void *data, u32 size)
+{
+       return client->driver->ioctl(client->base.priv, client->super, data, size, NULL);
+}
+
+int
+nvif_client_suspend(struct nvif_client *client)
+{
+       return client->driver->suspend(client->base.priv);
+}
+
+int
+nvif_client_resume(struct nvif_client *client)
+{
+       return client->driver->resume(client->base.priv);
+}
+
+void
+nvif_client_fini(struct nvif_client *client)
+{
+       if (client->driver) {
+               client->driver->fini(client->base.priv);
+               client->driver = NULL;
+               client->base.parent = NULL;
+               nvif_object_fini(&client->base);
+       }
+}
+
+const struct nvif_driver *
+nvif_drivers[] = {
+#ifdef __KERNEL__
+#if 0
+       &nvif_driver_nvkm,
+#endif
+#else
+       &nvif_driver_lib,
+#endif
+       NULL
+};
+
+int
+nvif_client_init(void (*dtor)(struct nvif_client *), const char *driver,
+                const char *name, u64 device, const char *cfg, const char *dbg,
+                struct nvif_client *client)
+{
+       int ret, i;
+
+       ret = nvif_object_init(NULL, (void*)dtor, 0, 0, NULL, 0, &client->base);
+       if (ret)
+               return ret;
+
+       client->base.parent = &client->base;
+       client->base.handle = ~0;
+       client->object = &client->base;
+       client->super = true;
+
+       for (i = 0, ret = -EINVAL; (client->driver = nvif_drivers[i]); i++) {
+               if (!driver || !strcmp(client->driver->name, driver)) {
+                       ret = client->driver->init(name, device, cfg, dbg,
+                                                 &client->base.priv);
+                       if (!ret || driver)
+                               break;
+               }
+       }
+
+       if (ret)
+               nvif_client_fini(client);
+       return ret;
+}
+
+static void
+nvif_client_del(struct nvif_client *client)
+{
+       nvif_client_fini(client);
+       kfree(client);
+}
+
+int
+nvif_client_new(const char *driver, const char *name, u64 device,
+               const char *cfg, const char *dbg,
+               struct nvif_client **pclient)
+{
+       struct nvif_client *client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (client) {
+               int ret = nvif_client_init(nvif_client_del, driver, name,
+                                          device, cfg, dbg, client);
+               if (ret) {
+                       kfree(client);
+                       client = NULL;
+               }
+               *pclient = client;
+               return ret;
+       }
+       return -ENOMEM;
+}
+
+void
+nvif_client_ref(struct nvif_client *client, struct nvif_client **pclient)
+{
+       nvif_object_ref(&client->base, (struct nvif_object **)pclient);
+}
diff --git a/drivers/gpu/drm/nouveau/nvif/client.h b/drivers/gpu/drm/nouveau/nvif/client.h
new file mode 100644 (file)
index 0000000..28352f0
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __NVIF_CLIENT_H__
+#define __NVIF_CLIENT_H__
+
+#include "object.h"
+
+struct nvif_client {
+       struct nvif_object base;
+       struct nvif_object *object; /*XXX: hack for nvif_object() */
+       const struct nvif_driver *driver;
+       bool super;
+};
+
+static inline struct nvif_client *
+nvif_client(struct nvif_object *object)
+{
+       while (object && object->parent != object)
+               object = object->parent;
+       return (void *)object;
+}
+
+int  nvif_client_init(void (*dtor)(struct nvif_client *), const char *,
+                     const char *, u64, const char *, const char *,
+                     struct nvif_client *);
+void nvif_client_fini(struct nvif_client *);
+int  nvif_client_new(const char *, const char *, u64, const char *,
+                    const char *, struct nvif_client **);
+void nvif_client_ref(struct nvif_client *, struct nvif_client **);
+int  nvif_client_ioctl(struct nvif_client *, void *, u32);
+int  nvif_client_suspend(struct nvif_client *);
+int  nvif_client_resume(struct nvif_client *);
+
+/*XXX*/
+#include <core/client.h>
+#define nvkm_client(a) ({ \
+       struct nvif_client *_client = nvif_client(nvif_object(a)); \
+       nouveau_client(_client->base.priv); \
+})
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c
new file mode 100644 (file)
index 0000000..f477579
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 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 <bskeggs@redhat.com>
+ */
+
+#include "device.h"
+
+void
+nvif_device_fini(struct nvif_device *device)
+{
+       nvif_object_fini(&device->base);
+}
+
+int
+nvif_device_init(struct nvif_object *parent, void (*dtor)(struct nvif_device *),
+                u32 handle, u32 oclass, void *data, u32 size,
+                struct nvif_device *device)
+{
+       int ret = nvif_object_init(parent, (void *)dtor, handle, oclass,
+                                  data, size, &device->base);
+       if (ret == 0) {
+               device->object = &device->base;
+               device->info.version = 0;
+               ret = nvif_object_mthd(&device->base, NV_DEVICE_V0_INFO,
+                                      &device->info, sizeof(device->info));
+       }
+       return ret;
+}
+
+static void
+nvif_device_del(struct nvif_device *device)
+{
+       nvif_device_fini(device);
+       kfree(device);
+}
+
+int
+nvif_device_new(struct nvif_object *parent, u32 handle, u32 oclass,
+               void *data, u32 size, struct nvif_device **pdevice)
+{
+       struct nvif_device *device = kzalloc(sizeof(*device), GFP_KERNEL);
+       if (device) {
+               int ret = nvif_device_init(parent, nvif_device_del, handle,
+                                          oclass, data, size, device);
+               if (ret) {
+                       kfree(device);
+                       device = NULL;
+               }
+               *pdevice = device;
+               return ret;
+       }
+       return -ENOMEM;
+}
+
+void
+nvif_device_ref(struct nvif_device *device, struct nvif_device **pdevice)
+{
+       nvif_object_ref(&device->base, (struct nvif_object **)pdevice);
+}
diff --git a/drivers/gpu/drm/nouveau/nvif/device.h b/drivers/gpu/drm/nouveau/nvif/device.h
new file mode 100644 (file)
index 0000000..c208bad
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __NVIF_DEVICE_H__
+#define __NVIF_DEVICE_H__
+
+#include "object.h"
+#include "class.h"
+
+struct nvif_device {
+       struct nvif_object base;
+       struct nvif_object *object; /*XXX: hack for nvif_object() */
+       struct nv_device_info_v0 info;
+};
+
+static inline struct nvif_device *
+nvif_device(struct nvif_object *object)
+{
+       while (object && object->oclass != 0x0080 /*XXX: NV_DEVICE_CLASS*/ )
+               object = object->parent;
+       return (void *)object;
+}
+
+int  nvif_device_init(struct nvif_object *, void (*dtor)(struct nvif_device *),
+                     u32 handle, u32 oclass, void *, u32,
+                     struct nvif_device *);
+void nvif_device_fini(struct nvif_device *);
+int  nvif_device_new(struct nvif_object *, u32 handle, u32 oclass,
+                    void *, u32, struct nvif_device **);
+void nvif_device_ref(struct nvif_device *, struct nvif_device **);
+
+/*XXX*/
+#include <subdev/bios.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/vm.h>
+#include <subdev/bar.h>
+#include <subdev/gpio.h>
+#include <subdev/clock.h>
+#include <subdev/i2c.h>
+#include <subdev/timer.h>
+#include <subdev/therm.h>
+
+#define nvkm_device(a) nv_device(nvkm_object((a)))
+#define nvkm_bios(a) nouveau_bios(nvkm_device(a))
+#define nvkm_fb(a) nouveau_fb(nvkm_device(a))
+#define nvkm_instmem(a) nouveau_instmem(nvkm_device(a))
+#define nvkm_vmmgr(a) nouveau_vmmgr(nvkm_device(a))
+#define nvkm_bar(a) nouveau_bar(nvkm_device(a))
+#define nvkm_gpio(a) nouveau_gpio(nvkm_device(a))
+#define nvkm_clock(a) nouveau_clock(nvkm_device(a))
+#define nvkm_i2c(a) nouveau_i2c(nvkm_device(a))
+#define nvkm_timer(a) nouveau_timer(nvkm_device(a))
+#define nvkm_wait(a,b,c,d) nv_wait(nvkm_timer(a), (b), (c), (d))
+#define nvkm_wait_cb(a,b,c) nv_wait_cb(nvkm_timer(a), (b), (c))
+#define nvkm_therm(a) nouveau_therm(nvkm_device(a))
+
+#include <engine/device.h>
+#include <engine/fifo.h>
+#include <engine/disp.h>
+#include <engine/graph.h>
+#include <engine/software.h>
+
+#define nvkm_fifo(a) nouveau_fifo(nvkm_device(a))
+#define nvkm_fifo_chan(a) ((struct nouveau_fifo_chan *)nvkm_object(a))
+#define nvkm_disp(a) nouveau_disp(nvkm_device(a))
+#define nvkm_gr(a) ((struct nouveau_graph *)nouveau_engine(nvkm_object(a), NVDEV_ENGINE_GR))
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/driver.h b/drivers/gpu/drm/nouveau/nvif/driver.h
new file mode 100644 (file)
index 0000000..ea5b1b8
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __NVIF_DRIVER_H__
+#define __NVIF_DRIVER_H__
+
+struct nvif_driver {
+       const char *name;
+       int (*init)(const char *name, u64 device, const char *cfg,
+                   const char *dbg, void **priv);
+       void (*fini)(void *priv);
+       int (*suspend)(void *priv);
+       int (*resume)(void *priv);
+       int (*ioctl)(void *priv, bool super, void *data, u32 size, void **hack);
+       void *(*map)(void *priv, u64 handle, u32 size);
+       void (*unmap)(void *priv, void *ptr, u32 size);
+       bool keep;
+};
+
+extern const struct nvif_driver nvif_driver_nvkm;
+extern const struct nvif_driver nvif_driver_lib;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/list.h b/drivers/gpu/drm/nouveau/nvif/list.h
new file mode 100644 (file)
index 0000000..8af5d14
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright Â© 2010 Intel Corporation
+ * Copyright Â© 2010 Francisco Jerez <currojerez@riseup.net>
+ *
+ * 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 AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ */
+
+/* Modified by Ben Skeggs <bskeggs@redhat.com> to match kernel list APIs */
+
+#ifndef _XORG_LIST_H_
+#define _XORG_LIST_H_
+
+/**
+ * @file Classic doubly-link circular list implementation.
+ * For real usage examples of the linked list, see the file test/list.c
+ *
+ * Example:
+ * We need to keep a list of struct foo in the parent struct bar, i.e. what
+ * we want is something like this.
+ *
+ *     struct bar {
+ *          ...
+ *          struct foo *list_of_foos; -----> struct foo {}, struct foo {}, struct foo{}
+ *          ...
+ *     }
+ *
+ * We need one list head in bar and a list element in all list_of_foos (both are of
+ * data type 'struct list_head').
+ *
+ *     struct bar {
+ *          ...
+ *          struct list_head list_of_foos;
+ *          ...
+ *     }
+ *
+ *     struct foo {
+ *          ...
+ *          struct list_head entry;
+ *          ...
+ *     }
+ *
+ * Now we initialize the list head:
+ *
+ *     struct bar bar;
+ *     ...
+ *     INIT_LIST_HEAD(&bar.list_of_foos);
+ *
+ * Then we create the first element and add it to this list:
+ *
+ *     struct foo *foo = malloc(...);
+ *     ....
+ *     list_add(&foo->entry, &bar.list_of_foos);
+ *
+ * Repeat the above for each element you want to add to the list. Deleting
+ * works with the element itself.
+ *      list_del(&foo->entry);
+ *      free(foo);
+ *
+ * Note: calling list_del(&bar.list_of_foos) will set bar.list_of_foos to an empty
+ * list again.
+ *
+ * Looping through the list requires a 'struct foo' as iterator and the
+ * name of the field the subnodes use.
+ *
+ * struct foo *iterator;
+ * list_for_each_entry(iterator, &bar.list_of_foos, entry) {
+ *      if (iterator->something == ...)
+ *             ...
+ * }
+ *
+ * Note: You must not call list_del() on the iterator if you continue the
+ * loop. You need to run the safe for-each loop instead:
+ *
+ * struct foo *iterator, *next;
+ * list_for_each_entry_safe(iterator, next, &bar.list_of_foos, entry) {
+ *      if (...)
+ *              list_del(&iterator->entry);
+ * }
+ *
+ */
+
+/**
+ * The linkage struct for list nodes. This struct must be part of your
+ * to-be-linked struct. struct list_head is required for both the head of the
+ * list and for each list node.
+ *
+ * Position and name of the struct list_head field is irrelevant.
+ * There are no requirements that elements of a list are of the same type.
+ * There are no requirements for a list head, any struct list_head can be a list
+ * head.
+ */
+struct list_head {
+    struct list_head *next, *prev;
+};
+
+/**
+ * Initialize the list as an empty list.
+ *
+ * Example:
+ * INIT_LIST_HEAD(&bar->list_of_foos);
+ *
+ * @param The list to initialized.
+ */
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void
+INIT_LIST_HEAD(struct list_head *list)
+{
+    list->next = list->prev = list;
+}
+
+static inline void
+__list_add(struct list_head *entry,
+                struct list_head *prev, struct list_head *next)
+{
+    next->prev = entry;
+    entry->next = next;
+    entry->prev = prev;
+    prev->next = entry;
+}
+
+/**
+ * Insert a new element after the given list head. The new element does not
+ * need to be initialised as empty list.
+ * The list changes from:
+ *      head â†’ some element â†’ ...
+ * to
+ *      head â†’ new element â†’ older element â†’ ...
+ *
+ * Example:
+ * struct foo *newfoo = malloc(...);
+ * list_add(&newfoo->entry, &bar->list_of_foos);
+ *
+ * @param entry The new element to prepend to the list.
+ * @param head The existing list.
+ */
+static inline void
+list_add(struct list_head *entry, struct list_head *head)
+{
+    __list_add(entry, head, head->next);
+}
+
+/**
+ * Append a new element to the end of the list given with this list head.
+ *
+ * The list changes from:
+ *      head â†’ some element â†’ ... â†’ lastelement
+ * to
+ *      head â†’ some element â†’ ... â†’ lastelement â†’ new element
+ *
+ * Example:
+ * struct foo *newfoo = malloc(...);
+ * list_add_tail(&newfoo->entry, &bar->list_of_foos);
+ *
+ * @param entry The new element to prepend to the list.
+ * @param head The existing list.
+ */
+static inline void
+list_add_tail(struct list_head *entry, struct list_head *head)
+{
+    __list_add(entry, head->prev, head);
+}
+
+static inline void
+__list_del(struct list_head *prev, struct list_head *next)
+{
+    next->prev = prev;
+    prev->next = next;
+}
+
+/**
+ * Remove the element from the list it is in. Using this function will reset
+ * the pointers to/from this element so it is removed from the list. It does
+ * NOT free the element itself or manipulate it otherwise.
+ *
+ * Using list_del on a pure list head (like in the example at the top of
+ * this file) will NOT remove the first element from
+ * the list but rather reset the list as empty list.
+ *
+ * Example:
+ * list_del(&foo->entry);
+ *
+ * @param entry The element to remove.
+ */
+static inline void
+list_del(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+}
+
+static inline void
+list_del_init(struct list_head *entry)
+{
+    __list_del(entry->prev, entry->next);
+    INIT_LIST_HEAD(entry);
+}
+
+static inline void list_move_tail(struct list_head *list,
+                                 struct list_head *head)
+{
+       __list_del(list->prev, list->next);
+       list_add_tail(list, head);
+}
+
+/**
+ * Check if the list is empty.
+ *
+ * Example:
+ * list_empty(&bar->list_of_foos);
+ *
+ * @return True if the list contains one or more elements or False otherwise.
+ */
+static inline bool
+list_empty(struct list_head *head)
+{
+    return head->next == head;
+}
+
+/**
+ * Returns a pointer to the container of this list element.
+ *
+ * Example:
+ * struct foo* f;
+ * f = container_of(&foo->entry, struct foo, entry);
+ * assert(f == foo);
+ *
+ * @param ptr Pointer to the struct list_head.
+ * @param type Data type of the list element.
+ * @param member Member name of the struct list_head field in the list element.
+ * @return A pointer to the data struct containing the list head.
+ */
+#ifndef container_of
+#define container_of(ptr, type, member) \
+    (type *)((char *)(ptr) - (char *) &((type *)0)->member)
+#endif
+
+/**
+ * Alias of container_of
+ */
+#define list_entry(ptr, type, member) \
+    container_of(ptr, type, member)
+
+/**
+ * Retrieve the first list entry for the given list pointer.
+ *
+ * Example:
+ * struct foo *first;
+ * first = list_first_entry(&bar->list_of_foos, struct foo, list_of_foos);
+ *
+ * @param ptr The list head
+ * @param type Data type of the list element to retrieve
+ * @param member Member name of the struct list_head field in the list element.
+ * @return A pointer to the first list element.
+ */
+#define list_first_entry(ptr, type, member) \
+    list_entry((ptr)->next, type, member)
+
+/**
+ * Retrieve the last list entry for the given listpointer.
+ *
+ * Example:
+ * struct foo *first;
+ * first = list_last_entry(&bar->list_of_foos, struct foo, list_of_foos);
+ *
+ * @param ptr The list head
+ * @param type Data type of the list element to retrieve
+ * @param member Member name of the struct list_head field in the list element.
+ * @return A pointer to the last list element.
+ */
+#define list_last_entry(ptr, type, member) \
+    list_entry((ptr)->prev, type, member)
+
+#define __container_of(ptr, sample, member)                            \
+    (void *)container_of((ptr), typeof(*(sample)), member)
+
+/**
+ * Loop through the list given by head and set pos to struct in the list.
+ *
+ * Example:
+ * struct foo *iterator;
+ * list_for_each_entry(iterator, &bar->list_of_foos, entry) {
+ *      [modify iterator]
+ * }
+ *
+ * This macro is not safe for node deletion. Use list_for_each_entry_safe
+ * instead.
+ *
+ * @param pos Iterator variable of the type of the list elements.
+ * @param head List head
+ * @param member Member name of the struct list_head in the list elements.
+ *
+ */
+#define list_for_each_entry(pos, head, member)                         \
+    for (pos = __container_of((head)->next, pos, member);              \
+        &pos->member != (head);                                        \
+        pos = __container_of(pos->member.next, pos, member))
+
+/**
+ * Loop through the list, keeping a backup pointer to the element. This
+ * macro allows for the deletion of a list element while looping through the
+ * list.
+ *
+ * See list_for_each_entry for more details.
+ */
+#define list_for_each_entry_safe(pos, tmp, head, member)               \
+    for (pos = __container_of((head)->next, pos, member),              \
+        tmp = __container_of(pos->member.next, pos, member);           \
+        &pos->member != (head);                                        \
+        pos = tmp, tmp = __container_of(pos->member.next, tmp, member))
+
+
+#define list_for_each_entry_reverse(pos, head, member)                 \
+       for (pos = __container_of((head)->prev, pos, member);           \
+            &pos->member != (head);                                    \
+            pos = __container_of(pos->member.prev, pos, member))
+
+#define list_for_each_entry_continue(pos, head, member)                        \
+       for (pos = __container_of(pos->member.next, pos, member);       \
+            &pos->member != (head);                                    \
+            pos = __container_of(pos->member.next, pos, member))
+
+#define list_for_each_entry_continue_reverse(pos, head, member)                \
+       for (pos = __container_of(pos->member.prev, pos, member);       \
+            &pos->member != (head);                                    \
+            pos = __container_of(pos->member.prev, pos, member))
+
+#define list_for_each_entry_from(pos, head, member)                    \
+       for (;                                                          \
+            &pos->member != (head);                                    \
+            pos = __container_of(pos->member.next, pos, member))
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c
new file mode 100644 (file)
index 0000000..7c06123
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2014 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 <bskeggs@redhat.com>
+ */
+
+#include <nvif/client.h>
+#include <nvif/driver.h>
+#include <nvif/notify.h>
+#include <nvif/object.h>
+#include <nvif/ioctl.h>
+#include <nvif/event.h>
+
+static inline int
+nvif_notify_put_(struct nvif_notify *notify)
+{
+       struct nvif_object *object = notify->object;
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_ntfy_put_v0 ntfy;
+       } args = {
+               .ioctl.type = NVIF_IOCTL_V0_NTFY_PUT,
+               .ntfy.index = notify->index,
+       };
+
+       if (atomic_inc_return(&notify->putcnt) != 1)
+               return 0;
+
+       return nvif_object_ioctl(object, &args, sizeof(args), NULL);
+}
+
+int
+nvif_notify_put(struct nvif_notify *notify)
+{
+       if (likely(notify->object) &&
+           test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
+               int ret = nvif_notify_put_(notify);
+               if (test_bit(NVIF_NOTIFY_WORK, &notify->flags))
+                       flush_work(&notify->work);
+               return ret;
+       }
+       return 0;
+}
+
+static inline int
+nvif_notify_get_(struct nvif_notify *notify)
+{
+       struct nvif_object *object = notify->object;
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_ntfy_get_v0 ntfy;
+       } args = {
+               .ioctl.type = NVIF_IOCTL_V0_NTFY_GET,
+               .ntfy.index = notify->index,
+       };
+
+       if (atomic_dec_return(&notify->putcnt) != 0)
+               return 0;
+
+       return nvif_object_ioctl(object, &args, sizeof(args), NULL);
+}
+
+int
+nvif_notify_get(struct nvif_notify *notify)
+{
+       if (likely(notify->object) &&
+           !test_and_set_bit(NVIF_NOTIFY_USER, &notify->flags))
+               return nvif_notify_get_(notify);
+       return 0;
+}
+
+static void
+nvif_notify_work(struct work_struct *work)
+{
+       struct nvif_notify *notify = container_of(work, typeof(*notify), work);
+       if (notify->func(notify) == NVIF_NOTIFY_KEEP)
+               nvif_notify_get_(notify);
+}
+
+int
+nvif_notify(const void *header, u32 length, const void *data, u32 size)
+{
+       struct nvif_notify *notify = NULL;
+       const union {
+               struct nvif_notify_rep_v0 v0;
+       } *args = header;
+       int ret = NVIF_NOTIFY_DROP;
+
+       if (length == sizeof(args->v0) && args->v0.version == 0) {
+               if (WARN_ON(args->v0.route))
+                       return NVIF_NOTIFY_DROP;
+               notify = (void *)(unsigned long)args->v0.token;
+       }
+
+       if (!WARN_ON(notify == NULL)) {
+               struct nvif_client *client = nvif_client(notify->object);
+               if (!WARN_ON(notify->size != size)) {
+                       if (test_bit(NVIF_NOTIFY_WORK, &notify->flags)) {
+                               atomic_inc(&notify->putcnt);
+                               memcpy((void *)notify->data, data, size);
+                               schedule_work(&notify->work);
+                               return NVIF_NOTIFY_DROP;
+                       }
+                       notify->data = data;
+                       ret = notify->func(notify);
+                       notify->data = NULL;
+                       if (ret != NVIF_NOTIFY_DROP && client->driver->keep) {
+                               atomic_inc(&notify->putcnt);
+                               nvif_notify_get_(notify);
+                       }
+               }
+       }
+
+       return ret;
+}
+
+int
+nvif_notify_fini(struct nvif_notify *notify)
+{
+       struct nvif_object *object = notify->object;
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_ntfy_del_v0 ntfy;
+       } args = {
+               .ioctl.type = NVIF_IOCTL_V0_NTFY_DEL,
+               .ntfy.index = notify->index,
+       };
+       int ret = nvif_notify_put(notify);
+       if (ret >= 0 && object) {
+               ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
+               if (ret == 0) {
+                       nvif_object_ref(NULL, &notify->object);
+                       kfree((void *)notify->data);
+               }
+       }
+       return ret;
+}
+
+int
+nvif_notify_init(struct nvif_object *object, void (*dtor)(struct nvif_notify *),
+                int (*func)(struct nvif_notify *), bool work, u8 event,
+                void *data, u32 size, u32 reply, struct nvif_notify *notify)
+{
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_ntfy_new_v0 ntfy;
+               struct nvif_notify_req_v0 req;
+       } *args;
+       int ret = -ENOMEM;
+
+       notify->object = NULL;
+       nvif_object_ref(object, &notify->object);
+       notify->flags = 0;
+       atomic_set(&notify->putcnt, 1);
+       notify->dtor = dtor;
+       notify->func = func;
+       notify->data = NULL;
+       notify->size = reply;
+       if (work) {
+               INIT_WORK(&notify->work, nvif_notify_work);
+               set_bit(NVIF_NOTIFY_WORK, &notify->flags);
+               notify->data = kmalloc(notify->size, GFP_KERNEL);
+               if (!notify->data)
+                       goto done;
+       }
+
+       if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
+               goto done;
+       args->ioctl.version = 0;
+       args->ioctl.type = NVIF_IOCTL_V0_NTFY_NEW;
+       args->ntfy.version = 0;
+       args->ntfy.event = event;
+       args->req.version = 0;
+       args->req.reply = notify->size;
+       args->req.route = 0;
+       args->req.token = (unsigned long)(void *)notify;
+
+       memcpy(args->req.data, data, size);
+       ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
+       notify->index = args->ntfy.index;
+       kfree(args);
+done:
+       if (ret)
+               nvif_notify_fini(notify);
+       return ret;
+}
+
+static void
+nvif_notify_del(struct nvif_notify *notify)
+{
+       nvif_notify_fini(notify);
+       kfree(notify);
+}
+
+void
+nvif_notify_ref(struct nvif_notify *notify, struct nvif_notify **pnotify)
+{
+       BUG_ON(notify != NULL);
+       if (*pnotify)
+               (*pnotify)->dtor(*pnotify);
+       *pnotify = notify;
+}
+
+int
+nvif_notify_new(struct nvif_object *object, int (*func)(struct nvif_notify *),
+               bool work, u8 type, void *data, u32 size, u32 reply,
+               struct nvif_notify **pnotify)
+{
+       struct nvif_notify *notify = kzalloc(sizeof(*notify), GFP_KERNEL);
+       if (notify) {
+               int ret = nvif_notify_init(object, nvif_notify_del, func, work,
+                                          type, data, size, reply, notify);
+               if (ret)
+                       kfree(notify);
+               *pnotify = notify;
+               return ret;
+       }
+       return -ENOMEM;
+}
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.h b/drivers/gpu/drm/nouveau/nvif/notify.h
new file mode 100644 (file)
index 0000000..9ebfa3b
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __NVIF_NOTIFY_H__
+#define __NVIF_NOTIFY_H__
+
+struct nvif_notify {
+       struct nvif_object *object;
+       int index;
+
+#define NVIF_NOTIFY_USER 0
+#define NVIF_NOTIFY_WORK 1
+       unsigned long flags;
+       atomic_t putcnt;
+       void (*dtor)(struct nvif_notify *);
+#define NVIF_NOTIFY_DROP 0
+#define NVIF_NOTIFY_KEEP 1
+       int  (*func)(struct nvif_notify *);
+
+       /* this is const for a *very* good reason - the data might be on the
+        * stack from an irq handler.  if you're not nvif/notify.c then you
+        * should probably think twice before casting it away...
+        */
+       const void *data;
+       u32 size;
+       struct work_struct work;
+};
+
+int  nvif_notify_init(struct nvif_object *, void (*dtor)(struct nvif_notify *),
+                     int (*func)(struct nvif_notify *), bool work, u8 type,
+                     void *data, u32 size, u32 reply, struct nvif_notify *);
+int  nvif_notify_fini(struct nvif_notify *);
+int  nvif_notify_get(struct nvif_notify *);
+int  nvif_notify_put(struct nvif_notify *);
+int  nvif_notify(const void *, u32, const void *, u32);
+
+int  nvif_notify_new(struct nvif_object *, int (*func)(struct nvif_notify *),
+                    bool work, u8 type, void *data, u32 size, u32 reply,
+                    struct nvif_notify **);
+void nvif_notify_ref(struct nvif_notify *, struct nvif_notify **);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c
new file mode 100644 (file)
index 0000000..b0c8220
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2014 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 <bskeggs@redhat.com>
+ */
+
+#include "object.h"
+#include "client.h"
+#include "driver.h"
+#include "ioctl.h"
+
+int
+nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
+{
+       struct nvif_client *client = nvif_client(object);
+       union {
+               struct nvif_ioctl_v0 v0;
+       } *args = data;
+
+       if (size >= sizeof(*args) && args->v0.version == 0) {
+               args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
+               args->v0.path_nr = 0;
+               while (args->v0.path_nr < ARRAY_SIZE(args->v0.path)) {
+                       args->v0.path[args->v0.path_nr++] = object->handle;
+                       if (object->parent == object)
+                               break;
+                       object = object->parent;
+               }
+       } else
+               return -ENOSYS;
+
+       return client->driver->ioctl(client->base.priv, client->super, data, size, hack);
+}
+
+int
+nvif_object_sclass(struct nvif_object *object, u32 *oclass, int count)
+{
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_sclass_v0 sclass;
+       } *args;
+       u32 size = count * sizeof(args->sclass.oclass[0]);
+       int ret;
+
+       if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
+               return -ENOMEM;
+       args->ioctl.version = 0;
+       args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
+       args->sclass.version = 0;
+       args->sclass.count = count;
+
+       memcpy(args->sclass.oclass, oclass, size);
+       ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
+       ret = ret ? ret : args->sclass.count;
+       memcpy(oclass, args->sclass.oclass, size);
+       kfree(args);
+       return ret;
+}
+
+u32
+nvif_object_rd(struct nvif_object *object, int size, u64 addr)
+{
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_rd_v0 rd;
+       } args = {
+               .ioctl.type = NVIF_IOCTL_V0_RD,
+               .rd.size = size,
+               .rd.addr = addr,
+       };
+       int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
+       if (ret) {
+               /*XXX: warn? */
+               return 0;
+       }
+       return args.rd.data;
+}
+
+void
+nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data)
+{
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_wr_v0 wr;
+       } args = {
+               .ioctl.type = NVIF_IOCTL_V0_WR,
+               .wr.size = size,
+               .wr.addr = addr,
+               .wr.data = data,
+       };
+       int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
+       if (ret) {
+               /*XXX: warn? */
+       }
+}
+
+int
+nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
+{
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_mthd_v0 mthd;
+       } *args;
+       u8 stack[128];
+       int ret;
+
+       if (sizeof(*args) + size > sizeof(stack)) {
+               if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
+                       return -ENOMEM;
+       } else {
+               args = (void *)stack;
+       }
+       args->ioctl.version = 0;
+       args->ioctl.type = NVIF_IOCTL_V0_MTHD;
+       args->mthd.version = 0;
+       args->mthd.method = mthd;
+
+       memcpy(args->mthd.data, data, size);
+       ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
+       memcpy(data, args->mthd.data, size);
+       if (args != (void *)stack)
+               kfree(args);
+       return ret;
+}
+
+void
+nvif_object_unmap(struct nvif_object *object)
+{
+       if (object->map.size) {
+               struct nvif_client *client = nvif_client(object);
+               struct {
+                       struct nvif_ioctl_v0 ioctl;
+                       struct nvif_ioctl_unmap unmap;
+               } args = {
+                       .ioctl.type = NVIF_IOCTL_V0_UNMAP,
+               };
+
+               if (object->map.ptr) {
+                       client->driver->unmap(client, object->map.ptr,
+                                                     object->map.size);
+                       object->map.ptr = NULL;
+               }
+
+               nvif_object_ioctl(object, &args, sizeof(args), NULL);
+               object->map.size = 0;
+       }
+}
+
+int
+nvif_object_map(struct nvif_object *object)
+{
+       struct nvif_client *client = nvif_client(object);
+       struct {
+               struct nvif_ioctl_v0 ioctl;
+               struct nvif_ioctl_map_v0 map;
+       } args = {
+               .ioctl.type = NVIF_IOCTL_V0_MAP,
+       };
+       int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
+       if (ret == 0) {
+               object->map.size = args.map.length;
+               object->map.ptr = client->driver->map(client, args.map.handle,
+                                                     object->map.size);
+               if (ret = -ENOMEM, object->map.ptr)
+                       return 0;
+               nvif_object_unmap(object);
+       }
+       return ret;
+}
+
+struct ctor {
+       struct nvif_ioctl_v0 ioctl;
+       struct nvif_ioctl_new_v0 new;
+};
+
+void
+nvif_object_fini(struct nvif_object *object)
+{
+       struct ctor *ctor = container_of(object->data, typeof(*ctor), new.data);
+       if (object->parent) {
+               struct {
+                       struct nvif_ioctl_v0 ioctl;
+                       struct nvif_ioctl_del del;
+               } args = {
+                       .ioctl.type = NVIF_IOCTL_V0_DEL,
+               };
+
+               nvif_object_unmap(object);
+               nvif_object_ioctl(object, &args, sizeof(args), NULL);
+               if (object->data) {
+                       object->size = 0;
+                       object->data = NULL;
+                       kfree(ctor);
+               }
+               nvif_object_ref(NULL, &object->parent);
+       }
+}
+
+int
+nvif_object_init(struct nvif_object *parent, void (*dtor)(struct nvif_object *),
+                u32 handle, u32 oclass, void *data, u32 size,
+                struct nvif_object *object)
+{
+       struct ctor *ctor;
+       int ret = 0;
+
+       object->parent = NULL;
+       object->object = object;
+       nvif_object_ref(parent, &object->parent);
+       kref_init(&object->refcount);
+       object->handle = handle;
+       object->oclass = oclass;
+       object->data = NULL;
+       object->size = 0;
+       object->dtor = dtor;
+       object->map.ptr = NULL;
+       object->map.size = 0;
+
+       if (object->parent) {
+               if (!(ctor = kmalloc(sizeof(*ctor) + size, GFP_KERNEL))) {
+                       nvif_object_fini(object);
+                       return -ENOMEM;
+               }
+               object->data = ctor->new.data;
+               object->size = size;
+               memcpy(object->data, data, size);
+
+               ctor->ioctl.version = 0;
+               ctor->ioctl.type = NVIF_IOCTL_V0_NEW;
+               ctor->new.version = 0;
+               ctor->new.route = NVIF_IOCTL_V0_ROUTE_NVIF;
+               ctor->new.token = (unsigned long)(void *)object;
+               ctor->new.handle = handle;
+               ctor->new.oclass = oclass;
+
+               ret = nvif_object_ioctl(parent, ctor, sizeof(*ctor) +
+                                       object->size, &object->priv);
+       }
+
+       if (ret)
+               nvif_object_fini(object);
+       return ret;
+}
+
+static void
+nvif_object_del(struct nvif_object *object)
+{
+       nvif_object_fini(object);
+       kfree(object);
+}
+
+int
+nvif_object_new(struct nvif_object *parent, u32 handle, u32 oclass,
+               void *data, u32 size, struct nvif_object **pobject)
+{
+       struct nvif_object *object = kzalloc(sizeof(*object), GFP_KERNEL);
+       if (object) {
+               int ret = nvif_object_init(parent, nvif_object_del, handle,
+                                          oclass, data, size, object);
+               if (ret)
+                       kfree(object);
+               *pobject = object;
+               return ret;
+       }
+       return -ENOMEM;
+}
+
+static void
+nvif_object_put(struct kref *kref)
+{
+       struct nvif_object *object =
+               container_of(kref, typeof(*object), refcount);
+       object->dtor(object);
+}
+
+void
+nvif_object_ref(struct nvif_object *object, struct nvif_object **pobject)
+{
+       if (object)
+               kref_get(&object->refcount);
+       if (*pobject)
+               kref_put(&(*pobject)->refcount, nvif_object_put);
+       *pobject = object;
+}
diff --git a/drivers/gpu/drm/nouveau/nvif/object.h b/drivers/gpu/drm/nouveau/nvif/object.h
new file mode 100644 (file)
index 0000000..dce6273
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef __NVIF_OBJECT_H__
+#define __NVIF_OBJECT_H__
+
+#include <nvif/os.h>
+
+struct nvif_object {
+       struct nvif_object *parent;
+       struct nvif_object *object; /*XXX: hack for nvif_object() */
+       struct kref refcount;
+       u32 handle;
+       u32 oclass;
+       void *data;
+       u32   size;
+       void *priv; /*XXX: hack */
+       void (*dtor)(struct nvif_object *);
+       struct {
+               void *ptr;
+               u32 size;
+       } map;
+};
+
+int  nvif_object_init(struct nvif_object *, void (*dtor)(struct nvif_object *),
+                     u32 handle, u32 oclass, void *, u32,
+                     struct nvif_object *);
+void nvif_object_fini(struct nvif_object *);
+int  nvif_object_new(struct nvif_object *, u32 handle, u32 oclass,
+                    void *, u32, struct nvif_object **);
+void nvif_object_ref(struct nvif_object *, struct nvif_object **);
+int  nvif_object_ioctl(struct nvif_object *, void *, u32, void **);
+int  nvif_object_sclass(struct nvif_object *, u32 *, int);
+u32  nvif_object_rd(struct nvif_object *, int, u64);
+void nvif_object_wr(struct nvif_object *, int, u64, u32);
+int  nvif_object_mthd(struct nvif_object *, u32, void *, u32);
+int  nvif_object_map(struct nvif_object *);
+void nvif_object_unmap(struct nvif_object *);
+
+#define nvif_object(a) (a)->object
+
+#define ioread8_native ioread8
+#define iowrite8_native iowrite8
+#define nvif_rd(a,b,c) ({                                                      \
+       struct nvif_object *_object = nvif_object(a);                          \
+       u32 _data;                                                             \
+       if (likely(_object->map.ptr))                                          \
+               _data = ioread##b##_native((u8 *)_object->map.ptr + (c));      \
+       else                                                                   \
+               _data = nvif_object_rd(_object, (b) / 8, (c));                 \
+       _data;                                                                 \
+})
+#define nvif_wr(a,b,c,d) ({                                                    \
+       struct nvif_object *_object = nvif_object(a);                          \
+       if (likely(_object->map.ptr))                                          \
+               iowrite##b##_native((d), (u8 *)_object->map.ptr + (c));        \
+       else                                                                   \
+               nvif_object_wr(_object, (b) / 8, (c), (d));                    \
+})
+
+#define nvif_rd08(a,b) ({ u8  _v = nvif_rd((a), 8, (b)); _v; })
+#define nvif_rd16(a,b) ({ u16 _v = nvif_rd((a), 16, (b)); _v; })
+#define nvif_rd32(a,b) ({ u32 _v = nvif_rd((a), 32, (b)); _v; })
+#define nvif_wr08(a,b,c) nvif_wr((a), 8, (b), (u8)(c))
+#define nvif_wr16(a,b,c) nvif_wr((a), 16, (b), (u16)(c))
+#define nvif_wr32(a,b,c) nvif_wr((a), 32, (b), (u32)(c))
+#define nvif_mask(a,b,c,d) ({                                                  \
+       u32 _v = nvif_rd32(nvif_object(a), (b));                               \
+       nvif_wr32(nvif_object(a), (b), (_v & ~(c)) | (d));                     \
+       _v;                                                                    \
+})
+
+#define nvif_mthd(a,b,c,d) nvif_object_mthd(nvif_object(a), (b), (c), (d))
+
+/*XXX*/
+#include <core/object.h>
+#define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv)
+#define nvif_exec(a,b,c,d) nv_exec(nvkm_object(a), (b), (c), (d))
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/os.h b/drivers/gpu/drm/nouveau/nvif/os.h
new file mode 120000 (symlink)
index 0000000..bd744b2
--- /dev/null
@@ -0,0 +1 @@
+../core/os.h
\ No newline at end of file