1ebb945a9SBen Skeggs /* 2ebb945a9SBen Skeggs * Copyright 2012 Red Hat Inc. 3ebb945a9SBen Skeggs * 4ebb945a9SBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a 5ebb945a9SBen Skeggs * copy of this software and associated documentation files (the "Software"), 6ebb945a9SBen Skeggs * to deal in the Software without restriction, including without limitation 7ebb945a9SBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8ebb945a9SBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the 9ebb945a9SBen Skeggs * Software is furnished to do so, subject to the following conditions: 10ebb945a9SBen Skeggs * 11ebb945a9SBen Skeggs * The above copyright notice and this permission notice shall be included in 12ebb945a9SBen Skeggs * all copies or substantial portions of the Software. 13ebb945a9SBen Skeggs * 14ebb945a9SBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15ebb945a9SBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16ebb945a9SBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17ebb945a9SBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18ebb945a9SBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ebb945a9SBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20ebb945a9SBen Skeggs * OTHER DEALINGS IN THE SOFTWARE. 21ebb945a9SBen Skeggs * 22ebb945a9SBen Skeggs * Authors: Ben Skeggs 23ebb945a9SBen Skeggs */ 24ebb945a9SBen Skeggs 25fdb751efSBen Skeggs #include <nvif/os.h> 26fdb751efSBen Skeggs #include <nvif/class.h> 27845f2725SBen Skeggs #include <nvif/cl0002.h> 288ed1730cSBen Skeggs #include <nvif/cl006b.h> 298ed1730cSBen Skeggs #include <nvif/cl506f.h> 308ed1730cSBen Skeggs #include <nvif/cl906f.h> 318ed1730cSBen Skeggs #include <nvif/cla06f.h> 32f58ddf95SBen Skeggs #include <nvif/ioctl.h> 33fdb751efSBen Skeggs 34fdb751efSBen Skeggs /*XXX*/ 35ebb945a9SBen Skeggs #include <core/client.h> 36ebb945a9SBen Skeggs 374dc28134SBen Skeggs #include "nouveau_drv.h" 38ebb945a9SBen Skeggs #include "nouveau_dma.h" 39ebb945a9SBen Skeggs #include "nouveau_bo.h" 40ebb945a9SBen Skeggs #include "nouveau_chan.h" 41ebb945a9SBen Skeggs #include "nouveau_fence.h" 42ebb945a9SBen Skeggs #include "nouveau_abi16.h" 43ebb945a9SBen Skeggs 44ebb945a9SBen Skeggs MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM"); 45703fa264SPierre Moreau int nouveau_vram_pushbuf; 46ebb945a9SBen Skeggs module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); 47ebb945a9SBen Skeggs 48ebb945a9SBen Skeggs int 49ebb945a9SBen Skeggs nouveau_channel_idle(struct nouveau_channel *chan) 50ebb945a9SBen Skeggs { 51fbd58ebdSBen Skeggs if (likely(chan && chan->fence)) { 52a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)chan->user.client; 53ebb945a9SBen Skeggs struct nouveau_fence *fence = NULL; 54ebb945a9SBen Skeggs int ret; 55ebb945a9SBen Skeggs 56264ce192SBen Skeggs ret = nouveau_fence_new(chan, false, &fence); 57ebb945a9SBen Skeggs if (!ret) { 58ebb945a9SBen Skeggs ret = nouveau_fence_wait(fence, false, false); 59ebb945a9SBen Skeggs nouveau_fence_unref(&fence); 60ebb945a9SBen Skeggs } 61ebb945a9SBen Skeggs 62fbd58ebdSBen Skeggs if (ret) { 63fcf3f91cSBen Skeggs NV_PRINTK(err, cli, "failed to idle channel %d [%s]\n", 64fcf3f91cSBen Skeggs chan->chid, nvxx_client(&cli->base)->name); 65ebb945a9SBen Skeggs return ret; 66ebb945a9SBen Skeggs } 67fbd58ebdSBen Skeggs } 68fbd58ebdSBen Skeggs return 0; 69fbd58ebdSBen Skeggs } 70ebb945a9SBen Skeggs 71ebb945a9SBen Skeggs void 72ebb945a9SBen Skeggs nouveau_channel_del(struct nouveau_channel **pchan) 73ebb945a9SBen Skeggs { 74ebb945a9SBen Skeggs struct nouveau_channel *chan = *pchan; 75ebb945a9SBen Skeggs if (chan) { 76fbd58ebdSBen Skeggs if (chan->fence) 77ebb945a9SBen Skeggs nouveau_fence(chan->drm)->context_del(chan); 780ad72863SBen Skeggs nvif_object_fini(&chan->nvsw); 790ad72863SBen Skeggs nvif_object_fini(&chan->gart); 800ad72863SBen Skeggs nvif_object_fini(&chan->vram); 81a01ca78cSBen Skeggs nvif_object_fini(&chan->user); 820ad72863SBen Skeggs nvif_object_fini(&chan->push.ctxdma); 83ebb945a9SBen Skeggs nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma); 84ebb945a9SBen Skeggs nouveau_bo_unmap(chan->push.buffer); 85124ea297SMarcin Slusarz if (chan->push.buffer && chan->push.buffer->pin_refcnt) 86124ea297SMarcin Slusarz nouveau_bo_unpin(chan->push.buffer); 87ebb945a9SBen Skeggs nouveau_bo_ref(NULL, &chan->push.buffer); 88ebb945a9SBen Skeggs kfree(chan); 89ebb945a9SBen Skeggs } 90ebb945a9SBen Skeggs *pchan = NULL; 91ebb945a9SBen Skeggs } 92ebb945a9SBen Skeggs 93ebb945a9SBen Skeggs static int 940ad72863SBen Skeggs nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, 95fcf3f91cSBen Skeggs u32 size, struct nouveau_channel **pchan) 96ebb945a9SBen Skeggs { 97a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)device->object.client; 98be83cd4eSBen Skeggs struct nvkm_mmu *mmu = nvxx_mmu(device); 994acfd707SBen Skeggs struct nv_dma_v0 args = {}; 100ebb945a9SBen Skeggs struct nouveau_channel *chan; 101ebb945a9SBen Skeggs u32 target; 102ebb945a9SBen Skeggs int ret; 103ebb945a9SBen Skeggs 104ebb945a9SBen Skeggs chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL); 105ebb945a9SBen Skeggs if (!chan) 106ebb945a9SBen Skeggs return -ENOMEM; 107ebb945a9SBen Skeggs 108a01ca78cSBen Skeggs chan->device = device; 109ebb945a9SBen Skeggs chan->drm = drm; 110ebb945a9SBen Skeggs 111ebb945a9SBen Skeggs /* allocate memory for dma push buffer */ 112a81349a7SAlexandre Courbot target = TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED; 113ebb945a9SBen Skeggs if (nouveau_vram_pushbuf) 114ebb945a9SBen Skeggs target = TTM_PL_FLAG_VRAM; 115ebb945a9SBen Skeggs 116*bab7cc18SBen Skeggs ret = nouveau_bo_new(cli, size, 0, target, 0, 0, NULL, NULL, 117ebb945a9SBen Skeggs &chan->push.buffer); 118ebb945a9SBen Skeggs if (ret == 0) { 119ad76b3f7SBen Skeggs ret = nouveau_bo_pin(chan->push.buffer, target, false); 120ebb945a9SBen Skeggs if (ret == 0) 121ebb945a9SBen Skeggs ret = nouveau_bo_map(chan->push.buffer); 122ebb945a9SBen Skeggs } 123ebb945a9SBen Skeggs 124ebb945a9SBen Skeggs if (ret) { 125ebb945a9SBen Skeggs nouveau_channel_del(pchan); 126ebb945a9SBen Skeggs return ret; 127ebb945a9SBen Skeggs } 128ebb945a9SBen Skeggs 129ebb945a9SBen Skeggs /* create dma object covering the *entire* memory space that the 130ebb945a9SBen Skeggs * pushbuf lives in, this is because the GEM code requires that 131ebb945a9SBen Skeggs * we be able to call out to other (indirect) push buffers 132ebb945a9SBen Skeggs */ 133ebb945a9SBen Skeggs chan->push.vma.offset = chan->push.buffer->bo.offset; 134ebb945a9SBen Skeggs 135967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 1360ad72863SBen Skeggs ret = nouveau_bo_vma_add(chan->push.buffer, cli->vm, 137ebb945a9SBen Skeggs &chan->push.vma); 138ebb945a9SBen Skeggs if (ret) { 139ebb945a9SBen Skeggs nouveau_channel_del(pchan); 140ebb945a9SBen Skeggs return ret; 141ebb945a9SBen Skeggs } 142ebb945a9SBen Skeggs 1434acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 1444acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 145ebb945a9SBen Skeggs args.start = 0; 1465ce3bf3cSBen Skeggs args.limit = cli->vm->mmu->limit - 1; 147ebb945a9SBen Skeggs } else 148ebb945a9SBen Skeggs if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) { 149967e7bdeSBen Skeggs if (device->info.family == NV_DEVICE_INFO_V0_TNT) { 150ebb945a9SBen Skeggs /* nv04 vram pushbuf hack, retarget to its location in 151ebb945a9SBen Skeggs * the framebuffer bar rather than direct vram access.. 152ebb945a9SBen Skeggs * nfi why this exists, it came from the -nv ddx. 153ebb945a9SBen Skeggs */ 1544acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_PCI; 1554acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 1567e8820feSBen Skeggs args.start = nvxx_device(device)->func-> 1577e8820feSBen Skeggs resource_addr(nvxx_device(device), 1); 158f392ec4bSBen Skeggs args.limit = args.start + device->info.ram_user - 1; 159ebb945a9SBen Skeggs } else { 1604acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VRAM; 1614acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 162ebb945a9SBen Skeggs args.start = 0; 163f392ec4bSBen Skeggs args.limit = device->info.ram_user - 1; 164ebb945a9SBen Skeggs } 165ebb945a9SBen Skeggs } else { 166340b0e7cSBen Skeggs if (chan->drm->agp.bridge) { 1674acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_AGP; 1684acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 169ebb945a9SBen Skeggs args.start = chan->drm->agp.base; 170ebb945a9SBen Skeggs args.limit = chan->drm->agp.base + 171ebb945a9SBen Skeggs chan->drm->agp.size - 1; 172ebb945a9SBen Skeggs } else { 1734acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 1744acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 175ebb945a9SBen Skeggs args.start = 0; 1765ce3bf3cSBen Skeggs args.limit = mmu->limit - 1; 177ebb945a9SBen Skeggs } 178ebb945a9SBen Skeggs } 179ebb945a9SBen Skeggs 180fcf3f91cSBen Skeggs ret = nvif_object_init(&device->object, 0, NV_DMA_FROM_MEMORY, 1810ad72863SBen Skeggs &args, sizeof(args), &chan->push.ctxdma); 182ebb945a9SBen Skeggs if (ret) { 183ebb945a9SBen Skeggs nouveau_channel_del(pchan); 184ebb945a9SBen Skeggs return ret; 185ebb945a9SBen Skeggs } 186ebb945a9SBen Skeggs 187ebb945a9SBen Skeggs return 0; 188ebb945a9SBen Skeggs } 189ebb945a9SBen Skeggs 1905b8a43aeSMarcin Slusarz static int 1910ad72863SBen Skeggs nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, 192fcf3f91cSBen Skeggs u32 engine, struct nouveau_channel **pchan) 193ebb945a9SBen Skeggs { 194e8ff9794SBen Skeggs static const u16 oclasses[] = { PASCAL_CHANNEL_GPFIFO_A, 195e8ff9794SBen Skeggs MAXWELL_CHANNEL_GPFIFO_A, 19663f8c9b7SBen Skeggs KEPLER_CHANNEL_GPFIFO_B, 197a1020afeSBen Skeggs KEPLER_CHANNEL_GPFIFO_A, 198bbf8906bSBen Skeggs FERMI_CHANNEL_GPFIFO, 199bbf8906bSBen Skeggs G82_CHANNEL_GPFIFO, 200bbf8906bSBen Skeggs NV50_CHANNEL_GPFIFO, 201c97f8c92SBen Skeggs 0 }; 202ebb945a9SBen Skeggs const u16 *oclass = oclasses; 203bbf8906bSBen Skeggs union { 204bbf8906bSBen Skeggs struct nv50_channel_gpfifo_v0 nv50; 205159045cdSBen Skeggs struct fermi_channel_gpfifo_v0 fermi; 206bbf8906bSBen Skeggs struct kepler_channel_gpfifo_a_v0 kepler; 207a01ca78cSBen Skeggs } args; 208ebb945a9SBen Skeggs struct nouveau_channel *chan; 209bbf8906bSBen Skeggs u32 size; 210ebb945a9SBen Skeggs int ret; 211ebb945a9SBen Skeggs 212ebb945a9SBen Skeggs /* allocate dma push buffer */ 213fcf3f91cSBen Skeggs ret = nouveau_channel_prep(drm, device, 0x12000, &chan); 214ebb945a9SBen Skeggs *pchan = chan; 215ebb945a9SBen Skeggs if (ret) 216ebb945a9SBen Skeggs return ret; 217ebb945a9SBen Skeggs 218ebb945a9SBen Skeggs /* create channel object */ 219ebb945a9SBen Skeggs do { 220bbf8906bSBen Skeggs if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { 221bbf8906bSBen Skeggs args.kepler.version = 0; 2221f5ff7f5SBen Skeggs args.kepler.engines = engine; 223bbf8906bSBen Skeggs args.kepler.ilength = 0x02000; 224bbf8906bSBen Skeggs args.kepler.ioffset = 0x10000 + chan->push.vma.offset; 225159045cdSBen Skeggs args.kepler.vm = 0; 226bbf8906bSBen Skeggs size = sizeof(args.kepler); 227159045cdSBen Skeggs } else 228159045cdSBen Skeggs if (oclass[0] >= FERMI_CHANNEL_GPFIFO) { 229159045cdSBen Skeggs args.fermi.version = 0; 230159045cdSBen Skeggs args.fermi.ilength = 0x02000; 231159045cdSBen Skeggs args.fermi.ioffset = 0x10000 + chan->push.vma.offset; 232159045cdSBen Skeggs args.fermi.vm = 0; 233159045cdSBen Skeggs size = sizeof(args.fermi); 234bbf8906bSBen Skeggs } else { 235bbf8906bSBen Skeggs args.nv50.version = 0; 236bbf8906bSBen Skeggs args.nv50.ilength = 0x02000; 237bbf8906bSBen Skeggs args.nv50.ioffset = 0x10000 + chan->push.vma.offset; 238159045cdSBen Skeggs args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma); 239159045cdSBen Skeggs args.nv50.vm = 0; 240bbf8906bSBen Skeggs size = sizeof(args.nv50); 241bbf8906bSBen Skeggs } 242bbf8906bSBen Skeggs 243fcf3f91cSBen Skeggs ret = nvif_object_init(&device->object, 0, *oclass++, 244a01ca78cSBen Skeggs &args, size, &chan->user); 245bbf8906bSBen Skeggs if (ret == 0) { 246a01ca78cSBen Skeggs if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) 247a01ca78cSBen Skeggs chan->chid = args.kepler.chid; 248bbf8906bSBen Skeggs else 249159045cdSBen Skeggs if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) 250159045cdSBen Skeggs chan->chid = args.fermi.chid; 251159045cdSBen Skeggs else 252a01ca78cSBen Skeggs chan->chid = args.nv50.chid; 253ebb945a9SBen Skeggs return ret; 254bbf8906bSBen Skeggs } 255ebb945a9SBen Skeggs } while (*oclass); 256ebb945a9SBen Skeggs 257ebb945a9SBen Skeggs nouveau_channel_del(pchan); 258ebb945a9SBen Skeggs return ret; 259ebb945a9SBen Skeggs } 260ebb945a9SBen Skeggs 261ebb945a9SBen Skeggs static int 2620ad72863SBen Skeggs nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, 263fcf3f91cSBen Skeggs struct nouveau_channel **pchan) 264ebb945a9SBen Skeggs { 265bbf8906bSBen Skeggs static const u16 oclasses[] = { NV40_CHANNEL_DMA, 266bbf8906bSBen Skeggs NV17_CHANNEL_DMA, 267bbf8906bSBen Skeggs NV10_CHANNEL_DMA, 268bbf8906bSBen Skeggs NV03_CHANNEL_DMA, 269c97f8c92SBen Skeggs 0 }; 270ebb945a9SBen Skeggs const u16 *oclass = oclasses; 271a01ca78cSBen Skeggs struct nv03_channel_dma_v0 args; 272ebb945a9SBen Skeggs struct nouveau_channel *chan; 273ebb945a9SBen Skeggs int ret; 274ebb945a9SBen Skeggs 275ebb945a9SBen Skeggs /* allocate dma push buffer */ 276fcf3f91cSBen Skeggs ret = nouveau_channel_prep(drm, device, 0x10000, &chan); 277ebb945a9SBen Skeggs *pchan = chan; 278ebb945a9SBen Skeggs if (ret) 279ebb945a9SBen Skeggs return ret; 280ebb945a9SBen Skeggs 281ebb945a9SBen Skeggs /* create channel object */ 282bbf8906bSBen Skeggs args.version = 0; 283bf81df9bSBen Skeggs args.pushbuf = nvif_handle(&chan->push.ctxdma); 284ebb945a9SBen Skeggs args.offset = chan->push.vma.offset; 285ebb945a9SBen Skeggs 286ebb945a9SBen Skeggs do { 287fcf3f91cSBen Skeggs ret = nvif_object_init(&device->object, 0, *oclass++, 288a01ca78cSBen Skeggs &args, sizeof(args), &chan->user); 289bbf8906bSBen Skeggs if (ret == 0) { 290a01ca78cSBen Skeggs chan->chid = args.chid; 291ebb945a9SBen Skeggs return ret; 292bbf8906bSBen Skeggs } 293ebb945a9SBen Skeggs } while (ret && *oclass); 294ebb945a9SBen Skeggs 295ebb945a9SBen Skeggs nouveau_channel_del(pchan); 296ebb945a9SBen Skeggs return ret; 297ebb945a9SBen Skeggs } 298ebb945a9SBen Skeggs 299ebb945a9SBen Skeggs static int 300ebb945a9SBen Skeggs nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) 301ebb945a9SBen Skeggs { 3020ad72863SBen Skeggs struct nvif_device *device = chan->device; 303a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)chan->user.client; 304be83cd4eSBen Skeggs struct nvkm_mmu *mmu = nvxx_mmu(device); 3054acfd707SBen Skeggs struct nv_dma_v0 args = {}; 306ebb945a9SBen Skeggs int ret, i; 307ebb945a9SBen Skeggs 308a01ca78cSBen Skeggs nvif_object_map(&chan->user); 3096c6ae061SBen Skeggs 310ebb945a9SBen Skeggs /* allocate dma objects to cover all allowed vram, and gart */ 311967e7bdeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { 312967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 3134acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 3144acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 315ebb945a9SBen Skeggs args.start = 0; 3165ce3bf3cSBen Skeggs args.limit = cli->vm->mmu->limit - 1; 317ebb945a9SBen Skeggs } else { 3184acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VRAM; 3194acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 320ebb945a9SBen Skeggs args.start = 0; 321f392ec4bSBen Skeggs args.limit = device->info.ram_user - 1; 322ebb945a9SBen Skeggs } 323ebb945a9SBen Skeggs 324a01ca78cSBen Skeggs ret = nvif_object_init(&chan->user, vram, NV_DMA_IN_MEMORY, 325a01ca78cSBen Skeggs &args, sizeof(args), &chan->vram); 326ebb945a9SBen Skeggs if (ret) 327ebb945a9SBen Skeggs return ret; 328ebb945a9SBen Skeggs 329967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 3304acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 3314acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 332ebb945a9SBen Skeggs args.start = 0; 3335ce3bf3cSBen Skeggs args.limit = cli->vm->mmu->limit - 1; 334ebb945a9SBen Skeggs } else 335340b0e7cSBen Skeggs if (chan->drm->agp.bridge) { 3364acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_AGP; 3374acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 338ebb945a9SBen Skeggs args.start = chan->drm->agp.base; 339ebb945a9SBen Skeggs args.limit = chan->drm->agp.base + 340ebb945a9SBen Skeggs chan->drm->agp.size - 1; 341ebb945a9SBen Skeggs } else { 3424acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 3434acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 344ebb945a9SBen Skeggs args.start = 0; 3455ce3bf3cSBen Skeggs args.limit = mmu->limit - 1; 346ebb945a9SBen Skeggs } 347ebb945a9SBen Skeggs 348a01ca78cSBen Skeggs ret = nvif_object_init(&chan->user, gart, NV_DMA_IN_MEMORY, 349a01ca78cSBen Skeggs &args, sizeof(args), &chan->gart); 350ebb945a9SBen Skeggs if (ret) 351ebb945a9SBen Skeggs return ret; 352ebb945a9SBen Skeggs } 353ebb945a9SBen Skeggs 354ebb945a9SBen Skeggs /* initialise dma tracking parameters */ 355a01ca78cSBen Skeggs switch (chan->user.oclass & 0x00ff) { 356503b0f1cSBen Skeggs case 0x006b: 357ebb945a9SBen Skeggs case 0x006e: 358ebb945a9SBen Skeggs chan->user_put = 0x40; 359ebb945a9SBen Skeggs chan->user_get = 0x44; 360ebb945a9SBen Skeggs chan->dma.max = (0x10000 / 4) - 2; 361ebb945a9SBen Skeggs break; 362ebb945a9SBen Skeggs default: 363ebb945a9SBen Skeggs chan->user_put = 0x40; 364ebb945a9SBen Skeggs chan->user_get = 0x44; 365ebb945a9SBen Skeggs chan->user_get_hi = 0x60; 366ebb945a9SBen Skeggs chan->dma.ib_base = 0x10000 / 4; 367ebb945a9SBen Skeggs chan->dma.ib_max = (0x02000 / 8) - 1; 368ebb945a9SBen Skeggs chan->dma.ib_put = 0; 369ebb945a9SBen Skeggs chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put; 370ebb945a9SBen Skeggs chan->dma.max = chan->dma.ib_base; 371ebb945a9SBen Skeggs break; 372ebb945a9SBen Skeggs } 373ebb945a9SBen Skeggs 374ebb945a9SBen Skeggs chan->dma.put = 0; 375ebb945a9SBen Skeggs chan->dma.cur = chan->dma.put; 376ebb945a9SBen Skeggs chan->dma.free = chan->dma.max - chan->dma.cur; 377ebb945a9SBen Skeggs 378ebb945a9SBen Skeggs ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); 379ebb945a9SBen Skeggs if (ret) 380ebb945a9SBen Skeggs return ret; 381ebb945a9SBen Skeggs 382ebb945a9SBen Skeggs for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) 383ebb945a9SBen Skeggs OUT_RING(chan, 0x00000000); 384ebb945a9SBen Skeggs 38569a6146dSBen Skeggs /* allocate software object class (used for fences on <= nv05) */ 386967e7bdeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { 387f58ddf95SBen Skeggs ret = nvif_object_init(&chan->user, 0x006e, 38808f7633cSBen Skeggs NVIF_CLASS_SW_NV04, 3890ad72863SBen Skeggs NULL, 0, &chan->nvsw); 390ebb945a9SBen Skeggs if (ret) 391ebb945a9SBen Skeggs return ret; 392ebb945a9SBen Skeggs 393ebb945a9SBen Skeggs ret = RING_SPACE(chan, 2); 394ebb945a9SBen Skeggs if (ret) 395ebb945a9SBen Skeggs return ret; 396ebb945a9SBen Skeggs 397ebb945a9SBen Skeggs BEGIN_NV04(chan, NvSubSw, 0x0000, 1); 398f45f55c4SBen Skeggs OUT_RING (chan, chan->nvsw.handle); 399ebb945a9SBen Skeggs FIRE_RING (chan); 400ebb945a9SBen Skeggs } 401ebb945a9SBen Skeggs 402ebb945a9SBen Skeggs /* initialise synchronisation */ 4034894f662SBen Skeggs return nouveau_fence(chan->drm)->context_new(chan); 404ebb945a9SBen Skeggs } 405ebb945a9SBen Skeggs 406ebb945a9SBen Skeggs int 4070ad72863SBen Skeggs nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, 408fcf3f91cSBen Skeggs u32 arg0, u32 arg1, struct nouveau_channel **pchan) 409ebb945a9SBen Skeggs { 410a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)device->object.client; 41167e26e41SBen Skeggs bool super; 412ebb945a9SBen Skeggs int ret; 413ebb945a9SBen Skeggs 41467e26e41SBen Skeggs /* hack until fencenv50 is fixed, and agp access relaxed */ 41567e26e41SBen Skeggs super = cli->base.super; 41667e26e41SBen Skeggs cli->base.super = true; 41767e26e41SBen Skeggs 418fcf3f91cSBen Skeggs ret = nouveau_channel_ind(drm, device, arg0, pchan); 419ebb945a9SBen Skeggs if (ret) { 4209ad97edeSBen Skeggs NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret); 421fcf3f91cSBen Skeggs ret = nouveau_channel_dma(drm, device, pchan); 422ebb945a9SBen Skeggs if (ret) { 4239ad97edeSBen Skeggs NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret); 42467e26e41SBen Skeggs goto done; 425ebb945a9SBen Skeggs } 426ebb945a9SBen Skeggs } 427ebb945a9SBen Skeggs 42849981046SBen Skeggs ret = nouveau_channel_init(*pchan, arg0, arg1); 429ebb945a9SBen Skeggs if (ret) { 4309ad97edeSBen Skeggs NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret); 431ebb945a9SBen Skeggs nouveau_channel_del(pchan); 432ebb945a9SBen Skeggs } 433ebb945a9SBen Skeggs 43467e26e41SBen Skeggs done: 43567e26e41SBen Skeggs cli->base.super = super; 43667e26e41SBen Skeggs return ret; 437ebb945a9SBen Skeggs } 438