summaryrefslogtreecommitdiffstats
path: root/drivers/uio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uio')
-rw-r--r--drivers/uio/uio.c47
-rw-r--r--drivers/uio/uio_dmem_genirq.c22
-rw-r--r--drivers/uio/uio_pruss.c6
3 files changed, 59 insertions, 16 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 2d572f6c8e..009158fef2 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -24,6 +24,7 @@
#include <linux/kobject.h>
#include <linux/cdev.h>
#include <linux/uio_driver.h>
+#include <linux/dma-mapping.h>
#define UIO_MAX_DEVICES (1U << MINORBITS)
@@ -759,6 +760,49 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
vma->vm_page_prot);
}
+static int uio_mmap_dma_coherent(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ struct uio_mem *mem;
+ void *addr;
+ int ret = 0;
+ int mi;
+
+ mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return -EINVAL;
+
+ mem = idev->info->mem + mi;
+
+ if (mem->addr & ~PAGE_MASK)
+ return -ENODEV;
+ if (mem->dma_addr & ~PAGE_MASK)
+ return -ENODEV;
+ if (!mem->dma_device)
+ return -ENODEV;
+ if (vma->vm_end - vma->vm_start > mem->size)
+ return -EINVAL;
+
+ dev_warn(mem->dma_device,
+ "use of UIO_MEM_DMA_COHERENT is highly discouraged");
+
+ /*
+ * UIO uses offset to index into the maps for a device.
+ * We need to clear vm_pgoff for dma_mmap_coherent.
+ */
+ vma->vm_pgoff = 0;
+
+ addr = (void *)(uintptr_t)mem->addr;
+ ret = dma_mmap_coherent(mem->dma_device,
+ vma,
+ addr,
+ mem->dma_addr,
+ vma->vm_end - vma->vm_start);
+ vma->vm_pgoff = mi;
+
+ return ret;
+}
+
static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct uio_listener *listener = filep->private_data;
@@ -806,6 +850,9 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
case UIO_MEM_VIRTUAL:
ret = uio_mmap_logical(vma);
break;
+ case UIO_MEM_DMA_COHERENT:
+ ret = uio_mmap_dma_coherent(vma);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index 5313307c27..13cc35ab5d 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -36,7 +36,6 @@ struct uio_dmem_genirq_platdata {
struct platform_device *pdev;
unsigned int dmem_region_start;
unsigned int num_dmem_regions;
- void *dmem_region_vaddr[MAX_UIO_MAPS];
struct mutex alloc_lock;
unsigned int refcnt;
};
@@ -50,7 +49,6 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
{
struct uio_dmem_genirq_platdata *priv = info->priv;
struct uio_mem *uiomem;
- int dmem_region = priv->dmem_region_start;
uiomem = &priv->uioinfo->mem[priv->dmem_region_start];
@@ -61,11 +59,8 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
break;
addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size,
- (dma_addr_t *)&uiomem->addr, GFP_KERNEL);
- if (!addr) {
- uiomem->addr = DMEM_MAP_ERROR;
- }
- priv->dmem_region_vaddr[dmem_region++] = addr;
+ &uiomem->dma_addr, GFP_KERNEL);
+ uiomem->addr = addr ? (uintptr_t) addr : DMEM_MAP_ERROR;
++uiomem;
}
priv->refcnt++;
@@ -80,7 +75,6 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
{
struct uio_dmem_genirq_platdata *priv = info->priv;
struct uio_mem *uiomem;
- int dmem_region = priv->dmem_region_start;
/* Tell the Runtime PM code that the device has become idle */
pm_runtime_put_sync(&priv->pdev->dev);
@@ -93,13 +87,12 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) {
if (!uiomem->size)
break;
- if (priv->dmem_region_vaddr[dmem_region]) {
- dma_free_coherent(&priv->pdev->dev, uiomem->size,
- priv->dmem_region_vaddr[dmem_region],
- uiomem->addr);
+ if (uiomem->addr) {
+ dma_free_coherent(uiomem->dma_device, uiomem->size,
+ (void *) (uintptr_t) uiomem->addr,
+ uiomem->dma_addr);
}
uiomem->addr = DMEM_MAP_ERROR;
- ++dmem_region;
++uiomem;
}
@@ -264,7 +257,8 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev)
" dynamic and fixed memory regions.\n");
break;
}
- uiomem->memtype = UIO_MEM_PHYS;
+ uiomem->memtype = UIO_MEM_DMA_COHERENT;
+ uiomem->dma_device = &pdev->dev;
uiomem->addr = DMEM_MAP_ERROR;
uiomem->size = pdata->dynamic_region_sizes[i];
++uiomem;
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
index 77e2dc4048..f67881cba6 100644
--- a/drivers/uio/uio_pruss.c
+++ b/drivers/uio/uio_pruss.c
@@ -191,9 +191,11 @@ static int pruss_probe(struct platform_device *pdev)
p->mem[1].size = sram_pool_sz;
p->mem[1].memtype = UIO_MEM_PHYS;
- p->mem[2].addr = gdev->ddr_paddr;
+ p->mem[2].addr = (uintptr_t) gdev->ddr_vaddr;
+ p->mem[2].dma_addr = gdev->ddr_paddr;
p->mem[2].size = extram_pool_sz;
- p->mem[2].memtype = UIO_MEM_PHYS;
+ p->mem[2].memtype = UIO_MEM_DMA_COHERENT;
+ p->mem[2].dma_device = dev;
p->name = devm_kasprintf(dev, GFP_KERNEL, "pruss_evt%d", cnt);
p->version = DRV_VERSION;