Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * Copyright (C) 2007 Ben Skeggs.
  3 *
  4 * All Rights Reserved.
  5 *
  6 * Permission is hereby granted, free of charge, to any person obtaining
  7 * a copy of this software and associated documentation files (the
  8 * "Software"), to deal in the Software without restriction, including
  9 * without limitation the rights to use, copy, modify, merge, publish,
 10 * distribute, sublicense, and/or sell copies of the Software, and to
 11 * permit persons to whom the Software is furnished to do so, subject to
 12 * the following conditions:
 13 *
 14 * The above copyright notice and this permission notice (including the
 15 * next paragraph) shall be included in all copies or substantial
 16 * portions of the Software.
 17 *
 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
 22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 25 *
 26 */
 27
 28#include "drmP.h"
 29#include "drm.h"
 30#include "nouveau_drv.h"
 31#include "nouveau_ramht.h"
 32
 33int
 34nouveau_notifier_init_channel(struct nouveau_channel *chan)
 35{
 36	struct drm_device *dev = chan->dev;
 37	struct drm_nouveau_private *dev_priv = dev->dev_private;
 38	struct nouveau_bo *ntfy = NULL;
 39	uint32_t flags, ttmpl;
 40	int ret;
 41
 42	if (nouveau_vram_notify) {
 43		flags = NOUVEAU_GEM_DOMAIN_VRAM;
 44		ttmpl = TTM_PL_FLAG_VRAM;
 45	} else {
 46		flags = NOUVEAU_GEM_DOMAIN_GART;
 47		ttmpl = TTM_PL_FLAG_TT;
 48	}
 49
 50	ret = nouveau_gem_new(dev, PAGE_SIZE, 0, flags, 0, 0, &ntfy);
 51	if (ret)
 52		return ret;
 53
 54	ret = nouveau_bo_pin(ntfy, ttmpl);
 55	if (ret)
 56		goto out_err;
 57
 58	ret = nouveau_bo_map(ntfy);
 59	if (ret)
 60		goto out_err;
 61
 62	if (dev_priv->card_type >= NV_50) {
 63		ret = nouveau_bo_vma_add(ntfy, chan->vm, &chan->notifier_vma);
 64		if (ret)
 65			goto out_err;
 66	}
 67
 68	ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
 69	if (ret)
 70		goto out_err;
 71
 72	chan->notifier_bo = ntfy;
 73out_err:
 74	if (ret) {
 75		nouveau_bo_vma_del(ntfy, &chan->notifier_vma);
 76		drm_gem_object_unreference_unlocked(ntfy->gem);
 77	}
 78
 79	return ret;
 80}
 81
 82void
 83nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
 84{
 85	struct drm_device *dev = chan->dev;
 86
 87	if (!chan->notifier_bo)
 88		return;
 89
 90	nouveau_bo_vma_del(chan->notifier_bo, &chan->notifier_vma);
 91	nouveau_bo_unmap(chan->notifier_bo);
 92	mutex_lock(&dev->struct_mutex);
 93	nouveau_bo_unpin(chan->notifier_bo);
 94	mutex_unlock(&dev->struct_mutex);
 95	drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
 96	drm_mm_takedown(&chan->notifier_heap);
 97}
 98
 99static void
100nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
101			     struct nouveau_gpuobj *gpuobj)
102{
103	NV_DEBUG(dev, "\n");
104
105	if (gpuobj->priv)
106		drm_mm_put_block(gpuobj->priv);
107}
108
109int
110nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
111		       int size, uint32_t start, uint32_t end,
112		       uint32_t *b_offset)
113{
114	struct drm_device *dev = chan->dev;
115	struct drm_nouveau_private *dev_priv = dev->dev_private;
116	struct nouveau_gpuobj *nobj = NULL;
117	struct drm_mm_node *mem;
118	uint32_t offset;
119	int target, ret;
120
121	mem = drm_mm_search_free_in_range(&chan->notifier_heap, size, 0,
122					  start, end, 0);
123	if (mem)
124		mem = drm_mm_get_block_range(mem, size, 0, start, end);
125	if (!mem) {
126		NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
127		return -ENOMEM;
128	}
129
130	if (dev_priv->card_type < NV_50) {
131		if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM)
132			target = NV_MEM_TARGET_VRAM;
133		else
134			target = NV_MEM_TARGET_GART;
135		offset  = chan->notifier_bo->bo.offset;
136	} else {
137		target = NV_MEM_TARGET_VM;
138		offset = chan->notifier_vma.offset;
139	}
140	offset += mem->start;
141
142	ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset,
143				     mem->size, NV_MEM_ACCESS_RW, target,
144				     &nobj);
145	if (ret) {
146		drm_mm_put_block(mem);
147		NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);
148		return ret;
149	}
150	nobj->dtor = nouveau_notifier_gpuobj_dtor;
151	nobj->priv = mem;
152
153	ret = nouveau_ramht_insert(chan, handle, nobj);
154	nouveau_gpuobj_ref(NULL, &nobj);
155	if (ret) {
156		drm_mm_put_block(mem);
157		NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);
158		return ret;
159	}
160
161	*b_offset = mem->start;
162	return 0;
163}
164
165int
166nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
167{
168	if (!nobj || nobj->dtor != nouveau_notifier_gpuobj_dtor)
169		return -EINVAL;
170
171	if (poffset) {
172		struct drm_mm_node *mem = nobj->priv;
173
174		if (*poffset >= mem->size)
175			return false;
176
177		*poffset += mem->start;
178	}
179
180	return 0;
181}
182
183int
184nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
185			     struct drm_file *file_priv)
186{
187	struct drm_nouveau_private *dev_priv = dev->dev_private;
188	struct drm_nouveau_notifierobj_alloc *na = data;
189	struct nouveau_channel *chan;
190	int ret;
191
192	/* completely unnecessary for these chipsets... */
193	if (unlikely(dev_priv->card_type >= NV_C0))
194		return -EINVAL;
195
196	chan = nouveau_channel_get(file_priv, na->channel);
197	if (IS_ERR(chan))
198		return PTR_ERR(chan);
199
200	ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000,
201				     &na->offset);
202	nouveau_channel_put(&chan);
203	return ret;
204}