mirror of
https://github.com/torvalds/linux.git
synced 2024-12-14 15:13:52 +00:00
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: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
803c1787ef
commit
a04d04231b
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef __NOUVEAU_CLASS_H__
|
||||
#define __NOUVEAU_CLASS_H__
|
||||
|
||||
#include <nvif/class.h>
|
||||
|
||||
/* Device class
|
||||
*
|
||||
* 0080: NV_DEVICE
|
||||
|
130
drivers/gpu/drm/nouveau/nvif/client.c
Normal file
130
drivers/gpu/drm/nouveau/nvif/client.c
Normal file
@ -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);
|
||||
}
|
39
drivers/gpu/drm/nouveau/nvif/client.h
Normal file
39
drivers/gpu/drm/nouveau/nvif/client.h
Normal file
@ -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
|
78
drivers/gpu/drm/nouveau/nvif/device.c
Normal file
78
drivers/gpu/drm/nouveau/nvif/device.c
Normal file
@ -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);
|
||||
}
|
66
drivers/gpu/drm/nouveau/nvif/device.h
Normal file
66
drivers/gpu/drm/nouveau/nvif/device.h
Normal file
@ -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
|
20
drivers/gpu/drm/nouveau/nvif/driver.h
Normal file
20
drivers/gpu/drm/nouveau/nvif/driver.h
Normal file
@ -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
|
353
drivers/gpu/drm/nouveau/nvif/list.h
Normal file
353
drivers/gpu/drm/nouveau/nvif/list.h
Normal file
@ -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
|
237
drivers/gpu/drm/nouveau/nvif/notify.c
Normal file
237
drivers/gpu/drm/nouveau/nvif/notify.c
Normal file
@ -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(¬ify->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, ¬ify->flags)) {
|
||||
int ret = nvif_notify_put_(notify);
|
||||
if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags))
|
||||
flush_work(¬ify->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(¬ify->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, ¬ify->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, ¬ify->flags)) {
|
||||
atomic_inc(¬ify->putcnt);
|
||||
memcpy((void *)notify->data, data, size);
|
||||
schedule_work(¬ify->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(¬ify->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, ¬ify->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, ¬ify->object);
|
||||
notify->flags = 0;
|
||||
atomic_set(¬ify->putcnt, 1);
|
||||
notify->dtor = dtor;
|
||||
notify->func = func;
|
||||
notify->data = NULL;
|
||||
notify->size = reply;
|
||||
if (work) {
|
||||
INIT_WORK(¬ify->work, nvif_notify_work);
|
||||
set_bit(NVIF_NOTIFY_WORK, ¬ify->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;
|
||||
}
|
39
drivers/gpu/drm/nouveau/nvif/notify.h
Normal file
39
drivers/gpu/drm/nouveau/nvif/notify.h
Normal file
@ -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
|
302
drivers/gpu/drm/nouveau/nvif/object.c
Normal file
302
drivers/gpu/drm/nouveau/nvif/object.c
Normal file
@ -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;
|
||||
}
|
77
drivers/gpu/drm/nouveau/nvif/object.h
Normal file
77
drivers/gpu/drm/nouveau/nvif/object.h
Normal file
@ -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
|
1
drivers/gpu/drm/nouveau/nvif/os.h
Symbolic link
1
drivers/gpu/drm/nouveau/nvif/os.h
Symbolic link
@ -0,0 +1 @@
|
||||
../core/os.h
|
Loading…
Reference in New Issue
Block a user