[PATCH 09/11] swiotlb: add swiotlb_map/unmap_page

Becky Bruce
2008-12-19T05:11:57Z

Also, change swiotlb_map/unmap_single to call the page
versions by converting the arguments into a page address and
offset.

Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
---
include/linux/swiotlb.h | 10 +++++++
lib/swiotlb.c | 63 ++++++++++++++++++++++++++++++++---------------
2 files changed, 53 insertions(+), 20 deletions(-)

diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index f4d1be3..ecb5eac 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -79,6 +79,16 @@ swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
unsigned long offset, size_t size,
enum dma_data_direction dir);

+extern dma_addr_t
+swiotlb_map_page_attrs(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs);
+
+extern void
+swiotlb_unmap_page_attrs(struct device *hwdev, dma_addr_t dev_addr, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs);
+
extern int
swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);

diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index fc906d5..166aa78 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -606,19 +606,17 @@ swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
}
}

-/*
- * Map a single buffer of the indicated size for DMA in streaming mode. The
- * physical address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory until
- * either swiotlb_unmap_single or swiotlb_dma_sync_single is performed.
- */
-dma_addr_t
-swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
- enum dma_data_direction dir, struct dma_attrs *attrs)
+dma_addr_t swiotlb_map_page_attrs(struct device *hwdev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
{
- dma_addr_t dev_addr = virt_to_dma_addr(hwdev, ptr);
+ dma_addr_t dev_addr;
void *map;
+ phys_addr_t phys;
+
+ phys = page_to_phys(page) + offset;
+ dev_addr = phys_to_dma_addr(hwdev, phys);

BUG_ON(dir == DMA_NONE);
/*
@@ -633,7 +631,7 @@ swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
/*
* Oh well, have to allocate and map a bounce buffer.
*/
- map = map_single(hwdev, virt_to_phys(ptr), size, dir);
+ map = map_single(hwdev, phys, size, dir);
if (!map) {
swiotlb_full(hwdev, size, dir, 1);
map = io_tlb_overflow_buffer;
@@ -646,9 +644,40 @@ swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
*/
if (swiotlb_addr_needs_mapping(hwdev, dev_addr, size))
panic("map_single: bounce buffer is not DMA'ble");
-
return dev_addr;
}
+EXPORT_SYMBOL(swiotlb_map_page_attrs);
+
+void swiotlb_unmap_page_attrs(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ char *dma_addr = dma_addr_to_virt(hwdev, dev_addr);
+
+ BUG_ON(dir == DMA_NONE);
+ if (is_swiotlb_buffer(dma_addr))
+ unmap_single(hwdev, dma_addr, size, dir);
+ else if (dir == DMA_FROM_DEVICE)
+ dma_mark_clean(dma_addr, size);
+
+}
+EXPORT_SYMBOL(swiotlb_unmap_page_attrs);
+
+/*
+ * Map a single buffer of the indicated size for DMA in streaming mode. The
+ * physical address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory until
+ * either swiotlb_unmap_single or swiotlb_dma_sync_single is performed.
+ */
+dma_addr_t
+swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ return swiotlb_map_page_attrs(hwdev, virt_to_page(ptr),
+ (unsigned long)ptr % PAGE_SIZE,
+ size, dir, attrs);
+}
EXPORT_SYMBOL(swiotlb_map_single_attrs);

dma_addr_t
@@ -671,13 +700,7 @@ swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
- char *dma_addr = dma_addr_to_virt(hwdev, dev_addr);
-
- BUG_ON(dir == DMA_NONE);
- if (is_swiotlb_buffer(dma_addr))
- unmap_single(hwdev, dma_addr, size, dir);
- else if (dir == DMA_FROM_DEVICE)
- dma_mark_clean(dma_addr, size);
+ return swiotlb_unmap_page_attrs(hwdev, dev_addr, size, dir, attrs);
}
EXPORT_SYMBOL(swiotlb_unmap_single_attrs);

--
1.5.6.5