Commit a04d0423 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/nvif: import library functions for the ioctl/event interfaces



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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 803c1787
......@@ -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
......
......@@ -146,9 +146,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
}
hprintk(handle, TRACE, "created\n");
*phandle = handle;
return 0;
}
......
#ifndef __NOUVEAU_CLASS_H__
#define __NOUVEAU_CLASS_H__
#include <nvif/class.h>
/* Device class
*
* 0080: NV_DEVICE
......
/*
* 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);
}
#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
/*
* 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);
}
#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
#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
/*
* 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.