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> 27fdb751efSBen Skeggs 28fdb751efSBen Skeggs /*XXX*/ 29ebb945a9SBen Skeggs #include <core/client.h> 30ebb945a9SBen Skeggs 31ebb945a9SBen Skeggs #include "nouveau_drm.h" 32ebb945a9SBen Skeggs #include "nouveau_dma.h" 33ebb945a9SBen Skeggs #include "nouveau_bo.h" 34ebb945a9SBen Skeggs #include "nouveau_chan.h" 35ebb945a9SBen Skeggs #include "nouveau_fence.h" 36ebb945a9SBen Skeggs #include "nouveau_abi16.h" 37ebb945a9SBen Skeggs 38ebb945a9SBen Skeggs MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM"); 39*703fa264SPierre Moreau int nouveau_vram_pushbuf; 40ebb945a9SBen Skeggs module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); 41ebb945a9SBen Skeggs 42ebb945a9SBen Skeggs int 43ebb945a9SBen Skeggs nouveau_channel_idle(struct nouveau_channel *chan) 44ebb945a9SBen Skeggs { 450ad72863SBen Skeggs struct nouveau_cli *cli = (void *)nvif_client(chan->object); 46ebb945a9SBen Skeggs struct nouveau_fence *fence = NULL; 47ebb945a9SBen Skeggs int ret; 48ebb945a9SBen Skeggs 49264ce192SBen Skeggs ret = nouveau_fence_new(chan, false, &fence); 50ebb945a9SBen Skeggs if (!ret) { 51ebb945a9SBen Skeggs ret = nouveau_fence_wait(fence, false, false); 52ebb945a9SBen Skeggs nouveau_fence_unref(&fence); 53ebb945a9SBen Skeggs } 54ebb945a9SBen Skeggs 55ebb945a9SBen Skeggs if (ret) 56fa2bade9SBen Skeggs NV_PRINTK(error, cli, "failed to idle channel 0x%08x [%s]\n", 570ad72863SBen Skeggs chan->object->handle, nvkm_client(&cli->base)->name); 58ebb945a9SBen Skeggs return ret; 59ebb945a9SBen Skeggs } 60ebb945a9SBen Skeggs 61ebb945a9SBen Skeggs void 62ebb945a9SBen Skeggs nouveau_channel_del(struct nouveau_channel **pchan) 63ebb945a9SBen Skeggs { 64ebb945a9SBen Skeggs struct nouveau_channel *chan = *pchan; 65ebb945a9SBen Skeggs if (chan) { 66ebb945a9SBen Skeggs if (chan->fence) { 67ebb945a9SBen Skeggs nouveau_channel_idle(chan); 68ebb945a9SBen Skeggs nouveau_fence(chan->drm)->context_del(chan); 69ebb945a9SBen Skeggs } 700ad72863SBen Skeggs nvif_object_fini(&chan->nvsw); 710ad72863SBen Skeggs nvif_object_fini(&chan->gart); 720ad72863SBen Skeggs nvif_object_fini(&chan->vram); 730ad72863SBen Skeggs nvif_object_ref(NULL, &chan->object); 740ad72863SBen Skeggs nvif_object_fini(&chan->push.ctxdma); 75ebb945a9SBen Skeggs nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma); 76ebb945a9SBen Skeggs nouveau_bo_unmap(chan->push.buffer); 77124ea297SMarcin Slusarz if (chan->push.buffer && chan->push.buffer->pin_refcnt) 78124ea297SMarcin Slusarz nouveau_bo_unpin(chan->push.buffer); 79ebb945a9SBen Skeggs nouveau_bo_ref(NULL, &chan->push.buffer); 800ad72863SBen Skeggs nvif_device_ref(NULL, &chan->device); 81ebb945a9SBen Skeggs kfree(chan); 82ebb945a9SBen Skeggs } 83ebb945a9SBen Skeggs *pchan = NULL; 84ebb945a9SBen Skeggs } 85ebb945a9SBen Skeggs 86ebb945a9SBen Skeggs static int 870ad72863SBen Skeggs nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, 880ad72863SBen Skeggs u32 handle, u32 size, struct nouveau_channel **pchan) 89ebb945a9SBen Skeggs { 900ad72863SBen Skeggs struct nouveau_cli *cli = (void *)nvif_client(&device->base); 91967e7bdeSBen Skeggs struct nouveau_vmmgr *vmm = nvkm_vmmgr(device); 924acfd707SBen Skeggs struct nv_dma_v0 args = {}; 93ebb945a9SBen Skeggs struct nouveau_channel *chan; 94ebb945a9SBen Skeggs u32 target; 95ebb945a9SBen Skeggs int ret; 96ebb945a9SBen Skeggs 97ebb945a9SBen Skeggs chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL); 98ebb945a9SBen Skeggs if (!chan) 99ebb945a9SBen Skeggs return -ENOMEM; 100ebb945a9SBen Skeggs 1010ad72863SBen Skeggs nvif_device_ref(device, &chan->device); 102ebb945a9SBen Skeggs chan->drm = drm; 103ebb945a9SBen Skeggs 104ebb945a9SBen Skeggs /* allocate memory for dma push buffer */ 105ebb945a9SBen Skeggs target = TTM_PL_FLAG_TT; 106ebb945a9SBen Skeggs if (nouveau_vram_pushbuf) 107ebb945a9SBen Skeggs target = TTM_PL_FLAG_VRAM; 108ebb945a9SBen Skeggs 109ebb945a9SBen Skeggs ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL, 110ebb945a9SBen Skeggs &chan->push.buffer); 111ebb945a9SBen Skeggs if (ret == 0) { 112ebb945a9SBen Skeggs ret = nouveau_bo_pin(chan->push.buffer, target); 113ebb945a9SBen Skeggs if (ret == 0) 114ebb945a9SBen Skeggs ret = nouveau_bo_map(chan->push.buffer); 115ebb945a9SBen Skeggs } 116ebb945a9SBen Skeggs 117ebb945a9SBen Skeggs if (ret) { 118ebb945a9SBen Skeggs nouveau_channel_del(pchan); 119ebb945a9SBen Skeggs return ret; 120ebb945a9SBen Skeggs } 121ebb945a9SBen Skeggs 122ebb945a9SBen Skeggs /* create dma object covering the *entire* memory space that the 123ebb945a9SBen Skeggs * pushbuf lives in, this is because the GEM code requires that 124ebb945a9SBen Skeggs * we be able to call out to other (indirect) push buffers 125ebb945a9SBen Skeggs */ 126ebb945a9SBen Skeggs chan->push.vma.offset = chan->push.buffer->bo.offset; 127ebb945a9SBen Skeggs 128967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 1290ad72863SBen Skeggs ret = nouveau_bo_vma_add(chan->push.buffer, cli->vm, 130ebb945a9SBen Skeggs &chan->push.vma); 131ebb945a9SBen Skeggs if (ret) { 132ebb945a9SBen Skeggs nouveau_channel_del(pchan); 133ebb945a9SBen Skeggs return ret; 134ebb945a9SBen Skeggs } 135ebb945a9SBen Skeggs 1364acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 1374acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 138ebb945a9SBen Skeggs args.start = 0; 1390ad72863SBen Skeggs args.limit = cli->vm->vmm->limit - 1; 140ebb945a9SBen Skeggs } else 141ebb945a9SBen Skeggs if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) { 142967e7bdeSBen Skeggs if (device->info.family == NV_DEVICE_INFO_V0_TNT) { 143ebb945a9SBen Skeggs /* nv04 vram pushbuf hack, retarget to its location in 144ebb945a9SBen Skeggs * the framebuffer bar rather than direct vram access.. 145ebb945a9SBen Skeggs * nfi why this exists, it came from the -nv ddx. 146ebb945a9SBen Skeggs */ 1474acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_PCI; 1484acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 149967e7bdeSBen Skeggs args.start = nv_device_resource_start(nvkm_device(device), 1); 150f392ec4bSBen Skeggs args.limit = args.start + device->info.ram_user - 1; 151ebb945a9SBen Skeggs } else { 1524acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VRAM; 1534acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 154ebb945a9SBen Skeggs args.start = 0; 155f392ec4bSBen Skeggs args.limit = device->info.ram_user - 1; 156ebb945a9SBen Skeggs } 157ebb945a9SBen Skeggs } else { 158ebb945a9SBen Skeggs if (chan->drm->agp.stat == ENABLED) { 1594acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_AGP; 1604acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 161ebb945a9SBen Skeggs args.start = chan->drm->agp.base; 162ebb945a9SBen Skeggs args.limit = chan->drm->agp.base + 163ebb945a9SBen Skeggs chan->drm->agp.size - 1; 164ebb945a9SBen Skeggs } else { 1654acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 1664acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 167ebb945a9SBen Skeggs args.start = 0; 168ebb945a9SBen Skeggs args.limit = vmm->limit - 1; 169ebb945a9SBen Skeggs } 170ebb945a9SBen Skeggs } 171ebb945a9SBen Skeggs 1720ad72863SBen Skeggs ret = nvif_object_init(nvif_object(device), NULL, NVDRM_PUSH | 1734acfd707SBen Skeggs (handle & 0xffff), NV_DMA_FROM_MEMORY, 1740ad72863SBen Skeggs &args, sizeof(args), &chan->push.ctxdma); 175ebb945a9SBen Skeggs if (ret) { 176ebb945a9SBen Skeggs nouveau_channel_del(pchan); 177ebb945a9SBen Skeggs return ret; 178ebb945a9SBen Skeggs } 179ebb945a9SBen Skeggs 180ebb945a9SBen Skeggs return 0; 181ebb945a9SBen Skeggs } 182ebb945a9SBen Skeggs 1835b8a43aeSMarcin Slusarz static int 1840ad72863SBen Skeggs nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, 1850ad72863SBen Skeggs u32 handle, u32 engine, struct nouveau_channel **pchan) 186ebb945a9SBen Skeggs { 187bbf8906bSBen Skeggs static const u16 oclasses[] = { KEPLER_CHANNEL_GPFIFO_A, 188bbf8906bSBen Skeggs FERMI_CHANNEL_GPFIFO, 189bbf8906bSBen Skeggs G82_CHANNEL_GPFIFO, 190bbf8906bSBen Skeggs NV50_CHANNEL_GPFIFO, 191c97f8c92SBen Skeggs 0 }; 192ebb945a9SBen Skeggs const u16 *oclass = oclasses; 193bbf8906bSBen Skeggs union { 194bbf8906bSBen Skeggs struct nv50_channel_gpfifo_v0 nv50; 195bbf8906bSBen Skeggs struct kepler_channel_gpfifo_a_v0 kepler; 196bbf8906bSBen Skeggs } args, *retn; 197ebb945a9SBen Skeggs struct nouveau_channel *chan; 198bbf8906bSBen Skeggs u32 size; 199ebb945a9SBen Skeggs int ret; 200ebb945a9SBen Skeggs 201ebb945a9SBen Skeggs /* allocate dma push buffer */ 2020ad72863SBen Skeggs ret = nouveau_channel_prep(drm, device, handle, 0x12000, &chan); 203ebb945a9SBen Skeggs *pchan = chan; 204ebb945a9SBen Skeggs if (ret) 205ebb945a9SBen Skeggs return ret; 206ebb945a9SBen Skeggs 207ebb945a9SBen Skeggs /* create channel object */ 208ebb945a9SBen Skeggs do { 209bbf8906bSBen Skeggs if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { 210bbf8906bSBen Skeggs args.kepler.version = 0; 211bbf8906bSBen Skeggs args.kepler.engine = engine; 212bbf8906bSBen Skeggs args.kepler.pushbuf = chan->push.ctxdma.handle; 213bbf8906bSBen Skeggs args.kepler.ilength = 0x02000; 214bbf8906bSBen Skeggs args.kepler.ioffset = 0x10000 + chan->push.vma.offset; 215bbf8906bSBen Skeggs size = sizeof(args.kepler); 216bbf8906bSBen Skeggs } else { 217bbf8906bSBen Skeggs args.nv50.version = 0; 218bbf8906bSBen Skeggs args.nv50.pushbuf = chan->push.ctxdma.handle; 219bbf8906bSBen Skeggs args.nv50.ilength = 0x02000; 220bbf8906bSBen Skeggs args.nv50.ioffset = 0x10000 + chan->push.vma.offset; 221bbf8906bSBen Skeggs size = sizeof(args.nv50); 222bbf8906bSBen Skeggs } 223bbf8906bSBen Skeggs 2240ad72863SBen Skeggs ret = nvif_object_new(nvif_object(device), handle, *oclass++, 225bbf8906bSBen Skeggs &args, size, &chan->object); 226bbf8906bSBen Skeggs if (ret == 0) { 227bbf8906bSBen Skeggs retn = chan->object->data; 228bbf8906bSBen Skeggs if (chan->object->oclass >= KEPLER_CHANNEL_GPFIFO_A) 229bbf8906bSBen Skeggs chan->chid = retn->kepler.chid; 230bbf8906bSBen Skeggs else 231bbf8906bSBen Skeggs chan->chid = retn->nv50.chid; 232ebb945a9SBen Skeggs return ret; 233bbf8906bSBen Skeggs } 234ebb945a9SBen Skeggs } while (*oclass); 235ebb945a9SBen Skeggs 236ebb945a9SBen Skeggs nouveau_channel_del(pchan); 237ebb945a9SBen Skeggs return ret; 238ebb945a9SBen Skeggs } 239ebb945a9SBen Skeggs 240ebb945a9SBen Skeggs static int 2410ad72863SBen Skeggs nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, 2420ad72863SBen Skeggs u32 handle, struct nouveau_channel **pchan) 243ebb945a9SBen Skeggs { 244bbf8906bSBen Skeggs static const u16 oclasses[] = { NV40_CHANNEL_DMA, 245bbf8906bSBen Skeggs NV17_CHANNEL_DMA, 246bbf8906bSBen Skeggs NV10_CHANNEL_DMA, 247bbf8906bSBen Skeggs NV03_CHANNEL_DMA, 248c97f8c92SBen Skeggs 0 }; 249ebb945a9SBen Skeggs const u16 *oclass = oclasses; 250bbf8906bSBen Skeggs struct nv03_channel_dma_v0 args, *retn; 251ebb945a9SBen Skeggs struct nouveau_channel *chan; 252ebb945a9SBen Skeggs int ret; 253ebb945a9SBen Skeggs 254ebb945a9SBen Skeggs /* allocate dma push buffer */ 2550ad72863SBen Skeggs ret = nouveau_channel_prep(drm, device, handle, 0x10000, &chan); 256ebb945a9SBen Skeggs *pchan = chan; 257ebb945a9SBen Skeggs if (ret) 258ebb945a9SBen Skeggs return ret; 259ebb945a9SBen Skeggs 260ebb945a9SBen Skeggs /* create channel object */ 261bbf8906bSBen Skeggs args.version = 0; 2620ad72863SBen Skeggs args.pushbuf = chan->push.ctxdma.handle; 263ebb945a9SBen Skeggs args.offset = chan->push.vma.offset; 264ebb945a9SBen Skeggs 265ebb945a9SBen Skeggs do { 2660ad72863SBen Skeggs ret = nvif_object_new(nvif_object(device), handle, *oclass++, 2670ad72863SBen Skeggs &args, sizeof(args), &chan->object); 268bbf8906bSBen Skeggs if (ret == 0) { 269bbf8906bSBen Skeggs retn = chan->object->data; 270bbf8906bSBen Skeggs chan->chid = retn->chid; 271ebb945a9SBen Skeggs return ret; 272bbf8906bSBen Skeggs } 273ebb945a9SBen Skeggs } while (ret && *oclass); 274ebb945a9SBen Skeggs 275ebb945a9SBen Skeggs nouveau_channel_del(pchan); 276ebb945a9SBen Skeggs return ret; 277ebb945a9SBen Skeggs } 278ebb945a9SBen Skeggs 279ebb945a9SBen Skeggs static int 280ebb945a9SBen Skeggs nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) 281ebb945a9SBen Skeggs { 2820ad72863SBen Skeggs struct nvif_device *device = chan->device; 2830ad72863SBen Skeggs struct nouveau_cli *cli = (void *)nvif_client(&device->base); 284967e7bdeSBen Skeggs struct nouveau_vmmgr *vmm = nvkm_vmmgr(device); 285ebb945a9SBen Skeggs struct nouveau_software_chan *swch; 2864acfd707SBen Skeggs struct nv_dma_v0 args = {}; 287ebb945a9SBen Skeggs int ret, i; 288ebb945a9SBen Skeggs 2896c6ae061SBen Skeggs nvif_object_map(chan->object); 2906c6ae061SBen Skeggs 291ebb945a9SBen Skeggs /* allocate dma objects to cover all allowed vram, and gart */ 292967e7bdeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { 293967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 2944acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 2954acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 296ebb945a9SBen Skeggs args.start = 0; 2970ad72863SBen Skeggs args.limit = cli->vm->vmm->limit - 1; 298ebb945a9SBen Skeggs } else { 2994acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VRAM; 3004acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 301ebb945a9SBen Skeggs args.start = 0; 302f392ec4bSBen Skeggs args.limit = device->info.ram_user - 1; 303ebb945a9SBen Skeggs } 304ebb945a9SBen Skeggs 3050ad72863SBen Skeggs ret = nvif_object_init(chan->object, NULL, vram, 3064acfd707SBen Skeggs NV_DMA_IN_MEMORY, &args, 3070ad72863SBen Skeggs sizeof(args), &chan->vram); 308ebb945a9SBen Skeggs if (ret) 309ebb945a9SBen Skeggs return ret; 310ebb945a9SBen Skeggs 311967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 3124acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 3134acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 314ebb945a9SBen Skeggs args.start = 0; 3150ad72863SBen Skeggs args.limit = cli->vm->vmm->limit - 1; 316ebb945a9SBen Skeggs } else 317ebb945a9SBen Skeggs if (chan->drm->agp.stat == ENABLED) { 3184acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_AGP; 3194acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 320ebb945a9SBen Skeggs args.start = chan->drm->agp.base; 321ebb945a9SBen Skeggs args.limit = chan->drm->agp.base + 322ebb945a9SBen Skeggs chan->drm->agp.size - 1; 323ebb945a9SBen Skeggs } else { 3244acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 3254acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 326ebb945a9SBen Skeggs args.start = 0; 327ebb945a9SBen Skeggs args.limit = vmm->limit - 1; 328ebb945a9SBen Skeggs } 329ebb945a9SBen Skeggs 3300ad72863SBen Skeggs ret = nvif_object_init(chan->object, NULL, gart, 3314acfd707SBen Skeggs NV_DMA_IN_MEMORY, &args, 3320ad72863SBen Skeggs sizeof(args), &chan->gart); 333ebb945a9SBen Skeggs if (ret) 334ebb945a9SBen Skeggs return ret; 335ebb945a9SBen Skeggs } 336ebb945a9SBen Skeggs 337ebb945a9SBen Skeggs /* initialise dma tracking parameters */ 3380ad72863SBen Skeggs switch (chan->object->oclass & 0x00ff) { 339503b0f1cSBen Skeggs case 0x006b: 340ebb945a9SBen Skeggs case 0x006e: 341ebb945a9SBen Skeggs chan->user_put = 0x40; 342ebb945a9SBen Skeggs chan->user_get = 0x44; 343ebb945a9SBen Skeggs chan->dma.max = (0x10000 / 4) - 2; 344ebb945a9SBen Skeggs break; 345ebb945a9SBen Skeggs default: 346ebb945a9SBen Skeggs chan->user_put = 0x40; 347ebb945a9SBen Skeggs chan->user_get = 0x44; 348ebb945a9SBen Skeggs chan->user_get_hi = 0x60; 349ebb945a9SBen Skeggs chan->dma.ib_base = 0x10000 / 4; 350ebb945a9SBen Skeggs chan->dma.ib_max = (0x02000 / 8) - 1; 351ebb945a9SBen Skeggs chan->dma.ib_put = 0; 352ebb945a9SBen Skeggs chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put; 353ebb945a9SBen Skeggs chan->dma.max = chan->dma.ib_base; 354ebb945a9SBen Skeggs break; 355ebb945a9SBen Skeggs } 356ebb945a9SBen Skeggs 357ebb945a9SBen Skeggs chan->dma.put = 0; 358ebb945a9SBen Skeggs chan->dma.cur = chan->dma.put; 359ebb945a9SBen Skeggs chan->dma.free = chan->dma.max - chan->dma.cur; 360ebb945a9SBen Skeggs 361ebb945a9SBen Skeggs ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); 362ebb945a9SBen Skeggs if (ret) 363ebb945a9SBen Skeggs return ret; 364ebb945a9SBen Skeggs 365ebb945a9SBen Skeggs for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) 366ebb945a9SBen Skeggs OUT_RING(chan, 0x00000000); 367ebb945a9SBen Skeggs 36869a6146dSBen Skeggs /* allocate software object class (used for fences on <= nv05) */ 369967e7bdeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { 370f45f55c4SBen Skeggs ret = nvif_object_init(chan->object, NULL, 0x006e, 0x006e, 3710ad72863SBen Skeggs NULL, 0, &chan->nvsw); 372ebb945a9SBen Skeggs if (ret) 373ebb945a9SBen Skeggs return ret; 374ebb945a9SBen Skeggs 3750ad72863SBen Skeggs swch = (void *)nvkm_object(&chan->nvsw)->parent; 376ebb945a9SBen Skeggs swch->flip = nouveau_flip_complete; 377ebb945a9SBen Skeggs swch->flip_data = chan; 378ebb945a9SBen Skeggs 379ebb945a9SBen Skeggs ret = RING_SPACE(chan, 2); 380ebb945a9SBen Skeggs if (ret) 381ebb945a9SBen Skeggs return ret; 382ebb945a9SBen Skeggs 383ebb945a9SBen Skeggs BEGIN_NV04(chan, NvSubSw, 0x0000, 1); 384f45f55c4SBen Skeggs OUT_RING (chan, chan->nvsw.handle); 385ebb945a9SBen Skeggs FIRE_RING (chan); 386ebb945a9SBen Skeggs } 387ebb945a9SBen Skeggs 388ebb945a9SBen Skeggs /* initialise synchronisation */ 389ebb945a9SBen Skeggs return nouveau_fence(chan->drm)->context_new(chan); 390ebb945a9SBen Skeggs } 391ebb945a9SBen Skeggs 392ebb945a9SBen Skeggs int 3930ad72863SBen Skeggs nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, 3940ad72863SBen Skeggs u32 handle, u32 arg0, u32 arg1, 395ebb945a9SBen Skeggs struct nouveau_channel **pchan) 396ebb945a9SBen Skeggs { 3970ad72863SBen Skeggs struct nouveau_cli *cli = (void *)nvif_client(&device->base); 398ebb945a9SBen Skeggs int ret; 399ebb945a9SBen Skeggs 4000ad72863SBen Skeggs ret = nouveau_channel_ind(drm, device, handle, arg0, pchan); 401ebb945a9SBen Skeggs if (ret) { 402fa2bade9SBen Skeggs NV_PRINTK(debug, cli, "ib channel create, %d\n", ret); 4030ad72863SBen Skeggs ret = nouveau_channel_dma(drm, device, handle, pchan); 404ebb945a9SBen Skeggs if (ret) { 405fa2bade9SBen Skeggs NV_PRINTK(debug, cli, "dma channel create, %d\n", ret); 406ebb945a9SBen Skeggs return ret; 407ebb945a9SBen Skeggs } 408ebb945a9SBen Skeggs } 409ebb945a9SBen Skeggs 41049981046SBen Skeggs ret = nouveau_channel_init(*pchan, arg0, arg1); 411ebb945a9SBen Skeggs if (ret) { 412fa2bade9SBen Skeggs NV_PRINTK(error, cli, "channel failed to initialise, %d\n", ret); 413ebb945a9SBen Skeggs nouveau_channel_del(pchan); 414ebb945a9SBen Skeggs return ret; 415ebb945a9SBen Skeggs } 416ebb945a9SBen Skeggs 417ebb945a9SBen Skeggs return 0; 418ebb945a9SBen Skeggs } 419