Path: blob/master/drivers/gpu/drm/nouveau/nouveau_notifier.c
15112 views
/*1* Copyright (C) 2007 Ben Skeggs.2*3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining6* a copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sublicense, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial15* portions of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,18* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.20* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE21* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION22* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION23* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25*/2627#include "drmP.h"28#include "drm.h"29#include "nouveau_drv.h"30#include "nouveau_ramht.h"3132int33nouveau_notifier_init_channel(struct nouveau_channel *chan)34{35struct drm_device *dev = chan->dev;36struct nouveau_bo *ntfy = NULL;37uint32_t flags, ttmpl;38int ret;3940if (nouveau_vram_notify) {41flags = NOUVEAU_GEM_DOMAIN_VRAM;42ttmpl = TTM_PL_FLAG_VRAM;43} else {44flags = NOUVEAU_GEM_DOMAIN_GART;45ttmpl = TTM_PL_FLAG_TT;46}4748ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy);49if (ret)50return ret;5152ret = nouveau_bo_pin(ntfy, ttmpl);53if (ret)54goto out_err;5556ret = nouveau_bo_map(ntfy);57if (ret)58goto out_err;5960ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);61if (ret)62goto out_err;6364chan->notifier_bo = ntfy;65out_err:66if (ret)67drm_gem_object_unreference_unlocked(ntfy->gem);6869return ret;70}7172void73nouveau_notifier_takedown_channel(struct nouveau_channel *chan)74{75struct drm_device *dev = chan->dev;7677if (!chan->notifier_bo)78return;7980nouveau_bo_unmap(chan->notifier_bo);81mutex_lock(&dev->struct_mutex);82nouveau_bo_unpin(chan->notifier_bo);83mutex_unlock(&dev->struct_mutex);84drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);85drm_mm_takedown(&chan->notifier_heap);86}8788static void89nouveau_notifier_gpuobj_dtor(struct drm_device *dev,90struct nouveau_gpuobj *gpuobj)91{92NV_DEBUG(dev, "\n");9394if (gpuobj->priv)95drm_mm_put_block(gpuobj->priv);96}9798int99nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,100int size, uint32_t start, uint32_t end,101uint32_t *b_offset)102{103struct drm_device *dev = chan->dev;104struct drm_nouveau_private *dev_priv = dev->dev_private;105struct nouveau_gpuobj *nobj = NULL;106struct drm_mm_node *mem;107uint32_t offset;108int target, ret;109110mem = drm_mm_search_free_in_range(&chan->notifier_heap, size, 0,111start, end, 0);112if (mem)113mem = drm_mm_get_block_range(mem, size, 0, start, end);114if (!mem) {115NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);116return -ENOMEM;117}118119if (dev_priv->card_type < NV_50) {120if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM)121target = NV_MEM_TARGET_VRAM;122else123target = NV_MEM_TARGET_GART;124offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;125} else {126target = NV_MEM_TARGET_VM;127offset = chan->notifier_bo->vma.offset;128}129offset += mem->start;130131ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset,132mem->size, NV_MEM_ACCESS_RW, target,133&nobj);134if (ret) {135drm_mm_put_block(mem);136NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);137return ret;138}139nobj->dtor = nouveau_notifier_gpuobj_dtor;140nobj->priv = mem;141142ret = nouveau_ramht_insert(chan, handle, nobj);143nouveau_gpuobj_ref(NULL, &nobj);144if (ret) {145drm_mm_put_block(mem);146NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);147return ret;148}149150*b_offset = mem->start;151return 0;152}153154int155nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)156{157if (!nobj || nobj->dtor != nouveau_notifier_gpuobj_dtor)158return -EINVAL;159160if (poffset) {161struct drm_mm_node *mem = nobj->priv;162163if (*poffset >= mem->size)164return false;165166*poffset += mem->start;167}168169return 0;170}171172int173nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,174struct drm_file *file_priv)175{176struct drm_nouveau_private *dev_priv = dev->dev_private;177struct drm_nouveau_notifierobj_alloc *na = data;178struct nouveau_channel *chan;179int ret;180181/* completely unnecessary for these chipsets... */182if (unlikely(dev_priv->card_type >= NV_C0))183return -EINVAL;184185chan = nouveau_channel_get(dev, file_priv, na->channel);186if (IS_ERR(chan))187return PTR_ERR(chan);188189ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000,190&na->offset);191nouveau_channel_put(&chan);192return ret;193}194195196