From 02a841d434513c7b3620250271c372fabce56de5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Jul 2012 23:44:54 +1000 Subject: drm/nouveau: restructure source tree, split core from drm implementation Future work will be headed in the way of separating the policy supplied by the nouveau drm module from the mechanisms provided by the driver core. There will be a couple of major classes (subdev, engine) of driver modules that have clearly defined tasks, and the further directory structure change is to reflect this. No code changes here whatsoever, aside from fixing up a couple of include file pathnames. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_abi16.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 3ca240b..1b9db80 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -26,7 +26,7 @@ #include "nouveau_drv.h" #include "nouveau_dma.h" #include "nouveau_abi16.h" -#include "nouveau_ramht.h" +#include #include "nouveau_software.h" int -- cgit v1.1 From 5a5c7432bbbd2e318dff107b4ff960ab543a7cef Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Jul 2012 16:08:25 +1000 Subject: drm/nouveau/timer: port to subdev interfaces Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_abi16.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 1b9db80..9b3a461 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -64,7 +64,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = 0; /* deprecated */ break; case NOUVEAU_GETPARAM_PTIMER_TIME: - getparam->value = dev_priv->engine.timer.read(dev); + getparam->value = nv_timer_read(dev); break; case NOUVEAU_GETPARAM_HAS_BO_USAGE: getparam->value = 1; -- cgit v1.1 From ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 20 Jul 2012 08:17:34 +1000 Subject: drm/nouveau: port all engines to new engine module format This is a HUGE commit, but it's not nearly as bad as it looks - any problems can be isolated to a particular chipset and engine combination. It was simply too difficult to port each one at a time, the compat layers are *already* ridiculous. Most of the changes here are simply to the glue, the process for each of the engine modules was to start with a standard skeleton and copy+paste the old code into the appropriate places, fixing up variable names etc as needed. v2: Marcin Slusarz - fix find/replace bug in license header v3: Ben Skeggs - bump indirect pushbuf size to 8KiB, 4KiB barely enough for userspace and left no space for kernel's requirements during GEM pushbuf submission. - fix duplicate assignments noticed by clang v4: Marcin Slusarz - add sparse annotations to nv04_fifo_pause/nv04_fifo_start - use ioread32_native/iowrite32_native for fifo control registers v5: Ben Skeggs - rebase on v3.6-rc4, modified to keep copy engine fix intact - nv10/fence: unmap fence bo before destroying - fixed fermi regression when using nvidia gr fuc - fixed typo in supported dma_mask checking Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 421 ++++++++++++++++++++++++-------- 1 file changed, 325 insertions(+), 96 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_abi16.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 9b3a461..9e6ced3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -21,23 +21,153 @@ * */ -#include "drmP.h" +#include +#include +#include +#include +#include -#include "nouveau_drv.h" +#include +#include +#include + +#include "nouveau_drm.h" #include "nouveau_dma.h" +#include "nouveau_gem.h" +#include "nouveau_chan.h" #include "nouveau_abi16.h" -#include -#include "nouveau_software.h" + +struct nouveau_abi16 * +nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) +{ + struct nouveau_cli *cli = nouveau_cli(file_priv); + mutex_lock(&cli->mutex); + if (!cli->abi16) { + struct nouveau_abi16 *abi16; + cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL); + if (cli->abi16) { + INIT_LIST_HEAD(&abi16->channels); + abi16->client = nv_object(cli); + + /* allocate device object targeting client's default + * device (ie. the one that belongs to the fd it + * opened) + */ + if (nouveau_object_new(abi16->client, NVDRM_CLIENT, + NVDRM_DEVICE, 0x0080, + &(struct nv_device_class) { + .device = ~0ULL, + }, + sizeof(struct nv_device_class), + &abi16->device) == 0) + return cli->abi16; + + kfree(cli->abi16); + cli->abi16 = NULL; + } + + mutex_unlock(&cli->mutex); + } + return cli->abi16; +} + +int +nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret) +{ + struct nouveau_cli *cli = (void *)abi16->client; + mutex_unlock(&cli->mutex); + return ret; +} + +u16 +nouveau_abi16_swclass(struct nouveau_drm *drm) +{ + switch (nv_device(drm->device)->card_type) { + case NV_04: + return 0x006e; + case NV_10: + case NV_20: + case NV_30: + case NV_40: + return 0x016e; + case NV_50: + return 0x506e; + case NV_C0: + case NV_D0: + case NV_E0: + return 0x906e; + } + + return 0x0000; +} + +static void +nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan, + struct nouveau_abi16_ntfy *ntfy) +{ + nouveau_mm_free(&chan->heap, &ntfy->node); + list_del(&ntfy->head); + kfree(ntfy); +} + +static void +nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, + struct nouveau_abi16_chan *chan) +{ + struct nouveau_abi16_ntfy *ntfy, *temp; + + /* cleanup notifier state */ + list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) { + nouveau_abi16_ntfy_fini(chan, ntfy); + } + + if (chan->ntfy) { + nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma); + drm_gem_object_unreference_unlocked(chan->ntfy->gem); + } + + if (chan->heap.block_size) + nouveau_mm_fini(&chan->heap); + + /* destroy channel object, all children will be killed too */ + if (chan->chan) { + abi16->handles &= ~(1 << (chan->chan->handle & 0xffff)); + nouveau_channel_del(&chan->chan); + } + + list_del(&chan->head); + kfree(chan); +} + +void +nouveau_abi16_fini(struct nouveau_abi16 *abi16) +{ + struct nouveau_cli *cli = (void *)abi16->client; + struct nouveau_abi16_chan *chan, *temp; + + /* cleanup channels */ + list_for_each_entry_safe(chan, temp, &abi16->channels, head) { + nouveau_abi16_chan_fini(abi16, chan); + } + + /* destroy the device object */ + nouveau_object_del(abi16->client, NVDRM_CLIENT, NVDRM_DEVICE); + + kfree(cli->abi16); + cli->abi16 = NULL; +} int nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nv_device(drm->device); + struct nouveau_timer *ptimer = nouveau_timer(device); struct drm_nouveau_getparam *getparam = data; switch (getparam->param) { case NOUVEAU_GETPARAM_CHIPSET_ID: - getparam->value = dev_priv->chipset; + getparam->value = device->chipset; break; case NOUVEAU_GETPARAM_PCI_VENDOR: getparam->value = dev->pci_vendor; @@ -55,16 +185,16 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = 2; break; case NOUVEAU_GETPARAM_FB_SIZE: - getparam->value = dev_priv->fb_available_size; + getparam->value = drm->gem.vram_available; break; case NOUVEAU_GETPARAM_AGP_SIZE: - getparam->value = dev_priv->gart_info.aper_size; + getparam->value = drm->gem.gart_available; break; case NOUVEAU_GETPARAM_VM_VRAM_BASE: getparam->value = 0; /* deprecated */ break; case NOUVEAU_GETPARAM_PTIMER_TIME: - getparam->value = nv_timer_read(dev); + getparam->value = ptimer->read(ptimer); break; case NOUVEAU_GETPARAM_HAS_BO_USAGE: getparam->value = 1; @@ -76,13 +206,13 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) /* NV40 and NV50 versions are quite different, but register * address is the same. User is supposed to know the card * family anyway... */ - if (dev_priv->chipset >= 0x40) { - getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS); + if (device->chipset >= 0x40) { + getparam->value = nv_rd32(device, 0x001540); break; } /* FALLTHRU */ default: - NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param); + nv_debug(device, "unknown parameter %lld\n", getparam->param); return -EINVAL; } @@ -98,148 +228,247 @@ nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS) int nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_channel_alloc *init = data; - struct nouveau_channel *chan; + struct nouveau_cli *cli = nouveau_cli(file_priv); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); + struct nouveau_abi16_chan *chan; + struct nouveau_client *client; + struct nouveau_device *device; + struct nouveau_instmem *imem; + struct nouveau_fb *pfb; int ret; - if (!dev_priv->eng[NVOBJ_ENGINE_GR]) - return -ENODEV; + if (unlikely(!abi16)) + return -ENOMEM; + client = nv_client(abi16->client); if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) - return -EINVAL; + return nouveau_abi16_put(abi16, -EINVAL); + + device = nv_device(abi16->device); + imem = nouveau_instmem(device); + pfb = nouveau_fb(device); + + /* allocate "abi16 channel" data and make up a handle for it */ + init->channel = ffsll(~abi16->handles); + if (!init->channel--) + return nouveau_abi16_put(abi16, -ENOSPC); + + chan = kzalloc(sizeof(*chan), GFP_KERNEL); + if (!chan) + return nouveau_abi16_put(abi16, -ENOMEM); + + INIT_LIST_HEAD(&chan->notifiers); + list_add(&chan->head, &abi16->channels); + abi16->handles |= (1 << init->channel); - ret = nouveau_channel_alloc(dev, &chan, file_priv, - init->fb_ctxdma_handle, - init->tt_ctxdma_handle); + /* create channel object and initialise dma and fence management */ + ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN | + init->channel, init->fb_ctxdma_handle, + init->tt_ctxdma_handle, &chan->chan); if (ret) - return ret; - init->channel = chan->id; - - if (nouveau_vram_pushbuf == 0) { - if (chan->dma.ib_max) - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | - NOUVEAU_GEM_DOMAIN_GART; - else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; - else - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; - } else { + goto done; + + if (device->card_type >= NV_50) + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | + NOUVEAU_GEM_DOMAIN_GART; + else + if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; - } + else + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; - if (dev_priv->card_type < NV_C0) { + if (device->card_type < NV_C0) { init->subchan[0].handle = 0x00000000; init->subchan[0].grclass = 0x0000; init->subchan[1].handle = NvSw; - init->subchan[1].grclass = NV_SW; + init->subchan[1].grclass = 0x506e; init->nr_subchan = 2; } /* Named memory object area */ - ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem, + ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART, + 0, 0, &chan->ntfy); + if (ret == 0) + ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT); + if (ret) + goto done; + + if (device->card_type >= NV_50) { + ret = nouveau_bo_vma_add(chan->ntfy, client->vm, + &chan->ntfy_vma); + if (ret) + goto done; + } + + ret = drm_gem_handle_create(file_priv, chan->ntfy->gem, &init->notifier_handle); + if (ret) + goto done; - if (ret == 0) - atomic_inc(&chan->users); /* userspace reference */ - nouveau_channel_put(&chan); - return ret; + ret = nouveau_mm_init(&chan->heap, 0, PAGE_SIZE, 1); +done: + if (ret) + nouveau_abi16_chan_fini(abi16, chan); + return nouveau_abi16_put(abi16, ret); } + int nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS) { struct drm_nouveau_channel_free *req = data; - struct nouveau_channel *chan; + struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); + struct nouveau_abi16_chan *chan; + int ret = -ENOENT; - chan = nouveau_channel_get(file_priv, req->channel); - if (IS_ERR(chan)) - return PTR_ERR(chan); + if (unlikely(!abi16)) + return -ENOMEM; - list_del(&chan->list); - atomic_dec(&chan->users); - nouveau_channel_put(&chan); - return 0; + list_for_each_entry(chan, &abi16->channels, head) { + if (chan->chan->handle == (NVDRM_CHAN | req->channel)) { + nouveau_abi16_chan_fini(abi16, chan); + return nouveau_abi16_put(abi16, 0); + } + } + + return nouveau_abi16_put(abi16, ret); } int nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) { struct drm_nouveau_grobj_alloc *init = data; - struct nouveau_channel *chan; + struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_object *object; int ret; + if (unlikely(!abi16)) + return -ENOMEM; + if (init->handle == ~0) - return -EINVAL; + return nouveau_abi16_put(abi16, -EINVAL); /* compatibility with userspace that assumes 506e for all chipsets */ if (init->class == 0x506e) { - init->class = nouveau_software_class(dev); + init->class = nouveau_abi16_swclass(drm); if (init->class == 0x906e) - return 0; - } else - if (init->class == 0x906e) { - NV_DEBUG(dev, "906e not supported yet\n"); - return -EINVAL; - } - - chan = nouveau_channel_get(file_priv, init->channel); - if (IS_ERR(chan)) - return PTR_ERR(chan); - - if (nouveau_ramht_find(chan, init->handle)) { - ret = -EEXIST; - goto out; + return nouveau_abi16_put(abi16, 0); } - ret = nouveau_gpuobj_gr_new(chan, init->handle, init->class); - if (ret) { - NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n", - ret, init->channel, init->handle); - } - -out: - nouveau_channel_put(&chan); - return ret; + ret = nouveau_object_new(abi16->client, NVDRM_CHAN | init->channel, + init->handle, init->class, NULL, 0, &object); + return nouveau_abi16_put(abi16, ret); } int nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_nouveau_notifierobj_alloc *na = data; - struct nouveau_channel *chan; + struct drm_nouveau_notifierobj_alloc *info = data; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nv_device(drm->device); + struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); + struct nouveau_abi16_chan *chan, *temp; + struct nouveau_abi16_ntfy *ntfy; + struct nouveau_object *object; + struct nv_dma_class args; int ret; + if (unlikely(!abi16)) + return -ENOMEM; + /* completely unnecessary for these chipsets... */ - if (unlikely(dev_priv->card_type >= NV_C0)) - return -EINVAL; + if (unlikely(nv_device(abi16->device)->card_type >= NV_C0)) + return nouveau_abi16_put(abi16, -EINVAL); - chan = nouveau_channel_get(file_priv, na->channel); - if (IS_ERR(chan)) - return PTR_ERR(chan); + list_for_each_entry_safe(chan, temp, &abi16->channels, head) { + if (chan->chan->handle == (NVDRM_CHAN | info->channel)) + break; + chan = NULL; + } - ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000, - &na->offset); - nouveau_channel_put(&chan); - return ret; + if (!chan) + return nouveau_abi16_put(abi16, -ENOENT); + + ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL); + if (!ntfy) + return nouveau_abi16_put(abi16, -ENOMEM); + + list_add(&ntfy->head, &chan->notifiers); + ntfy->handle = info->handle; + + ret = nouveau_mm_head(&chan->heap, 1, info->size, info->size, 1, + &ntfy->node); + if (ret) + goto done; + + args.start = ntfy->node->offset; + args.limit = ntfy->node->offset + ntfy->node->length - 1; + if (device->card_type >= NV_50) { + args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; + args.start += chan->ntfy_vma.offset; + args.limit += chan->ntfy_vma.offset; + } else + if (drm->agp.stat == ENABLED) { + args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR; + args.start += drm->agp.base + chan->ntfy->bo.offset; + args.limit += drm->agp.base + chan->ntfy->bo.offset; + } else { + args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR; + args.start += chan->ntfy->bo.offset; + args.limit += chan->ntfy->bo.offset; + } + + ret = nouveau_object_new(abi16->client, chan->chan->handle, + ntfy->handle, 0x003d, &args, + sizeof(args), &object); + if (ret) + goto done; + +done: + if (ret) + nouveau_abi16_ntfy_fini(chan, ntfy); + return nouveau_abi16_put(abi16, ret); } int nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS) { - struct drm_nouveau_gpuobj_free *objfree = data; - struct nouveau_channel *chan; + struct drm_nouveau_gpuobj_free *fini = data; + struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); + struct nouveau_abi16_chan *chan, *temp; + struct nouveau_abi16_ntfy *ntfy; int ret; - chan = nouveau_channel_get(file_priv, objfree->channel); - if (IS_ERR(chan)) - return PTR_ERR(chan); + if (unlikely(!abi16)) + return -ENOMEM; + + list_for_each_entry_safe(chan, temp, &abi16->channels, head) { + if (chan->chan->handle == (NVDRM_CHAN | fini->channel)) + break; + chan = NULL; + } + + if (!chan) + return nouveau_abi16_put(abi16, -ENOENT); - /* Synchronize with the user channel */ - nouveau_channel_idle(chan); + /* synchronize with the user channel and destroy the gpu object */ + nouveau_channel_idle(chan->chan); - ret = nouveau_ramht_remove(chan, objfree->handle); - nouveau_channel_put(&chan); - return ret; + ret = nouveau_object_del(abi16->client, chan->chan->handle, fini->handle); + if (ret) + return nouveau_abi16_put(abi16, ret); + + /* cleanup extra state if this object was a notifier */ + list_for_each_entry(ntfy, &chan->notifiers, head) { + if (ntfy->handle == fini->handle) { + nouveau_mm_free(&chan->heap, &ntfy->node); + list_del(&ntfy->head); + break; + } + } + + return nouveau_abi16_put(abi16, 0); } -- cgit v1.1 From 49981046e3dc2f934663548a270d4bf1a4534bb9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 Aug 2012 19:38:25 +1000 Subject: drm/nve0: use async copy engine for ttm buffer moves if available Kepler PFIFO lost the ability to address multiple engines from a single channel, so we need a separate one for the copy engine. v2: Marcin Slusarz - regression fix: restore hw accelerated buffer copies Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/nouveau/nouveau_abi16.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 9e6ced3..cc79c79 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -264,6 +264,11 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) abi16->handles |= (1 << init->channel); /* create channel object and initialise dma and fence management */ + if (device->card_type >= NV_E0) { + init->fb_ctxdma_handle = NVE0_CHANNEL_IND_ENGINE_GR; + init->tt_ctxdma_handle = 0; + } + ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN | init->channel, init->fb_ctxdma_handle, init->tt_ctxdma_handle, &chan->chan); -- cgit v1.1