diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_chan.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_chan.c | 246 |
1 files changed, 133 insertions, 113 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index ccb6b452d6d0..99cd9e4a2aa6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -22,16 +22,11 @@ * Authors: Ben Skeggs */ -#include <core/object.h> -#include <core/client.h> -#include <core/device.h> -#include <core/class.h> - -#include <subdev/fb.h> -#include <subdev/vm.h> -#include <subdev/instmem.h> +#include <nvif/os.h> +#include <nvif/class.h> -#include <engine/software.h> +/*XXX*/ +#include <core/client.h> #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -47,7 +42,7 @@ module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); int nouveau_channel_idle(struct nouveau_channel *chan) { - struct nouveau_cli *cli = chan->cli; + struct nouveau_cli *cli = (void *)nvif_client(chan->object); struct nouveau_fence *fence = NULL; int ret; @@ -58,8 +53,8 @@ nouveau_channel_idle(struct nouveau_channel *chan) } if (ret) - NV_ERROR(cli, "failed to idle channel 0x%08x [%s]\n", - chan->handle, cli->base.name); + NV_PRINTK(error, cli, "failed to idle channel 0x%08x [%s]\n", + chan->object->handle, nvkm_client(&cli->base)->name); return ret; } @@ -68,36 +63,34 @@ nouveau_channel_del(struct nouveau_channel **pchan) { struct nouveau_channel *chan = *pchan; if (chan) { - struct nouveau_object *client = nv_object(chan->cli); if (chan->fence) { nouveau_channel_idle(chan); nouveau_fence(chan->drm)->context_del(chan); } - nouveau_object_del(client, NVDRM_DEVICE, chan->handle); - nouveau_object_del(client, NVDRM_DEVICE, chan->push.handle); + nvif_object_fini(&chan->nvsw); + nvif_object_fini(&chan->gart); + nvif_object_fini(&chan->vram); + nvif_object_ref(NULL, &chan->object); + nvif_object_fini(&chan->push.ctxdma); nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma); nouveau_bo_unmap(chan->push.buffer); if (chan->push.buffer && chan->push.buffer->pin_refcnt) nouveau_bo_unpin(chan->push.buffer); nouveau_bo_ref(NULL, &chan->push.buffer); + nvif_device_ref(NULL, &chan->device); kfree(chan); } *pchan = NULL; } static int -nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, u32 size, - struct nouveau_channel **pchan) +nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, u32 size, struct nouveau_channel **pchan) { - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_instmem *imem = nouveau_instmem(device); - struct nouveau_vmmgr *vmm = nouveau_vmmgr(device); - struct nouveau_fb *pfb = nouveau_fb(device); - struct nouveau_client *client = &cli->base; - struct nv_dma_class args = {}; + struct nouveau_cli *cli = (void *)nvif_client(&device->base); + struct nouveau_vmmgr *vmm = nvkm_vmmgr(device); + struct nv_dma_v0 args = {}; struct nouveau_channel *chan; - struct nouveau_object *push; u32 target; int ret; @@ -105,9 +98,8 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, if (!chan) return -ENOMEM; - chan->cli = cli; + nvif_device_ref(device, &chan->device); chan->drm = drm; - chan->handle = handle; /* allocate memory for dma push buffer */ target = TTM_PL_FLAG_TT; @@ -132,51 +124,54 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, * we be able to call out to other (indirect) push buffers */ chan->push.vma.offset = chan->push.buffer->bo.offset; - chan->push.handle = NVDRM_PUSH | (handle & 0xffff); - if (device->card_type >= NV_50) { - ret = nouveau_bo_vma_add(chan->push.buffer, client->vm, + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_bo_vma_add(chan->push.buffer, cli->vm, &chan->push.vma); if (ret) { nouveau_channel_del(pchan); return ret; } - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_VM; args.start = 0; - args.limit = client->vm->vmm->limit - 1; + args.limit = cli->vm->vmm->limit - 1; } else if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) { - u64 limit = pfb->ram->size - imem->reserved - 1; - if (device->card_type == NV_04) { + if (device->info.family == NV_DEVICE_INFO_V0_TNT) { /* nv04 vram pushbuf hack, retarget to its location in * the framebuffer bar rather than direct vram access.. * nfi why this exists, it came from the -nv ddx. */ - args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR; - args.start = nv_device_resource_start(device, 1); - args.limit = args.start + limit; + args.target = NV_DMA_V0_TARGET_PCI; + args.access = NV_DMA_V0_ACCESS_RDWR; + args.start = nv_device_resource_start(nvkm_device(device), 1); + args.limit = args.start + device->info.ram_user - 1; } else { - args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VRAM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; - args.limit = limit; + args.limit = device->info.ram_user - 1; } } else { if (chan->drm->agp.stat == ENABLED) { - args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_AGP; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = chan->drm->agp.base; args.limit = chan->drm->agp.base + chan->drm->agp.size - 1; } else { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; args.limit = vmm->limit - 1; } } - ret = nouveau_object_new(nv_object(chan->cli), parent, - chan->push.handle, 0x0002, - &args, sizeof(args), &push); + ret = nvif_object_init(nvif_object(device), NULL, NVDRM_PUSH | + (handle & 0xffff), NV_DMA_FROM_MEMORY, + &args, sizeof(args), &chan->push.ctxdma); if (ret) { nouveau_channel_del(pchan); return ret; @@ -186,38 +181,56 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, } static int -nouveau_channel_ind(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, u32 engine, - struct nouveau_channel **pchan) +nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, u32 engine, struct nouveau_channel **pchan) { - static const u16 oclasses[] = { NVE0_CHANNEL_IND_CLASS, - NVC0_CHANNEL_IND_CLASS, - NV84_CHANNEL_IND_CLASS, - NV50_CHANNEL_IND_CLASS, + static const u16 oclasses[] = { KEPLER_CHANNEL_GPFIFO_A, + FERMI_CHANNEL_GPFIFO, + G82_CHANNEL_GPFIFO, + NV50_CHANNEL_GPFIFO, 0 }; const u16 *oclass = oclasses; - struct nve0_channel_ind_class args; + union { + struct nv50_channel_gpfifo_v0 nv50; + struct kepler_channel_gpfifo_a_v0 kepler; + } args, *retn; struct nouveau_channel *chan; + u32 size; int ret; /* allocate dma push buffer */ - ret = nouveau_channel_prep(drm, cli, parent, handle, 0x12000, &chan); + ret = nouveau_channel_prep(drm, device, handle, 0x12000, &chan); *pchan = chan; if (ret) return ret; /* create channel object */ - args.pushbuf = chan->push.handle; - args.ioffset = 0x10000 + chan->push.vma.offset; - args.ilength = 0x02000; - args.engine = engine; - do { - ret = nouveau_object_new(nv_object(cli), parent, handle, - *oclass++, &args, sizeof(args), - &chan->object); - if (ret == 0) + if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { + args.kepler.version = 0; + args.kepler.engine = engine; + args.kepler.pushbuf = chan->push.ctxdma.handle; + args.kepler.ilength = 0x02000; + args.kepler.ioffset = 0x10000 + chan->push.vma.offset; + size = sizeof(args.kepler); + } else { + args.nv50.version = 0; + args.nv50.pushbuf = chan->push.ctxdma.handle; + args.nv50.ilength = 0x02000; + args.nv50.ioffset = 0x10000 + chan->push.vma.offset; + size = sizeof(args.nv50); + } + + ret = nvif_object_new(nvif_object(device), handle, *oclass++, + &args, size, &chan->object); + if (ret == 0) { + retn = chan->object->data; + if (chan->object->oclass >= KEPLER_CHANNEL_GPFIFO_A) + chan->chid = retn->kepler.chid; + else + chan->chid = retn->nv50.chid; return ret; + } } while (*oclass); nouveau_channel_del(pchan); @@ -225,35 +238,38 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nouveau_cli *cli, } static int -nouveau_channel_dma(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, struct nouveau_channel **pchan) +nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, struct nouveau_channel **pchan) { - static const u16 oclasses[] = { NV40_CHANNEL_DMA_CLASS, - NV17_CHANNEL_DMA_CLASS, - NV10_CHANNEL_DMA_CLASS, - NV03_CHANNEL_DMA_CLASS, + static const u16 oclasses[] = { NV40_CHANNEL_DMA, + NV17_CHANNEL_DMA, + NV10_CHANNEL_DMA, + NV03_CHANNEL_DMA, 0 }; const u16 *oclass = oclasses; - struct nv03_channel_dma_class args; + struct nv03_channel_dma_v0 args, *retn; struct nouveau_channel *chan; int ret; /* allocate dma push buffer */ - ret = nouveau_channel_prep(drm, cli, parent, handle, 0x10000, &chan); + ret = nouveau_channel_prep(drm, device, handle, 0x10000, &chan); *pchan = chan; if (ret) return ret; /* create channel object */ - args.pushbuf = chan->push.handle; + args.version = 0; + args.pushbuf = chan->push.ctxdma.handle; args.offset = chan->push.vma.offset; do { - ret = nouveau_object_new(nv_object(cli), parent, handle, - *oclass++, &args, sizeof(args), - &chan->object); - if (ret == 0) + ret = nvif_object_new(nvif_object(device), handle, *oclass++, + &args, sizeof(args), &chan->object); + if (ret == 0) { + retn = chan->object->data; + chan->chid = retn->chid; return ret; + } } while (ret && *oclass); nouveau_channel_del(pchan); @@ -263,60 +279,63 @@ nouveau_channel_dma(struct nouveau_drm *drm, struct nouveau_cli *cli, static int nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) { - struct nouveau_client *client = nv_client(chan->cli); - struct nouveau_device *device = nv_device(chan->drm->device); - struct nouveau_instmem *imem = nouveau_instmem(device); - struct nouveau_vmmgr *vmm = nouveau_vmmgr(device); - struct nouveau_fb *pfb = nouveau_fb(device); + struct nvif_device *device = chan->device; + struct nouveau_cli *cli = (void *)nvif_client(&device->base); + struct nouveau_vmmgr *vmm = nvkm_vmmgr(device); struct nouveau_software_chan *swch; - struct nouveau_object *object; - struct nv_dma_class args = {}; + struct nv_dma_v0 args = {}; int ret, i; + nvif_object_map(chan->object); + /* allocate dma objects to cover all allowed vram, and gart */ - if (device->card_type < NV_C0) { - if (device->card_type >= NV_50) { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_VM; args.start = 0; - args.limit = client->vm->vmm->limit - 1; + args.limit = cli->vm->vmm->limit - 1; } else { - args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VRAM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; - args.limit = pfb->ram->size - imem->reserved - 1; + args.limit = device->info.ram_user - 1; } - ret = nouveau_object_new(nv_object(client), chan->handle, vram, - 0x003d, &args, sizeof(args), &object); + ret = nvif_object_init(chan->object, NULL, vram, + NV_DMA_IN_MEMORY, &args, + sizeof(args), &chan->vram); if (ret) return ret; - if (device->card_type >= NV_50) { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_VM; args.start = 0; - args.limit = client->vm->vmm->limit - 1; + args.limit = cli->vm->vmm->limit - 1; } else if (chan->drm->agp.stat == ENABLED) { - args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_AGP; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = chan->drm->agp.base; args.limit = chan->drm->agp.base + chan->drm->agp.size - 1; } else { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; args.limit = vmm->limit - 1; } - ret = nouveau_object_new(nv_object(client), chan->handle, gart, - 0x003d, &args, sizeof(args), &object); + ret = nvif_object_init(chan->object, NULL, gart, + NV_DMA_IN_MEMORY, &args, + sizeof(args), &chan->gart); if (ret) return ret; - - chan->vram = vram; - chan->gart = gart; } /* initialise dma tracking parameters */ - switch (nv_hclass(chan->object) & 0x00ff) { + switch (chan->object->oclass & 0x00ff) { case 0x006b: case 0x006e: chan->user_put = 0x40; @@ -347,13 +366,13 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) OUT_RING(chan, 0x00000000); /* allocate software object class (used for fences on <= nv05) */ - if (device->card_type < NV_10) { - ret = nouveau_object_new(nv_object(client), chan->handle, - NvSw, 0x006e, NULL, 0, &object); + if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { + ret = nvif_object_init(chan->object, NULL, 0x006e, 0x006e, + NULL, 0, &chan->nvsw); if (ret) return ret; - swch = (void *)object->parent; + swch = (void *)nvkm_object(&chan->nvsw)->parent; swch->flip = nouveau_flip_complete; swch->flip_data = chan; @@ -362,7 +381,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) return ret; BEGIN_NV04(chan, NvSubSw, 0x0000, 1); - OUT_RING (chan, NvSw); + OUT_RING (chan, chan->nvsw.handle); FIRE_RING (chan); } @@ -371,25 +390,26 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) } int -nouveau_channel_new(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, u32 arg0, u32 arg1, +nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, u32 arg0, u32 arg1, struct nouveau_channel **pchan) { + struct nouveau_cli *cli = (void *)nvif_client(&device->base); int ret; - ret = nouveau_channel_ind(drm, cli, parent, handle, arg0, pchan); + ret = nouveau_channel_ind(drm, device, handle, arg0, pchan); if (ret) { - NV_DEBUG(cli, "ib channel create, %d\n", ret); - ret = nouveau_channel_dma(drm, cli, parent, handle, pchan); + NV_PRINTK(debug, cli, "ib channel create, %d\n", ret); + ret = nouveau_channel_dma(drm, device, handle, pchan); if (ret) { - NV_DEBUG(cli, "dma channel create, %d\n", ret); + NV_PRINTK(debug, cli, "dma channel create, %d\n", ret); return ret; } } ret = nouveau_channel_init(*pchan, arg0, arg1); if (ret) { - NV_ERROR(cli, "channel failed to initialise, %d\n", ret); + NV_PRINTK(error, cli, "channel failed to initialise, %d\n", ret); nouveau_channel_del(pchan); return ret; } |