1 1.7 riastrad /* $NetBSD: nouveau_chan.c,v 1.7 2021/12/18 23:45:32 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2012 Red Hat Inc. 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice shall be included in 14 1.1 riastrad * all copies or substantial portions of the Software. 15 1.1 riastrad * 16 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 1.1 riastrad * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 1.1 riastrad * OTHER DEALINGS IN THE SOFTWARE. 23 1.1 riastrad * 24 1.1 riastrad * Authors: Ben Skeggs 25 1.1 riastrad */ 26 1.1 riastrad 27 1.2 riastrad #include <sys/cdefs.h> 28 1.7 riastrad __KERNEL_RCSID(0, "$NetBSD: nouveau_chan.c,v 1.7 2021/12/18 23:45:32 riastradh Exp $"); 29 1.2 riastrad 30 1.3 riastrad #include <nvif/os.h> 31 1.3 riastrad #include <nvif/class.h> 32 1.7 riastrad #include <nvif/cl0002.h> 33 1.7 riastrad #include <nvif/cl006b.h> 34 1.7 riastrad #include <nvif/cl506f.h> 35 1.7 riastrad #include <nvif/cl906f.h> 36 1.7 riastrad #include <nvif/cla06f.h> 37 1.7 riastrad #include <nvif/clc36f.h> 38 1.3 riastrad #include <nvif/ioctl.h> 39 1.3 riastrad 40 1.3 riastrad /*XXX*/ 41 1.1 riastrad #include <core/client.h> 42 1.1 riastrad 43 1.7 riastrad #include "nouveau_drv.h" 44 1.1 riastrad #include "nouveau_dma.h" 45 1.1 riastrad #include "nouveau_bo.h" 46 1.1 riastrad #include "nouveau_chan.h" 47 1.1 riastrad #include "nouveau_fence.h" 48 1.1 riastrad #include "nouveau_abi16.h" 49 1.7 riastrad #include "nouveau_vmm.h" 50 1.7 riastrad #include "nouveau_svm.h" 51 1.1 riastrad 52 1.1 riastrad MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM"); 53 1.3 riastrad int nouveau_vram_pushbuf; 54 1.1 riastrad module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); 55 1.1 riastrad 56 1.7 riastrad static int 57 1.7 riastrad nouveau_channel_killed(struct nvif_notify *ntfy) 58 1.7 riastrad { 59 1.7 riastrad struct nouveau_channel *chan = container_of(ntfy, typeof(*chan), kill); 60 1.7 riastrad struct nouveau_cli *cli = (void *)chan->user.client; 61 1.7 riastrad NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid); 62 1.7 riastrad atomic_set(&chan->killed, 1); 63 1.7 riastrad if (chan->fence) 64 1.7 riastrad nouveau_fence_context_kill(chan->fence, -ENODEV); 65 1.7 riastrad return NVIF_NOTIFY_DROP; 66 1.7 riastrad } 67 1.7 riastrad 68 1.1 riastrad int 69 1.1 riastrad nouveau_channel_idle(struct nouveau_channel *chan) 70 1.1 riastrad { 71 1.7 riastrad if (likely(chan && chan->fence && !atomic_read(&chan->killed))) { 72 1.3 riastrad struct nouveau_cli *cli = (void *)chan->user.client; 73 1.3 riastrad struct nouveau_fence *fence = NULL; 74 1.3 riastrad int ret; 75 1.3 riastrad 76 1.3 riastrad ret = nouveau_fence_new(chan, false, &fence); 77 1.3 riastrad if (!ret) { 78 1.3 riastrad ret = nouveau_fence_wait(fence, false, false); 79 1.3 riastrad nouveau_fence_unref(&fence); 80 1.3 riastrad } 81 1.1 riastrad 82 1.3 riastrad if (ret) { 83 1.3 riastrad NV_PRINTK(err, cli, "failed to idle channel %d [%s]\n", 84 1.3 riastrad chan->chid, nvxx_client(&cli->base)->name); 85 1.3 riastrad return ret; 86 1.3 riastrad } 87 1.1 riastrad } 88 1.3 riastrad return 0; 89 1.1 riastrad } 90 1.1 riastrad 91 1.1 riastrad void 92 1.1 riastrad nouveau_channel_del(struct nouveau_channel **pchan) 93 1.1 riastrad { 94 1.1 riastrad struct nouveau_channel *chan = *pchan; 95 1.1 riastrad if (chan) { 96 1.7 riastrad struct nouveau_cli *cli = (void *)chan->user.client; 97 1.7 riastrad bool super; 98 1.7 riastrad 99 1.7 riastrad if (cli) { 100 1.7 riastrad super = cli->base.super; 101 1.7 riastrad cli->base.super = true; 102 1.7 riastrad } 103 1.7 riastrad 104 1.3 riastrad if (chan->fence) 105 1.1 riastrad nouveau_fence(chan->drm)->context_del(chan); 106 1.7 riastrad 107 1.7 riastrad if (cli) 108 1.7 riastrad nouveau_svmm_part(chan->vmm->svmm, chan->inst); 109 1.7 riastrad 110 1.3 riastrad nvif_object_fini(&chan->nvsw); 111 1.3 riastrad nvif_object_fini(&chan->gart); 112 1.3 riastrad nvif_object_fini(&chan->vram); 113 1.7 riastrad nvif_notify_fini(&chan->kill); 114 1.3 riastrad nvif_object_fini(&chan->user); 115 1.3 riastrad nvif_object_fini(&chan->push.ctxdma); 116 1.7 riastrad nouveau_vma_del(&chan->push.vma); 117 1.1 riastrad nouveau_bo_unmap(chan->push.buffer); 118 1.1 riastrad if (chan->push.buffer && chan->push.buffer->pin_refcnt) 119 1.1 riastrad nouveau_bo_unpin(chan->push.buffer); 120 1.1 riastrad nouveau_bo_ref(NULL, &chan->push.buffer); 121 1.1 riastrad kfree(chan); 122 1.7 riastrad 123 1.7 riastrad if (cli) 124 1.7 riastrad cli->base.super = super; 125 1.1 riastrad } 126 1.1 riastrad *pchan = NULL; 127 1.1 riastrad } 128 1.1 riastrad 129 1.1 riastrad static int 130 1.3 riastrad nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, 131 1.3 riastrad u32 size, struct nouveau_channel **pchan) 132 1.1 riastrad { 133 1.3 riastrad struct nouveau_cli *cli = (void *)device->object.client; 134 1.6 riastrad struct nv_dma_v0 args = {}; 135 1.1 riastrad struct nouveau_channel *chan; 136 1.1 riastrad u32 target; 137 1.1 riastrad int ret; 138 1.1 riastrad 139 1.1 riastrad chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL); 140 1.1 riastrad if (!chan) 141 1.1 riastrad return -ENOMEM; 142 1.1 riastrad 143 1.3 riastrad chan->device = device; 144 1.1 riastrad chan->drm = drm; 145 1.7 riastrad chan->vmm = cli->svm.cli ? &cli->svm : &cli->vmm; 146 1.7 riastrad atomic_set(&chan->killed, 0); 147 1.1 riastrad 148 1.1 riastrad /* allocate memory for dma push buffer */ 149 1.3 riastrad target = TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED; 150 1.1 riastrad if (nouveau_vram_pushbuf) 151 1.1 riastrad target = TTM_PL_FLAG_VRAM; 152 1.1 riastrad 153 1.7 riastrad ret = nouveau_bo_new(cli, size, 0, target, 0, 0, NULL, NULL, 154 1.1 riastrad &chan->push.buffer); 155 1.1 riastrad if (ret == 0) { 156 1.3 riastrad ret = nouveau_bo_pin(chan->push.buffer, target, false); 157 1.1 riastrad if (ret == 0) 158 1.1 riastrad ret = nouveau_bo_map(chan->push.buffer); 159 1.1 riastrad } 160 1.1 riastrad 161 1.1 riastrad if (ret) { 162 1.1 riastrad nouveau_channel_del(pchan); 163 1.1 riastrad return ret; 164 1.1 riastrad } 165 1.1 riastrad 166 1.1 riastrad /* create dma object covering the *entire* memory space that the 167 1.1 riastrad * pushbuf lives in, this is because the GEM code requires that 168 1.1 riastrad * we be able to call out to other (indirect) push buffers 169 1.1 riastrad */ 170 1.7 riastrad chan->push.addr = chan->push.buffer->bo.offset; 171 1.1 riastrad 172 1.3 riastrad if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 173 1.7 riastrad ret = nouveau_vma_new(chan->push.buffer, chan->vmm, 174 1.7 riastrad &chan->push.vma); 175 1.1 riastrad if (ret) { 176 1.1 riastrad nouveau_channel_del(pchan); 177 1.1 riastrad return ret; 178 1.1 riastrad } 179 1.1 riastrad 180 1.7 riastrad chan->push.addr = chan->push.vma->addr; 181 1.7 riastrad 182 1.7 riastrad if (device->info.family >= NV_DEVICE_INFO_V0_FERMI) 183 1.7 riastrad return 0; 184 1.7 riastrad 185 1.3 riastrad args.target = NV_DMA_V0_TARGET_VM; 186 1.3 riastrad args.access = NV_DMA_V0_ACCESS_VM; 187 1.1 riastrad args.start = 0; 188 1.7 riastrad args.limit = chan->vmm->vmm.limit - 1; 189 1.1 riastrad } else 190 1.1 riastrad if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) { 191 1.3 riastrad if (device->info.family == NV_DEVICE_INFO_V0_TNT) { 192 1.1 riastrad /* nv04 vram pushbuf hack, retarget to its location in 193 1.1 riastrad * the framebuffer bar rather than direct vram access.. 194 1.1 riastrad * nfi why this exists, it came from the -nv ddx. 195 1.1 riastrad */ 196 1.3 riastrad args.target = NV_DMA_V0_TARGET_PCI; 197 1.3 riastrad args.access = NV_DMA_V0_ACCESS_RDWR; 198 1.3 riastrad args.start = nvxx_device(device)->func-> 199 1.3 riastrad resource_addr(nvxx_device(device), 1); 200 1.3 riastrad args.limit = args.start + device->info.ram_user - 1; 201 1.1 riastrad } else { 202 1.3 riastrad args.target = NV_DMA_V0_TARGET_VRAM; 203 1.3 riastrad args.access = NV_DMA_V0_ACCESS_RDWR; 204 1.1 riastrad args.start = 0; 205 1.3 riastrad args.limit = device->info.ram_user - 1; 206 1.1 riastrad } 207 1.1 riastrad } else { 208 1.3 riastrad if (chan->drm->agp.bridge) { 209 1.3 riastrad args.target = NV_DMA_V0_TARGET_AGP; 210 1.3 riastrad args.access = NV_DMA_V0_ACCESS_RDWR; 211 1.1 riastrad args.start = chan->drm->agp.base; 212 1.1 riastrad args.limit = chan->drm->agp.base + 213 1.1 riastrad chan->drm->agp.size - 1; 214 1.1 riastrad } else { 215 1.3 riastrad args.target = NV_DMA_V0_TARGET_VM; 216 1.3 riastrad args.access = NV_DMA_V0_ACCESS_RDWR; 217 1.1 riastrad args.start = 0; 218 1.7 riastrad args.limit = chan->vmm->vmm.limit - 1; 219 1.1 riastrad } 220 1.1 riastrad } 221 1.1 riastrad 222 1.3 riastrad ret = nvif_object_init(&device->object, 0, NV_DMA_FROM_MEMORY, 223 1.3 riastrad &args, sizeof(args), &chan->push.ctxdma); 224 1.1 riastrad if (ret) { 225 1.1 riastrad nouveau_channel_del(pchan); 226 1.1 riastrad return ret; 227 1.1 riastrad } 228 1.1 riastrad 229 1.1 riastrad return 0; 230 1.1 riastrad } 231 1.1 riastrad 232 1.1 riastrad static int 233 1.3 riastrad nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, 234 1.7 riastrad u64 runlist, bool priv, struct nouveau_channel **pchan) 235 1.1 riastrad { 236 1.7 riastrad static const u16 oclasses[] = { TURING_CHANNEL_GPFIFO_A, 237 1.7 riastrad VOLTA_CHANNEL_GPFIFO_A, 238 1.7 riastrad PASCAL_CHANNEL_GPFIFO_A, 239 1.7 riastrad MAXWELL_CHANNEL_GPFIFO_A, 240 1.7 riastrad KEPLER_CHANNEL_GPFIFO_B, 241 1.3 riastrad KEPLER_CHANNEL_GPFIFO_A, 242 1.3 riastrad FERMI_CHANNEL_GPFIFO, 243 1.3 riastrad G82_CHANNEL_GPFIFO, 244 1.3 riastrad NV50_CHANNEL_GPFIFO, 245 1.1 riastrad 0 }; 246 1.1 riastrad const u16 *oclass = oclasses; 247 1.3 riastrad union { 248 1.3 riastrad struct nv50_channel_gpfifo_v0 nv50; 249 1.3 riastrad struct fermi_channel_gpfifo_v0 fermi; 250 1.3 riastrad struct kepler_channel_gpfifo_a_v0 kepler; 251 1.7 riastrad struct volta_channel_gpfifo_a_v0 volta; 252 1.3 riastrad } args; 253 1.1 riastrad struct nouveau_channel *chan; 254 1.3 riastrad u32 size; 255 1.1 riastrad int ret; 256 1.1 riastrad 257 1.1 riastrad /* allocate dma push buffer */ 258 1.3 riastrad ret = nouveau_channel_prep(drm, device, 0x12000, &chan); 259 1.1 riastrad *pchan = chan; 260 1.1 riastrad if (ret) 261 1.1 riastrad return ret; 262 1.1 riastrad 263 1.1 riastrad /* create channel object */ 264 1.3 riastrad do { 265 1.7 riastrad if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) { 266 1.7 riastrad args.volta.version = 0; 267 1.7 riastrad args.volta.ilength = 0x02000; 268 1.7 riastrad args.volta.ioffset = 0x10000 + chan->push.addr; 269 1.7 riastrad args.volta.runlist = runlist; 270 1.7 riastrad args.volta.vmm = nvif_handle(&chan->vmm->vmm.object); 271 1.7 riastrad args.volta.priv = priv; 272 1.7 riastrad size = sizeof(args.volta); 273 1.7 riastrad } else 274 1.3 riastrad if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { 275 1.3 riastrad args.kepler.version = 0; 276 1.3 riastrad args.kepler.ilength = 0x02000; 277 1.7 riastrad args.kepler.ioffset = 0x10000 + chan->push.addr; 278 1.7 riastrad args.kepler.runlist = runlist; 279 1.7 riastrad args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object); 280 1.7 riastrad args.kepler.priv = priv; 281 1.3 riastrad size = sizeof(args.kepler); 282 1.3 riastrad } else 283 1.3 riastrad if (oclass[0] >= FERMI_CHANNEL_GPFIFO) { 284 1.3 riastrad args.fermi.version = 0; 285 1.3 riastrad args.fermi.ilength = 0x02000; 286 1.7 riastrad args.fermi.ioffset = 0x10000 + chan->push.addr; 287 1.7 riastrad args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object); 288 1.3 riastrad size = sizeof(args.fermi); 289 1.3 riastrad } else { 290 1.3 riastrad args.nv50.version = 0; 291 1.3 riastrad args.nv50.ilength = 0x02000; 292 1.7 riastrad args.nv50.ioffset = 0x10000 + chan->push.addr; 293 1.3 riastrad args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma); 294 1.7 riastrad args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object); 295 1.3 riastrad size = sizeof(args.nv50); 296 1.3 riastrad } 297 1.1 riastrad 298 1.3 riastrad ret = nvif_object_init(&device->object, 0, *oclass++, 299 1.3 riastrad &args, size, &chan->user); 300 1.3 riastrad if (ret == 0) { 301 1.7 riastrad if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) { 302 1.7 riastrad chan->chid = args.volta.chid; 303 1.7 riastrad chan->inst = args.volta.inst; 304 1.7 riastrad chan->token = args.volta.token; 305 1.7 riastrad } else 306 1.7 riastrad if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) { 307 1.3 riastrad chan->chid = args.kepler.chid; 308 1.7 riastrad chan->inst = args.kepler.inst; 309 1.7 riastrad } else 310 1.7 riastrad if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) { 311 1.3 riastrad chan->chid = args.fermi.chid; 312 1.7 riastrad } else { 313 1.3 riastrad chan->chid = args.nv50.chid; 314 1.7 riastrad } 315 1.1 riastrad return ret; 316 1.3 riastrad } 317 1.1 riastrad } while (*oclass); 318 1.1 riastrad 319 1.1 riastrad nouveau_channel_del(pchan); 320 1.1 riastrad return ret; 321 1.1 riastrad } 322 1.1 riastrad 323 1.1 riastrad static int 324 1.3 riastrad nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, 325 1.3 riastrad struct nouveau_channel **pchan) 326 1.1 riastrad { 327 1.3 riastrad static const u16 oclasses[] = { NV40_CHANNEL_DMA, 328 1.3 riastrad NV17_CHANNEL_DMA, 329 1.3 riastrad NV10_CHANNEL_DMA, 330 1.3 riastrad NV03_CHANNEL_DMA, 331 1.1 riastrad 0 }; 332 1.1 riastrad const u16 *oclass = oclasses; 333 1.3 riastrad struct nv03_channel_dma_v0 args; 334 1.1 riastrad struct nouveau_channel *chan; 335 1.1 riastrad int ret; 336 1.1 riastrad 337 1.1 riastrad /* allocate dma push buffer */ 338 1.3 riastrad ret = nouveau_channel_prep(drm, device, 0x10000, &chan); 339 1.1 riastrad *pchan = chan; 340 1.1 riastrad if (ret) 341 1.1 riastrad return ret; 342 1.1 riastrad 343 1.1 riastrad /* create channel object */ 344 1.3 riastrad args.version = 0; 345 1.3 riastrad args.pushbuf = nvif_handle(&chan->push.ctxdma); 346 1.7 riastrad args.offset = chan->push.addr; 347 1.1 riastrad 348 1.1 riastrad do { 349 1.3 riastrad ret = nvif_object_init(&device->object, 0, *oclass++, 350 1.3 riastrad &args, sizeof(args), &chan->user); 351 1.3 riastrad if (ret == 0) { 352 1.3 riastrad chan->chid = args.chid; 353 1.1 riastrad return ret; 354 1.3 riastrad } 355 1.1 riastrad } while (ret && *oclass); 356 1.1 riastrad 357 1.1 riastrad nouveau_channel_del(pchan); 358 1.1 riastrad return ret; 359 1.1 riastrad } 360 1.1 riastrad 361 1.1 riastrad static int 362 1.1 riastrad nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) 363 1.1 riastrad { 364 1.3 riastrad struct nvif_device *device = chan->device; 365 1.7 riastrad struct nouveau_drm *drm = chan->drm; 366 1.6 riastrad struct nv_dma_v0 args = {}; 367 1.1 riastrad int ret, i; 368 1.1 riastrad 369 1.7 riastrad nvif_object_map(&chan->user, NULL, 0); 370 1.7 riastrad 371 1.7 riastrad if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) { 372 1.7 riastrad ret = nvif_notify_init(&chan->user, nouveau_channel_killed, 373 1.7 riastrad true, NV906F_V0_NTFY_KILLED, 374 1.7 riastrad NULL, 0, 0, &chan->kill); 375 1.7 riastrad if (ret == 0) 376 1.7 riastrad ret = nvif_notify_get(&chan->kill); 377 1.7 riastrad if (ret) { 378 1.7 riastrad NV_ERROR(drm, "Failed to request channel kill " 379 1.7 riastrad "notification: %d\n", ret); 380 1.7 riastrad return ret; 381 1.7 riastrad } 382 1.5 riastrad } 383 1.3 riastrad 384 1.1 riastrad /* allocate dma objects to cover all allowed vram, and gart */ 385 1.3 riastrad if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { 386 1.3 riastrad if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 387 1.3 riastrad args.target = NV_DMA_V0_TARGET_VM; 388 1.3 riastrad args.access = NV_DMA_V0_ACCESS_VM; 389 1.1 riastrad args.start = 0; 390 1.7 riastrad args.limit = chan->vmm->vmm.limit - 1; 391 1.1 riastrad } else { 392 1.3 riastrad args.target = NV_DMA_V0_TARGET_VRAM; 393 1.3 riastrad args.access = NV_DMA_V0_ACCESS_RDWR; 394 1.1 riastrad args.start = 0; 395 1.3 riastrad args.limit = device->info.ram_user - 1; 396 1.1 riastrad } 397 1.1 riastrad 398 1.3 riastrad ret = nvif_object_init(&chan->user, vram, NV_DMA_IN_MEMORY, 399 1.3 riastrad &args, sizeof(args), &chan->vram); 400 1.1 riastrad if (ret) 401 1.1 riastrad return ret; 402 1.1 riastrad 403 1.3 riastrad if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 404 1.3 riastrad args.target = NV_DMA_V0_TARGET_VM; 405 1.3 riastrad args.access = NV_DMA_V0_ACCESS_VM; 406 1.1 riastrad args.start = 0; 407 1.7 riastrad args.limit = chan->vmm->vmm.limit - 1; 408 1.1 riastrad } else 409 1.3 riastrad if (chan->drm->agp.bridge) { 410 1.3 riastrad args.target = NV_DMA_V0_TARGET_AGP; 411 1.3 riastrad args.access = NV_DMA_V0_ACCESS_RDWR; 412 1.1 riastrad args.start = chan->drm->agp.base; 413 1.1 riastrad args.limit = chan->drm->agp.base + 414 1.1 riastrad chan->drm->agp.size - 1; 415 1.1 riastrad } else { 416 1.3 riastrad args.target = NV_DMA_V0_TARGET_VM; 417 1.3 riastrad args.access = NV_DMA_V0_ACCESS_RDWR; 418 1.1 riastrad args.start = 0; 419 1.7 riastrad args.limit = chan->vmm->vmm.limit - 1; 420 1.1 riastrad } 421 1.1 riastrad 422 1.3 riastrad ret = nvif_object_init(&chan->user, gart, NV_DMA_IN_MEMORY, 423 1.3 riastrad &args, sizeof(args), &chan->gart); 424 1.1 riastrad if (ret) 425 1.1 riastrad return ret; 426 1.1 riastrad } 427 1.1 riastrad 428 1.1 riastrad /* initialise dma tracking parameters */ 429 1.3 riastrad switch (chan->user.oclass & 0x00ff) { 430 1.1 riastrad case 0x006b: 431 1.1 riastrad case 0x006e: 432 1.1 riastrad chan->user_put = 0x40; 433 1.1 riastrad chan->user_get = 0x44; 434 1.1 riastrad chan->dma.max = (0x10000 / 4) - 2; 435 1.1 riastrad break; 436 1.1 riastrad default: 437 1.1 riastrad chan->user_put = 0x40; 438 1.1 riastrad chan->user_get = 0x44; 439 1.1 riastrad chan->user_get_hi = 0x60; 440 1.1 riastrad chan->dma.ib_base = 0x10000 / 4; 441 1.1 riastrad chan->dma.ib_max = (0x02000 / 8) - 1; 442 1.1 riastrad chan->dma.ib_put = 0; 443 1.1 riastrad chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put; 444 1.1 riastrad chan->dma.max = chan->dma.ib_base; 445 1.1 riastrad break; 446 1.1 riastrad } 447 1.1 riastrad 448 1.1 riastrad chan->dma.put = 0; 449 1.1 riastrad chan->dma.cur = chan->dma.put; 450 1.1 riastrad chan->dma.free = chan->dma.max - chan->dma.cur; 451 1.1 riastrad 452 1.1 riastrad ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); 453 1.1 riastrad if (ret) 454 1.1 riastrad return ret; 455 1.1 riastrad 456 1.1 riastrad for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) 457 1.1 riastrad OUT_RING(chan, 0x00000000); 458 1.1 riastrad 459 1.1 riastrad /* allocate software object class (used for fences on <= nv05) */ 460 1.3 riastrad if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { 461 1.3 riastrad ret = nvif_object_init(&chan->user, 0x006e, 462 1.7 riastrad NVIF_CLASS_SW_NV04, 463 1.3 riastrad NULL, 0, &chan->nvsw); 464 1.1 riastrad if (ret) 465 1.1 riastrad return ret; 466 1.1 riastrad 467 1.1 riastrad ret = RING_SPACE(chan, 2); 468 1.1 riastrad if (ret) 469 1.1 riastrad return ret; 470 1.1 riastrad 471 1.1 riastrad BEGIN_NV04(chan, NvSubSw, 0x0000, 1); 472 1.3 riastrad OUT_RING (chan, chan->nvsw.handle); 473 1.1 riastrad FIRE_RING (chan); 474 1.1 riastrad } 475 1.1 riastrad 476 1.1 riastrad /* initialise synchronisation */ 477 1.1 riastrad return nouveau_fence(chan->drm)->context_new(chan); 478 1.1 riastrad } 479 1.1 riastrad 480 1.1 riastrad int 481 1.3 riastrad nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, 482 1.7 riastrad u32 arg0, u32 arg1, bool priv, 483 1.7 riastrad struct nouveau_channel **pchan) 484 1.1 riastrad { 485 1.3 riastrad struct nouveau_cli *cli = (void *)device->object.client; 486 1.3 riastrad bool super; 487 1.1 riastrad int ret; 488 1.1 riastrad 489 1.3 riastrad /* hack until fencenv50 is fixed, and agp access relaxed */ 490 1.3 riastrad super = cli->base.super; 491 1.3 riastrad cli->base.super = true; 492 1.3 riastrad 493 1.7 riastrad ret = nouveau_channel_ind(drm, device, arg0, priv, pchan); 494 1.1 riastrad if (ret) { 495 1.3 riastrad NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret); 496 1.3 riastrad ret = nouveau_channel_dma(drm, device, pchan); 497 1.1 riastrad if (ret) { 498 1.3 riastrad NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret); 499 1.3 riastrad goto done; 500 1.1 riastrad } 501 1.1 riastrad } 502 1.1 riastrad 503 1.1 riastrad ret = nouveau_channel_init(*pchan, arg0, arg1); 504 1.1 riastrad if (ret) { 505 1.3 riastrad NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret); 506 1.1 riastrad nouveau_channel_del(pchan); 507 1.1 riastrad } 508 1.1 riastrad 509 1.7 riastrad ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst); 510 1.7 riastrad if (ret) 511 1.7 riastrad nouveau_channel_del(pchan); 512 1.7 riastrad 513 1.3 riastrad done: 514 1.3 riastrad cli->base.super = super; 515 1.3 riastrad return ret; 516 1.1 riastrad } 517 1.7 riastrad 518 1.7 riastrad int 519 1.7 riastrad nouveau_channels_init(struct nouveau_drm *drm) 520 1.7 riastrad { 521 1.7 riastrad struct { 522 1.7 riastrad struct nv_device_info_v1 m; 523 1.7 riastrad struct { 524 1.7 riastrad struct nv_device_info_v1_data channels; 525 1.7 riastrad } v; 526 1.7 riastrad } args = { 527 1.7 riastrad .m.version = 1, 528 1.7 riastrad .m.count = sizeof(args.v) / sizeof(args.v.channels), 529 1.7 riastrad .v.channels.mthd = NV_DEVICE_FIFO_CHANNELS, 530 1.7 riastrad }; 531 1.7 riastrad struct nvif_object *device = &drm->client.device.object; 532 1.7 riastrad int ret; 533 1.7 riastrad 534 1.7 riastrad ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args)); 535 1.7 riastrad if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID) 536 1.7 riastrad return -ENODEV; 537 1.7 riastrad 538 1.7 riastrad drm->chan.nr = args.v.channels.data; 539 1.7 riastrad drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr); 540 1.7 riastrad return 0; 541 1.7 riastrad } 542