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

drm/nouveau/dmaobj: switch to a slightly saner design


Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent bc98540b
......@@ -30,22 +30,43 @@
#include "priv.h"
static int
nouveau_dmaobj_ctor(struct nouveau_object *parent,
nvkm_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent,
struct nouveau_gpuobj **pgpuobj)
{
const struct nvkm_dmaeng_impl *impl = (void *)
nv_oclass(nv_object(dmaobj)->engine);
int ret = 0;
if (nv_object(dmaobj) == parent) { /* ctor bind */
if (nv_mclass(parent->parent) == NV_DEVICE) {
/* delayed, or no, binding */
return 0;
}
ret = impl->bind(dmaobj, parent, pgpuobj);
if (ret == 0)
nouveau_object_ref(NULL, &parent);
return ret;
}
return impl->bind(dmaobj, parent, pgpuobj);
}
int
nvkm_dmaobj_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
struct nouveau_oclass *oclass, void **pdata, u32 *psize,
int length, void **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
struct nv_dma_class *args = *pdata;
struct nouveau_dmaobj *dmaobj;
struct nouveau_gpuobj *gpuobj;
struct nv_dma_class *args = data;
int ret;
if (size < sizeof(*args))
if (*psize < sizeof(*args))
return -EINVAL;
*pdata = &args->conf0;
ret = nouveau_object_create(parent, engine, oclass, 0, &dmaobj);
*pobject = nv_object(dmaobj);
ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
dmaobj = *pobject;
if (ret)
return ret;
......@@ -87,39 +108,9 @@ nouveau_dmaobj_ctor(struct nouveau_object *parent,
dmaobj->start = args->start;
dmaobj->limit = args->limit;
dmaobj->conf0 = args->conf0;
switch (nv_mclass(parent)) {
case NV_DEVICE:
/* delayed, or no, binding */
break;
default:
ret = dmaeng->bind(dmaeng, *pobject, dmaobj, &gpuobj);
if (ret == 0) {
nouveau_object_ref(NULL, pobject);
*pobject = nv_object(gpuobj);
}
break;
}
return ret;
}
static struct nouveau_ofuncs
nouveau_dmaobj_ofuncs = {
.ctor = nouveau_dmaobj_ctor,
.dtor = nouveau_object_destroy,
.init = nouveau_object_init,
.fini = nouveau_object_fini,
};
static struct nouveau_oclass
nouveau_dmaobj_sclass[] = {
{ NV_DMA_FROM_MEMORY_CLASS, &nouveau_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY_CLASS, &nouveau_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY_CLASS, &nouveau_dmaobj_ofuncs },
{}
};
int
_nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
......@@ -135,7 +126,7 @@ _nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
nv_engine(dmaeng)->sclass = nouveau_dmaobj_sclass;
dmaeng->bind = impl->bind;
nv_engine(dmaeng)->sclass = impl->sclass;
dmaeng->bind = nvkm_dmaobj_bind;
return 0;
}
......@@ -30,19 +30,23 @@
#include "priv.h"
struct nv04_dmaobj_priv {
struct nouveau_dmaobj base;
bool clone;
u32 flags0;
u32 flags2;
};
static int
nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
nv04_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj)
{
struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaeng);
struct nv04_dmaobj_priv *priv = (void *)dmaobj;
struct nouveau_gpuobj *gpuobj;
u32 flags0 = nv_mclass(dmaobj);
u32 flags2 = 0x00000000;
u64 offset = dmaobj->start & 0xfffff000;
u64 adjust = dmaobj->start & 0x00000fff;
u32 length = dmaobj->limit - dmaobj->start;
u64 offset = priv->base.start & 0xfffff000;
u64 adjust = priv->base.start & 0x00000fff;
u32 length = priv->base.limit - priv->base.start;
int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
......@@ -57,58 +61,96 @@ nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
}
}
if (dmaobj->target == NV_MEM_TARGET_VM) {
if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) {
struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
if (!dmaobj->start)
return nouveau_gpuobj_dup(parent, pgt, pgpuobj);
offset = nv_ro32(pgt, 8 + (offset >> 10));
offset &= 0xfffff000;
}
if (priv->clone) {
struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaobj);
struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
if (!dmaobj->start)
return nouveau_gpuobj_dup(parent, pgt, pgpuobj);
offset = nv_ro32(pgt, 8 + (offset >> 10));
offset &= 0xfffff000;
}
ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
*pgpuobj = gpuobj;
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20));
nv_wo32(*pgpuobj, 0x04, length);
nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset);
nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset);
}
return ret;
}
static int
nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
struct nv04_vmmgr_priv *vmm = nv04_vmmgr(engine);
struct nv04_dmaobj_priv *priv;
int ret;
ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
dmaobj->target = NV_MEM_TARGET_PCI;
dmaobj->access = NV_MEM_ACCESS_RW;
if (priv->base.target == NV_MEM_TARGET_VM) {
if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass)
priv->clone = true;
priv->base.target = NV_MEM_TARGET_PCI;
priv->base.access = NV_MEM_ACCESS_RW;
}
switch (dmaobj->target) {
priv->flags0 = nv_mclass(priv);
switch (priv->base.target) {
case NV_MEM_TARGET_VRAM:
flags0 |= 0x00003000;
priv->flags0 |= 0x00003000;
break;
case NV_MEM_TARGET_PCI:
flags0 |= 0x00023000;
priv->flags0 |= 0x00023000;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
flags0 |= 0x00033000;
priv->flags0 |= 0x00033000;
break;
default:
return -EINVAL;
}
switch (dmaobj->access) {
switch (priv->base.access) {
case NV_MEM_ACCESS_RO:
flags0 |= 0x00004000;
priv->flags0 |= 0x00004000;
break;
case NV_MEM_ACCESS_WO:
flags0 |= 0x00008000;
priv->flags0 |= 0x00008000;
case NV_MEM_ACCESS_RW:
flags2 |= 0x00000002;
priv->flags2 |= 0x00000002;
break;
default:
return -EINVAL;
}
ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
*pgpuobj = gpuobj;
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, flags0 | (adjust << 20));
nv_wo32(*pgpuobj, 0x04, length);
nv_wo32(*pgpuobj, 0x08, flags2 | offset);
nv_wo32(*pgpuobj, 0x0c, flags2 | offset);
}
return ret;
return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}
static struct nouveau_ofuncs
nv04_dmaobj_ofuncs = {
.ctor = nv04_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nv04_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY_CLASS, &nv04_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY_CLASS, &nv04_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY_CLASS, &nv04_dmaobj_ofuncs },
{}
};
struct nouveau_oclass *
nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0x04),
......@@ -118,5 +160,6 @@ nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini,
},
.sclass = nv04_dmaeng_sclass,
.bind = nv04_dmaobj_bind,
}.base;
......@@ -29,14 +29,18 @@
#include "priv.h"
struct nv50_dmaobj_priv {
struct nouveau_dmaobj base;
u32 flags0;
u32 flags5;
};
static int
nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
nv50_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj)
{
u32 flags0 = nv_mclass(dmaobj);
u32 flags5 = 0x00000000;
struct nv50_dmaobj_priv *priv = (void *)dmaobj;
int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
......@@ -66,68 +70,107 @@ nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
}
}
if (!(dmaobj->conf0 & NV50_DMA_CONF0_ENABLE)) {
if (dmaobj->target == NV_MEM_TARGET_VM) {
dmaobj->conf0 = NV50_DMA_CONF0_PRIV_VM;
dmaobj->conf0 |= NV50_DMA_CONF0_PART_VM;
dmaobj->conf0 |= NV50_DMA_CONF0_COMP_VM;
dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_VM;
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
upper_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, priv->flags5);
}
return ret;
}
static int
nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
struct nv50_dmaobj_priv *priv;
union {
u32 conf0;
} *args;
int ret;
ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
args = data;
if (!(args->conf0 & NV50_DMA_CONF0_ENABLE)) {
if (priv->base.target == NV_MEM_TARGET_VM) {
args->conf0 = NV50_DMA_CONF0_PRIV_VM;
args->conf0 |= NV50_DMA_CONF0_PART_VM;
args->conf0 |= NV50_DMA_CONF0_COMP_VM;
args->conf0 |= NV50_DMA_CONF0_TYPE_VM;
} else {
dmaobj->conf0 = NV50_DMA_CONF0_PRIV_US;
dmaobj->conf0 |= NV50_DMA_CONF0_PART_256;
dmaobj->conf0 |= NV50_DMA_CONF0_COMP_NONE;
dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_LINEAR;
args->conf0 = NV50_DMA_CONF0_PRIV_US;
args->conf0 |= NV50_DMA_CONF0_PART_256;
args->conf0 |= NV50_DMA_CONF0_COMP_NONE;
args->conf0 |= NV50_DMA_CONF0_TYPE_LINEAR;
}
}
flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_COMP) << 22;
flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_TYPE) << 22;
flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_PRIV);
flags5 |= (dmaobj->conf0 & NV50_DMA_CONF0_PART);
priv->flags0 |= (args->conf0 & NV50_DMA_CONF0_COMP) << 22;
priv->flags0 |= (args->conf0 & NV50_DMA_CONF0_TYPE) << 22;
priv->flags0 |= (args->conf0 & NV50_DMA_CONF0_PRIV);
priv->flags5 |= (args->conf0 & NV50_DMA_CONF0_PART);
switch (dmaobj->target) {
switch (priv->base.target) {
case NV_MEM_TARGET_VM:
flags0 |= 0x00000000;
priv->flags0 |= 0x00000000;
break;
case NV_MEM_TARGET_VRAM:
flags0 |= 0x00010000;
priv->flags0 |= 0x00010000;
break;
case NV_MEM_TARGET_PCI:
flags0 |= 0x00020000;
priv->flags0 |= 0x00020000;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
flags0 |= 0x00030000;
priv->flags0 |= 0x00030000;
break;
default:
return -EINVAL;
}
switch (dmaobj->access) {
switch (priv->base.access) {
case NV_MEM_ACCESS_VM:
break;
case NV_MEM_ACCESS_RO:
flags0 |= 0x00040000;
priv->flags0 |= 0x00040000;
break;
case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW:
flags0 |= 0x00080000;
priv->flags0 |= 0x00080000;
break;
default:
return -EINVAL;
}
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, flags0);
nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 |
upper_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, flags5);
}
return ret;
return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}
static struct nouveau_ofuncs
nv50_dmaobj_ofuncs = {
.ctor = nv50_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nv50_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY_CLASS, &nv50_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY_CLASS, &nv50_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY_CLASS, &nv50_dmaobj_ofuncs },
{}
};
struct nouveau_oclass *
nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0x50),
......@@ -137,5 +180,6 @@ nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini,
},
.sclass = nv50_dmaeng_sclass,
.bind = nv50_dmaobj_bind,
}.base;
......@@ -30,14 +30,18 @@
#include "priv.h"
struct nvc0_dmaobj_priv {
struct nouveau_dmaobj base;
u32 flags0;
u32 flags5;
};
static int
nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
nvc0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj)
{
u32 flags0 = nv_mclass(dmaobj);
u32 flags5 = 0x00000000;
struct nvc0_dmaobj_priv *priv = (void *)dmaobj;
int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
......@@ -52,64 +56,101 @@ nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
} else
return 0;
if (!(dmaobj->conf0 & NVC0_DMA_CONF0_ENABLE)) {
if (dmaobj->target == NV_MEM_TARGET_VM) {
dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_VM;
dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_VM;
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
upper_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, priv->flags5);
}
return ret;
}
static int
nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
struct nvc0_dmaobj_priv *priv;
union {
u32 conf0;
} *args;
int ret;
ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
args = data;
if (!(args->conf0 & NVC0_DMA_CONF0_ENABLE)) {
if (priv->base.target == NV_MEM_TARGET_VM) {
args->conf0 = NVC0_DMA_CONF0_PRIV_VM;
args->conf0 |= NVC0_DMA_CONF0_TYPE_VM;
} else {
dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_US;
dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_LINEAR;
dmaobj->conf0 |= 0x00020000;
args->conf0 = NVC0_DMA_CONF0_PRIV_US;
args->conf0 |= NVC0_DMA_CONF0_TYPE_LINEAR;
args->conf0 |= 0x00020000;
}
}
flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_TYPE) << 22;
flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_PRIV);
flags5 |= (dmaobj->conf0 & NVC0_DMA_CONF0_UNKN);
priv->flags0 |= (args->conf0 & NVC0_DMA_CONF0_TYPE) << 22;
priv->flags0 |= (args->conf0 & NVC0_DMA_CONF0_PRIV);
priv->flags5 |= (args->conf0 & NVC0_DMA_CONF0_UNKN);
switch (dmaobj->target) {
switch (priv->base.target) {
case NV_MEM_TARGET_VM:
flags0 |= 0x00000000;
priv->flags0 |= 0x00000000;
break;
case NV_MEM_TARGET_VRAM:
flags0 |= 0x00010000;
priv->flags0 |= 0x00010000;
break;
case NV_MEM_TARGET_PCI:
flags0 |= 0x00020000;
priv->flags0 |= 0x00020000;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
flags0 |= 0x00030000;
priv->flags0 |= 0x00030000;
break;
default:
return -EINVAL;
}
switch (dmaobj->access) {
switch (priv->base.access) {
case NV_MEM_ACCESS_VM:
break;
case NV_MEM_ACCESS_RO:
flags0 |= 0x00040000;
priv->flags0 |= 0x00040000;
break;
case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW:
flags0 |= 0x00080000;
priv->flags0 |= 0x00080000;
break;
}
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, flags0);
nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 |
upper_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, flags5);
}
return ret;
return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}
static struct nouveau_ofuncs
nvc0_dmaobj_ofuncs = {
.ctor = nvc0_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nvc0_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY_CLASS, &nvc0_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY_CLASS, &nvc0_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY_CLASS, &nvc0_dmaobj_ofuncs },
{}
};
struct nouveau_oclass *
nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0xc0),
......@@ -119,5 +160,6 @@ nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini,
},
.sclass = nvc0_dmaeng_sclass,