1/* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 */ 24#include "priv.h" 25 26#include <core/gpuobj.h> 27#include <subdev/fb.h> 28#include <subdev/mmu/nv04.h> 29 30#include <nvif/class.h> 31 32struct nv04_dmaobj_priv { 33 struct nvkm_dmaobj base; 34 bool clone; 35 u32 flags0; 36 u32 flags2; 37}; 38 39static int 40nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, 41 struct nvkm_gpuobj **pgpuobj) 42{ 43 struct nv04_dmaobj_priv *priv = (void *)dmaobj; 44 struct nvkm_gpuobj *gpuobj; 45 u64 offset = priv->base.start & 0xfffff000; 46 u64 adjust = priv->base.start & 0x00000fff; 47 u32 length = priv->base.limit - priv->base.start; 48 int ret; 49 50 if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { 51 switch (nv_mclass(parent->parent)) { 52 case NV03_CHANNEL_DMA: 53 case NV10_CHANNEL_DMA: 54 case NV17_CHANNEL_DMA: 55 case NV40_CHANNEL_DMA: 56 break; 57 default: 58 return -EINVAL; 59 } 60 } 61 62 if (priv->clone) { 63 struct nv04_mmu_priv *mmu = nv04_mmu(dmaobj); 64 struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0]; 65 if (!dmaobj->start) 66 return nvkm_gpuobj_dup(parent, pgt, pgpuobj); 67 offset = nv_ro32(pgt, 8 + (offset >> 10)); 68 offset &= 0xfffff000; 69 } 70 71 ret = nvkm_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); 72 *pgpuobj = gpuobj; 73 if (ret == 0) { 74 nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20)); 75 nv_wo32(*pgpuobj, 0x04, length); 76 nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset); 77 nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset); 78 } 79 80 return ret; 81} 82 83static int 84nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, 85 struct nvkm_oclass *oclass, void *data, u32 size, 86 struct nvkm_object **pobject) 87{ 88 struct nvkm_dmaeng *dmaeng = (void *)engine; 89 struct nv04_mmu_priv *mmu = nv04_mmu(engine); 90 struct nv04_dmaobj_priv *priv; 91 int ret; 92 93 ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); 94 *pobject = nv_object(priv); 95 if (ret || (ret = -ENOSYS, size)) 96 return ret; 97 98 if (priv->base.target == NV_MEM_TARGET_VM) { 99 if (nv_object(mmu)->oclass == &nv04_mmu_oclass) 100 priv->clone = true; 101 priv->base.target = NV_MEM_TARGET_PCI; 102 priv->base.access = NV_MEM_ACCESS_RW; 103 } 104 105 priv->flags0 = nv_mclass(priv); 106 switch (priv->base.target) { 107 case NV_MEM_TARGET_VRAM: 108 priv->flags0 |= 0x00003000; 109 break; 110 case NV_MEM_TARGET_PCI: 111 priv->flags0 |= 0x00023000; 112 break; 113 case NV_MEM_TARGET_PCI_NOSNOOP: 114 priv->flags0 |= 0x00033000; 115 break; 116 default: 117 return -EINVAL; 118 } 119 120 switch (priv->base.access) { 121 case NV_MEM_ACCESS_RO: 122 priv->flags0 |= 0x00004000; 123 break; 124 case NV_MEM_ACCESS_WO: 125 priv->flags0 |= 0x00008000; 126 case NV_MEM_ACCESS_RW: 127 priv->flags2 |= 0x00000002; 128 break; 129 default: 130 return -EINVAL; 131 } 132 133 return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); 134} 135 136static struct nvkm_ofuncs 137nv04_dmaobj_ofuncs = { 138 .ctor = nv04_dmaobj_ctor, 139 .dtor = _nvkm_dmaobj_dtor, 140 .init = _nvkm_dmaobj_init, 141 .fini = _nvkm_dmaobj_fini, 142}; 143 144static struct nvkm_oclass 145nv04_dmaeng_sclass[] = { 146 { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs }, 147 { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs }, 148 { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs }, 149 {} 150}; 151 152struct nvkm_oclass * 153nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { 154 .base.handle = NV_ENGINE(DMAOBJ, 0x04), 155 .base.ofuncs = &(struct nvkm_ofuncs) { 156 .ctor = _nvkm_dmaeng_ctor, 157 .dtor = _nvkm_dmaeng_dtor, 158 .init = _nvkm_dmaeng_init, 159 .fini = _nvkm_dmaeng_fini, 160 }, 161 .sclass = nv04_dmaeng_sclass, 162 .bind = nv04_dmaobj_bind, 163}.base; 164