⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i915_dma.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- *//************************************************************************** * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * 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, sub license, 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 NON-INFRINGEMENT. * IN NO EVENT SHALL TUNGSTEN GRAPHICS 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 "i915_drm.h"#include "i915_drv.h"/* Really want an OS-independent resettable timer.  Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring * actually stalls for (eg) 3 seconds. */int i915_wait_ring(drm_device_t * dev, int n, const char *caller){	drm_i915_private_t *dev_priv = dev->dev_private;	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);	u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;	int i;	for (i = 0; i < 10000; i++) {		ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;		ring->space = ring->head - (ring->tail + 8);		if (ring->space < 0)			ring->space += ring->Size;		if (ring->space >= n)			return 0;		dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;		if (ring->head != last_head)			i = 0;		last_head = ring->head;	}	return DRM_ERR(EBUSY);}void i915_kernel_lost_context(drm_device_t * dev){	drm_i915_private_t *dev_priv = dev->dev_private;	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);	ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;	ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;	ring->space = ring->head - (ring->tail + 8);	if (ring->space < 0)		ring->space += ring->Size;	if (ring->head == ring->tail)		dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;}static int i915_dma_cleanup(drm_device_t * dev){	/* Make sure interrupts are disabled here because the uninstall ioctl	 * may not have been called from userspace and after dev_private	 * is freed, it's too late.	 */	if (dev->irq)		drm_irq_uninstall(dev);	if (dev->dev_private) {		drm_i915_private_t *dev_priv =		    (drm_i915_private_t *) dev->dev_private;		if (dev_priv->ring.virtual_start) {			drm_core_ioremapfree(&dev_priv->ring.map, dev);		}		if (dev_priv->status_page_dmah) {			drm_pci_free(dev, dev_priv->status_page_dmah);			/* Need to rewrite hardware status page */			I915_WRITE(0x02080, 0x1ffff000);		}		drm_free(dev->dev_private, sizeof(drm_i915_private_t),			 DRM_MEM_DRIVER);		dev->dev_private = NULL;	}	return 0;}static int i915_initialize(drm_device_t * dev,			   drm_i915_private_t * dev_priv,			   drm_i915_init_t * init){	memset(dev_priv, 0, sizeof(drm_i915_private_t));	DRM_GETSAREA();	if (!dev_priv->sarea) {		DRM_ERROR("can not find sarea!\n");		dev->dev_private = (void *)dev_priv;		i915_dma_cleanup(dev);		return DRM_ERR(EINVAL);	}	dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);	if (!dev_priv->mmio_map) {		dev->dev_private = (void *)dev_priv;		i915_dma_cleanup(dev);		DRM_ERROR("can not find mmio map!\n");		return DRM_ERR(EINVAL);	}	dev_priv->sarea_priv = (drm_i915_sarea_t *)	    ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);	dev_priv->ring.Start = init->ring_start;	dev_priv->ring.End = init->ring_end;	dev_priv->ring.Size = init->ring_size;	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;	dev_priv->ring.map.offset = init->ring_start;	dev_priv->ring.map.size = init->ring_size;	dev_priv->ring.map.type = 0;	dev_priv->ring.map.flags = 0;	dev_priv->ring.map.mtrr = 0;	drm_core_ioremap(&dev_priv->ring.map, dev);	if (dev_priv->ring.map.handle == NULL) {		dev->dev_private = (void *)dev_priv;		i915_dma_cleanup(dev);		DRM_ERROR("can not ioremap virtual address for"			  " ring buffer\n");		return DRM_ERR(ENOMEM);	}	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;	dev_priv->back_offset = init->back_offset;	dev_priv->front_offset = init->front_offset;	dev_priv->current_page = 0;	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;	/* We are using separate values as placeholders for mechanisms for	 * private backbuffer/depthbuffer usage.	 */	dev_priv->use_mi_batchbuffer_start = 0;	/* Allow hardware batchbuffers unless told otherwise.	 */	dev_priv->allow_batchbuffer = 1;	/* Program Hardware Status Page */	dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,						   0xffffffff);	if (!dev_priv->status_page_dmah) {		dev->dev_private = (void *)dev_priv;		i915_dma_cleanup(dev);		DRM_ERROR("Can not allocate hardware status page\n");		return DRM_ERR(ENOMEM);	}	dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;	dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);	I915_WRITE(0x02080, dev_priv->dma_status_page);	DRM_DEBUG("Enabled hardware status page\n");	dev->dev_private = (void *)dev_priv;	return 0;}static int i915_resume(drm_device_t * dev){	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;	DRM_DEBUG("%s\n", __FUNCTION__);	if (!dev_priv->sarea) {		DRM_ERROR("can not find sarea!\n");		return DRM_ERR(EINVAL);	}	if (!dev_priv->mmio_map) {		DRM_ERROR("can not find mmio map!\n");		return DRM_ERR(EINVAL);	}	if (dev_priv->ring.map.handle == NULL) {		DRM_ERROR("can not ioremap virtual address for"			  " ring buffer\n");		return DRM_ERR(ENOMEM);	}	/* Program Hardware Status Page */	if (!dev_priv->hw_status_page) {		DRM_ERROR("Can not find hardware status page\n");		return DRM_ERR(EINVAL);	}	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);	I915_WRITE(0x02080, dev_priv->dma_status_page);	DRM_DEBUG("Enabled hardware status page\n");	return 0;}static int i915_dma_init(DRM_IOCTL_ARGS){	DRM_DEVICE;	drm_i915_private_t *dev_priv;	drm_i915_init_t init;	int retcode = 0;	DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data,				 sizeof(init));	switch (init.func) {	case I915_INIT_DMA:		dev_priv = drm_alloc(sizeof(drm_i915_private_t),				     DRM_MEM_DRIVER);		if (dev_priv == NULL)			return DRM_ERR(ENOMEM);		retcode = i915_initialize(dev, dev_priv, &init);		break;	case I915_CLEANUP_DMA:		retcode = i915_dma_cleanup(dev);		break;	case I915_RESUME_DMA:		retcode = i915_resume(dev);		break;	default:		retcode = -EINVAL;		break;	}	return retcode;}/* Implement basically the same security restrictions as hardware does * for MI_BATCH_NON_SECURE.  These can be made stricter at any time. * * Most of the calculations below involve calculating the size of a * particular instruction.  It's important to get the size right as * that tells us where the next instruction to check is.  Any illegal * instruction detected will be given a size of zero, which is a * signal to abort the rest of the buffer. */static int do_validate_cmd(int cmd){	switch (((cmd >> 29) & 0x7)) {	case 0x0:		switch ((cmd >> 23) & 0x3f) {		case 0x0:			return 1;	/* MI_NOOP */		case 0x4:			return 1;	/* MI_FLUSH */		default:			return 0;	/* disallow everything else */		}		break;	case 0x1:		return 0;	/* reserved */	case 0x2:		return (cmd & 0xff) + 2;	/* 2d commands */	case 0x3:		if (((cmd >> 24) & 0x1f) <= 0x18)			return 1;		switch ((cmd >> 24) & 0x1f) {		case 0x1c:			return 1;		case 0x1d:			switch ((cmd >> 16) & 0xff) {			case 0x3:				return (cmd & 0x1f) + 2;			case 0x4:				return (cmd & 0xf) + 2;			default:				return (cmd & 0xffff) + 2;			}		case 0x1e:			if (cmd & (1 << 23))				return (cmd & 0xffff) + 1;			else				return 1;		case 0x1f:			if ((cmd & (1 << 23)) == 0)	/* inline vertices */				return (cmd & 0x1ffff) + 2;			else if (cmd & (1 << 17))	/* indirect random */				if ((cmd & 0xffff) == 0)					return 0;	/* unknown length, too hard */				else					return (((cmd & 0xffff) + 1) / 2) + 1;			else				return 2;	/* indirect sequential */		default:			return 0;		}	default:		return 0;	}	return 0;}static int validate_cmd(int cmd){	int ret = do_validate_cmd(cmd);/* 	printk("validate_cmd( %x ): %d\n", cmd, ret); */	return ret;}static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords){	drm_i915_private_t *dev_priv = dev->dev_private;	int i;	RING_LOCALS;	for (i = 0; i < dwords;) {		int cmd, sz;		if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))			return DRM_ERR(EINVAL);/* 		printk("%d/%d ", i, dwords); */		if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)			return DRM_ERR(EINVAL);		BEGIN_LP_RING(sz);		OUT_RING(cmd);		while (++i, --sz) {			if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],							 sizeof(cmd))) {				return DRM_ERR(EINVAL);			}			OUT_RING(cmd);		}		ADVANCE_LP_RING();	}	return 0;}static int i915_emit_box(drm_device_t * dev,			 drm_clip_rect_t __user * boxes,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -