summaryrefslogtreecommitdiff
path: root/linux/radeon_bufs.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/radeon_bufs.c')
-rw-r--r--linux/radeon_bufs.c188
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;