diff options
Diffstat (limited to 'linux/r128_dma.c')
-rw-r--r-- | linux/r128_dma.c | 909 |
1 files changed, 0 insertions, 909 deletions
diff --git a/linux/r128_dma.c b/linux/r128_dma.c deleted file mode 100644 index bcba6782..00000000 --- a/linux/r128_dma.c +++ /dev/null @@ -1,909 +0,0 @@ -/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- - * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com - * - * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * 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 - * PRECISION INSIGHT 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. - * - * Authors: Kevin E. Martin <martin@valinux.com> - * - */ - -#define __NO_VERSION__ -#include "drmP.h" -#include "r128_drv.h" - -#include <linux/interrupt.h> /* For task queue support */ -#include <linux/delay.h> - - - -#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) - -#define DO_REMAPFREE(_m) \ - do { \ - if ((_m)->handle && (_m)->size) \ - drm_ioremapfree((_m)->handle, (_m)->size); \ - } while (0) - -#define DO_FIND_MAP(_m, _o) \ - do { \ - int _i; \ - for (_i = 0; _i < dev->map_count; _i++) { \ - if (dev->maplist[_i]->offset == _o) { \ - _m = dev->maplist[_i]; \ - break; \ - } \ - } \ - } while (0) - - -#define R128_MAX_VBUF_AGE 0x10000000 -#define R128_VB_AGE_REG R128_GUI_SCRATCH_REG0 - -int R128_READ_PLL(drm_device_t *dev, int addr) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - - R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); - return R128_READ(R128_CLOCK_CNTL_DATA); -} - -#define r128_flush_write_combine() mb() - - -static void r128_status(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - - printk("GUI_STAT = 0x%08x\n", - (unsigned int)R128_READ(R128_GUI_STAT)); - printk("PM4_STAT = 0x%08x\n", - (unsigned int)R128_READ(R128_PM4_STAT)); - printk("PM4_BUFFER_DL_WPTR = 0x%08x\n", - (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR)); - printk("PM4_BUFFER_DL_RPTR = 0x%08x\n", - (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR)); -} - -static int r128_do_cleanup_cce(drm_device_t *dev) -{ - if (dev->dev_private) { - drm_r128_private_t *dev_priv = dev->dev_private; - - if (!dev_priv->is_pci) { - DO_REMAPFREE(dev_priv->agp_ring); - DO_REMAPFREE(dev_priv->agp_read_ptr); - DO_REMAPFREE(dev_priv->agp_vertbufs); - DO_REMAPFREE(dev_priv->agp_indbufs); - DO_REMAPFREE(dev_priv->agp_textures); - } - - drm_free(dev->dev_private, sizeof(drm_r128_private_t), - DRM_MEM_DRIVER); - dev->dev_private = NULL; - } - - return 0; -} - -static int r128_do_init_cce(drm_device_t *dev, drm_r128_init_t *init) -{ - drm_r128_private_t *dev_priv; - int i; - - dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); - if (dev_priv == NULL) return -ENOMEM; - dev->dev_private = (void *)dev_priv; - - memset(dev_priv, 0, sizeof(drm_r128_private_t)); - - dev_priv->is_pci = init->is_pci; - - dev_priv->usec_timeout = init->usec_timeout; - if (dev_priv->usec_timeout < 1 || - dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) { - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); - dev->dev_private = NULL; - return -EINVAL; - } - - dev_priv->cce_mode = init->cce_mode; - dev_priv->cce_fifo_size = init->cce_fifo_size; - dev_priv->cce_is_bm_mode = - ((init->cce_mode == R128_PM4_192BM) || - (init->cce_mode == R128_PM4_128BM_64INDBM) || - (init->cce_mode == R128_PM4_64BM_128INDBM) || - (init->cce_mode == R128_PM4_64BM_64VCBM_64INDBM)); - dev_priv->cce_secure = init->cce_secure; - - if (dev_priv->cce_is_bm_mode && dev_priv->is_pci) { - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); - dev->dev_private = NULL; - return -EINVAL; - } - - for (i = 0; i < dev->map_count; i++) { - if (dev->maplist[i]->type == _DRM_SHM) { - dev_priv->sarea = dev->maplist[i]; - break; - } - } - - DO_FIND_MAP(dev_priv->fb, init->fb_offset); - if (!dev_priv->is_pci) { - DO_FIND_MAP(dev_priv->agp_ring, init->agp_ring_offset); - DO_FIND_MAP(dev_priv->agp_read_ptr, init->agp_read_ptr_offset); - DO_FIND_MAP(dev_priv->agp_vertbufs, init->agp_vertbufs_offset); - DO_FIND_MAP(dev_priv->agp_indbufs, init->agp_indbufs_offset); - DO_FIND_MAP(dev_priv->agp_textures, init->agp_textures_offset); - } - DO_FIND_MAP(dev_priv->mmio, init->mmio_offset); - - dev_priv->sarea_priv = - (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + - init->sarea_priv_offset); - - if (!dev_priv->is_pci) { - DO_REMAP(dev_priv->agp_ring); - DO_REMAP(dev_priv->agp_read_ptr); - DO_REMAP(dev_priv->agp_vertbufs); -#if 0 - DO_REMAP(dev_priv->agp_indirectbufs); - DO_REMAP(dev_priv->agp_textures); -#endif - - dev_priv->ring_size = init->ring_size; - dev_priv->ring_sizel2qw = drm_order(init->ring_size/8); - dev_priv->ring_entries = init->ring_size/sizeof(u32); - dev_priv->ring_read_ptr = ((__volatile__ u32 *) - dev_priv->agp_read_ptr->handle); - dev_priv->ring_start = (u32 *)dev_priv->agp_ring->handle; - dev_priv->ring_end = ((u32 *)dev_priv->agp_ring->handle - + dev_priv->ring_entries); - } - - dev_priv->submit_age = 0; - R128_WRITE(R128_VB_AGE_REG, dev_priv->submit_age); - - return 0; -} - -int r128_init_cce(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_r128_init_t init; - - if (copy_from_user(&init, (drm_r128_init_t *)arg, sizeof(init))) - return -EFAULT; - - 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; -} - -static void r128_mark_vertbufs_done(drm_device_t *dev) -{ - drm_device_dma_t *dma = dev->dma; - int i; - - for (i = 0; i < dma->buf_count; i++) { - drm_buf_t *buf = dma->buflist[i]; - drm_r128_buf_priv_t *buf_priv = buf->dev_private; - buf_priv->age = 0; - } -} - -static int r128_do_pixcache_flush(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 tmp; - int i; - - tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL; - R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp); - - for (i = 0; i < dev_priv->usec_timeout; i++) { - if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) - return 0; - udelay(1); - } - - return -EBUSY; -} - -static int r128_do_wait_for_fifo(drm_device_t *dev, int entries) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK; - if (slots >= entries) return 0; - udelay(1); - } - return -EBUSY; -} - -static int r128_do_wait_for_idle(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i, ret; - - if (!(ret = r128_do_wait_for_fifo(dev, 64))) return ret; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) { - (void)r128_do_pixcache_flush(dev); - return 0; - } - udelay(1); - } - return -EBUSY; -} - -int r128_do_engine_reset(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; - - (void)r128_do_pixcache_flush(dev); - - clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX); - mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL); - - R128_WRITE_PLL(R128_MCLK_CNTL, - mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP); - - gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL); - - R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI); - (void)R128_READ(R128_GEN_RESET_CNTL); - R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI); - (void)R128_READ(R128_GEN_RESET_CNTL); - - R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl); - R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index); - R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl); - - /* For CCE ring buffer only */ - if (dev_priv->cce_is_bm_mode) { - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0); - R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0); - *dev_priv->ring_read_ptr = 0; - dev_priv->sarea_priv->ring_write = 0; - } - - /* Reset the CCE mode */ - (void)r128_do_wait_for_idle(dev); - R128_WRITE(R128_PM4_BUFFER_CNTL, - dev_priv->cce_mode | dev_priv->ring_sizel2qw); - (void)R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */ - R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN); - - r128_mark_vertbufs_done(dev); - return 0; -} - -int r128_eng_reset(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_eng_reset called without holding the lock\n"); - return -EINVAL; - } - - return r128_do_engine_reset(dev); -} - -static int r128_do_engine_flush(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 tmp; - - tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR); - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp | R128_PM4_BUFFER_DL_DONE); - - return 0; -} - -int r128_eng_flush(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_eng_flush called without holding the lock\n"); - return -EINVAL; - } - - return r128_do_engine_flush(dev); -} - -static int r128_do_cce_wait_for_fifo(drm_device_t *dev, int entries) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - int slots = R128_READ(R128_PM4_STAT) & R128_PM4_FIFOCNT_MASK; - if (slots >= entries) return 0; - udelay(1); - } - return -EBUSY; -} - -int r128_do_cce_wait_for_idle(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i; - - if (dev_priv->cce_is_bm_mode) { - for (i = 0; i < dev_priv->usec_timeout; i++) { - if (*dev_priv->ring_read_ptr == dev_priv->sarea_priv->ring_write) { - int pm4stat = R128_READ(R128_PM4_STAT); - if ((pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size && - !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { - return r128_do_pixcache_flush(dev); - } - } - udelay(1); - } - return -EBUSY; - } else { - int ret = r128_do_cce_wait_for_fifo(dev, dev_priv->cce_fifo_size); - if (ret < 0) return ret; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - int pm4stat = R128_READ(R128_PM4_STAT); - if (!(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { - return r128_do_pixcache_flush(dev); - } - udelay(1); - } - return -EBUSY; - } -} - -int r128_cce_idle(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_wait_idle called without holding the lock\n"); - return -EINVAL; - } - - return r128_do_cce_wait_for_idle(dev); -} - -static int r128_submit_packets_ring_secure(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int write = dev_priv->sarea_priv->ring_write; - int *write_ptr = dev_priv->ring_start + write; - int c = *count; - u32 tmp = 0; - int psize = 0; - int writing = 1; - int timeout; - - while (c > 0) { - tmp = *commands++; - if (!psize) { - writing = 1; - - if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= - (0x1004 << 9)) { - if ((tmp & R128_CCE_PACKET1_REG1_MASK) != - (R128_PM4_VC_FPU_SETUP << 9)) { - writing = 0; - } - } - psize = 3; - } else { - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } - } - psize--; - - if (writing) { - write++; - *write_ptr++ = tmp; - } - if (write >= dev_priv->ring_entries) { - write = 0; - write_ptr = dev_priv->ring_start; - } - timeout = 0; - while (write == *dev_priv->ring_read_ptr) { - (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); - if (timeout++ >= dev_priv->usec_timeout) - return -EBUSY; - udelay(1); - } - c--; - } - - if (write < 32) - memcpy(dev_priv->ring_end, - dev_priv->ring_start, - write * sizeof(u32)); - - /* Make sure WC cache has been flushed */ - r128_flush_write_combine(); - - dev_priv->sarea_priv->ring_write = write; - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); - - *count = 0; - - return 0; -} - -static int r128_submit_packets_pio_secure(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 tmp = 0; - int psize = 0; - int writing = 1; - int addr = R128_PM4_FIFO_DATA_EVEN; - int ret; - - while (*count > 0) { - tmp = *commands++; - if (!psize) { - writing = 1; - - if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= - (0x1004 << 9)) { - if ((tmp & R128_CCE_PACKET1_REG1_MASK) != - (R128_PM4_VC_FPU_SETUP << 9)) { - writing = 0; - } - } - psize = 3; - } else { - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } - } - psize--; - - if (writing) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) - return ret; - R128_WRITE(addr, tmp); - addr ^= 0x0004; - } - - *count -= 1; - } - - if (addr == R128_PM4_FIFO_DATA_ODD) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) return ret; - R128_WRITE(addr, R128_CCE_PACKET2); - } - - return 0; -} - -static int r128_submit_packets_ring(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int write = dev_priv->sarea_priv->ring_write; - int *write_ptr = dev_priv->ring_start + write; - int c = *count; - int timeout; - - while (c > 0) { - write++; - *write_ptr++ = *commands++; - if (write >= dev_priv->ring_entries) { - write = 0; - write_ptr = dev_priv->ring_start; - } - timeout = 0; - while (write == *dev_priv->ring_read_ptr) { - (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); - if (timeout++ >= dev_priv->usec_timeout) - return -EBUSY; - udelay(1); - } - c--; - } - - if (write < 32) - memcpy(dev_priv->ring_end, - dev_priv->ring_start, - write * sizeof(u32)); - - /* Make sure WC cache has been flushed */ - r128_flush_write_combine(); - - dev_priv->sarea_priv->ring_write = write; - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); - - *count = 0; - - return 0; -} - -static int r128_submit_packets_pio(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int ret; - - while (*count > 1) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; - R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); - R128_WRITE(R128_PM4_FIFO_DATA_ODD, *commands++); - *count -= 2; - } - - if (*count) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; - R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); - R128_WRITE(R128_PM4_FIFO_DATA_ODD, R128_CCE_PACKET2); - *count = 0; - } - - return 0; -} - -static int r128_do_submit_packets(drm_device_t *dev, u32 *buffer, int count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int c = count; - int ret; - - if (dev_priv->cce_is_bm_mode) { - int left = 0; - - if (c >= dev_priv->ring_entries) { - c = dev_priv->ring_entries-1; - left = count - c; - } - - /* Since this is only used by the kernel we can use the - insecure ring buffer submit packet routine */ - ret = r128_submit_packets_ring(dev, buffer, &c); - - c += left; - } else { - /* Since this is only used by the kernel we can use the - insecure PIO submit packet routine */ - ret = r128_submit_packets_pio(dev, buffer, &c); - } - - if (ret < 0) return ret; - else return c; -} - -int r128_submit_pkt(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_packet_t packet; - u32 *buffer; - int c; - int size; - int ret = 0; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_submit_pkt called without holding the lock\n"); - return -EINVAL; - } - - if (copy_from_user(&packet, (drm_r128_packet_t *)arg, sizeof(packet))) - return -EFAULT; - - c = packet.count; - size = c * sizeof(*buffer); - - if (dev_priv->cce_is_bm_mode) { - int left = 0; - - if (c >= dev_priv->ring_entries) { - c = dev_priv->ring_entries-1; - size = c * sizeof(*buffer); - left = packet.count - c; - } - - if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; - if (copy_from_user(buffer, packet.buffer, size)) - return -EFAULT; - - if (dev_priv->cce_secure) - ret = r128_submit_packets_ring_secure(dev, buffer, &c); - else - ret = r128_submit_packets_ring(dev, buffer, &c); - - c += left; - } else { - if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; - if (copy_from_user(buffer, packet.buffer, size)) - return -EFAULT; - - if (dev_priv->cce_secure) - ret = r128_submit_packets_pio_secure(dev, buffer, &c); - else - ret = r128_submit_packets_pio(dev, buffer, &c); - } - - kfree(buffer); - - packet.count = c; - if (copy_to_user((drm_r128_packet_t *)arg, &packet, sizeof(packet))) - return -EFAULT; - - if (ret) return ret; - else if (c > 0) return -EAGAIN; - - return 0; -} - -static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) -{ - drm_device_dma_t *dma = dev->dma; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_buf_priv_t *buf_priv; - drm_buf_t *buf; - int i, ret; - u32 cce[2]; - - /* Make sure we have valid data */ - for (i = 0; i < v->send_count; i++) { - int idx = v->send_indices[i]; - - if (idx < 0 || idx >= dma->buf_count) { - DRM_ERROR("Index %d (of %d max)\n", - idx, dma->buf_count - 1); - return -EINVAL; - } - buf = dma->buflist[idx]; - if (buf->pid != current->pid) { - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); - return -EINVAL; - } - if (buf->pending) { - DRM_ERROR("Sending pending buffer:" - " buffer %d, offset %d\n", - v->send_indices[i], i); - return -EINVAL; - } - } - - /* Wait for idle, if we've wrapped to make sure that all pending - buffers have been processed */ - if (dev_priv->submit_age == R128_MAX_VBUF_AGE) { - if ((ret = r128_do_cce_wait_for_idle(dev)) < 0) return ret; - dev_priv->submit_age = 0; - r128_mark_vertbufs_done(dev); - } - - /* Make sure WC cache has been flushed (if in PIO mode) */ - if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine(); - - /* FIXME: Add support for sending vertex buffer to the CCE here - instead of in client code. The v->prim holds the primitive - type that should be drawn. Loop over the list buffers in - send_indices[] and submit a packet for each VB. - - This will require us to loop over the clip rects here as - well, which implies that we extend the kernel driver to allow - cliprects to be stored here. Note that the cliprects could - possibly come from the X server instead of the client, but - this will require additional changes to the DRI to allow for - this optimization. */ - - /* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */ - cce[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0); - cce[1] = dev_priv->submit_age; - if ((ret = r128_do_submit_packets(dev, cce, 2)) < 0) { - /* Until we add support for sending VBs to the CCE in - this routine, we can recover from this error. After - we add that support, we won't be able to easily - recover, so we will probably have to implement - another mechanism for handling timeouts from packets - submitted directly by the kernel. */ - return ret; - } - - /* Now that the submit packet request has succeeded, we can mark - the buffers as pending */ - for (i = 0; i < v->send_count; i++) { - buf = dma->buflist[v->send_indices[i]]; - buf->pending = 1; - - buf_priv = buf->dev_private; - buf_priv->age = dev_priv->submit_age; - } - - dev_priv->submit_age++; - - return 0; -} - -static drm_buf_t *r128_freelist_get(drm_device_t *dev) -{ - drm_device_dma_t *dma = dev->dma; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_buf_priv_t *buf_priv; - drm_buf_t *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->pid == 0) return buf; - } - - for (t = 0; t < dev_priv->usec_timeout; t++) { - u32 done_age = R128_READ(R128_VB_AGE_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; - } - } - udelay(1); - } - - r128_status(dev); - return NULL; -} - - -static int r128_get_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) -{ - drm_buf_t *buf; - int i; - - for (i = v->granted_count; i < v->request_count; i++) { - buf = r128_freelist_get(dev); - if (!buf) break; - buf->pid = current->pid; - if (copy_to_user(&v->request_indices[i], - &buf->idx, - sizeof(buf->idx)) || - copy_to_user(&v->request_sizes[i], - &buf->total, - sizeof(buf->total))) - return -EFAULT; - ++v->granted_count; - } - return 0; -} - -int r128_vertex_buf(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_device_dma_t *dma = dev->dma; - int retcode = 0; - drm_r128_vertex_t v; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_vertex_buf called without holding the lock\n"); - return -EINVAL; - } - - if (!dev_priv || dev_priv->is_pci) { - DRM_ERROR("r128_vertex_buf called with a PCI card\n"); - return -EINVAL; - } - - if (copy_from_user(&v, (drm_r128_vertex_t *)arg, sizeof(v))) - return -EFAULT; - DRM_DEBUG("%d: %d send, %d req\n", - current->pid, v.send_count, v.request_count); - - if (v.send_count < 0 || v.send_count > dma->buf_count) { - DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", - current->pid, v.send_count, dma->buf_count); - return -EINVAL; - } - if (v.request_count < 0 || v.request_count > dma->buf_count) { - DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", - current->pid, v.request_count, dma->buf_count); - return -EINVAL; - } - - if (v.send_count) { - retcode = r128_send_vertbufs(dev, &v); - } - - v.granted_count = 0; - - if (!retcode && v.request_count) { - retcode = r128_get_vertbufs(dev, &v); - } - - DRM_DEBUG("%d returning, granted = %d\n", - current->pid, v.granted_count); - if (copy_to_user((drm_r128_vertex_t *)arg, &v, sizeof(v))) - return -EFAULT; - - return retcode; -} |