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
Loading
Loading
Loading
Loading
+32 −41
Original line number Diff line number Diff line
@@ -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;
}
+79 −36
Original line number Diff line number Diff line
@@ -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,8 +61,8 @@ nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
		}
	}

	if (dmaobj->target == NV_MEM_TARGET_VM) {
		if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) {
	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);
@@ -66,48 +70,86 @@ nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
		offset &= 0xfffff000;
	}

		dmaobj->target = NV_MEM_TARGET_PCI;
		dmaobj->access = NV_MEM_ACCESS_RW;
	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;
}

	switch (dmaobj->target) {
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;

	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;
	}

	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 dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}

	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 *
nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
@@ -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;
+82 −38
Original line number Diff line number Diff line
@@ -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,67 +70,106 @@ 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 dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}

	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 *
nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
@@ -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;
+76 −34
Original line number Diff line number Diff line
@@ -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,63 +56,100 @@ 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 dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}

	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 *
nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
@@ -119,5 +160,6 @@ nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
		.init = _nvkm_dmaeng_init,
		.fini = _nvkm_dmaeng_fini,
	},
	.sclass = nvc0_dmaeng_sclass,
	.bind = nvc0_dmaobj_bind,
}.base;
+73 −27
Original line number Diff line number Diff line
@@ -30,17 +30,17 @@

#include "priv.h"

struct nvd0_dmaeng_priv {
	struct nouveau_dmaeng base;
struct nvd0_dmaobj_priv {
	struct nouveau_dmaobj base;
	u32 flags0;
};

static int
nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
		 struct nouveau_object *parent,
		 struct nouveau_dmaobj *dmaobj,
		 struct nouveau_gpuobj **pgpuobj)
{
	u32 flags0 = 0x00000000;
	struct nvd0_dmaobj_priv *priv = (void *)dmaobj;
	int ret;

	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
@@ -64,40 +64,85 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
	} else
		return 0;

	if (!(dmaobj->conf0 & NVD0_DMA_CONF0_ENABLE)) {
		if (dmaobj->target == NV_MEM_TARGET_VM) {
			dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_VM;
			dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_LP;
	ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
	if (ret == 0) {
		nv_wo32(*pgpuobj, 0x00, priv->flags0);
		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 {
			dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_LINEAR;
			dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_SP;
			args->conf0 |= NVD0_DMA_CONF0_TYPE_LINEAR;
			args->conf0 |= NVD0_DMA_CONF0_PAGE_SP;
		}
	}

	flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_TYPE) << 20;
	flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_PAGE) >> 4;
	priv->flags0 |= (args->conf0 & NVD0_DMA_CONF0_TYPE) << 20;
	priv->flags0 |= (args->conf0 & NVD0_DMA_CONF0_PAGE) >> 4;

	switch (dmaobj->target) {
	switch (priv->base.target) {
	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;
	default:
		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 dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}

	return ret;
}
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 *
nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
@@ -108,5 +153,6 @@ nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
		.init = _nvkm_dmaeng_init,
		.fini = _nvkm_dmaeng_fini,
	},
	.sclass = nvd0_dmaeng_sclass,
	.bind = nvd0_dmaobj_bind,
}.base;
Loading