struct nv03_channel_dma_v0 {
__u8 version;
__u8 chid;
- __u8 pad02[2];
- __u32 pushbuf;
+ __u8 pad02[6];
+ __u64 pushbuf;
__u64 offset;
};
struct nv50_channel_gpfifo_v0 {
__u8 version;
__u8 chid;
- __u8 pad01[6];
- __u32 pushbuf;
+ __u8 pad02[2];
__u32 ilength;
__u64 ioffset;
+ __u64 pushbuf;
};
struct kepler_channel_gpfifo_a_v0 {
#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC 0x40
__u8 engine;
__u16 chid;
- __u8 pad04[4];
- __u32 pushbuf;
__u32 ilength;
__u64 ioffset;
+ __u64 pushbuf;
};
/*******************************************************************************
/* core */
struct nv50_disp_core_channel_dma_v0 {
__u8 version;
- __u8 pad01[3];
- __u32 pushbuf;
+ __u8 pad01[7];
+ __u64 pushbuf;
};
#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
/* base */
struct nv50_disp_base_channel_dma_v0 {
__u8 version;
- __u8 pad01[2];
__u8 head;
- __u32 pushbuf;
+ __u8 pad02[6];
+ __u64 pushbuf;
};
#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
/* overlay */
struct nv50_disp_overlay_channel_dma_v0 {
__u8 version;
- __u8 pad01[2];
__u8 head;
- __u32 pushbuf;
+ __u8 pad02[6];
+ __u64 pushbuf;
};
#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
struct nvif_ioctl_v0 {
__u8 version;
-#define NVIF_IOCTL_V0_OWNER_NVIF 0x00
-#define NVIF_IOCTL_V0_OWNER_ANY 0xff
- __u8 owner;
#define NVIF_IOCTL_V0_NOP 0x00
#define NVIF_IOCTL_V0_SCLASS 0x01
#define NVIF_IOCTL_V0_NEW 0x02
#define NVIF_IOCTL_V0_NTFY_GET 0x0b
#define NVIF_IOCTL_V0_NTFY_PUT 0x0c
__u8 type;
- __u8 path_nr;
+ __u8 pad02[4];
+#define NVIF_IOCTL_V0_OWNER_NVIF 0x00
+#define NVIF_IOCTL_V0_OWNER_ANY 0xff
+ __u8 owner;
#define NVIF_IOCTL_V0_ROUTE_NVIF 0x00
#define NVIF_IOCTL_V0_ROUTE_HIDDEN 0xff
- __u8 pad04[3];
__u8 route;
__u64 token;
- __u32 path[8]; /* in reverse */
+ __u64 object;
__u8 data[]; /* ioctl data (below) */
};
__u8 pad01[6];
__u8 route;
__u64 token;
+ __u64 object;
__u32 handle;
/* these class numbers are made up by us, and not nvidia-assigned */
#define NVIF_IOCTL_NEW_V0_PERFMON 0x0000ffff
struct nvif_object {
struct nvif_client *client;
- struct nvif_object *parent;
u32 handle;
u32 oclass;
void *priv; /*XXX: hack */
int nvif_object_map(struct nvif_object *);
void nvif_object_unmap(struct nvif_object *);
+#define nvif_handle(a) (unsigned long)(void *)(a)
#define nvif_object(a) (a)->object
#define nvif_rd(a,f,b,c) ({ \
int (*ntfy)(const void *, u32, const void *, u32);
struct nvkm_client_notify *notify[16];
+
+ struct rb_root objroot;
};
+bool nvkm_client_insert(struct nvkm_client *, struct nvkm_handle *);
+void nvkm_client_remove(struct nvkm_client *, struct nvkm_handle *);
+struct nvkm_handle *nvkm_client_search(struct nvkm_client *, u64 handle);
+
static inline struct nvkm_client *
nv_client(void *obj)
{
struct nvkm_handle *parent;
struct nvkm_object *object;
+
+ struct rb_node rb;
+ u64 handle;
};
int nvkm_handle_create(struct nvkm_object *, u32 parent, u32 handle,
int nvkm_handle_init(struct nvkm_handle *);
int nvkm_handle_fini(struct nvkm_handle *, bool suspend);
-struct nvkm_object *nvkm_handle_ref(struct nvkm_object *, u32 name);
-
struct nvkm_handle *nvkm_handle_get_class(struct nvkm_object *, u16);
struct nvkm_handle *nvkm_handle_get_vinst(struct nvkm_object *, u64);
struct nvkm_handle *nvkm_handle_get_cinst(struct nvkm_object *, u32);
struct nvkm_fifo_chan {
struct nvkm_namedb namedb;
- struct nvkm_dmaobj *pushdma;
struct nvkm_gpuobj *pushgpu;
void __iomem *user;
u64 addr;
int nvkm_fifo_channel_create_(struct nvkm_object *,
struct nvkm_object *,
struct nvkm_oclass *,
- int bar, u32 addr, u32 size, u32 push,
+ int bar, u32 addr, u32 size, u64 push,
u64 engmask, int len, void **);
void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *);
if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
args.kepler.version = 0;
args.kepler.engine = engine;
- args.kepler.pushbuf = chan->push.ctxdma.handle;
+ args.kepler.pushbuf = nvif_handle(&chan->push.ctxdma);
args.kepler.ilength = 0x02000;
args.kepler.ioffset = 0x10000 + chan->push.vma.offset;
size = sizeof(args.kepler);
} else {
args.nv50.version = 0;
- args.nv50.pushbuf = chan->push.ctxdma.handle;
+ args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma);
args.nv50.ilength = 0x02000;
args.nv50.ioffset = 0x10000 + chan->push.vma.offset;
size = sizeof(args.nv50);
/* create channel object */
args.version = 0;
- args.pushbuf = chan->push.ctxdma.handle;
+ args.pushbuf = nvif_handle(&chan->push.ctxdma);
args.offset = chan->push.vma.offset;
do {
if (!dmac->ptr)
return -ENOMEM;
- ret = nvif_object_init(&device->object, args->pushbuf,
+ ret = nvif_object_init(&device->object, 0xd0000000,
NV_DMA_FROM_MEMORY, &(struct nv_dma_v0) {
.target = NV_DMA_V0_TARGET_PCI_US,
.access = NV_DMA_V0_ACCESS_RD,
if (ret)
return ret;
+ args->pushbuf = nvif_handle(&pushbuf);
+
ret = nv50_chan_create(device, disp, oclass, head, data, size,
&dmac->base);
nvif_object_fini(&pushbuf);
if (client->driver) {
client->driver->fini(client->object.priv);
client->driver = NULL;
- client->object.parent = NULL;
client->object.client = NULL;
nvif_object_fini(&client->object);
}
return ret;
client->object.client = client;
- client->object.parent = &client->object;
client->object.handle = ~0;
client->route = NVIF_IOCTL_V0_ROUTE_NVIF;
client->super = true;
} *args = data;
if (size >= sizeof(*args) && args->v0.version == 0) {
+ if (object != &client->object)
+ args->v0.object = nvif_handle(object);
+ else
+ args->v0.object = 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;
int ret = 0;
object->client = NULL;
- object->parent = parent;
object->handle = handle;
object->oclass = oclass;
object->map.ptr = NULL;
object->map.size = 0;
- if (object->parent) {
+ if (parent) {
if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) {
nvif_object_fini(object);
return -ENOMEM;
args->ioctl.type = NVIF_IOCTL_V0_NEW;
args->new.version = 0;
args->new.route = parent->client->route;
- args->new.token = (unsigned long)(void *)object;
+ args->new.token = nvif_handle(object);
+ args->new.object = nvif_handle(object);
args->new.handle = handle;
args->new.oclass = oclass;
},
};
+void
+nvkm_client_remove(struct nvkm_client *client, struct nvkm_handle *object)
+{
+ if (!RB_EMPTY_NODE(&object->rb))
+ rb_erase(&object->rb, &client->objroot);
+}
+
+bool
+nvkm_client_insert(struct nvkm_client *client, struct nvkm_handle *object)
+{
+ struct rb_node **ptr = &client->objroot.rb_node;
+ struct rb_node *parent = NULL;
+
+ while (*ptr) {
+ struct nvkm_handle *this =
+ container_of(*ptr, typeof(*this), rb);
+ parent = *ptr;
+ if (object->handle < this->handle)
+ ptr = &parent->rb_left;
+ else
+ if (object->handle > this->handle)
+ ptr = &parent->rb_right;
+ else
+ return false;
+ }
+
+ rb_link_node(&object->rb, parent, ptr);
+ rb_insert_color(&object->rb, &client->objroot);
+ return true;
+}
+
+struct nvkm_handle *
+nvkm_client_search(struct nvkm_client *client, u64 handle)
+{
+ struct rb_node *node = client->objroot.rb_node;
+ while (node) {
+ struct nvkm_handle *object =
+ container_of(node, typeof(*object), rb);
+ if (handle < object->handle)
+ node = node->rb_left;
+ else
+ if (handle > object->handle)
+ node = node->rb_right;
+ else
+ return object;
+ }
+ return NULL;
+}
+
int
nvkm_client_fini(struct nvkm_client *client, bool suspend)
{
client->device = device;
snprintf(client->name, sizeof(client->name), "%s", name);
client->debug = nvkm_dbgopt(dbg, "CLIENT");
+ client->objroot = RB_ROOT;
return 0;
}
INIT_LIST_HEAD(&handle->tree);
handle->name = _handle;
handle->priv = ~0;
+ RB_CLEAR_NODE(&handle->rb);
ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, object, handle);
if (ret) {
void
nvkm_handle_destroy(struct nvkm_handle *handle)
{
+ struct nvkm_client *client = nvkm_client(handle->object);
struct nvkm_handle *item, *temp;
hprintk(handle, TRACE, "destroy running\n");
list_for_each_entry_safe(item, temp, &handle->tree, head) {
nvkm_handle_destroy(item);
}
+
+ nvkm_client_remove(client, handle);
list_del(&handle->head);
if (handle->priv != ~0) {
kfree(handle);
}
-struct nvkm_object *
-nvkm_handle_ref(struct nvkm_object *parent, u32 name)
-{
- struct nvkm_object *object = NULL;
- struct nvkm_handle *handle;
-
- while (!nv_iclass(parent, NV_NAMEDB_CLASS))
- parent = parent->parent;
-
- handle = nvkm_namedb_get(nv_namedb(parent), name);
- if (handle) {
- nvkm_object_ref(handle->object, &object);
- nvkm_namedb_put(handle);
- }
-
- return object;
-}
-
struct nvkm_handle *
nvkm_handle_get_class(struct nvkm_object *engctx, u16 oclass)
{
return ret;
nvif_ioctl(handle->object, "new vers %d handle %08x class %08x "
- "route %02x token %llx\n",
+ "route %02x token %llx object %016llx\n",
args->v0.version, _handle, _oclass,
- args->v0.route, args->v0.token);
+ args->v0.route, args->v0.token, args->v0.object);
if (!nv_iclass(handle->object, NV_PARENT_CLASS)) {
nvif_debug(handle->object, "cannot have children (ctor)\n");
if (ret)
nvkm_handle_destroy(handle);
+ handle->handle = args->v0.object;
+ nvkm_client_insert(client, handle);
fail_handle:
nvkm_object_dec(object, false);
fail_init:
};
static int
-nvkm_ioctl_path(struct nvkm_handle *parent, u32 type, u32 nr, u32 *path,
+nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type,
void *data, u32 size, u8 owner, u8 *route, u64 *token)
{
- struct nvkm_handle *handle = parent;
- struct nvkm_namedb *namedb;
- struct nvkm_object *object;
+ struct nvkm_handle *object;
int ret;
- while ((object = parent->object), nr--) {
- nvif_ioctl(object, "path 0x%08x\n", path[nr]);
- if (!nv_iclass(object, NV_PARENT_CLASS)) {
- nvif_debug(object, "cannot have children (path)\n");
- return -EINVAL;
- }
-
- if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||
- !(handle = nvkm_namedb_get(namedb, path[nr]))) {
- nvif_debug(object, "handle 0x%08x not found\n", path[nr]);
- return -ENOENT;
- }
- nvkm_namedb_put(handle);
- parent = handle;
+ if (handle)
+ object = nvkm_client_search(client, handle);
+ else
+ object = client->root;
+ if (unlikely(!object)) {
+ nvif_ioctl(&client->namedb.parent.object, "object not found\n");
+ return -ENOENT;
}
- if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != handle->route) {
- nvif_ioctl(object, "object route != owner\n");
+ if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != object->route) {
+ nvif_ioctl(&client->namedb.parent.object, "route != owner\n");
return -EACCES;
}
- *route = handle->route;
- *token = handle->token;
+ *route = object->route;
+ *token = object->token;
if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
if (nvkm_ioctl_v0[type].version == 0)
- ret = nvkm_ioctl_v0[type].func(handle, data, size);
+ ret = nvkm_ioctl_v0[type].func(object, data, size);
}
return ret;
nvif_ioctl(object, "size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
- nvif_ioctl(object, "vers %d type %02x path %d owner %02x\n",
- args->v0.version, args->v0.type, args->v0.path_nr,
+ nvif_ioctl(object,
+ "vers %d type %02x object %016llx owner %02x\n",
+ args->v0.version, args->v0.type, args->v0.object,
args->v0.owner);
- ret = nvkm_ioctl_path(client->root, args->v0.type,
- args->v0.path_nr, args->v0.path,
+ ret = nvkm_ioctl_path(client, args->v0.object, args->v0.type,
data, size, args->v0.owner,
&args->v0.route, &args->v0.token);
}
static int
nv50_disp_dmac_create_(struct nvkm_object *parent,
struct nvkm_object *engine,
- struct nvkm_oclass *oclass, u32 pushbuf, int head,
+ struct nvkm_oclass *oclass, u64 pushbuf, int head,
int length, void **pobject)
{
+ struct nvkm_client *client = nvkm_client(parent);
+ struct nvkm_handle *handle;
+ struct nvkm_dmaobj *dmaobj;
struct nv50_disp_dmac *dmac;
int ret;
if (ret)
return ret;
- dmac->pushdma = (void *)nvkm_handle_ref(parent, pushbuf);
- if (!dmac->pushdma)
+ handle = nvkm_client_search(client, pushbuf);
+ if (!handle)
return -ENOENT;
+ dmaobj = (void *)handle->object;
- switch (nv_mclass(dmac->pushdma)) {
+ switch (nv_mclass(dmaobj)) {
case 0x0002:
case 0x003d:
- if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
+ if (dmaobj->limit - dmaobj->start != 0xfff)
return -EINVAL;
- switch (dmac->pushdma->target) {
+ switch (dmaobj->target) {
case NV_MEM_TARGET_VRAM:
- dmac->push = 0x00000001 | dmac->pushdma->start >> 8;
+ dmac->push = 0x00000001 | dmaobj->start >> 8;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
- dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
+ dmac->push = 0x00000003 | dmaobj->start >> 8;
break;
default:
return -EINVAL;
nv50_disp_dmac_dtor(struct nvkm_object *object)
{
struct nv50_disp_dmac *dmac = (void *)object;
- nvkm_object_ref(NULL, (struct nvkm_object **)&dmac->pushdma);
nv50_disp_chan_destroy(&dmac->base);
}
nvif_ioctl(parent, "create disp core channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nvif_ioctl(parent, "create disp core channel dma vers %d "
- "pushbuf %08x\n",
+ "pushbuf %016llx\n",
args->v0.version, args->v0.pushbuf);
} else
return ret;
nvif_ioctl(parent, "create disp base channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nvif_ioctl(parent, "create disp base channel dma vers %d "
- "pushbuf %08x head %d\n",
+ "pushbuf %016llx head %d\n",
args->v0.version, args->v0.pushbuf, args->v0.head);
if (args->v0.head > disp->head.nr)
return -EINVAL;
nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nvif_ioctl(parent, "create disp overlay channel dma vers %d "
- "pushbuf %08x head %d\n",
+ "pushbuf %016llx head %d\n",
args->v0.version, args->v0.pushbuf, args->v0.head);
if (args->v0.head > disp->head.nr)
return -EINVAL;
struct nv50_disp_dmac {
struct nv50_disp_chan base;
- struct nvkm_dmaobj *pushdma;
u32 push;
};
nvkm_fifo_channel_create_(struct nvkm_object *parent,
struct nvkm_object *engine,
struct nvkm_oclass *oclass,
- int bar, u32 addr, u32 size, u32 pushbuf,
+ int bar, u32 addr, u32 size, u64 pushbuf,
u64 engmask, int len, void **ptr)
{
+ struct nvkm_client *client = nvkm_client(parent);
+ struct nvkm_handle *handle;
+ struct nvkm_dmaobj *dmaobj;
struct nvkm_fifo *fifo = (void *)engine;
struct nvkm_fifo_chan *chan;
struct nvkm_dmaeng *dmaeng;
return ret;
/* validate dma object representing push buffer */
- chan->pushdma = (void *)nvkm_handle_ref(parent, pushbuf);
- if (!chan->pushdma)
+ handle = nvkm_client_search(client, pushbuf);
+ if (!handle)
return -ENOENT;
+ dmaobj = (void *)handle->object;
- dmaeng = (void *)chan->pushdma->base.engine;
- switch (chan->pushdma->base.oclass->handle) {
+ dmaeng = (void *)dmaobj->base.engine;
+ switch (dmaobj->base.oclass->handle) {
case NV_DMA_FROM_MEMORY:
case NV_DMA_IN_MEMORY:
break;
return -EINVAL;
}
- ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu);
+ ret = dmaeng->bind(dmaobj, parent, &chan->pushgpu);
if (ret)
return ret;
spin_unlock_irqrestore(&fifo->lock, flags);
nvkm_gpuobj_ref(NULL, &chan->pushgpu);
- nvkm_object_ref(NULL, (struct nvkm_object **)&chan->pushdma);
nvkm_namedb_destroy(&chan->namedb);
}
nvif_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx "
"ioffset %016llx ilength %08x\n",
args->v0.version, args->v0.pushbuf, args->v0.ioffset,
args->v0.ilength);
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx "
"ioffset %016llx ilength %08x\n",
args->v0.version, args->v0.pushbuf, args->v0.ioffset,
args->v0.ilength);
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx "
"ioffset %016llx ilength %08x engine %08x\n",
args->v0.version, args->v0.pushbuf, args->v0.ioffset,
args->v0.ilength, args->v0.engine);
nvif_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
nvif_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
nvif_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
nvif_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
nvif_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
- nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx "
"ioffset %016llx ilength %08x\n",
args->v0.version, args->v0.pushbuf, args->v0.ioffset,
args->v0.ilength);