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 */ 24cd346a89SBen Skeggs #include <nvif/push006c.h> 25ebb945a9SBen Skeggs 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> 329d24907cSBen Skeggs #include <nvif/clc36f.h> 33f58ddf95SBen Skeggs #include <nvif/ioctl.h> 34fdb751efSBen Skeggs 354dc28134SBen Skeggs #include "nouveau_drv.h" 36ebb945a9SBen Skeggs #include "nouveau_dma.h" 37ebb945a9SBen Skeggs #include "nouveau_bo.h" 38ebb945a9SBen Skeggs #include "nouveau_chan.h" 39ebb945a9SBen Skeggs #include "nouveau_fence.h" 40ebb945a9SBen Skeggs #include "nouveau_abi16.h" 4124e8375bSBen Skeggs #include "nouveau_vmm.h" 42eeaf06acSBen Skeggs #include "nouveau_svm.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 48d8cc37d8SBen Skeggs static int 49d8cc37d8SBen Skeggs nouveau_channel_killed(struct nvif_notify *ntfy) 50d8cc37d8SBen Skeggs { 51d8cc37d8SBen Skeggs struct nouveau_channel *chan = container_of(ntfy, typeof(*chan), kill); 52d8cc37d8SBen Skeggs struct nouveau_cli *cli = (void *)chan->user.client; 53d8cc37d8SBen Skeggs NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid); 54d8cc37d8SBen Skeggs atomic_set(&chan->killed, 1); 55ea13e5abSBen Skeggs if (chan->fence) 56ea13e5abSBen Skeggs nouveau_fence_context_kill(chan->fence, -ENODEV); 57d8cc37d8SBen Skeggs return NVIF_NOTIFY_DROP; 58d8cc37d8SBen Skeggs } 59d8cc37d8SBen Skeggs 60ebb945a9SBen Skeggs int 61ebb945a9SBen Skeggs nouveau_channel_idle(struct nouveau_channel *chan) 62ebb945a9SBen Skeggs { 6384cd0a55SBen Skeggs if (likely(chan && chan->fence && !atomic_read(&chan->killed))) { 64a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)chan->user.client; 65ebb945a9SBen Skeggs struct nouveau_fence *fence = NULL; 66ebb945a9SBen Skeggs int ret; 67ebb945a9SBen Skeggs 68264ce192SBen Skeggs ret = nouveau_fence_new(chan, false, &fence); 69ebb945a9SBen Skeggs if (!ret) { 70ebb945a9SBen Skeggs ret = nouveau_fence_wait(fence, false, false); 71ebb945a9SBen Skeggs nouveau_fence_unref(&fence); 72ebb945a9SBen Skeggs } 73ebb945a9SBen Skeggs 74fbd58ebdSBen Skeggs if (ret) { 75fcf3f91cSBen Skeggs NV_PRINTK(err, cli, "failed to idle channel %d [%s]\n", 76fcf3f91cSBen Skeggs chan->chid, nvxx_client(&cli->base)->name); 77ebb945a9SBen Skeggs return ret; 78ebb945a9SBen Skeggs } 79fbd58ebdSBen Skeggs } 80fbd58ebdSBen Skeggs return 0; 81fbd58ebdSBen Skeggs } 82ebb945a9SBen Skeggs 83ebb945a9SBen Skeggs void 84ebb945a9SBen Skeggs nouveau_channel_del(struct nouveau_channel **pchan) 85ebb945a9SBen Skeggs { 86ebb945a9SBen Skeggs struct nouveau_channel *chan = *pchan; 87ebb945a9SBen Skeggs if (chan) { 88d7722134SBen Skeggs struct nouveau_cli *cli = (void *)chan->user.client; 89d7722134SBen Skeggs bool super; 90d7722134SBen Skeggs 91d7722134SBen Skeggs if (cli) { 92d7722134SBen Skeggs super = cli->base.super; 93d7722134SBen Skeggs cli->base.super = true; 94d7722134SBen Skeggs } 95d7722134SBen Skeggs 96fbd58ebdSBen Skeggs if (chan->fence) 97ebb945a9SBen Skeggs nouveau_fence(chan->drm)->context_del(chan); 98eeaf06acSBen Skeggs 99eeaf06acSBen Skeggs if (cli) 100eeaf06acSBen Skeggs nouveau_svmm_part(chan->vmm->svmm, chan->inst); 101eeaf06acSBen Skeggs 1029ac596a4SBen Skeggs nvif_object_dtor(&chan->nvsw); 1039ac596a4SBen Skeggs nvif_object_dtor(&chan->gart); 1049ac596a4SBen Skeggs nvif_object_dtor(&chan->vram); 105f7a7d22aSBen Skeggs nvif_notify_dtor(&chan->kill); 1069ac596a4SBen Skeggs nvif_object_dtor(&chan->user); 1079ac596a4SBen Skeggs nvif_object_dtor(&chan->push.ctxdma); 10824e8375bSBen Skeggs nouveau_vma_del(&chan->push.vma); 109ebb945a9SBen Skeggs nouveau_bo_unmap(chan->push.buffer); 1106797cea1SChristian König if (chan->push.buffer && chan->push.buffer->bo.pin_count) 111124ea297SMarcin Slusarz nouveau_bo_unpin(chan->push.buffer); 112ebb945a9SBen Skeggs nouveau_bo_ref(NULL, &chan->push.buffer); 113ebb945a9SBen Skeggs kfree(chan); 114d7722134SBen Skeggs 115d7722134SBen Skeggs if (cli) 116d7722134SBen Skeggs cli->base.super = super; 117ebb945a9SBen Skeggs } 118ebb945a9SBen Skeggs *pchan = NULL; 119ebb945a9SBen Skeggs } 120ebb945a9SBen Skeggs 121fdb06e2bSBen Skeggs static void 122fdb06e2bSBen Skeggs nouveau_channel_kick(struct nvif_push *push) 123fdb06e2bSBen Skeggs { 124fdb06e2bSBen Skeggs struct nouveau_channel *chan = container_of(push, typeof(*chan), chan._push); 125fdb06e2bSBen Skeggs chan->dma.cur = chan->dma.cur + (chan->chan._push.cur - chan->chan._push.bgn); 126fdb06e2bSBen Skeggs FIRE_RING(chan); 127fdb06e2bSBen Skeggs chan->chan._push.bgn = chan->chan._push.cur; 128fdb06e2bSBen Skeggs } 129fdb06e2bSBen Skeggs 130fdb06e2bSBen Skeggs static int 131fdb06e2bSBen Skeggs nouveau_channel_wait(struct nvif_push *push, u32 size) 132fdb06e2bSBen Skeggs { 133fdb06e2bSBen Skeggs struct nouveau_channel *chan = container_of(push, typeof(*chan), chan._push); 134fdb06e2bSBen Skeggs int ret; 135fdb06e2bSBen Skeggs chan->dma.cur = chan->dma.cur + (chan->chan._push.cur - chan->chan._push.bgn); 136fdb06e2bSBen Skeggs ret = RING_SPACE(chan, size); 137fdb06e2bSBen Skeggs if (ret == 0) { 138fdb06e2bSBen Skeggs chan->chan._push.bgn = chan->chan._push.mem.object.map.ptr; 139fdb06e2bSBen Skeggs chan->chan._push.bgn = chan->chan._push.bgn + chan->dma.cur; 140fdb06e2bSBen Skeggs chan->chan._push.cur = chan->chan._push.bgn; 141fdb06e2bSBen Skeggs chan->chan._push.end = chan->chan._push.bgn + size; 142fdb06e2bSBen Skeggs } 143fdb06e2bSBen Skeggs return ret; 144fdb06e2bSBen Skeggs } 145fdb06e2bSBen Skeggs 146ebb945a9SBen Skeggs static int 1470ad72863SBen Skeggs nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, 148fcf3f91cSBen Skeggs u32 size, struct nouveau_channel **pchan) 149ebb945a9SBen Skeggs { 150a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)device->object.client; 1514acfd707SBen Skeggs struct nv_dma_v0 args = {}; 152ebb945a9SBen Skeggs struct nouveau_channel *chan; 153ebb945a9SBen Skeggs u32 target; 154ebb945a9SBen Skeggs int ret; 155ebb945a9SBen Skeggs 156ebb945a9SBen Skeggs chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL); 157ebb945a9SBen Skeggs if (!chan) 158ebb945a9SBen Skeggs return -ENOMEM; 159ebb945a9SBen Skeggs 160a01ca78cSBen Skeggs chan->device = device; 161ebb945a9SBen Skeggs chan->drm = drm; 162bfe91afaSBen Skeggs chan->vmm = cli->svm.cli ? &cli->svm : &cli->vmm; 163d8cc37d8SBen Skeggs atomic_set(&chan->killed, 0); 164ebb945a9SBen Skeggs 165ebb945a9SBen Skeggs /* allocate memory for dma push buffer */ 16681b61579SChristian König target = NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT; 167ebb945a9SBen Skeggs if (nouveau_vram_pushbuf) 16881b61579SChristian König target = NOUVEAU_GEM_DOMAIN_VRAM; 169ebb945a9SBen Skeggs 170bab7cc18SBen Skeggs ret = nouveau_bo_new(cli, size, 0, target, 0, 0, NULL, NULL, 171ebb945a9SBen Skeggs &chan->push.buffer); 172ebb945a9SBen Skeggs if (ret == 0) { 173ad76b3f7SBen Skeggs ret = nouveau_bo_pin(chan->push.buffer, target, false); 174ebb945a9SBen Skeggs if (ret == 0) 175ebb945a9SBen Skeggs ret = nouveau_bo_map(chan->push.buffer); 176ebb945a9SBen Skeggs } 177ebb945a9SBen Skeggs 178ebb945a9SBen Skeggs if (ret) { 179ebb945a9SBen Skeggs nouveau_channel_del(pchan); 180ebb945a9SBen Skeggs return ret; 181ebb945a9SBen Skeggs } 182ebb945a9SBen Skeggs 183fdb06e2bSBen Skeggs chan->chan._push.mem.object.parent = cli->base.object.parent; 184fdb06e2bSBen Skeggs chan->chan._push.mem.object.client = &cli->base; 185fdb06e2bSBen Skeggs chan->chan._push.mem.object.name = "chanPush"; 186fdb06e2bSBen Skeggs chan->chan._push.mem.object.map.ptr = chan->push.buffer->kmap.virtual; 187fdb06e2bSBen Skeggs chan->chan._push.wait = nouveau_channel_wait; 188fdb06e2bSBen Skeggs chan->chan._push.kick = nouveau_channel_kick; 189fdb06e2bSBen Skeggs chan->chan.push = &chan->chan._push; 190fdb06e2bSBen Skeggs 191ebb945a9SBen Skeggs /* create dma object covering the *entire* memory space that the 192ebb945a9SBen Skeggs * pushbuf lives in, this is because the GEM code requires that 193ebb945a9SBen Skeggs * we be able to call out to other (indirect) push buffers 194ebb945a9SBen Skeggs */ 1950dc9b286SNirmoy Das chan->push.addr = chan->push.buffer->offset; 196ebb945a9SBen Skeggs 197967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 198bfe91afaSBen Skeggs ret = nouveau_vma_new(chan->push.buffer, chan->vmm, 199ebb945a9SBen Skeggs &chan->push.vma); 200ebb945a9SBen Skeggs if (ret) { 201ebb945a9SBen Skeggs nouveau_channel_del(pchan); 202ebb945a9SBen Skeggs return ret; 203ebb945a9SBen Skeggs } 204ebb945a9SBen Skeggs 20592b4eaafSBen Skeggs chan->push.addr = chan->push.vma->addr; 20692b4eaafSBen Skeggs 20792b4eaafSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_FERMI) 20892b4eaafSBen Skeggs return 0; 20992b4eaafSBen Skeggs 2104acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 2114acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 212ebb945a9SBen Skeggs args.start = 0; 213bfe91afaSBen Skeggs args.limit = chan->vmm->vmm.limit - 1; 214ebb945a9SBen Skeggs } else 215*d3116756SChristian König if (chan->push.buffer->bo.resource->mem_type == TTM_PL_VRAM) { 216967e7bdeSBen Skeggs if (device->info.family == NV_DEVICE_INFO_V0_TNT) { 217ebb945a9SBen Skeggs /* nv04 vram pushbuf hack, retarget to its location in 218ebb945a9SBen Skeggs * the framebuffer bar rather than direct vram access.. 219ebb945a9SBen Skeggs * nfi why this exists, it came from the -nv ddx. 220ebb945a9SBen Skeggs */ 2214acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_PCI; 2224acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 2237e8820feSBen Skeggs args.start = nvxx_device(device)->func-> 2247e8820feSBen Skeggs resource_addr(nvxx_device(device), 1); 225f392ec4bSBen Skeggs args.limit = args.start + device->info.ram_user - 1; 226ebb945a9SBen Skeggs } else { 2274acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VRAM; 2284acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 229ebb945a9SBen Skeggs args.start = 0; 230f392ec4bSBen Skeggs args.limit = device->info.ram_user - 1; 231ebb945a9SBen Skeggs } 232ebb945a9SBen Skeggs } else { 233340b0e7cSBen Skeggs if (chan->drm->agp.bridge) { 2344acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_AGP; 2354acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 236ebb945a9SBen Skeggs args.start = chan->drm->agp.base; 237ebb945a9SBen Skeggs args.limit = chan->drm->agp.base + 238ebb945a9SBen Skeggs chan->drm->agp.size - 1; 239ebb945a9SBen Skeggs } else { 2404acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 2414acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 242ebb945a9SBen Skeggs args.start = 0; 243bfe91afaSBen Skeggs args.limit = chan->vmm->vmm.limit - 1; 244ebb945a9SBen Skeggs } 245ebb945a9SBen Skeggs } 246ebb945a9SBen Skeggs 2479ac596a4SBen Skeggs ret = nvif_object_ctor(&device->object, "abi16PushCtxDma", 0, 2489ac596a4SBen Skeggs NV_DMA_FROM_MEMORY, &args, sizeof(args), 2499ac596a4SBen Skeggs &chan->push.ctxdma); 250ebb945a9SBen Skeggs if (ret) { 251ebb945a9SBen Skeggs nouveau_channel_del(pchan); 252ebb945a9SBen Skeggs return ret; 253ebb945a9SBen Skeggs } 254ebb945a9SBen Skeggs 255ebb945a9SBen Skeggs return 0; 256ebb945a9SBen Skeggs } 257ebb945a9SBen Skeggs 2585b8a43aeSMarcin Slusarz static int 2590ad72863SBen Skeggs nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, 26085532bd9SBen Skeggs u64 runlist, bool priv, struct nouveau_channel **pchan) 261ebb945a9SBen Skeggs { 262641d0b30SBen Skeggs static const u16 oclasses[] = { TURING_CHANNEL_GPFIFO_A, 263641d0b30SBen Skeggs VOLTA_CHANNEL_GPFIFO_A, 26437e1c45aSBen Skeggs PASCAL_CHANNEL_GPFIFO_A, 265e8ff9794SBen Skeggs MAXWELL_CHANNEL_GPFIFO_A, 26663f8c9b7SBen Skeggs KEPLER_CHANNEL_GPFIFO_B, 267a1020afeSBen Skeggs KEPLER_CHANNEL_GPFIFO_A, 268bbf8906bSBen Skeggs FERMI_CHANNEL_GPFIFO, 269bbf8906bSBen Skeggs G82_CHANNEL_GPFIFO, 270bbf8906bSBen Skeggs NV50_CHANNEL_GPFIFO, 271c97f8c92SBen Skeggs 0 }; 272ebb945a9SBen Skeggs const u16 *oclass = oclasses; 273bbf8906bSBen Skeggs union { 274bbf8906bSBen Skeggs struct nv50_channel_gpfifo_v0 nv50; 275159045cdSBen Skeggs struct fermi_channel_gpfifo_v0 fermi; 276bbf8906bSBen Skeggs struct kepler_channel_gpfifo_a_v0 kepler; 2779d24907cSBen Skeggs struct volta_channel_gpfifo_a_v0 volta; 278a01ca78cSBen Skeggs } args; 279ebb945a9SBen Skeggs struct nouveau_channel *chan; 280bbf8906bSBen Skeggs u32 size; 281ebb945a9SBen Skeggs int ret; 282ebb945a9SBen Skeggs 283ebb945a9SBen Skeggs /* allocate dma push buffer */ 284fcf3f91cSBen Skeggs ret = nouveau_channel_prep(drm, device, 0x12000, &chan); 285ebb945a9SBen Skeggs *pchan = chan; 286ebb945a9SBen Skeggs if (ret) 287ebb945a9SBen Skeggs return ret; 288ebb945a9SBen Skeggs 289ebb945a9SBen Skeggs /* create channel object */ 290ebb945a9SBen Skeggs do { 2919d24907cSBen Skeggs if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) { 2929d24907cSBen Skeggs args.volta.version = 0; 2939d24907cSBen Skeggs args.volta.ilength = 0x02000; 2949d24907cSBen Skeggs args.volta.ioffset = 0x10000 + chan->push.addr; 2959d24907cSBen Skeggs args.volta.runlist = runlist; 296bfe91afaSBen Skeggs args.volta.vmm = nvif_handle(&chan->vmm->vmm.object); 2979d24907cSBen Skeggs args.volta.priv = priv; 2989d24907cSBen Skeggs size = sizeof(args.volta); 2999d24907cSBen Skeggs } else 300bbf8906bSBen Skeggs if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { 301bbf8906bSBen Skeggs args.kepler.version = 0; 302bbf8906bSBen Skeggs args.kepler.ilength = 0x02000; 30324e8375bSBen Skeggs args.kepler.ioffset = 0x10000 + chan->push.addr; 304a7cf0180SBen Skeggs args.kepler.runlist = runlist; 305bfe91afaSBen Skeggs args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object); 30685532bd9SBen Skeggs args.kepler.priv = priv; 307bbf8906bSBen Skeggs size = sizeof(args.kepler); 308159045cdSBen Skeggs } else 309159045cdSBen Skeggs if (oclass[0] >= FERMI_CHANNEL_GPFIFO) { 310159045cdSBen Skeggs args.fermi.version = 0; 311159045cdSBen Skeggs args.fermi.ilength = 0x02000; 31224e8375bSBen Skeggs args.fermi.ioffset = 0x10000 + chan->push.addr; 313bfe91afaSBen Skeggs args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object); 314159045cdSBen Skeggs size = sizeof(args.fermi); 315bbf8906bSBen Skeggs } else { 316bbf8906bSBen Skeggs args.nv50.version = 0; 317bbf8906bSBen Skeggs args.nv50.ilength = 0x02000; 31824e8375bSBen Skeggs args.nv50.ioffset = 0x10000 + chan->push.addr; 319159045cdSBen Skeggs args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma); 320bfe91afaSBen Skeggs args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object); 321bbf8906bSBen Skeggs size = sizeof(args.nv50); 322bbf8906bSBen Skeggs } 323bbf8906bSBen Skeggs 3249ac596a4SBen Skeggs ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, 3259ac596a4SBen Skeggs *oclass++, &args, size, &chan->user); 326bbf8906bSBen Skeggs if (ret == 0) { 3279d24907cSBen Skeggs if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) { 3289d24907cSBen Skeggs chan->chid = args.volta.chid; 3299d24907cSBen Skeggs chan->inst = args.volta.inst; 3309d24907cSBen Skeggs chan->token = args.volta.token; 3319d24907cSBen Skeggs } else 33286b442d7SBen Skeggs if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) { 333a01ca78cSBen Skeggs chan->chid = args.kepler.chid; 33486b442d7SBen Skeggs chan->inst = args.kepler.inst; 33586b442d7SBen Skeggs } else 33686b442d7SBen Skeggs if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) { 337159045cdSBen Skeggs chan->chid = args.fermi.chid; 33886b442d7SBen Skeggs } else { 339a01ca78cSBen Skeggs chan->chid = args.nv50.chid; 34086b442d7SBen Skeggs } 341ebb945a9SBen Skeggs return ret; 342bbf8906bSBen Skeggs } 343ebb945a9SBen Skeggs } while (*oclass); 344ebb945a9SBen Skeggs 345ebb945a9SBen Skeggs nouveau_channel_del(pchan); 346ebb945a9SBen Skeggs return ret; 347ebb945a9SBen Skeggs } 348ebb945a9SBen Skeggs 349ebb945a9SBen Skeggs static int 3500ad72863SBen Skeggs nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, 351fcf3f91cSBen Skeggs struct nouveau_channel **pchan) 352ebb945a9SBen Skeggs { 353bbf8906bSBen Skeggs static const u16 oclasses[] = { NV40_CHANNEL_DMA, 354bbf8906bSBen Skeggs NV17_CHANNEL_DMA, 355bbf8906bSBen Skeggs NV10_CHANNEL_DMA, 356bbf8906bSBen Skeggs NV03_CHANNEL_DMA, 357c97f8c92SBen Skeggs 0 }; 358ebb945a9SBen Skeggs const u16 *oclass = oclasses; 359a01ca78cSBen Skeggs struct nv03_channel_dma_v0 args; 360ebb945a9SBen Skeggs struct nouveau_channel *chan; 361ebb945a9SBen Skeggs int ret; 362ebb945a9SBen Skeggs 363ebb945a9SBen Skeggs /* allocate dma push buffer */ 364fcf3f91cSBen Skeggs ret = nouveau_channel_prep(drm, device, 0x10000, &chan); 365ebb945a9SBen Skeggs *pchan = chan; 366ebb945a9SBen Skeggs if (ret) 367ebb945a9SBen Skeggs return ret; 368ebb945a9SBen Skeggs 369ebb945a9SBen Skeggs /* create channel object */ 370bbf8906bSBen Skeggs args.version = 0; 371bf81df9bSBen Skeggs args.pushbuf = nvif_handle(&chan->push.ctxdma); 37224e8375bSBen Skeggs args.offset = chan->push.addr; 373ebb945a9SBen Skeggs 374ebb945a9SBen Skeggs do { 3759ac596a4SBen Skeggs ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, 3769ac596a4SBen Skeggs *oclass++, &args, sizeof(args), 3779ac596a4SBen Skeggs &chan->user); 378bbf8906bSBen Skeggs if (ret == 0) { 379a01ca78cSBen Skeggs chan->chid = args.chid; 380ebb945a9SBen Skeggs return ret; 381bbf8906bSBen Skeggs } 382ebb945a9SBen Skeggs } while (ret && *oclass); 383ebb945a9SBen Skeggs 384ebb945a9SBen Skeggs nouveau_channel_del(pchan); 385ebb945a9SBen Skeggs return ret; 386ebb945a9SBen Skeggs } 387ebb945a9SBen Skeggs 388ebb945a9SBen Skeggs static int 389ebb945a9SBen Skeggs nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) 390ebb945a9SBen Skeggs { 3910ad72863SBen Skeggs struct nvif_device *device = chan->device; 392d8cc37d8SBen Skeggs struct nouveau_drm *drm = chan->drm; 3934acfd707SBen Skeggs struct nv_dma_v0 args = {}; 394ebb945a9SBen Skeggs int ret, i; 395ebb945a9SBen Skeggs 39601326050SBen Skeggs nvif_object_map(&chan->user, NULL, 0); 3976c6ae061SBen Skeggs 398d8cc37d8SBen Skeggs if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) { 399f7a7d22aSBen Skeggs ret = nvif_notify_ctor(&chan->user, "abi16ChanKilled", 400f7a7d22aSBen Skeggs nouveau_channel_killed, 401d8cc37d8SBen Skeggs true, NV906F_V0_NTFY_KILLED, 402d8cc37d8SBen Skeggs NULL, 0, 0, &chan->kill); 403d8cc37d8SBen Skeggs if (ret == 0) 404d8cc37d8SBen Skeggs ret = nvif_notify_get(&chan->kill); 405d8cc37d8SBen Skeggs if (ret) { 406d8cc37d8SBen Skeggs NV_ERROR(drm, "Failed to request channel kill " 407d8cc37d8SBen Skeggs "notification: %d\n", ret); 408d8cc37d8SBen Skeggs return ret; 409d8cc37d8SBen Skeggs } 410d8cc37d8SBen Skeggs } 411d8cc37d8SBen Skeggs 412ebb945a9SBen Skeggs /* allocate dma objects to cover all allowed vram, and gart */ 413967e7bdeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { 414967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 4154acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 4164acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 417ebb945a9SBen Skeggs args.start = 0; 418bfe91afaSBen Skeggs args.limit = chan->vmm->vmm.limit - 1; 419ebb945a9SBen Skeggs } else { 4204acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VRAM; 4214acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 422ebb945a9SBen Skeggs args.start = 0; 423f392ec4bSBen Skeggs args.limit = device->info.ram_user - 1; 424ebb945a9SBen Skeggs } 425ebb945a9SBen Skeggs 4269ac596a4SBen Skeggs ret = nvif_object_ctor(&chan->user, "abi16ChanVramCtxDma", vram, 4279ac596a4SBen Skeggs NV_DMA_IN_MEMORY, &args, sizeof(args), 4289ac596a4SBen Skeggs &chan->vram); 429ebb945a9SBen Skeggs if (ret) 430ebb945a9SBen Skeggs return ret; 431ebb945a9SBen Skeggs 432967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 4334acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 4344acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 435ebb945a9SBen Skeggs args.start = 0; 436bfe91afaSBen Skeggs args.limit = chan->vmm->vmm.limit - 1; 437ebb945a9SBen Skeggs } else 438340b0e7cSBen Skeggs if (chan->drm->agp.bridge) { 4394acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_AGP; 4404acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 441ebb945a9SBen Skeggs args.start = chan->drm->agp.base; 442ebb945a9SBen Skeggs args.limit = chan->drm->agp.base + 443ebb945a9SBen Skeggs chan->drm->agp.size - 1; 444ebb945a9SBen Skeggs } else { 4454acfd707SBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 4464acfd707SBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 447ebb945a9SBen Skeggs args.start = 0; 448bfe91afaSBen Skeggs args.limit = chan->vmm->vmm.limit - 1; 449ebb945a9SBen Skeggs } 450ebb945a9SBen Skeggs 4519ac596a4SBen Skeggs ret = nvif_object_ctor(&chan->user, "abi16ChanGartCtxDma", gart, 4529ac596a4SBen Skeggs NV_DMA_IN_MEMORY, &args, sizeof(args), 4539ac596a4SBen Skeggs &chan->gart); 454ebb945a9SBen Skeggs if (ret) 455ebb945a9SBen Skeggs return ret; 456ebb945a9SBen Skeggs } 457ebb945a9SBen Skeggs 458ebb945a9SBen Skeggs /* initialise dma tracking parameters */ 459a01ca78cSBen Skeggs switch (chan->user.oclass & 0x00ff) { 460503b0f1cSBen Skeggs case 0x006b: 461ebb945a9SBen Skeggs case 0x006e: 462ebb945a9SBen Skeggs chan->user_put = 0x40; 463ebb945a9SBen Skeggs chan->user_get = 0x44; 464ebb945a9SBen Skeggs chan->dma.max = (0x10000 / 4) - 2; 465ebb945a9SBen Skeggs break; 466ebb945a9SBen Skeggs default: 467ebb945a9SBen Skeggs chan->user_put = 0x40; 468ebb945a9SBen Skeggs chan->user_get = 0x44; 469ebb945a9SBen Skeggs chan->user_get_hi = 0x60; 470ebb945a9SBen Skeggs chan->dma.ib_base = 0x10000 / 4; 471ebb945a9SBen Skeggs chan->dma.ib_max = (0x02000 / 8) - 1; 472ebb945a9SBen Skeggs chan->dma.ib_put = 0; 473ebb945a9SBen Skeggs chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put; 474ebb945a9SBen Skeggs chan->dma.max = chan->dma.ib_base; 475ebb945a9SBen Skeggs break; 476ebb945a9SBen Skeggs } 477ebb945a9SBen Skeggs 478ebb945a9SBen Skeggs chan->dma.put = 0; 479ebb945a9SBen Skeggs chan->dma.cur = chan->dma.put; 480ebb945a9SBen Skeggs chan->dma.free = chan->dma.max - chan->dma.cur; 481ebb945a9SBen Skeggs 482cd346a89SBen Skeggs ret = PUSH_WAIT(chan->chan.push, NOUVEAU_DMA_SKIPS); 483ebb945a9SBen Skeggs if (ret) 484ebb945a9SBen Skeggs return ret; 485ebb945a9SBen Skeggs 486ebb945a9SBen Skeggs for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) 487cd346a89SBen Skeggs PUSH_DATA(chan->chan.push, 0x00000000); 488ebb945a9SBen Skeggs 48969a6146dSBen Skeggs /* allocate software object class (used for fences on <= nv05) */ 490967e7bdeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { 4919ac596a4SBen Skeggs ret = nvif_object_ctor(&chan->user, "abi16NvswFence", 0x006e, 49208f7633cSBen Skeggs NVIF_CLASS_SW_NV04, 4930ad72863SBen Skeggs NULL, 0, &chan->nvsw); 494ebb945a9SBen Skeggs if (ret) 495ebb945a9SBen Skeggs return ret; 496ebb945a9SBen Skeggs 497cd346a89SBen Skeggs ret = PUSH_WAIT(chan->chan.push, 2); 498ebb945a9SBen Skeggs if (ret) 499ebb945a9SBen Skeggs return ret; 500ebb945a9SBen Skeggs 501cd346a89SBen Skeggs PUSH_NVSQ(chan->chan.push, NV_SW, 0x0000, chan->nvsw.handle); 502cd346a89SBen Skeggs PUSH_KICK(chan->chan.push); 503ebb945a9SBen Skeggs } 504ebb945a9SBen Skeggs 505ebb945a9SBen Skeggs /* initialise synchronisation */ 5064894f662SBen Skeggs return nouveau_fence(chan->drm)->context_new(chan); 507ebb945a9SBen Skeggs } 508ebb945a9SBen Skeggs 509ebb945a9SBen Skeggs int 5100ad72863SBen Skeggs nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, 51185532bd9SBen Skeggs u32 arg0, u32 arg1, bool priv, 51285532bd9SBen Skeggs struct nouveau_channel **pchan) 513ebb945a9SBen Skeggs { 514a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)device->object.client; 51567e26e41SBen Skeggs bool super; 516ebb945a9SBen Skeggs int ret; 517ebb945a9SBen Skeggs 51867e26e41SBen Skeggs /* hack until fencenv50 is fixed, and agp access relaxed */ 51967e26e41SBen Skeggs super = cli->base.super; 52067e26e41SBen Skeggs cli->base.super = true; 52167e26e41SBen Skeggs 52285532bd9SBen Skeggs ret = nouveau_channel_ind(drm, device, arg0, priv, pchan); 523ebb945a9SBen Skeggs if (ret) { 5249ad97edeSBen Skeggs NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret); 525fcf3f91cSBen Skeggs ret = nouveau_channel_dma(drm, device, pchan); 526ebb945a9SBen Skeggs if (ret) { 5279ad97edeSBen Skeggs NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret); 52867e26e41SBen Skeggs goto done; 529ebb945a9SBen Skeggs } 530ebb945a9SBen Skeggs } 531ebb945a9SBen Skeggs 53249981046SBen Skeggs ret = nouveau_channel_init(*pchan, arg0, arg1); 533ebb945a9SBen Skeggs if (ret) { 5349ad97edeSBen Skeggs NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret); 535ebb945a9SBen Skeggs nouveau_channel_del(pchan); 536eaba3b28SFrantisek Hrbata goto done; 537ebb945a9SBen Skeggs } 538ebb945a9SBen Skeggs 539eeaf06acSBen Skeggs ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst); 540eeaf06acSBen Skeggs if (ret) 541eeaf06acSBen Skeggs nouveau_channel_del(pchan); 542eeaf06acSBen Skeggs 54367e26e41SBen Skeggs done: 54467e26e41SBen Skeggs cli->base.super = super; 54567e26e41SBen Skeggs return ret; 546ebb945a9SBen Skeggs } 547eb47db4fSBen Skeggs 548eb47db4fSBen Skeggs int 549eb47db4fSBen Skeggs nouveau_channels_init(struct nouveau_drm *drm) 550eb47db4fSBen Skeggs { 551eb47db4fSBen Skeggs struct { 552eb47db4fSBen Skeggs struct nv_device_info_v1 m; 553eb47db4fSBen Skeggs struct { 554eb47db4fSBen Skeggs struct nv_device_info_v1_data channels; 555eb47db4fSBen Skeggs } v; 556eb47db4fSBen Skeggs } args = { 557eb47db4fSBen Skeggs .m.version = 1, 558eb47db4fSBen Skeggs .m.count = sizeof(args.v) / sizeof(args.v.channels), 559f8fabd31SBen Skeggs .v.channels.mthd = NV_DEVICE_HOST_CHANNELS, 560eb47db4fSBen Skeggs }; 561eb47db4fSBen Skeggs struct nvif_object *device = &drm->client.device.object; 562eb47db4fSBen Skeggs int ret; 563eb47db4fSBen Skeggs 564eb47db4fSBen Skeggs ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args)); 565eb47db4fSBen Skeggs if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID) 566eb47db4fSBen Skeggs return -ENODEV; 567eb47db4fSBen Skeggs 568eb47db4fSBen Skeggs drm->chan.nr = args.v.channels.data; 569eb47db4fSBen Skeggs drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr); 570eb47db4fSBen Skeggs return 0; 571eb47db4fSBen Skeggs } 572