diff options
| author | Dave Airlie <airlied@linux.ie> | 2007-07-11 11:23:41 +1000 | 
|---|---|---|
| committer | Dave Airlie <airlied@linux.ie> | 2007-07-11 11:23:41 +1000 | 
| commit | 2c9e05cf4c6eb18c941321f764ed1b282a314ba9 (patch) | |
| tree | d5bcbe9114fac7e03549ae05a9e6dffc793fcbaf /shared-core/nouveau_notifier.c | |
| parent | 9b9a127ed0fe9a6a8e2fde84739ccff6fa0bc5ac (diff) | |
| parent | 694e1c5c3f768436651ddf95e11ab5a89ccc8ffa (diff) | |
Merge branch 'master' into cleanup
Conflicts:
	libdrm/xf86drm.c
	linux-core/drm_bo.c
	linux-core/drm_fence.c
Diffstat (limited to 'shared-core/nouveau_notifier.c')
| -rw-r--r-- | shared-core/nouveau_notifier.c | 153 | 
1 files changed, 153 insertions, 0 deletions
| diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c new file mode 100644 index 00000000..30216293 --- /dev/null +++ b/shared-core/nouveau_notifier.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +int +nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) +{ +	drm_nouveau_private_t *dev_priv = dev->dev_private; +	struct nouveau_fifo *chan = dev_priv->fifos[channel]; +	int flags, ret; + +	/*TODO: PCI notifier blocks */ +	if (dev_priv->agp_heap) +		flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE; +	else +		flags = NOUVEAU_MEM_FB; +	flags |= NOUVEAU_MEM_MAPPED; + +	chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags,filp); +	if (!chan->notifier_block) +		return DRM_ERR(ENOMEM); + +	ret = nouveau_mem_init_heap(&chan->notifier_heap, +				    0, chan->notifier_block->size); +	if (ret) +		return ret; + +	return 0; +} + +void +nouveau_notifier_takedown_channel(drm_device_t *dev, int channel) +{ +	drm_nouveau_private_t *dev_priv = dev->dev_private; +	struct nouveau_fifo *chan = dev_priv->fifos[channel]; + +	if (chan->notifier_block) { +		nouveau_mem_free(dev, chan->notifier_block); +		chan->notifier_block = NULL; +	} + +	/*XXX: heap destroy */ +} + +int +nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, +		       int count, uint32_t *b_offset) +{ +	drm_nouveau_private_t *dev_priv = dev->dev_private; +	struct nouveau_fifo *chan = dev_priv->fifos[channel]; +	nouveau_gpuobj_t *nobj = NULL; +	struct mem_block *mem; +	uint32_t offset; +	int target, ret; + +	if (!chan->notifier_heap) { +		DRM_ERROR("Channel %d doesn't have a notifier heap!\n", +			  channel); +		return DRM_ERR(EINVAL); +	} + +	mem = nouveau_mem_alloc_block(chan->notifier_heap, 32, 0, chan->filp); +	if (!mem) { +		DRM_ERROR("Channel %d notifier block full\n", channel); +		return DRM_ERR(ENOMEM); +	} +	mem->flags = NOUVEAU_MEM_NOTIFIER; + +	offset = chan->notifier_block->start + mem->start; +	if (chan->notifier_block->flags & NOUVEAU_MEM_FB) { +		offset -= drm_get_resource_start(dev, 1); +		target = NV_DMA_TARGET_VIDMEM; +	} else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) { +		offset -= dev_priv->agp_phys; +		target = NV_DMA_TARGET_AGP; +	} else { +		DRM_ERROR("Bad DMA target, flags 0x%08x!\n", +			  chan->notifier_block->flags); +		return DRM_ERR(EINVAL); +	} + +	if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, +					  offset, mem->size, +					  NV_DMA_ACCESS_RW, target, &nobj))) { +		nouveau_mem_free_block(mem); +		DRM_ERROR("Error creating notifier ctxdma: %d\n", ret); +		return ret; +	} + +	if ((ret = nouveau_gpuobj_ref_add(dev, channel, handle, nobj, NULL))) { +		nouveau_gpuobj_del(dev, &nobj); +		nouveau_mem_free_block(mem); +		DRM_ERROR("Error referencing notifier ctxdma: %d\n", ret); +		return ret; +	} + +	*b_offset = mem->start; +	return 0; +} + +int +nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS) +{ +	DRM_DEVICE; +	drm_nouveau_notifier_alloc_t na; +	int ret; + +	DRM_COPY_FROM_USER_IOCTL(na, (drm_nouveau_notifier_alloc_t __user*)data, +				 sizeof(na)); + +	if (!nouveau_fifo_owner(dev, filp, na.channel)) { +		DRM_ERROR("pid %d doesn't own channel %d\n", +			  DRM_CURRENTPID, na.channel); +		return DRM_ERR(EPERM); +	} + +	ret = nouveau_notifier_alloc(dev, na.channel, na.handle, +				     na.count, &na.offset); +	if (ret) +		return ret; + +	DRM_COPY_TO_USER_IOCTL((drm_nouveau_notifier_alloc_t __user*)data, +			       na, sizeof(na)); +	return 0; +} + | 
