summary refs log tree commit diff
path: root/arch/sparc/mm/io-unit.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/mm/io-unit.c')
-rw-r--r--arch/sparc/mm/io-unit.c80
1 files changed, 54 insertions, 26 deletions
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index c8cb27d3ea75..f770ee7229d8 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -12,7 +12,7 @@
 #include <linux/mm.h>
 #include <linux/highmem.h>	/* pte_offset_map => kmap_atomic */
 #include <linux/bitops.h>
-#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 
@@ -140,34 +140,44 @@ nexti:	scan = find_next_zero_bit(iounit->bmap, limit, scan);
 	return vaddr;
 }
 
-static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len)
+static dma_addr_t iounit_map_page(struct device *dev, struct page *page,
+		unsigned long offset, size_t len, enum dma_data_direction dir,
+		unsigned long attrs)
 {
+	void *vaddr = page_address(page) + offset;
 	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long ret, flags;
 	
+	/* XXX So what is maxphys for us and how do drivers know it? */
+	if (!len || len > 256 * 1024)
+		return DMA_MAPPING_ERROR;
+
 	spin_lock_irqsave(&iounit->lock, flags);
 	ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
 	spin_unlock_irqrestore(&iounit->lock, flags);
 	return ret;
 }
 
-static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
+static int iounit_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
+		enum dma_data_direction dir, unsigned long attrs)
 {
 	struct iounit_struct *iounit = dev->archdata.iommu;
+	struct scatterlist *sg;
 	unsigned long flags;
+	int i;
 
 	/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
 	spin_lock_irqsave(&iounit->lock, flags);
-	while (sz != 0) {
-		--sz;
+	for_each_sg(sgl, sg, nents, i) {
 		sg->dma_address = iounit_get_area(iounit, (unsigned long) sg_virt(sg), sg->length);
 		sg->dma_length = sg->length;
-		sg = sg_next(sg);
 	}
 	spin_unlock_irqrestore(&iounit->lock, flags);
+	return nents;
 }
 
-static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
+static void iounit_unmap_page(struct device *dev, dma_addr_t vaddr, size_t len,
+		enum dma_data_direction dir, unsigned long attrs)
 {
 	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long flags;
@@ -181,34 +191,47 @@ static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned lo
 	spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
-static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
+static void iounit_unmap_sg(struct device *dev, struct scatterlist *sgl,
+		int nents, enum dma_data_direction dir, unsigned long attrs)
 {
 	struct iounit_struct *iounit = dev->archdata.iommu;
-	unsigned long flags;
-	unsigned long vaddr, len;
+	unsigned long flags, vaddr, len;
+	struct scatterlist *sg;
+	int i;
 
 	spin_lock_irqsave(&iounit->lock, flags);
-	while (sz != 0) {
-		--sz;
+	for_each_sg(sgl, sg, nents, i) {
 		len = ((sg->dma_address & ~PAGE_MASK) + sg->length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
 		vaddr = (sg->dma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
 		IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
 		for (len += vaddr; vaddr < len; vaddr++)
 			clear_bit(vaddr, iounit->bmap);
-		sg = sg_next(sg);
 	}
 	spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
 #ifdef CONFIG_SBUS
-static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, unsigned long addr, int len)
+static void *iounit_alloc(struct device *dev, size_t len,
+		dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
 	struct iounit_struct *iounit = dev->archdata.iommu;
-	unsigned long page, end;
+	unsigned long va, addr, page, end, ret;
 	pgprot_t dvma_prot;
 	iopte_t __iomem *iopte;
 
-	*pba = addr;
+	/* XXX So what is maxphys for us and how do drivers know it? */
+	if (!len || len > 256 * 1024)
+		return NULL;
+
+	len = PAGE_ALIGN(len);
+	va = __get_free_pages(gfp | __GFP_ZERO, get_order(len));
+	if (!va)
+		return NULL;
+
+	addr = ret = sparc_dma_alloc_resource(dev, len);
+	if (!addr)
+		goto out_free_pages;
+	*dma_handle = addr;
 
 	dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
 	end = PAGE_ALIGN((addr + len));
@@ -237,27 +260,32 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon
 	flush_cache_all();
 	flush_tlb_all();
 
-	return 0;
+	return (void *)ret;
+
+out_free_pages:
+	free_pages(va, get_order(len));
+	return NULL;
 }
 
-static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len)
+static void iounit_free(struct device *dev, size_t size, void *cpu_addr,
+		dma_addr_t dma_addr, unsigned long attrs)
 {
 	/* XXX Somebody please fill this in */
 }
 #endif
 
-static const struct sparc32_dma_ops iounit_dma_ops = {
-	.get_scsi_one		= iounit_get_scsi_one,
-	.get_scsi_sgl		= iounit_get_scsi_sgl,
-	.release_scsi_one	= iounit_release_scsi_one,
-	.release_scsi_sgl	= iounit_release_scsi_sgl,
+static const struct dma_map_ops iounit_dma_ops = {
 #ifdef CONFIG_SBUS
-	.map_dma_area		= iounit_map_dma_area,
-	.unmap_dma_area		= iounit_unmap_dma_area,
+	.alloc			= iounit_alloc,
+	.free			= iounit_free,
 #endif
+	.map_page		= iounit_map_page,
+	.unmap_page		= iounit_unmap_page,
+	.map_sg			= iounit_map_sg,
+	.unmap_sg		= iounit_unmap_sg,
 };
 
 void __init ld_mmu_iounit(void)
 {
-	sparc32_dma_ops = &iounit_dma_ops;
+	dma_ops = &iounit_dma_ops;
 }