Commit b2c81703 authored by Ben Skeggs's avatar Ben Skeggs

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

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent bc98540b
...@@ -30,22 +30,43 @@ ...@@ -30,22 +30,43 @@
#include "priv.h" #include "priv.h"
static int 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_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void **pdata, u32 *psize,
struct nouveau_object **pobject) int length, void **pobject)
{ {
struct nouveau_dmaeng *dmaeng = (void *)engine; struct nv_dma_class *args = *pdata;
struct nouveau_dmaobj *dmaobj; struct nouveau_dmaobj *dmaobj;
struct nouveau_gpuobj *gpuobj;
struct nv_dma_class *args = data;
int ret; int ret;
if (size < sizeof(*args)) if (*psize < sizeof(*args))
return -EINVAL; return -EINVAL;
*pdata = &args->conf0;
ret = nouveau_object_create(parent, engine, oclass, 0, &dmaobj); ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
*pobject = nv_object(dmaobj); dmaobj = *pobject;
if (ret) if (ret)
return ret; return ret;
...@@ -87,39 +108,9 @@ nouveau_dmaobj_ctor(struct nouveau_object *parent, ...@@ -87,39 +108,9 @@ nouveau_dmaobj_ctor(struct nouveau_object *parent,
dmaobj->start = args->start; dmaobj->start = args->start;
dmaobj->limit = args->limit; dmaobj->limit = args->limit;
dmaobj->conf0 = args->conf0; 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; 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 int
_nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, _nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -135,7 +126,7 @@ _nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -135,7 +126,7 @@ _nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(dmaeng)->sclass = nouveau_dmaobj_sclass; nv_engine(dmaeng)->sclass = impl->sclass;
dmaeng->bind = impl->bind; dmaeng->bind = nvkm_dmaobj_bind;
return 0; return 0;
} }
...@@ -30,19 +30,23 @@ ...@@ -30,19 +30,23 @@
#include "priv.h" #include "priv.h"
struct nv04_dmaobj_priv {
struct nouveau_dmaobj base;
bool clone;
u32 flags0;
u32 flags2;
};
static int static int
nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng, nv04_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent, struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj) struct nouveau_gpuobj **pgpuobj)
{ {
struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaeng); struct nv04_dmaobj_priv *priv = (void *)dmaobj;
struct nouveau_gpuobj *gpuobj; struct nouveau_gpuobj *gpuobj;
u32 flags0 = nv_mclass(dmaobj); u64 offset = priv->base.start & 0xfffff000;
u32 flags2 = 0x00000000; u64 adjust = priv->base.start & 0x00000fff;
u64 offset = dmaobj->start & 0xfffff000; u32 length = priv->base.limit - priv->base.start;
u64 adjust = dmaobj->start & 0x00000fff;
u32 length = dmaobj->limit - dmaobj->start;
int ret; int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
...@@ -57,58 +61,96 @@ nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng, ...@@ -57,58 +61,96 @@ nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
} }
} }
if (dmaobj->target == NV_MEM_TARGET_VM) { if (priv->clone) {
if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) { struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaobj);
struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0]; struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
if (!dmaobj->start) if (!dmaobj->start)
return nouveau_gpuobj_dup(parent, pgt, pgpuobj); return nouveau_gpuobj_dup(parent, pgt, pgpuobj);
offset = nv_ro32(pgt, 8 + (offset >> 10)); offset = nv_ro32(pgt, 8 + (offset >> 10));
offset &= 0xfffff000; 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; if (priv->base.target == NV_MEM_TARGET_VM) {
dmaobj->access = NV_MEM_ACCESS_RW; 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: case NV_MEM_TARGET_VRAM:
flags0 |= 0x00003000; priv->flags0 |= 0x00003000;
break; break;
case NV_MEM_TARGET_PCI: case NV_MEM_TARGET_PCI:
flags0 |= 0x00023000; priv->flags0 |= 0x00023000;
break; break;
case NV_MEM_TARGET_PCI_NOSNOOP: case NV_MEM_TARGET_PCI_NOSNOOP:
flags0 |= 0x00033000; priv->flags0 |= 0x00033000;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
switch (dmaobj->access) { switch (priv->base.access) {
case NV_MEM_ACCESS_RO: case NV_MEM_ACCESS_RO:
flags0 |= 0x00004000; priv->flags0 |= 0x00004000;
break; break;
case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_WO:
flags0 |= 0x00008000; priv->flags0 |= 0x00008000;
case NV_MEM_ACCESS_RW: case NV_MEM_ACCESS_RW:
flags2 |= 0x00000002; priv->flags2 |= 0x00000002;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
*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;
} }
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 * struct nouveau_oclass *
nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0x04), .base.handle = NV_ENGINE(DMAOBJ, 0x04),
...@@ -118,5 +160,6 @@ nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { ...@@ -118,5 +160,6 @@ nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.init = _nvkm_dmaeng_init, .init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini, .fini = _nvkm_dmaeng_fini,
}, },
.sclass = nv04_dmaeng_sclass,
.bind = nv04_dmaobj_bind, .bind = nv04_dmaobj_bind,
}.base; }.base;
...@@ -29,14 +29,18 @@ ...@@ -29,14 +29,18 @@
#include "priv.h" #include "priv.h"
struct nv50_dmaobj_priv {
struct nouveau_dmaobj base;
u32 flags0;
u32 flags5;
};
static int static int
nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng, nv50_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent, struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj) struct nouveau_gpuobj **pgpuobj)
{ {
u32 flags0 = nv_mclass(dmaobj); struct nv50_dmaobj_priv *priv = (void *)dmaobj;
u32 flags5 = 0x00000000;
int ret; int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
...@@ -66,68 +70,107 @@ nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng, ...@@ -66,68 +70,107 @@ nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
} }
} }
if (!(dmaobj->conf0 & NV50_DMA_CONF0_ENABLE)) { ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (dmaobj->target == NV_MEM_TARGET_VM) { if (ret == 0) {
dmaobj->conf0 = NV50_DMA_CONF0_PRIV_VM; nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
dmaobj->conf0 |= NV50_DMA_CONF0_PART_VM; nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
dmaobj->conf0 |= NV50_DMA_CONF0_COMP_VM; nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_VM; 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 { } else {
dmaobj->conf0 = NV50_DMA_CONF0_PRIV_US; args->conf0 = NV50_DMA_CONF0_PRIV_US;
dmaobj->conf0 |= NV50_DMA_CONF0_PART_256; args->conf0 |= NV50_DMA_CONF0_PART_256;
dmaobj->conf0 |= NV50_DMA_CONF0_COMP_NONE; args->conf0 |= NV50_DMA_CONF0_COMP_NONE;
dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_LINEAR; args->conf0 |= NV50_DMA_CONF0_TYPE_LINEAR;
} }
} }
flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_COMP) << 22; priv->flags0 |= (args->conf0 & NV50_DMA_CONF0_COMP) << 22;
flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_TYPE) << 22; priv->flags0 |= (args->conf0 & NV50_DMA_CONF0_TYPE) << 22;
flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_PRIV); priv->flags0 |= (args->conf0 & NV50_DMA_CONF0_PRIV);
flags5 |= (dmaobj->conf0 & NV50_DMA_CONF0_PART); priv->flags5 |= (args->conf0 & NV50_DMA_CONF0_PART);
switch (dmaobj->target) { switch (priv->base.target) {
case NV_MEM_TARGET_VM: case NV_MEM_TARGET_VM:
flags0 |= 0x00000000; priv->flags0 |= 0x00000000;
break; break;
case NV_MEM_TARGET_VRAM: case NV_MEM_TARGET_VRAM:
flags0 |= 0x00010000; priv->flags0 |= 0x00010000;
break; break;
case NV_MEM_TARGET_PCI: case NV_MEM_TARGET_PCI:
flags0 |= 0x00020000; priv->flags0 |= 0x00020000;
break; break;
case NV_MEM_TARGET_PCI_NOSNOOP: case NV_MEM_TARGET_PCI_NOSNOOP:
flags0 |= 0x00030000; priv->flags0 |= 0x00030000;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
switch (dmaobj->access) { switch (priv->base.access) {
case NV_MEM_ACCESS_VM: case NV_MEM_ACCESS_VM:
break; break;
case NV_MEM_ACCESS_RO: case NV_MEM_ACCESS_RO:
flags0 |= 0x00040000; priv->flags0 |= 0x00040000;
break; break;
case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW: case NV_MEM_ACCESS_RW:
flags0 |= 0x00080000; priv->flags0 |= 0x00080000;
break; break;
default:
return -EINVAL;
} }
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
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;
} }
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 * struct nouveau_oclass *
nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0x50), .base.handle = NV_ENGINE(DMAOBJ, 0x50),
...@@ -137,5 +180,6 @@ nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { ...@@ -137,5 +180,6 @@ nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.init = _nvkm_dmaeng_init, .init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini, .fini = _nvkm_dmaeng_fini,
}, },
.sclass = nv50_dmaeng_sclass,
.bind = nv50_dmaobj_bind, .bind = nv50_dmaobj_bind,
}.base; }.base;
...@@ -30,14 +30,18 @@ ...@@ -30,14 +30,18 @@
#include "priv.h" #include "priv.h"
struct nvc0_dmaobj_priv {
struct nouveau_dmaobj base;
u32 flags0;
u32 flags5;
};
static int static int
nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, nvc0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent, struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj) struct nouveau_gpuobj **pgpuobj)
{ {
u32 flags0 = nv_mclass(dmaobj); struct nvc0_dmaobj_priv *priv = (void *)dmaobj;
u32 flags5 = 0x00000000;
int ret; int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
...@@ -52,64 +56,101 @@ nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, ...@@ -52,64 +56,101 @@ nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
} else } else
return 0; return 0;
if (!(dmaobj->conf0 & NVC0_DMA_CONF0_ENABLE)) { ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (dmaobj->target == NV_MEM_TARGET_VM) { if (ret == 0) {
dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_VM; nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_VM; 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 { } else {
dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_US; args->conf0 = NVC0_DMA_CONF0_PRIV_US;
dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_LINEAR; args->conf0 |= NVC0_DMA_CONF0_TYPE_LINEAR;
dmaobj->conf0 |= 0x00020000; args->conf0 |= 0x00020000;
} }
} }
flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_TYPE) << 22; priv->flags0 |= (args->conf0 & NVC0_DMA_CONF0_TYPE) << 22;
flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_PRIV); priv->flags0 |= (args->conf0 & NVC0_DMA_CONF0_PRIV);
flags5 |= (dmaobj->conf0 & NVC0_DMA_CONF0_UNKN); priv->flags5 |= (args->conf0 & NVC0_DMA_CONF0_UNKN);
switch (dmaobj->target) { switch (priv->base.target) {
case NV_MEM_TARGET_VM: case NV_MEM_TARGET_VM:
flags0 |= 0x00000000; priv->flags0 |= 0x00000000;
break; break;
case NV_MEM_TARGET_VRAM: case NV_MEM_TARGET_VRAM:
flags0 |= 0x00010000; priv->flags0 |= 0x00010000;
break; break;
case NV_MEM_TARGET_PCI: case NV_MEM_TARGET_PCI:
flags0 |= 0x00020000; priv->flags0 |= 0x00020000;
break; break;
case NV_MEM_TARGET_PCI_NOSNOOP: case NV_MEM_TARGET_PCI_NOSNOOP:
flags0 |= 0x00030000; priv->flags0 |= 0x00030000;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
switch (dmaobj->access) { switch (priv->base.access) {
case NV_MEM_ACCESS_VM: case NV_MEM_ACCESS_VM:
break; break;
case NV_MEM_ACCESS_RO: case NV_MEM_ACCESS_RO:
flags0 |= 0x00040000; priv->flags0 |= 0x00040000;
break; break;
case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW: case NV_MEM_ACCESS_RW:
flags0 |= 0x00080000; priv->flags0 |= 0x00080000;
break; break;
} }
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
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;
} }
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 * struct nouveau_oclass *
nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0xc0), .base.handle = NV_ENGINE(DMAOBJ, 0xc0),
...@@ -119,5 +160,6 @@ nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { ...@@ -119,5 +160,6 @@ nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.init = _nvkm_dmaeng_init, .init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini, .fini = _nvkm_dmaeng_fini,
}, },
.sclass = nvc0_dmaeng_sclass,
.bind = nvc0_dmaobj_bind, .bind = nvc0_dmaobj_bind,
}.base; }.base;
...@@ -30,17 +30,17 @@ ...@@ -30,17 +30,17 @@
#include "priv.h" #include "priv.h"
struct nvd0_dmaeng_priv { struct nvd0_dmaobj_priv {
struct nouveau_dmaeng base; struct nouveau_dmaobj base;
u32 flags0;
}; };
static int static int
nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent, struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj) struct nouveau_gpuobj **pgpuobj)
{ {
u32 flags0 = 0x00000000; struct nvd0_dmaobj_priv *priv = (void *)dmaobj;
int ret; int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
...@@ -64,41 +64,86 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, ...@@ -64,41 +64,86 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
} else } else
return 0; return 0;
if (!(dmaobj->conf0 & NVD0_DMA_CONF0_ENABLE)) { ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (dmaobj->target == NV_MEM_TARGET_VM) { if (ret == 0) {
dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_VM; nv_wo32(*pgpuobj, 0x00, priv->flags0);
dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_LP; nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8);
nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8);
nv_wo32(*pgpuobj, 0x0c, 0x00000000);
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, 0x00000000);
}
return ret;
}
static int
nvd0_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 nvd0_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 & NVD0_DMA_CONF0_ENABLE)) {
if (priv->base.target == NV_MEM_TARGET_VM) {
args->conf0 |= NVD0_DMA_CONF0_TYPE_VM;
args->conf0 |= NVD0_DMA_CONF0_PAGE_LP;
} else { } else {
dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_LINEAR; args->conf0 |= NVD0_DMA_CONF0_TYPE_LINEAR;
dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_SP; args->conf0 |= NVD0_DMA_CONF0_PAGE_SP;
} }
} }
flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_TYPE) << 20; priv->flags0 |= (args->conf0 & NVD0_DMA_CONF0_TYPE) << 20;
flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_PAGE) >> 4; priv->flags0 |= (args->conf0 & NVD0_DMA_CONF0_PAGE) >> 4;
switch (dmaobj->target) { switch (priv->base.target) {
case NV_MEM_TARGET_VRAM: case NV_MEM_TARGET_VRAM:
flags0 |= 0x00000009; priv->flags0 |= 0x00000009;
break;
case NV_MEM_TARGET_VM:
case NV_MEM_TARGET_PCI:
case NV_MEM_TARGET_PCI_NOSNOOP:
/* XXX: don't currently know how to construct a real one
* of these. we only use them to represent pushbufs
* on these chipsets, and the classes that use them
* deal with the target themselves.
*/
break; break;
default: default:
return -EINVAL; return -EINVAL;
break;
}
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, flags0);
nv_wo32(*pgpuobj, 0x04, dmaobj->start >> 8);
nv_wo32(*pgpuobj, 0x08, dmaobj->limit >> 8);
nv_wo32(*pgpuobj, 0x0c, 0x00000000);
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, 0x00000000);
} }
return ret; return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
} }
static struct nouveau_ofuncs
nvd0_dmaobj_ofuncs = {
.ctor = nvd0_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nvd0_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY_CLASS, &nvd0_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY_CLASS, &nvd0_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY_CLASS, &nvd0_dmaobj_ofuncs },
{}
};
struct nouveau_oclass * struct nouveau_oclass *
nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0xd0), .base.handle = NV_ENGINE(DMAOBJ, 0xd0),
...@@ -108,5 +153,6 @@ nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { ...@@ -108,5 +153,6 @@ nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.init = _nvkm_dmaeng_init, .init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini, .fini = _nvkm_dmaeng_fini,
}, },
.sclass = nvd0_dmaeng_sclass,
.bind = nvd0_dmaobj_bind, .bind = nvd0_dmaobj_bind,
}.base; }.base;
...@@ -3,6 +3,16 @@ ...@@ -3,6 +3,16 @@
#include <engine/dmaobj.h> #include <engine/dmaobj.h>
#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \
nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d)
int nvkm_dmaobj_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void **, u32 *,
int, void **);
#define _nvkm_dmaobj_dtor nouveau_object_destroy
#define _nvkm_dmaobj_init nouveau_object_init
#define _nvkm_dmaobj_fini nouveau_object_fini
int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *, int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32, struct nouveau_oclass *, void *, u32,
struct nouveau_object **); struct nouveau_object **);
...@@ -12,8 +22,9 @@ int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *, ...@@ -12,8 +22,9 @@ int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *,
struct nvkm_dmaeng_impl { struct nvkm_dmaeng_impl {
struct nouveau_oclass base; struct nouveau_oclass base;
int (*bind)(struct nouveau_dmaeng *, struct nouveau_object *, struct nouveau_oclass *sclass;
struct nouveau_dmaobj *, struct nouveau_gpuobj **); int (*bind)(struct nouveau_dmaobj *, struct nouveau_object *,
struct nouveau_gpuobj **);
}; };
#endif #endif
...@@ -83,7 +83,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent, ...@@ -83,7 +83,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
return -EINVAL; return -EINVAL;
} }
ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu); ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu);
if (ret) if (ret)
return ret; return ret;
......
...@@ -19,9 +19,8 @@ struct nouveau_dmaeng { ...@@ -19,9 +19,8 @@ struct nouveau_dmaeng {
struct nouveau_engine base; struct nouveau_engine base;
/* creates a "physical" dma object from a struct nouveau_dmaobj */ /* creates a "physical" dma object from a struct nouveau_dmaobj */
int (*bind)(struct nouveau_dmaeng *dmaeng, int (*bind)(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent, struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **); struct nouveau_gpuobj **);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment