diff options
Diffstat (limited to 'linux/radeon_bufs.c')
-rw-r--r-- | linux/radeon_bufs.c | 188 |
1 files changed, 175 insertions, 13 deletions
diff --git a/linux/radeon_bufs.c b/linux/radeon_bufs.c index 9a3093eb..abcbd8da 100644 --- a/linux/radeon_bufs.c +++ b/linux/radeon_bufs.c @@ -37,8 +37,8 @@ #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -int radeon_addbufs_agp(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int radeon_addbufs_agp(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; @@ -57,9 +57,12 @@ int radeon_addbufs_agp(struct inode *inode, struct file *filp, int byte_count; int i; + printk("%s\n", __FUNCTION__); if (!dma) return -EINVAL; - if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request))) + if (copy_from_user(&request, + (drm_buf_desc_t *)arg, + sizeof(request))) return -EFAULT; count = request.count; @@ -71,7 +74,7 @@ int radeon_addbufs_agp(struct inode *inode, struct file *filp, total = PAGE_SIZE << page_order; byte_count = 0; - agp_offset = dev->agp->base + request.agp_start; + agp_offset = request.agp_start; DRM_DEBUG("count: %d\n", count); DRM_DEBUG("order: %d\n", order); @@ -122,7 +125,8 @@ int radeon_addbufs_agp(struct inode *inode, struct file *filp, buf->order = order; buf->used = 0; buf->offset = (dma->byte_count + offset); - buf->address = (void *)(agp_offset + offset); + buf->bus_address = agp_offset + offset; + buf->address = (void *)(agp_offset + dev->agp->base + offset); buf->next = NULL; buf->waiting = 0; buf->pending = 0; @@ -170,7 +174,9 @@ int radeon_addbufs_agp(struct inode *inode, struct file *filp, request.count = entry->buf_count; request.size = size; - if (copy_to_user((drm_buf_desc_t *)arg, &request, sizeof(request))) + if (copy_to_user((drm_buf_desc_t *)arg, + &request, + sizeof(request))) return -EFAULT; dma->flags = _DRM_DMA_USE_AGP; @@ -180,6 +186,153 @@ int radeon_addbufs_agp(struct inode *inode, struct file *filp, } #endif +int radeon_addbufs_sg(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + printk("%s\n", __FUNCTION__); + if (!dma) return -EINVAL; + + if (copy_from_user(&request, + (drm_buf_desc_t *)arg, + sizeof(request))) + return -EFAULT; + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = request.agp_start; + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; + + for (offset = 0; + entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + offset); + buf->bus_address = agp_offset + offset; + buf->address = (void *)(agp_offset + dev->sg->handle + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_priv_size = sizeof(drm_radeon_buf_priv_t); + buf->dev_private = drm_alloc(sizeof(drm_radeon_buf_priv_t), + DRM_MEM_BUFS); + memset(buf->dev_private, 0, buf->dev_priv_size); + +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + + byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + + DRM_DEBUG("byte_count: %d\n", byte_count); + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + if (copy_to_user((drm_buf_desc_t *)arg, + &request, + sizeof(request))) + return -EFAULT; + dma->flags = _DRM_DMA_USE_SG; + + atomic_dec(&dev->buf_alloc); + return 0; +} + int radeon_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -188,7 +341,8 @@ int radeon_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, drm_radeon_private_t *dev_priv = dev->dev_private; drm_buf_desc_t request; - if (!dev_priv || dev_priv->is_pci) return -EINVAL; + printk("%s\n", __FUNCTION__); + if (!dev_priv) return -EINVAL; if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request))) return -EFAULT; @@ -196,13 +350,16 @@ int radeon_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) if (request.flags & _DRM_AGP_BUFFER) return radeon_addbufs_agp(inode, filp, cmd, arg); - else #endif + if (request.flags & _DRM_SG_BUFFER) { + return radeon_addbufs_sg(inode, filp, cmd, arg); + } else { return -EINVAL; + } } int radeon_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) + unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -215,7 +372,7 @@ int radeon_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, drm_buf_map_t request; int i; - if (!dma || !dev_priv || dev_priv->is_pci) return -EINVAL; + if (!dma || !dev_priv) return -EINVAL; DRM_DEBUG("\n"); @@ -227,11 +384,14 @@ int radeon_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - if (copy_from_user(&request, (drm_buf_map_t *)arg, sizeof(request))) + if (copy_from_user(&request, + (drm_buf_map_t *)arg, + sizeof(request))) return -EFAULT; if (request.count >= dma->buf_count) { - if (dma->flags & _DRM_DMA_USE_AGP) { + if (dma->flags & _DRM_DMA_USE_AGP || + dma->flags & _DRM_DMA_USE_SG) { drm_map_t *map; map = dev_priv->buffers; @@ -291,7 +451,9 @@ int radeon_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, request.count = dma->buf_count; DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - if (copy_to_user((drm_buf_map_t *)arg, &request, sizeof(request))) + if (copy_to_user((drm_buf_map_t *)arg, + &request, + sizeof(request))) return -EFAULT; return retcode; |