|
@@ -98,6 +98,7 @@
|
|
|
#include <linux/seq_file.h>
|
|
|
#include <linux/highmem.h>
|
|
|
#include <linux/debugfs.h>
|
|
|
+#include <linux/vmalloc.h>
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/poll.h>
|
|
@@ -105,8 +106,6 @@
|
|
|
#include <linux/kref.h>
|
|
|
#include <linux/io.h>
|
|
|
|
|
|
-#include <media/videobuf-dma-sg.h>
|
|
|
-
|
|
|
/* system controller registers */
|
|
|
#define SYS_IRQ_SOURCE_CTL 0x24
|
|
|
#define SYS_IRQ_OUTPUT_EN 0x28
|
|
@@ -142,7 +141,10 @@ struct fpga_info {
|
|
|
|
|
|
struct data_buf {
|
|
|
struct list_head entry;
|
|
|
- struct videobuf_dmabuf vb;
|
|
|
+ void *vaddr;
|
|
|
+ struct scatterlist *sglist;
|
|
|
+ int sglen;
|
|
|
+ int nr_pages;
|
|
|
size_t size;
|
|
|
};
|
|
|
|
|
@@ -207,6 +209,68 @@ static void fpga_device_release(struct kref *ref)
|
|
|
* Data Buffer Allocation Helpers
|
|
|
*/
|
|
|
|
|
|
+static int carma_dma_init(struct data_buf *buf, int nr_pages)
|
|
|
+{
|
|
|
+ struct page *pg;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
|
|
|
+ if (NULL == buf->vaddr) {
|
|
|
+ pr_debug("vmalloc_32(%d pages) failed\n", nr_pages);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_debug("vmalloc is at addr 0x%08lx, size=%d\n",
|
|
|
+ (unsigned long)buf->vaddr,
|
|
|
+ nr_pages << PAGE_SHIFT);
|
|
|
+
|
|
|
+ memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
|
|
|
+ buf->nr_pages = nr_pages;
|
|
|
+
|
|
|
+ buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist));
|
|
|
+ if (NULL == buf->sglist)
|
|
|
+ goto vzalloc_err;
|
|
|
+
|
|
|
+ sg_init_table(buf->sglist, buf->nr_pages);
|
|
|
+ for (i = 0; i < buf->nr_pages; i++) {
|
|
|
+ pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);
|
|
|
+ if (NULL == pg)
|
|
|
+ goto vmalloc_to_page_err;
|
|
|
+ sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+
|
|
|
+vmalloc_to_page_err:
|
|
|
+ vfree(buf->sglist);
|
|
|
+ buf->sglist = NULL;
|
|
|
+vzalloc_err:
|
|
|
+ vfree(buf->vaddr);
|
|
|
+ buf->vaddr = NULL;
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+static int carma_dma_map(struct device *dev, struct data_buf *buf)
|
|
|
+{
|
|
|
+ buf->sglen = dma_map_sg(dev, buf->sglist,
|
|
|
+ buf->nr_pages, DMA_FROM_DEVICE);
|
|
|
+
|
|
|
+ if (0 == buf->sglen) {
|
|
|
+ pr_warn("%s: dma_map_sg failed\n", __func__);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int carma_dma_unmap(struct device *dev, struct data_buf *buf)
|
|
|
+{
|
|
|
+ if (!buf->sglen)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ dma_unmap_sg(dev, buf->sglist, buf->sglen, DMA_FROM_DEVICE);
|
|
|
+ buf->sglen = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* data_free_buffer() - free a single data buffer and all allocated memory
|
|
|
* @buf: the buffer to free
|
|
@@ -221,7 +285,8 @@ static void data_free_buffer(struct data_buf *buf)
|
|
|
return;
|
|
|
|
|
|
/* free all memory */
|
|
|
- videobuf_dma_free(&buf->vb);
|
|
|
+ vfree(buf->sglist);
|
|
|
+ vfree(buf->vaddr);
|
|
|
kfree(buf);
|
|
|
}
|
|
|
|
|
@@ -230,7 +295,7 @@ static void data_free_buffer(struct data_buf *buf)
|
|
|
* @bytes: the number of bytes required
|
|
|
*
|
|
|
* This allocates all space needed for a data buffer. It must be mapped before
|
|
|
- * use in a DMA transaction using videobuf_dma_map().
|
|
|
+ * use in a DMA transaction using carma_dma_map().
|
|
|
*
|
|
|
* Returns NULL on failure
|
|
|
*/
|
|
@@ -252,9 +317,8 @@ static struct data_buf *data_alloc_buffer(const size_t bytes)
|
|
|
INIT_LIST_HEAD(&buf->entry);
|
|
|
buf->size = bytes;
|
|
|
|
|
|
- /* allocate the videobuf */
|
|
|
- videobuf_dma_init(&buf->vb);
|
|
|
- ret = videobuf_dma_init_kernel(&buf->vb, DMA_FROM_DEVICE, nr_pages);
|
|
|
+ /* allocate the buffer */
|
|
|
+ ret = carma_dma_init(buf, nr_pages);
|
|
|
if (ret)
|
|
|
goto out_free_buf;
|
|
|
|
|
@@ -285,13 +349,13 @@ static void data_free_buffers(struct fpga_device *priv)
|
|
|
|
|
|
list_for_each_entry_safe(buf, tmp, &priv->free, entry) {
|
|
|
list_del_init(&buf->entry);
|
|
|
- videobuf_dma_unmap(priv->dev, &buf->vb);
|
|
|
+ carma_dma_unmap(priv->dev, buf);
|
|
|
data_free_buffer(buf);
|
|
|
}
|
|
|
|
|
|
list_for_each_entry_safe(buf, tmp, &priv->used, entry) {
|
|
|
list_del_init(&buf->entry);
|
|
|
- videobuf_dma_unmap(priv->dev, &buf->vb);
|
|
|
+ carma_dma_unmap(priv->dev, buf);
|
|
|
data_free_buffer(buf);
|
|
|
}
|
|
|
|
|
@@ -330,7 +394,7 @@ static int data_alloc_buffers(struct fpga_device *priv)
|
|
|
break;
|
|
|
|
|
|
/* map it for DMA */
|
|
|
- ret = videobuf_dma_map(priv->dev, &buf->vb);
|
|
|
+ ret = carma_dma_map(priv->dev, buf);
|
|
|
if (ret) {
|
|
|
data_free_buffer(buf);
|
|
|
break;
|
|
@@ -634,8 +698,8 @@ static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf)
|
|
|
dma_addr_t dst, src;
|
|
|
unsigned long dma_flags = 0;
|
|
|
|
|
|
- dst_sg = buf->vb.sglist;
|
|
|
- dst_nents = buf->vb.sglen;
|
|
|
+ dst_sg = buf->sglist;
|
|
|
+ dst_nents = buf->sglen;
|
|
|
|
|
|
src_sg = priv->corl_table.sgl;
|
|
|
src_nents = priv->corl_nents;
|
|
@@ -1134,7 +1198,7 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count,
|
|
|
spin_unlock_irq(&priv->lock);
|
|
|
|
|
|
/* Buffers are always mapped: unmap it */
|
|
|
- videobuf_dma_unmap(priv->dev, &dbuf->vb);
|
|
|
+ carma_dma_unmap(priv->dev, dbuf);
|
|
|
|
|
|
/* save the buffer for later */
|
|
|
reader->buf = dbuf;
|
|
@@ -1143,7 +1207,7 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count,
|
|
|
have_buffer:
|
|
|
/* Get the number of bytes available */
|
|
|
avail = dbuf->size - reader->buf_start;
|
|
|
- data = dbuf->vb.vaddr + reader->buf_start;
|
|
|
+ data = dbuf->vaddr + reader->buf_start;
|
|
|
|
|
|
/* Get the number of bytes we can transfer */
|
|
|
count = min(count, avail);
|
|
@@ -1171,7 +1235,7 @@ have_buffer:
|
|
|
* If it fails, we pretend that the read never happed and return
|
|
|
* -EFAULT to userspace. The read will be retried.
|
|
|
*/
|
|
|
- ret = videobuf_dma_map(priv->dev, &dbuf->vb);
|
|
|
+ ret = carma_dma_map(priv->dev, dbuf);
|
|
|
if (ret) {
|
|
|
dev_err(priv->dev, "unable to remap buffer for DMA\n");
|
|
|
return -EFAULT;
|
|
@@ -1203,7 +1267,7 @@ out_unlock:
|
|
|
spin_unlock_irq(&priv->lock);
|
|
|
|
|
|
if (drop_buffer) {
|
|
|
- videobuf_dma_unmap(priv->dev, &dbuf->vb);
|
|
|
+ carma_dma_unmap(priv->dev, dbuf);
|
|
|
data_free_buffer(dbuf);
|
|
|
}
|
|
|
|