forked from MIrrors/gasket-driver
staging: gasket: support mapping of dma-bufs.
This allows userspace to pass in dma-buf file descriptors for mapping in addition to userspace virtual memory pointers, leaving cache maintenance to the dma-buf exporter and userspace application. Bug: 149764192 Change-Id: Iee8b581db0a461fe13ee8712d47d66f8fb16e7c9 Signed-off-by: Jonas Larsson <ljonas@google.com>
This commit is contained in:
committed by
Leonid Lobachev
parent
6535f9ada1
commit
0d361c0493
22
gasket.h
22
gasket.h
@@ -74,6 +74,21 @@ struct gasket_coherent_alloc_config_ioctl {
|
|||||||
u64 dma_address;
|
u64 dma_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common structure for ioctls mapping and unmapping dma-bufs when using the
|
||||||
|
* Gasket page_table module.
|
||||||
|
* map: boolean, non-zero to map, 0 to unmap.
|
||||||
|
* flags: see gasket_page_table_ioctl_flags.flags.
|
||||||
|
*/
|
||||||
|
struct gasket_page_table_ioctl_dmabuf {
|
||||||
|
u64 page_table_index;
|
||||||
|
u64 device_address;
|
||||||
|
int dmabuf_fd;
|
||||||
|
u32 num_pages;
|
||||||
|
u32 map;
|
||||||
|
u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
/* Base number for all Gasket-common IOCTLs */
|
/* Base number for all Gasket-common IOCTLs */
|
||||||
#define GASKET_IOCTL_BASE 0xDC
|
#define GASKET_IOCTL_BASE 0xDC
|
||||||
|
|
||||||
@@ -152,4 +167,11 @@ struct gasket_coherent_alloc_config_ioctl {
|
|||||||
#define GASKET_IOCTL_MAP_BUFFER_FLAGS \
|
#define GASKET_IOCTL_MAP_BUFFER_FLAGS \
|
||||||
_IOW(GASKET_IOCTL_BASE, 12, struct gasket_page_table_ioctl_flags)
|
_IOW(GASKET_IOCTL_BASE, 12, struct gasket_page_table_ioctl_flags)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tells the kernel to map/unmap dma-buf with fd to device_address in
|
||||||
|
* page_table_index page table.
|
||||||
|
*/
|
||||||
|
#define GASKET_IOCTL_MAP_DMABUF \
|
||||||
|
_IOW(GASKET_IOCTL_BASE, 13, struct gasket_page_table_ioctl_dmabuf)
|
||||||
|
|
||||||
#endif /* __GASKET_H__ */
|
#endif /* __GASKET_H__ */
|
||||||
|
|||||||
@@ -212,6 +212,38 @@ static int gasket_unmap_buffers(struct gasket_dev *gasket_dev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map/unmap dma-buf to/from a device virtual address. */
|
||||||
|
static int gasket_map_dmabuf(struct gasket_dev *gasket_dev,
|
||||||
|
struct gasket_page_table_ioctl_dmabuf __user *argp)
|
||||||
|
{
|
||||||
|
struct gasket_page_table_ioctl_dmabuf dbuf;
|
||||||
|
struct gasket_page_table *pg_tbl;
|
||||||
|
|
||||||
|
if (copy_from_user(&dbuf, argp, sizeof(dbuf)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dbuf.page_table_index >= gasket_dev->num_page_tables)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
pg_tbl = gasket_dev->page_table[dbuf.page_table_index];
|
||||||
|
if (gasket_page_table_is_dev_addr_bad(pg_tbl,
|
||||||
|
dbuf.device_address,
|
||||||
|
dbuf.num_pages * PAGE_SIZE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (dbuf.map)
|
||||||
|
return gasket_page_table_map_dmabuf(pg_tbl,
|
||||||
|
dbuf.dmabuf_fd,
|
||||||
|
dbuf.device_address,
|
||||||
|
dbuf.num_pages,
|
||||||
|
dbuf.flags);
|
||||||
|
else
|
||||||
|
return gasket_page_table_unmap_dmabuf(pg_tbl,
|
||||||
|
dbuf.dmabuf_fd,
|
||||||
|
dbuf.device_address,
|
||||||
|
dbuf.num_pages);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reserve structures for coherent allocation, and allocate or free the
|
* Reserve structures for coherent allocation, and allocate or free the
|
||||||
* corresponding memory.
|
* corresponding memory.
|
||||||
@@ -291,6 +323,7 @@ static bool gasket_ioctl_check_permissions(struct file *filp, uint cmd)
|
|||||||
case GASKET_IOCTL_MAP_BUFFER:
|
case GASKET_IOCTL_MAP_BUFFER:
|
||||||
case GASKET_IOCTL_MAP_BUFFER_FLAGS:
|
case GASKET_IOCTL_MAP_BUFFER_FLAGS:
|
||||||
case GASKET_IOCTL_UNMAP_BUFFER:
|
case GASKET_IOCTL_UNMAP_BUFFER:
|
||||||
|
case GASKET_IOCTL_MAP_DMABUF:
|
||||||
return alive && write;
|
return alive && write;
|
||||||
|
|
||||||
case GASKET_IOCTL_CLEAR_EVENTFD:
|
case GASKET_IOCTL_CLEAR_EVENTFD:
|
||||||
@@ -388,6 +421,9 @@ long gasket_handle_ioctl(struct file *filp, uint cmd, void __user *argp)
|
|||||||
trace_gasket_ioctl_integer_data(0);
|
trace_gasket_ioctl_integer_data(0);
|
||||||
retval = gasket_interrupt_reset_counts(gasket_dev);
|
retval = gasket_interrupt_reset_counts(gasket_dev);
|
||||||
break;
|
break;
|
||||||
|
case GASKET_IOCTL_MAP_DMABUF:
|
||||||
|
retval = gasket_map_dmabuf(gasket_dev, argp);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* If we don't understand the ioctl, the best we can do is trace
|
/* If we don't understand the ioctl, the best we can do is trace
|
||||||
* the arg.
|
* the arg.
|
||||||
@@ -424,6 +460,7 @@ long gasket_is_supported_ioctl(uint cmd)
|
|||||||
case GASKET_IOCTL_MAP_BUFFER:
|
case GASKET_IOCTL_MAP_BUFFER:
|
||||||
case GASKET_IOCTL_MAP_BUFFER_FLAGS:
|
case GASKET_IOCTL_MAP_BUFFER_FLAGS:
|
||||||
case GASKET_IOCTL_UNMAP_BUFFER:
|
case GASKET_IOCTL_UNMAP_BUFFER:
|
||||||
|
case GASKET_IOCTL_MAP_DMABUF:
|
||||||
case GASKET_IOCTL_CLEAR_INTERRUPT_COUNTS:
|
case GASKET_IOCTL_CLEAR_INTERRUPT_COUNTS:
|
||||||
case GASKET_IOCTL_CONFIG_COHERENT_ALLOCATOR:
|
case GASKET_IOCTL_CONFIG_COHERENT_ALLOCATOR:
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -42,9 +42,11 @@
|
|||||||
#include "gasket_page_table.h"
|
#include "gasket_page_table.h"
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/dma-buf.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/list.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
@@ -177,6 +179,15 @@ struct gasket_coherent_page_entry {
|
|||||||
u32 in_use;
|
u32 in_use;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Storage for dmabuf mapping information. */
|
||||||
|
struct gasket_dmabuf_mapping {
|
||||||
|
struct dma_buf *dmabuf;
|
||||||
|
struct dma_buf_attachment *attachment;
|
||||||
|
struct sg_table *sgt;
|
||||||
|
enum dma_data_direction direction;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [Host-side] page table descriptor.
|
* [Host-side] page table descriptor.
|
||||||
*
|
*
|
||||||
@@ -237,6 +248,9 @@ struct gasket_page_table {
|
|||||||
* gasket_mmap function, so user_virt belongs in the driver anyhow.
|
* gasket_mmap function, so user_virt belongs in the driver anyhow.
|
||||||
*/
|
*/
|
||||||
struct gasket_coherent_page_entry *coherent_pages;
|
struct gasket_coherent_page_entry *coherent_pages;
|
||||||
|
|
||||||
|
/* List of dmabufs currently attached and mapped. */
|
||||||
|
struct list_head dmabufs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* See gasket_page_table.h for description. */
|
/* See gasket_page_table.h for description. */
|
||||||
@@ -306,6 +320,7 @@ int gasket_page_table_init(struct gasket_page_table **ppg_tbl,
|
|||||||
(u64 __iomem *)&bar_data->virt_base[page_table_config->extended_reg];
|
(u64 __iomem *)&bar_data->virt_base[page_table_config->extended_reg];
|
||||||
pg_tbl->device = get_device(device);
|
pg_tbl->device = get_device(device);
|
||||||
pg_tbl->pci_dev = pci_dev;
|
pg_tbl->pci_dev = pci_dev;
|
||||||
|
INIT_LIST_HEAD(&pg_tbl->dmabufs);
|
||||||
|
|
||||||
dev_dbg(device, "Page table initialized successfully\n");
|
dev_dbg(device, "Page table initialized successfully\n");
|
||||||
|
|
||||||
@@ -481,7 +496,9 @@ static bool gasket_release_page(struct page *page)
|
|||||||
*/
|
*/
|
||||||
static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
|
static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
|
||||||
struct gasket_page_table_entry *ptes,
|
struct gasket_page_table_entry *ptes,
|
||||||
u64 __iomem *slots, ulong host_addr,
|
u64 __iomem *slots,
|
||||||
|
struct sg_page_iter *sg_iter,
|
||||||
|
ulong host_addr,
|
||||||
uint num_pages, u32 flags,
|
uint num_pages, u32 flags,
|
||||||
int is_simple_mapping)
|
int is_simple_mapping)
|
||||||
{
|
{
|
||||||
@@ -492,6 +509,12 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
|
|||||||
ulong page_addr;
|
ulong page_addr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* Must have a virtual host address or a sg iterator, but not both. */
|
||||||
|
if(!((uintptr_t)host_addr ^ (uintptr_t)sg_iter)) {
|
||||||
|
dev_err(pg_tbl->device, "need sg_iter or host_addr\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (GET(FLAGS_DMA_DIRECTION, flags) == DMA_NONE) {
|
if (GET(FLAGS_DMA_DIRECTION, flags) == DMA_NONE) {
|
||||||
dev_err(pg_tbl->device, "invalid DMA direction flags=0x%lx\n",
|
dev_err(pg_tbl->device, "invalid DMA direction flags=0x%lx\n",
|
||||||
(unsigned long)flags);
|
(unsigned long)flags);
|
||||||
@@ -502,7 +525,15 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
|
|||||||
page_addr = host_addr + i * PAGE_SIZE;
|
page_addr = host_addr + i * PAGE_SIZE;
|
||||||
offset = page_addr & (PAGE_SIZE - 1);
|
offset = page_addr & (PAGE_SIZE - 1);
|
||||||
dev_dbg(pg_tbl->device, "%s i %d\n", __func__, i);
|
dev_dbg(pg_tbl->device, "%s i %d\n", __func__, i);
|
||||||
if (is_coherent(pg_tbl, host_addr)) {
|
if (sg_iter) {
|
||||||
|
if (!__sg_page_iter_next(sg_iter))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Page already mapped for DMA. */
|
||||||
|
ptes[i].dma_addr = sg_page_iter_dma_address(sg_iter);
|
||||||
|
ptes[i].page = NULL;
|
||||||
|
offset = 0;
|
||||||
|
} else if (is_coherent(pg_tbl, host_addr)) {
|
||||||
u64 off =
|
u64 off =
|
||||||
(u64)host_addr -
|
(u64)host_addr -
|
||||||
(u64)pg_tbl->coherent_pages[0].user_virt;
|
(u64)pg_tbl->coherent_pages[0].user_virt;
|
||||||
@@ -853,6 +884,7 @@ static void gasket_page_table_unmap_nolock(struct gasket_page_table *pg_tbl,
|
|||||||
* If there is an error, no pages are mapped.
|
* If there is an error, no pages are mapped.
|
||||||
*/
|
*/
|
||||||
static int gasket_map_simple_pages(struct gasket_page_table *pg_tbl,
|
static int gasket_map_simple_pages(struct gasket_page_table *pg_tbl,
|
||||||
|
struct sg_page_iter *sg_iter,
|
||||||
ulong host_addr, u64 dev_addr,
|
ulong host_addr, u64 dev_addr,
|
||||||
uint num_pages, u32 flags)
|
uint num_pages, u32 flags)
|
||||||
{
|
{
|
||||||
@@ -869,8 +901,8 @@ static int gasket_map_simple_pages(struct gasket_page_table *pg_tbl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = gasket_perform_mapping(pg_tbl, pg_tbl->entries + slot_idx,
|
ret = gasket_perform_mapping(pg_tbl, pg_tbl->entries + slot_idx,
|
||||||
pg_tbl->base_slot + slot_idx, host_addr,
|
pg_tbl->base_slot + slot_idx, sg_iter,
|
||||||
num_pages, flags, 1);
|
host_addr, num_pages, flags, 1);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
gasket_page_table_unmap_nolock(pg_tbl, dev_addr, num_pages);
|
gasket_page_table_unmap_nolock(pg_tbl, dev_addr, num_pages);
|
||||||
@@ -1000,6 +1032,7 @@ static int gasket_alloc_extended_entries(struct gasket_page_table *pg_tbl,
|
|||||||
* If there is an error, no pages are mapped.
|
* If there is an error, no pages are mapped.
|
||||||
*/
|
*/
|
||||||
static int gasket_map_extended_pages(struct gasket_page_table *pg_tbl,
|
static int gasket_map_extended_pages(struct gasket_page_table *pg_tbl,
|
||||||
|
struct sg_page_iter *sg_iter,
|
||||||
ulong host_addr, u64 dev_addr,
|
ulong host_addr, u64 dev_addr,
|
||||||
uint num_pages, u32 flags)
|
uint num_pages, u32 flags)
|
||||||
{
|
{
|
||||||
@@ -1034,8 +1067,8 @@ static int gasket_map_extended_pages(struct gasket_page_table *pg_tbl,
|
|||||||
slot_base =
|
slot_base =
|
||||||
(u64 __iomem *)(page_address(pte->page) + pte->offset);
|
(u64 __iomem *)(page_address(pte->page) + pte->offset);
|
||||||
ret = gasket_perform_mapping(pg_tbl, pte->sublevel + slot_idx,
|
ret = gasket_perform_mapping(pg_tbl, pte->sublevel + slot_idx,
|
||||||
slot_base + slot_idx, host_addr,
|
slot_base + slot_idx, sg_iter,
|
||||||
len, flags, 0);
|
host_addr, len, flags, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
gasket_page_table_unmap_nolock(pg_tbl, dev_addr,
|
gasket_page_table_unmap_nolock(pg_tbl, dev_addr,
|
||||||
num_pages);
|
num_pages);
|
||||||
@@ -1053,7 +1086,8 @@ static int gasket_map_extended_pages(struct gasket_page_table *pg_tbl,
|
|||||||
remain -= len;
|
remain -= len;
|
||||||
slot_idx = 0;
|
slot_idx = 0;
|
||||||
pte++;
|
pte++;
|
||||||
host_addr += len * PAGE_SIZE;
|
if (host_addr)
|
||||||
|
host_addr += len * PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1078,10 +1112,10 @@ int gasket_page_table_map(struct gasket_page_table *pg_tbl, ulong host_addr,
|
|||||||
mutex_lock(&pg_tbl->mutex);
|
mutex_lock(&pg_tbl->mutex);
|
||||||
|
|
||||||
if (gasket_addr_is_simple(pg_tbl, dev_addr)) {
|
if (gasket_addr_is_simple(pg_tbl, dev_addr)) {
|
||||||
ret = gasket_map_simple_pages(pg_tbl, host_addr, dev_addr,
|
ret = gasket_map_simple_pages(pg_tbl, NULL, host_addr, dev_addr,
|
||||||
num_pages, flags);
|
num_pages, flags);
|
||||||
} else {
|
} else {
|
||||||
ret = gasket_map_extended_pages(pg_tbl, host_addr, dev_addr,
|
ret = gasket_map_extended_pages(pg_tbl, NULL, host_addr, dev_addr,
|
||||||
num_pages, flags);
|
num_pages, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1116,8 +1150,144 @@ void gasket_page_table_unmap(struct gasket_page_table *pg_tbl, u64 dev_addr,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(gasket_page_table_unmap);
|
EXPORT_SYMBOL(gasket_page_table_unmap);
|
||||||
|
|
||||||
|
int gasket_page_table_map_dmabuf(struct gasket_page_table *pg_tbl, int fd,
|
||||||
|
u64 dev_addr, uint num_pages, u32 flags)
|
||||||
|
{
|
||||||
|
int ret, locked = 0;
|
||||||
|
struct dma_buf *dmabuf = NULL;
|
||||||
|
struct dma_buf_attachment *attachment = NULL;
|
||||||
|
struct sg_table *sgt = NULL;
|
||||||
|
struct sg_page_iter sg_iter;
|
||||||
|
struct gasket_dmabuf_mapping *mapping = NULL;
|
||||||
|
enum dma_data_direction direction = GET(FLAGS_DMA_DIRECTION, flags);
|
||||||
|
|
||||||
|
if (direction == DMA_NONE) {
|
||||||
|
dev_err(pg_tbl->device,
|
||||||
|
"invalid DMA direction flags=0x%x\n", flags);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!num_pages)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dmabuf = dma_buf_get(fd);
|
||||||
|
if (IS_ERR(dmabuf))
|
||||||
|
return PTR_ERR(dmabuf);
|
||||||
|
|
||||||
|
if (PAGE_ALIGN(dmabuf->size) / PAGE_SIZE < num_pages)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
|
||||||
|
if (!mapping) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment = dma_buf_attach(dmabuf, pg_tbl->device);
|
||||||
|
if (IS_ERR(attachment)) {
|
||||||
|
ret = PTR_ERR(attachment);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
sgt = dma_buf_map_attachment(attachment, direction);
|
||||||
|
if (IS_ERR(sgt)) {
|
||||||
|
ret = PTR_ERR(sgt);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&pg_tbl->mutex);
|
||||||
|
locked = 1;
|
||||||
|
|
||||||
|
__sg_page_iter_start(&sg_iter, sgt->sgl, sgt->nents, 0);
|
||||||
|
if (gasket_addr_is_simple(pg_tbl, dev_addr)) {
|
||||||
|
ret = gasket_map_simple_pages(pg_tbl, &sg_iter, 0, dev_addr,
|
||||||
|
num_pages, flags);
|
||||||
|
} else {
|
||||||
|
ret = gasket_map_extended_pages(pg_tbl, &sg_iter, 0, dev_addr,
|
||||||
|
num_pages, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
INIT_LIST_HEAD(&mapping->list);
|
||||||
|
get_dma_buf(dmabuf);
|
||||||
|
mapping->dmabuf = dmabuf;
|
||||||
|
mapping->attachment = attachment;
|
||||||
|
mapping->sgt = sgt;
|
||||||
|
mapping->direction = direction;
|
||||||
|
list_add(&mapping->list, &pg_tbl->dmabufs);
|
||||||
|
sgt = NULL;
|
||||||
|
attachment = NULL;
|
||||||
|
mapping = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (locked)
|
||||||
|
mutex_unlock(&pg_tbl->mutex);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(sgt))
|
||||||
|
dma_buf_unmap_attachment(attachment, sgt, direction);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(attachment))
|
||||||
|
dma_buf_detach(dmabuf, attachment);
|
||||||
|
|
||||||
|
kfree(mapping);
|
||||||
|
dma_buf_put(dmabuf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(gasket_page_table_map_dmabuf);
|
||||||
|
|
||||||
|
/* Detach dmabuf from our device if attached, NULL to detach all. */
|
||||||
|
static void gasket_page_table_detach_dmabuf_nolock(struct gasket_page_table *pg_tbl,
|
||||||
|
struct dma_buf *dmabuf)
|
||||||
|
{
|
||||||
|
struct gasket_dmabuf_mapping *mapping, *tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(mapping, tmp, &pg_tbl->dmabufs, list) {
|
||||||
|
if (!dmabuf || mapping->dmabuf == dmabuf) {
|
||||||
|
dma_buf_unmap_attachment(mapping->attachment,
|
||||||
|
mapping->sgt,
|
||||||
|
mapping->direction);
|
||||||
|
dma_buf_detach(mapping->dmabuf, mapping->attachment);
|
||||||
|
dma_buf_put(mapping->dmabuf);
|
||||||
|
list_del(&mapping->list);
|
||||||
|
kfree(mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int gasket_page_table_unmap_dmabuf(struct gasket_page_table *pg_tbl, int fd,
|
||||||
|
u64 dev_addr, uint num_pages)
|
||||||
|
{
|
||||||
|
struct dma_buf *dmabuf;
|
||||||
|
struct gasket_dmabuf_mapping *mapping, *tmp;
|
||||||
|
|
||||||
|
dmabuf = dma_buf_get(fd);
|
||||||
|
if (IS_ERR(dmabuf))
|
||||||
|
return PTR_ERR(dmabuf);
|
||||||
|
|
||||||
|
if (PAGE_ALIGN(dmabuf->size) / PAGE_SIZE < num_pages) {
|
||||||
|
dma_buf_put(dmabuf);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&pg_tbl->mutex);
|
||||||
|
|
||||||
|
gasket_page_table_unmap_nolock(pg_tbl, dev_addr, num_pages);
|
||||||
|
gasket_page_table_detach_dmabuf_nolock(pg_tbl, dmabuf);
|
||||||
|
|
||||||
|
mutex_unlock(&pg_tbl->mutex);
|
||||||
|
|
||||||
|
dma_buf_put(dmabuf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(gasket_page_table_unmap_dmabuf);
|
||||||
|
|
||||||
static void gasket_page_table_unmap_all_nolock(struct gasket_page_table *pg_tbl)
|
static void gasket_page_table_unmap_all_nolock(struct gasket_page_table *pg_tbl)
|
||||||
{
|
{
|
||||||
|
gasket_page_table_detach_dmabuf_nolock(pg_tbl, NULL);
|
||||||
|
|
||||||
gasket_unmap_simple_pages(pg_tbl,
|
gasket_unmap_simple_pages(pg_tbl,
|
||||||
gasket_components_to_dev_address(pg_tbl, 1, 0,
|
gasket_components_to_dev_address(pg_tbl, 1, 0,
|
||||||
0),
|
0),
|
||||||
|
|||||||
@@ -99,6 +99,38 @@ int gasket_page_table_partition(struct gasket_page_table *page_table,
|
|||||||
int gasket_page_table_map(struct gasket_page_table *page_table, ulong host_addr,
|
int gasket_page_table_map(struct gasket_page_table *page_table, ulong host_addr,
|
||||||
u64 dev_addr, uint num_pages, u32 flags);
|
u64 dev_addr, uint num_pages, u32 flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map dma-buf pages into device memory.
|
||||||
|
* @page_table: Gasket page table pointer.
|
||||||
|
* @fd: Dma-buf file descriptor.
|
||||||
|
* @dev_addr: Starting device address of the pages.
|
||||||
|
* @num_pages: Number of [4kB] pages to map.
|
||||||
|
* @flags: Specifies attributes to apply to the pages.
|
||||||
|
* Internal structure matches gasket_page_table_ioctl_flags.flags.
|
||||||
|
*
|
||||||
|
* Description: Maps "num_pages" pages of dma-buf pointed to by
|
||||||
|
* fd to the address "dev_addr" in device memory.
|
||||||
|
*
|
||||||
|
* The caller is responsible for checking the dev_addr range.
|
||||||
|
*
|
||||||
|
* Returns 0 if successful or a non-zero error number otherwise.
|
||||||
|
* If there is an error, no pages are mapped.
|
||||||
|
*/
|
||||||
|
int gasket_page_table_map_dmabuf(struct gasket_page_table *page_table, int fd,
|
||||||
|
u64 dev_addr, uint num_pages, u32 flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unmap dma-buf pages from device memory.
|
||||||
|
* @page_table: Gasket page table pointer.
|
||||||
|
* @fd: Dma-buf file descriptor.
|
||||||
|
* @dev_addr: Starting device address of the pages.
|
||||||
|
* @num_pages: Number of [4kB] pages to map.
|
||||||
|
*
|
||||||
|
* Description: The inverse of gasket_page_table_map_dmabuf.
|
||||||
|
*/
|
||||||
|
int gasket_page_table_unmap_dmabuf(struct gasket_page_table *page_table, int fd,
|
||||||
|
u64 dev_addr, uint num_pages);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Un-map host pages from device memory.
|
* Un-map host pages from device memory.
|
||||||
* @page_table: Gasket page table pointer.
|
* @page_table: Gasket page table pointer.
|
||||||
|
|||||||
Reference in New Issue
Block a user