summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-06-23 19:25:06 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-23 19:25:06 -0700
commit1d7cddf956a9a4be550b7bd4fc282a1ca362c8e2 (patch)
treef210f1bdc43b1e1417467e586098ffd1beec9874
parent3bef362a0d884ad5e8d896f7d3bfac5e6e5b38f4 (diff)
[PATCH] sh: dma-mapping updates.
From: Paul Mundt <lethal@Linux-SH.ORG> This updates the sh dma-mapping code, as well as doing some cleanup in the consistent API. We also add a consistent_{alloc,free} to the machvec for platforms that need special handling. Signed-off-by: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/sh/mm/consistent.c40
-rw-r--r--include/asm-sh/dma-mapping.h32
-rw-r--r--include/asm-sh/machvec.h4
3 files changed, 57 insertions, 19 deletions
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index f988035c7c86..789bacf1a7aa 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -24,56 +24,58 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle)
if (!page)
return NULL;
- ret = (void *)P2SEGADDR(page_to_bus(page));
+ ret = page_address(page);
+ *handle = virt_to_phys(ret);
/*
* We must flush the cache before we pass it on to the device
*/
dma_cache_wback_inv(ret, size);
- *handle = (unsigned long)ret;
-
+ page = virt_to_page(ret);
free = page + (size >> PAGE_SHIFT);
end = page + (1 << order);
- do {
+ while (++page < end) {
set_page_count(page, 1);
- page++;
- } while (size -= PAGE_SIZE);
- /*
- * Free any unused pages
- */
- while (page < end) {
- set_page_count(page, 1);
- __free_page(page);
- page++;
+ /* Free any unused pages */
+ if (page >= free) {
+ __free_page(page);
+ }
}
- return ret;
+ return P2SEGADDR(ret);
}
void consistent_free(void *vaddr, size_t size)
{
unsigned long addr = P1SEGADDR((unsigned long)vaddr);
+ struct page *page=virt_to_page(addr);
+ int num_pages=(size+PAGE_SIZE-1) >> PAGE_SHIFT;
+ int i;
- free_pages(addr, get_order(size));
+ for(i=0;i<num_pages;i++) {
+ __free_page((page+i));
+ }
}
void consistent_sync(void *vaddr, size_t size, int direction)
{
+ void * p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
+
switch (direction) {
case DMA_FROM_DEVICE: /* invalidate only */
- dma_cache_inv(vaddr, size);
+ dma_cache_inv(p1addr, size);
break;
case DMA_TO_DEVICE: /* writeback only */
- dma_cache_wback(vaddr, size);
+ dma_cache_wback(p1addr, size);
break;
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
- dma_cache_wback_inv(vaddr, size);
+ dma_cache_wback_inv(p1addr, size);
break;
default:
BUG();
}
}
-
+EXPORT_SYMBOL(consistent_sync);
diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
index f3817945edb5..8f149477ee2c 100644
--- a/include/asm-sh/dma-mapping.h
+++ b/include/asm-sh/dma-mapping.h
@@ -44,6 +44,8 @@ static inline void *dma_alloc_coherent(struct device *dev, size_t size,
if (dev && dev->bus == &pci_bus_type)
return __pci_alloc_consistent(NULL, size, dma_handle);
#endif
+ if (sh_mv.mv_consistent_alloc)
+ return sh_mv.mv_consistent_alloc(dev, size, dma_handle, flag);
return consistent_alloc(flag, size, dma_handle);
}
@@ -61,6 +63,11 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
}
#endif
+ if (sh_mv.mv_consistent_free) {
+ sh_mv.mv_consistent_free(dev, size, vaddr, dma_handle);
+ return;
+ }
+
consistent_free(vaddr, size);
}
@@ -152,6 +159,26 @@ static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
}
}
+static inline void dma_sync_single_for_cpu(struct device *dev,
+ dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction dir)
+ __attribute__ ((alias("dma_sync_single")));
+
+static inline void dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction dir)
+ __attribute__ ((alias("dma_sync_single")));
+
+static inline void dma_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction dir)
+ __attribute__ ((alias("dma_sync_sg")));
+
+static inline void dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction dir)
+ __attribute__ ((alias("dma_sync_sg")));
+
static inline int dma_get_cache_alignment(void)
{
/*
@@ -161,5 +188,10 @@ static inline int dma_get_cache_alignment(void)
return L1_CACHE_BYTES;
}
+static inline int dma_mapping_error(dma_addr_t dma_addr)
+{
+ return dma_addr == 0;
+}
+
#endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/include/asm-sh/machvec.h b/include/asm-sh/machvec.h
index 4953570c961d..8a2e3dcd1779 100644
--- a/include/asm-sh/machvec.h
+++ b/include/asm-sh/machvec.h
@@ -17,6 +17,7 @@
#include <asm/machtypes.h>
#include <asm/machvec_init.h>
+struct device;
struct timeval;
struct sh_machine_vector
@@ -62,6 +63,9 @@ struct sh_machine_vector
void (*mv_init_pci)(void);
void (*mv_heartbeat)(void);
+
+ void *(*mv_consistent_alloc)(struct device *, size_t, dma_addr_t *, int);
+ void (*mv_consistent_free)(struct device *, size_t, void *, dma_addr_t);
};
extern struct sh_machine_vector sh_mv;