diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c | 160 |
1 files changed, 91 insertions, 69 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c index 027d821..20c9dbf 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c @@ -23,121 +23,143 @@ */ #include <core/gpuobj.h> -#include <core/class.h> +#include <nvif/class.h> #include <subdev/fb.h> #include <subdev/vm/nv04.h> -#include <engine/dmaobj.h> +#include "priv.h" -struct nv04_dmaeng_priv { - struct nouveau_dmaeng base; +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)) { switch (nv_mclass(parent->parent)) { - case NV03_CHANNEL_DMA_CLASS: - case NV10_CHANNEL_DMA_CLASS: - case NV17_CHANNEL_DMA_CLASS: - case NV40_CHANNEL_DMA_CLASS: + case NV03_CHANNEL_DMA: + case NV10_CHANNEL_DMA: + case NV17_CHANNEL_DMA: + case NV40_CHANNEL_DMA: break; default: return -EINVAL; } } - 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 || (ret = -ENOSYS, size)) + 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 int -nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv04_dmaeng_priv *priv; - int ret; - - ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - 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, +}; - nv_engine(priv)->sclass = nouveau_dmaobj_sclass; - priv->base.bind = nv04_dmaobj_bind; - return 0; -} +static struct nouveau_oclass +nv04_dmaeng_sclass[] = { + { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs }, + { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs }, + { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs }, + {} +}; -struct nouveau_oclass -nv04_dmaeng_oclass = { - .handle = NV_ENGINE(DMAOBJ, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv04_dmaeng_ctor, - .dtor = _nouveau_dmaeng_dtor, - .init = _nouveau_dmaeng_init, - .fini = _nouveau_dmaeng_fini, +struct nouveau_oclass * +nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_dmaeng_ctor, + .dtor = _nvkm_dmaeng_dtor, + .init = _nvkm_dmaeng_init, + .fini = _nvkm_dmaeng_fini, }, -}; + .sclass = nv04_dmaeng_sclass, + .bind = nv04_dmaobj_bind, +}.base; |