r128_cce.c

来自「linux 内核源代码」· C语言 代码 · 共 935 行 · 第 1/2 页

C
935
字号
		DRM_ERROR("could not find mmio region!\n");		dev->dev_private = (void *)dev_priv;		r128_do_cleanup_cce(dev);		return -EINVAL;	}	dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);	if (!dev_priv->cce_ring) {		DRM_ERROR("could not find cce ring region!\n");		dev->dev_private = (void *)dev_priv;		r128_do_cleanup_cce(dev);		return -EINVAL;	}	dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);	if (!dev_priv->ring_rptr) {		DRM_ERROR("could not find ring read pointer!\n");		dev->dev_private = (void *)dev_priv;		r128_do_cleanup_cce(dev);		return -EINVAL;	}	dev->agp_buffer_token = init->buffers_offset;	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);	if (!dev->agp_buffer_map) {		DRM_ERROR("could not find dma buffer region!\n");		dev->dev_private = (void *)dev_priv;		r128_do_cleanup_cce(dev);		return -EINVAL;	}	if (!dev_priv->is_pci) {		dev_priv->agp_textures =		    drm_core_findmap(dev, init->agp_textures_offset);		if (!dev_priv->agp_textures) {			DRM_ERROR("could not find agp texture region!\n");			dev->dev_private = (void *)dev_priv;			r128_do_cleanup_cce(dev);			return -EINVAL;		}	}	dev_priv->sarea_priv =	    (drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle +				  init->sarea_priv_offset);#if __OS_HAS_AGP	if (!dev_priv->is_pci) {		drm_core_ioremap(dev_priv->cce_ring, dev);		drm_core_ioremap(dev_priv->ring_rptr, dev);		drm_core_ioremap(dev->agp_buffer_map, dev);		if (!dev_priv->cce_ring->handle ||		    !dev_priv->ring_rptr->handle ||		    !dev->agp_buffer_map->handle) {			DRM_ERROR("Could not ioremap agp regions!\n");			dev->dev_private = (void *)dev_priv;			r128_do_cleanup_cce(dev);			return -ENOMEM;		}	} else#endif	{		dev_priv->cce_ring->handle = (void *)dev_priv->cce_ring->offset;		dev_priv->ring_rptr->handle =		    (void *)dev_priv->ring_rptr->offset;		dev->agp_buffer_map->handle =		    (void *)dev->agp_buffer_map->offset;	}#if __OS_HAS_AGP	if (!dev_priv->is_pci)		dev_priv->cce_buffers_offset = dev->agp->base;	else#endif		dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;	dev_priv->ring.start = (u32 *) dev_priv->cce_ring->handle;	dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle			      + init->ring_size / sizeof(u32));	dev_priv->ring.size = init->ring_size;	dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);	dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;	dev_priv->ring.high_mark = 128;	dev_priv->sarea_priv->last_frame = 0;	R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);	dev_priv->sarea_priv->last_dispatch = 0;	R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch);#if __OS_HAS_AGP	if (dev_priv->is_pci) {#endif		dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;		dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;		dev_priv->gart_info.addr = NULL;		dev_priv->gart_info.bus_addr = 0;		dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {			DRM_ERROR("failed to init PCI GART!\n");			dev->dev_private = (void *)dev_priv;			r128_do_cleanup_cce(dev);			return -ENOMEM;		}		R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);#if __OS_HAS_AGP	}#endif	r128_cce_init_ring_buffer(dev, dev_priv);	r128_cce_load_microcode(dev_priv);	dev->dev_private = (void *)dev_priv;	r128_do_engine_reset(dev);	return 0;}int r128_do_cleanup_cce(struct drm_device * 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_enabled)		drm_irq_uninstall(dev);	if (dev->dev_private) {		drm_r128_private_t *dev_priv = dev->dev_private;#if __OS_HAS_AGP		if (!dev_priv->is_pci) {			if (dev_priv->cce_ring != NULL)				drm_core_ioremapfree(dev_priv->cce_ring, dev);			if (dev_priv->ring_rptr != NULL)				drm_core_ioremapfree(dev_priv->ring_rptr, dev);			if (dev->agp_buffer_map != NULL) {				drm_core_ioremapfree(dev->agp_buffer_map, dev);				dev->agp_buffer_map = NULL;			}		} else#endif		{			if (dev_priv->gart_info.bus_addr)				if (!drm_ati_pcigart_cleanup(dev,							&dev_priv->gart_info))					DRM_ERROR					    ("failed to cleanup PCI GART!\n");		}		drm_free(dev->dev_private, sizeof(drm_r128_private_t),			 DRM_MEM_DRIVER);		dev->dev_private = NULL;	}	return 0;}int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_r128_init_t *init = data;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	switch (init->func) {	case R128_INIT_CCE:		return r128_do_init_cce(dev, init);	case R128_CLEANUP_CCE:		return r128_do_cleanup_cce(dev);	}	return -EINVAL;}int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_r128_private_t *dev_priv = dev->dev_private;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {		DRM_DEBUG("%s while CCE running\n", __FUNCTION__);		return 0;	}	r128_do_cce_start(dev_priv);	return 0;}/* Stop the CCE.  The engine must have been idled before calling this * routine. */int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_r128_private_t *dev_priv = dev->dev_private;	drm_r128_cce_stop_t *stop = data;	int ret;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	/* Flush any pending CCE commands.  This ensures any outstanding	 * commands are exectuted by the engine before we turn it off.	 */	if (stop->flush) {		r128_do_cce_flush(dev_priv);	}	/* If we fail to make the engine go idle, we return an error	 * code so that the DRM ioctl wrapper can try again.	 */	if (stop->idle) {		ret = r128_do_cce_idle(dev_priv);		if (ret)			return ret;	}	/* Finally, we can turn off the CCE.  If the engine isn't idle,	 * we will get some dropped triangles as they won't be fully	 * rendered before the CCE is shut down.	 */	r128_do_cce_stop(dev_priv);	/* Reset the engine */	r128_do_engine_reset(dev);	return 0;}/* Just reset the CCE ring.  Called as part of an X Server engine reset. */int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_r128_private_t *dev_priv = dev->dev_private;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	if (!dev_priv) {		DRM_DEBUG("%s called before init done\n", __FUNCTION__);		return -EINVAL;	}	r128_do_cce_reset(dev_priv);	/* The CCE is no longer running after an engine reset */	dev_priv->cce_running = 0;	return 0;}int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_r128_private_t *dev_priv = dev->dev_private;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	if (dev_priv->cce_running) {		r128_do_cce_flush(dev_priv);	}	return r128_do_cce_idle(dev_priv);}int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv){	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	return r128_do_engine_reset(dev);}int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv){	return -EINVAL;}/* ================================================================ * Freelist management */#define R128_BUFFER_USED	0xffffffff#define R128_BUFFER_FREE	0#if 0static int r128_freelist_init(struct drm_device * dev){	struct drm_device_dma *dma = dev->dma;	drm_r128_private_t *dev_priv = dev->dev_private;	struct drm_buf *buf;	drm_r128_buf_priv_t *buf_priv;	drm_r128_freelist_t *entry;	int i;	dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);	if (dev_priv->head == NULL)		return -ENOMEM;	memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t));	dev_priv->head->age = R128_BUFFER_USED;	for (i = 0; i < dma->buf_count; i++) {		buf = dma->buflist[i];		buf_priv = buf->dev_private;		entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);		if (!entry)			return -ENOMEM;		entry->age = R128_BUFFER_FREE;		entry->buf = buf;		entry->prev = dev_priv->head;		entry->next = dev_priv->head->next;		if (!entry->next)			dev_priv->tail = entry;		buf_priv->discard = 0;		buf_priv->dispatched = 0;		buf_priv->list_entry = entry;		dev_priv->head->next = entry;		if (dev_priv->head->next)			dev_priv->head->next->prev = entry;	}	return 0;}#endifstatic struct drm_buf *r128_freelist_get(struct drm_device * dev){	struct drm_device_dma *dma = dev->dma;	drm_r128_private_t *dev_priv = dev->dev_private;	drm_r128_buf_priv_t *buf_priv;	struct drm_buf *buf;	int i, t;	/* FIXME: Optimize -- use freelist code */	for (i = 0; i < dma->buf_count; i++) {		buf = dma->buflist[i];		buf_priv = buf->dev_private;		if (buf->file_priv == 0)			return buf;	}	for (t = 0; t < dev_priv->usec_timeout; t++) {		u32 done_age = R128_READ(R128_LAST_DISPATCH_REG);		for (i = 0; i < dma->buf_count; i++) {			buf = dma->buflist[i];			buf_priv = buf->dev_private;			if (buf->pending && buf_priv->age <= done_age) {				/* The buffer has been processed, so it				 * can now be used.				 */				buf->pending = 0;				return buf;			}		}		DRM_UDELAY(1);	}	DRM_DEBUG("returning NULL!\n");	return NULL;}void r128_freelist_reset(struct drm_device * dev){	struct drm_device_dma *dma = dev->dma;	int i;	for (i = 0; i < dma->buf_count; i++) {		struct drm_buf *buf = dma->buflist[i];		drm_r128_buf_priv_t *buf_priv = buf->dev_private;		buf_priv->age = 0;	}}/* ================================================================ * CCE command submission */int r128_wait_ring(drm_r128_private_t * dev_priv, int n){	drm_r128_ring_buffer_t *ring = &dev_priv->ring;	int i;	for (i = 0; i < dev_priv->usec_timeout; i++) {		r128_update_ring_snapshot(dev_priv);		if (ring->space >= n)			return 0;		DRM_UDELAY(1);	}	/* FIXME: This is being ignored... */	DRM_ERROR("failed!\n");	return -EBUSY;}static int r128_cce_get_buffers(struct drm_device * dev,				struct drm_file *file_priv,				struct drm_dma * d){	int i;	struct drm_buf *buf;	for (i = d->granted_count; i < d->request_count; i++) {		buf = r128_freelist_get(dev);		if (!buf)			return -EAGAIN;		buf->file_priv = file_priv;		if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,				     sizeof(buf->idx)))			return -EFAULT;		if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,				     sizeof(buf->total)))			return -EFAULT;		d->granted_count++;	}	return 0;}int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv){	struct drm_device_dma *dma = dev->dma;	int ret = 0;	struct drm_dma *d = data;	LOCK_TEST_WITH_RETURN(dev, file_priv);	/* Please don't send us buffers.	 */	if (d->send_count != 0) {		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",			  DRM_CURRENTPID, d->send_count);		return -EINVAL;	}	/* We'll send you buffers.	 */	if (d->request_count < 0 || d->request_count > dma->buf_count) {		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",			  DRM_CURRENTPID, d->request_count, dma->buf_count);		return -EINVAL;	}	d->granted_count = 0;	if (d->request_count) {		ret = r128_cce_get_buffers(dev, file_priv, d);	}	return ret;}

⌨️ 快捷键说明

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