#define __NVKM_RAMHT_H__
#include <core/gpuobj.h>
+struct nvkm_ramht_data {
+ struct nvkm_gpuobj *inst;
+ int chid;
+ u32 handle;
+};
+
struct nvkm_ramht {
- struct nvkm_gpuobj gpuobj;
+ struct nvkm_device *device;
+ struct nvkm_gpuobj *parent;
+ struct nvkm_gpuobj *gpuobj;
+ int size;
int bits;
+ struct nvkm_ramht_data data[];
};
-int nvkm_ramht_insert(struct nvkm_ramht *, int chid, u32 handle, u32 context);
+int nvkm_ramht_new(struct nvkm_device *, u32 size, u32 align,
+ struct nvkm_gpuobj *, struct nvkm_ramht **);
+void nvkm_ramht_del(struct nvkm_ramht **);
+int nvkm_ramht_insert(struct nvkm_ramht *, struct nvkm_object *,
+ int chid, int addr, u32 handle, u32 context);
void nvkm_ramht_remove(struct nvkm_ramht *, int cookie);
-int nvkm_ramht_new(struct nvkm_object *, struct nvkm_object *, u32 size,
- u32 align, struct nvkm_ramht **);
-
-static inline void
-nvkm_ramht_ref(struct nvkm_ramht *obj, struct nvkm_ramht **ref)
-{
- nvkm_gpuobj_ref(&obj->gpuobj, (struct nvkm_gpuobj **)ref);
-}
+struct nvkm_gpuobj *
+nvkm_ramht_search(struct nvkm_ramht *, int chid, u32 handle);
#endif
}
hash ^= chid << (ramht->bits - 4);
- hash = hash << 3;
return hash;
}
-int
-nvkm_ramht_insert(struct nvkm_ramht *ramht, int chid, u32 handle, u32 context)
+struct nvkm_gpuobj *
+nvkm_ramht_search(struct nvkm_ramht *ramht, int chid, u32 handle)
{
- struct nvkm_gpuobj *gpuobj = &ramht->gpuobj;
- int ret = -ENOSPC;
u32 co, ho;
co = ho = nvkm_ramht_hash(ramht, chid, handle);
- nvkm_kmap(gpuobj);
do {
- if (!nvkm_ro32(gpuobj, co + 4)) {
- nvkm_wo32(gpuobj, co + 0, handle);
- nvkm_wo32(gpuobj, co + 4, context);
- ret = co;
- break;
+ if (ramht->data[co].chid == chid) {
+ if (ramht->data[co].handle == handle)
+ return ramht->data[co].inst;
}
- co += 8;
- if (co >= nv_gpuobj(ramht)->size)
+ if (++co >= ramht->size)
co = 0;
} while (co != ho);
- nvkm_done(gpuobj);
- return ret;
+ return NULL;
+}
+
+static int
+nvkm_ramht_update(struct nvkm_ramht *ramht, int co, struct nvkm_object *object,
+ int chid, int addr, u32 handle, u32 context)
+{
+ struct nvkm_ramht_data *data = &ramht->data[co];
+ u64 inst = 0x00000040; /* just non-zero for <=g8x fifo ramht */
+ int ret;
+
+ nvkm_gpuobj_del(&data->inst);
+ data->chid = chid;
+ data->handle = handle;
+
+ if (!object) {
+ inst = 0;
+ goto done;
+ }
+
+ if (nv_iclass(object, NV_GPUOBJ_CLASS)) {
+ struct nvkm_gpuobj *gpuobj = nv_gpuobj(object);
+ if (ramht->device->card_type >= NV_50)
+ inst = gpuobj->node->offset;
+ else
+ inst = gpuobj->addr;
+ goto done;
+ }
+
+ ret = nvkm_object_bind(object, ramht->parent, 16, &data->inst);
+ if (ret) {
+ if (ret != -ENODEV) {
+ data->chid = -1;
+ return ret;
+ }
+ data->inst = NULL;
+ }
+
+ if (data->inst) {
+ if (ramht->device->card_type >= NV_50)
+ inst = data->inst->node->offset;
+ else
+ inst = data->inst->addr;
+ }
+
+done:
+ if (addr < 0) context |= inst << -addr;
+ else context |= inst >> addr;
+
+ nvkm_kmap(ramht->gpuobj);
+ nvkm_wo32(ramht->gpuobj, (co << 3) + 0, handle);
+ nvkm_wo32(ramht->gpuobj, (co << 3) + 4, context);
+ nvkm_done(ramht->gpuobj);
+ return co + 1;
}
void
nvkm_ramht_remove(struct nvkm_ramht *ramht, int cookie)
{
- struct nvkm_gpuobj *gpuobj = &ramht->gpuobj;
- nvkm_kmap(gpuobj);
- nvkm_wo32(gpuobj, cookie + 0, 0x00000000);
- nvkm_wo32(gpuobj, cookie + 4, 0x00000000);
- nvkm_done(gpuobj);
+ if (--cookie >= 0)
+ nvkm_ramht_update(ramht, cookie, NULL, -1, 0, 0, 0);
}
-static struct nvkm_oclass
-nvkm_ramht_oclass = {
- .handle = 0x0000abcd,
- .ofuncs = &(struct nvkm_ofuncs) {
- .ctor = NULL,
- .dtor = _nvkm_gpuobj_dtor,
- .init = _nvkm_gpuobj_init,
- .fini = _nvkm_gpuobj_fini,
- .rd32 = _nvkm_gpuobj_rd32,
- .wr32 = _nvkm_gpuobj_wr32,
- },
-};
+int
+nvkm_ramht_insert(struct nvkm_ramht *ramht, struct nvkm_object *object,
+ int chid, int addr, u32 handle, u32 context)
+{
+ u32 co, ho;
+
+ if (nvkm_ramht_search(ramht, chid, handle))
+ return -EEXIST;
+
+ co = ho = nvkm_ramht_hash(ramht, chid, handle);
+ do {
+ if (ramht->data[co].chid < 0) {
+ return nvkm_ramht_update(ramht, co, object, chid,
+ addr, handle, context);
+ }
+
+ if (++co >= ramht->size)
+ co = 0;
+ } while (co != ho);
+
+ return -ENOSPC;
+}
+
+void
+nvkm_ramht_del(struct nvkm_ramht **pramht)
+{
+ struct nvkm_ramht *ramht = *pramht;
+ if (ramht) {
+ nvkm_gpuobj_del(&ramht->gpuobj);
+ kfree(*pramht);
+ *pramht = NULL;
+ }
+}
int
-nvkm_ramht_new(struct nvkm_object *parent, struct nvkm_object *pargpu,
- u32 size, u32 align, struct nvkm_ramht **pramht)
+nvkm_ramht_new(struct nvkm_device *device, u32 size, u32 align,
+ struct nvkm_gpuobj *parent, struct nvkm_ramht **pramht)
{
struct nvkm_ramht *ramht;
- int ret;
+ int ret, i;
- ret = nvkm_gpuobj_create(parent, parent->engine ?
- &parent->engine->subdev.object : NULL, /* <nv50 ramht */
- &nvkm_ramht_oclass, 0, pargpu, size,
- align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
- *pramht = ramht;
- if (ret)
- return ret;
+ if (!(ramht = *pramht = kzalloc(sizeof(*ramht) + (size >> 3) *
+ sizeof(*ramht->data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ ramht->device = device;
+ ramht->parent = parent;
+ ramht->size = size >> 3;
+ ramht->bits = order_base_2(ramht->size);
+ for (i = 0; i < ramht->size; i++)
+ ramht->data[i].chid = -1;
- ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
- return 0;
+ ret = nvkm_gpuobj_new(ramht->device, size, align, true,
+ ramht->parent, &ramht->gpuobj);
+ if (ret)
+ nvkm_ramht_del(pramht);
+ return ret;
}
struct nv50_disp_chan *chan = (void *)parent;
u32 addr = nv_gpuobj(object)->node->offset;
u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001;
- return nvkm_ramht_insert(base->ramht, chan->chid, name, data);
+ return nvkm_ramht_insert(base->ramht, NULL, chan->chid, 0, name, data);
}
static void
u32 addr = nv_gpuobj(object)->node->offset;
u32 chid = chan->chid;
u32 data = (chid << 28) | (addr << 10) | chid;
- return nvkm_ramht_insert(base->ramht, chid, name, data);
+ return nvkm_ramht_insert(base->ramht, NULL, chid, 0, name, data);
}
static void
{
struct nv50_disp *disp = (void *)engine;
struct nv50_disp_base *base;
+ struct nvkm_device *device = disp->base.engine.subdev.device;
+ struct nvkm_gpuobj *instmem = (void *)parent;
int ret;
ret = nvkm_parent_create(parent, engine, oclass, 0,
if (ret)
return ret;
- return nvkm_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
- &base->ramht);
+ return nvkm_ramht_new(device, 0x1000, 0, instmem, &base->ramht);
}
void
nv50_disp_main_dtor(struct nvkm_object *object)
{
struct nv50_disp_base *base = (void *)object;
- nvkm_ramht_ref(NULL, &base->ramht);
+ nvkm_ramht_del(&base->ramht);
nvkm_parent_destroy(&base->base);
}
}
/* point at display engine memory area (hash table, objects) */
- nvkm_wr32(device, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
+ nvkm_wr32(device, 0x610010, (base->ramht->gpuobj->addr >> 8) | 9);
/* enable supervisor interrupts, disable everything else */
nvkm_wr32(device, 0x61002c, 0x00000370);
}
}
- return nvkm_ramht_insert(chan->ramht, 0, handle, context);
+ return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context);
}
static int
union {
struct nv50_channel_dma_v0 v0;
} *args = data;
+ struct nvkm_device *device = parent->engine->subdev.device;
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
int ret;
args->v0.chid = chan->base.chid;
- ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj,
&chan->ramht);
if (ret)
return ret;
nvkm_wo32(base->ramfc, 0x7c, 0x30000001);
nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->gpuobj.node->offset >> 4));
+ (chan->ramht->gpuobj->node->offset >> 4));
nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
nvkm_done(base->ramfc);
union {
struct nv50_channel_gpfifo_v0 v0;
} *args = data;
+ struct nvkm_device *device = parent->engine->subdev.device;
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
u64 ioffset, ilength;
args->v0.chid = chan->base.chid;
- ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj,
&chan->ramht);
if (ret)
return ret;
nvkm_wo32(base->ramfc, 0x7c, 0x30000001);
nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->gpuobj.node->offset >> 4));
+ (chan->ramht->gpuobj->node->offset >> 4));
nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
nvkm_done(base->ramfc);
context |= chid << 24;
mutex_lock(&nv_subdev(fifo)->mutex);
- ret = nvkm_ramht_insert(imem->ramht, chid, handle, context);
+ ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context);
mutex_unlock(&nv_subdev(fifo)->mutex);
return ret;
}
nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((ramht->bits - 9) << 16) |
- (ramht->gpuobj.addr >> 8));
+ (ramht->gpuobj->addr >> 8));
nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8);
nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8);
nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((ramht->bits - 9) << 16) |
- (ramht->gpuobj.addr >> 8));
+ (ramht->gpuobj->addr >> 8));
nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8);
nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 |
0x00010000);
context |= chid << 23;
mutex_lock(&nv_subdev(fifo)->mutex);
- ret = nvkm_ramht_insert(imem->ramht, chid, handle, context);
+ ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context);
mutex_unlock(&nv_subdev(fifo)->mutex);
return ret;
}
nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((ramht->bits - 9) << 16) |
- (ramht->gpuobj.addr >> 8));
+ (ramht->gpuobj->addr >> 8));
nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8);
switch (nv_device(fifo)->chipset) {
}
}
- return nvkm_ramht_insert(chan->ramht, 0, handle, context);
+ return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context);
}
void
union {
struct nv50_channel_dma_v0 v0;
} *args = data;
+ struct nvkm_device *device = parent->engine->subdev.device;
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
int ret;
nv_parent(chan)->object_attach = nv50_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
- ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj,
&chan->ramht);
if (ret)
return ret;
nvkm_wo32(base->ramfc, 0x7c, 0x30000001);
nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->gpuobj.node->offset >> 4));
+ (chan->ramht->gpuobj->node->offset >> 4));
nvkm_done(base->ramfc);
return 0;
}
union {
struct nv50_channel_gpfifo_v0 v0;
} *args = data;
+ struct nvkm_device *device = parent->engine->subdev.device;
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
u64 ioffset, ilength;
nv_parent(chan)->object_attach = nv50_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
- ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj,
&chan->ramht);
if (ret)
return ret;
nvkm_wo32(base->ramfc, 0x7c, 0x30000001);
nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->gpuobj.node->offset >> 4));
+ (chan->ramht->gpuobj->node->offset >> 4));
nvkm_done(base->ramfc);
return 0;
}
nv50_fifo_chan_dtor(struct nvkm_object *object)
{
struct nv50_fifo_chan *chan = (void *)object;
- nvkm_ramht_ref(NULL, &chan->ramht);
+ nvkm_ramht_del(&chan->ramht);
nvkm_fifo_channel_destroy(&chan->base);
}
struct nv04_instmem *imem = (void *)object;
nvkm_memory_del(&imem->base.ramfc);
nvkm_memory_del(&imem->base.ramro);
- nvkm_ramht_ref(NULL, &imem->base.ramht);
+ nvkm_ramht_del(&imem->base.ramht);
nvkm_memory_del(&imem->base.vbios);
nvkm_mm_fini(&imem->heap);
nvkm_instmem_destroy(&imem->base);
return ret;
/* 0x10000-0x18000: reserve for RAMHT */
- ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0,
- &imem->base.ramht);
+ ret = nvkm_ramht_new(device, 0x08000, 0, NULL, &imem->base.ramht);
if (ret)
return ret;
struct nv40_instmem *imem = (void *)object;
nvkm_memory_del(&imem->base.ramfc);
nvkm_memory_del(&imem->base.ramro);
- nvkm_ramht_ref(NULL, &imem->base.ramht);
+ nvkm_ramht_del(&imem->base.ramht);
nvkm_memory_del(&imem->base.vbios);
nvkm_mm_fini(&imem->heap);
if (imem->iomem)
return ret;
/* 0x10000-0x18000: reserve for RAMHT */
- ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0,
- &imem->base.ramht);
+ ret = nvkm_ramht_new(device, 0x08000, 0, NULL, &imem->base.ramht);
if (ret)
return ret;