From: Paul Mundt <lethal@linux-sh.org>

This implements the DMA mapping API for sh, as well as cleaning up some
sh-specific DMA drivers.


---

 /dev/null                                   |   42 ------
 25-akpm/arch/sh/drivers/dma/Kconfig         |   15 ++
 25-akpm/arch/sh/drivers/dma/dma-api.c       |    6 
 25-akpm/arch/sh/drivers/dma/dma-sh.c        |  110 +++++++----------
 25-akpm/arch/sh/drivers/dma/dma-sh.h        |    6 
 25-akpm/arch/sh/drivers/pci/Kconfig         |    6 
 25-akpm/arch/sh/drivers/pci/Makefile        |    1 
 25-akpm/arch/sh/drivers/pci/dma-dreamcast.c |    4 
 25-akpm/arch/sh/mm/consistent.c             |   79 ++++++++++++
 25-akpm/arch/sh/mm/pg-dma.c                 |    2 
 25-akpm/include/asm-sh/cpu-sh4/dma.h        |    2 
 25-akpm/include/asm-sh/dma-mapping.h        |  166 ++++++++++++++++++++++++++
 25-akpm/include/asm-sh/dma.h                |    5 
 25-akpm/include/asm-sh/pci.h                |  174 ----------------------------
 14 files changed, 331 insertions(+), 287 deletions(-)

diff -puN arch/sh/drivers/dma/dma-api.c~sh-04-dma-mapping-api arch/sh/drivers/dma/dma-api.c
--- 25/arch/sh/drivers/dma/dma-api.c~sh-04-dma-mapping-api	2004-03-23 02:05:26.187122448 -0800
+++ 25-akpm/arch/sh/drivers/dma/dma-api.c	2004-03-23 02:05:26.206119560 -0800
@@ -104,6 +104,11 @@ void dma_wait_for_completion(unsigned in
 {
 	struct dma_info *info = get_dma_info(chan);
 
+	if (info->tei_capable) {
+		wait_event(info->wait_queue, (info->ops->get_residue(info) == 0));
+		return;
+	}
+
 	while (info->ops->get_residue(info))
 		cpu_relax();
 }
@@ -161,6 +166,7 @@ int __init register_dmac(struct dma_ops 
 		info->chan = i;
 
 		init_MUTEX(&info->sem);
+		init_waitqueue_head(&info->wait_queue);
 	}
 
 	return 0;
diff -puN arch/sh/drivers/dma/dma-sh.c~sh-04-dma-mapping-api arch/sh/drivers/dma/dma-sh.c
--- 25/arch/sh/drivers/dma/dma-sh.c~sh-04-dma-mapping-api	2004-03-23 02:05:26.189122144 -0800
+++ 25-akpm/arch/sh/drivers/dma/dma-sh.c	2004-03-23 02:05:26.207119408 -0800
@@ -55,9 +55,9 @@ struct sh_dmac_channel {
 } __attribute__ ((aligned(16)));
 
 struct sh_dmac_info {
-        struct sh_dmac_channel channel[MAX_DMAC_CHANNELS];
+        struct sh_dmac_channel channel[4];
         unsigned long dmaor;
-} __attribute__ ((packed));
+};
 
 static volatile struct sh_dmac_info *sh_dmac = (volatile struct sh_dmac_info *)SH_DMAC_BASE;
 
@@ -74,25 +74,12 @@ static inline unsigned int get_dmte_irq(
 	if (chan < 4) {
 		irq = DMTE0_IRQ + chan;
 	} else {
-		irq = DMTE4_IRQ + chan;
+		irq = DMTE4_IRQ + chan - 4;
 	}
 
 	return irq;
 }
 
-static inline int get_dmte_chan(unsigned int irq)
-{
-	int chan;
-
-	if ((irq - DMTE4_IRQ) < 0) {
-		chan = irq - DMTE0_IRQ;
-	} else {
-		chan = irq - DMTE4_IRQ + 4;
-	}
-
-	return chan;
-}
-
 /*
  * We determine the correct shift size based off of the CHCR transmit size
  * for the given channel. Since we know that it will take:
@@ -106,54 +93,42 @@ static inline unsigned int calc_xmit_shi
 	return ts_shift[(sh_dmac->channel[info->chan].chcr >> 4) & 0x0007];
 }
 
+/*
+ * The transfer end interrupt must read the chcr register to end the
+ * hardware interrupt active condition.
+ * Besides that it needs to waken any waiting process, which should handle
+ * setting up the next transfer.
+ */
 static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs)
 {
-	
-	int chan = get_dmte_chan(irq);
-	struct dma_info *info = get_dma_info(chan);
+	struct dma_info * info = (struct dma_info *)dev_id;
+	u32 chcr = sh_dmac->channel[info->chan].chcr;
 
-	if (info->sar)
-		sh_dmac->channel[info->chan].sar = info->sar;
-	if (info->dar)
-		sh_dmac->channel[info->chan].sar = info->dar;
+	if (!(chcr & CHCR_TE))
+		return IRQ_NONE;
 
-	sh_dmac->channel[info->chan].dmatcr = info->count >> calc_xmit_shift(info);
-	sh_dmac->channel[info->chan].chcr &= ~CHCR_TE;
+	sh_dmac->channel[info->chan].chcr = chcr & ~(CHCR_IE | CHCR_DE);
 
-	disable_irq(irq);
+	wake_up(&info->wait_queue);
 
 	return IRQ_HANDLED;
 }
 
-static struct irqaction irq_tei = {
-	.name		= "DMAC Transfer End",
-	.handler	= dma_tei,
-	.flags		= SA_INTERRUPT,
-};
-
 static int sh_dmac_request_dma(struct dma_info *info)
 {
-	int irq = get_dmte_irq(info->chan);
-	char *p = (char *)((&irq_tei)->name);
-
-	sprintf(p, "%s (Channel %d)", p, info->chan);
-
-	make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
-
-	return setup_irq(irq, &irq_tei);
+	return request_irq(get_dmte_irq(info->chan), dma_tei,
+			   SA_INTERRUPT, "DMAC Transfer End", info);
 }
 
 static void sh_dmac_free_dma(struct dma_info *info)
 {
-	free_irq(get_dmte_irq(info->chan), 0);
+	free_irq(get_dmte_irq(info->chan), info);
 }
 
 static void sh_dmac_configure_channel(struct dma_info *info, unsigned long chcr)
 {
-	if (!chcr) {
-		chcr = sh_dmac->channel[info->chan].chcr;
-		chcr |= /* CHCR_IE | */ RS_DUAL;
-	}
+	if (!chcr)
+		chcr = RS_DUAL;
 
 	sh_dmac->channel[info->chan].chcr = chcr;
 
@@ -162,12 +137,18 @@ static void sh_dmac_configure_channel(st
 
 static void sh_dmac_enable_dma(struct dma_info *info)
 {
-	sh_dmac->channel[info->chan].chcr |= CHCR_DE;
+	int irq = get_dmte_irq(info->chan);
+
+	sh_dmac->channel[info->chan].chcr |= (CHCR_DE | CHCR_IE);
+	enable_irq(irq);
 }
 
 static void sh_dmac_disable_dma(struct dma_info *info)
 {
-	sh_dmac->channel[info->chan].chcr &= ~(CHCR_DE | CHCR_TE);
+	int irq = get_dmte_irq(info->chan);
+
+	disable_irq(irq);
+	sh_dmac->channel[info->chan].chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
 }
 
 static int sh_dmac_xfer_dma(struct dma_info *info)
@@ -191,10 +172,14 @@ static int sh_dmac_xfer_dma(struct dma_i
 	 * In this case, only one address can be defined, anything else will
 	 * result in a DMA address error interrupt (at least on the SH-4),
 	 * which will subsequently halt the transfer.
+	 *
+	 * Channel 2 on the Dreamcast is a special case, as this is used for
+	 * cascading to the PVR2 DMAC. In this case, we still need to write
+	 * SAR and DAR, regardless of value, in order for cascading to work.
 	 */
-	if (info->sar)
+	if (info->sar || (mach_is_dreamcast() && info->chan == 2))
 		sh_dmac->channel[info->chan].sar = info->sar;
-	if (info->dar)
+	if (info->dar || (mach_is_dreamcast() && info->chan == 2))
 		sh_dmac->channel[info->chan].dar = info->dar;
 	
 	sh_dmac->channel[info->chan].dmatcr = info->count >> calc_xmit_shift(info);
@@ -206,6 +191,9 @@ static int sh_dmac_xfer_dma(struct dma_i
 
 static int sh_dmac_get_dma_residue(struct dma_info *info)
 {
+	if (!(sh_dmac->channel[info->chan].chcr & CHCR_DE))
+		return 0;
+
 	return sh_dmac->channel[info->chan].dmatcr << calc_xmit_shift(info);
 }
 
@@ -221,12 +209,6 @@ static irqreturn_t dma_err(int irq, void
 
 	return IRQ_HANDLED;
 }
-
-static struct irqaction irq_err = {
-	.name		= "DMAC Address Error",
-	.handler	= dma_err,
-	.flags		= SA_INTERRUPT,
-};
 #endif
 
 static struct dma_ops sh_dmac_ops = {
@@ -244,15 +226,21 @@ static int __init sh_dmac_init(void)
 
 #ifdef CONFIG_CPU_SH4
 	make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
-	setup_irq(DMAE_IRQ, &irq_err);
+	i = request_irq(DMAE_IRQ, dma_err, SA_INTERRUPT, "DMAC Address Error", 0);
+	if (i < 0)
+		return i;
 #endif
 
-	/* Kick the DMAOR */
-	sh_dmac->dmaor |= DMAOR_DME /* | 0x200 */ | 0x8000;	/* DDT = 1, PR1 = 1, DME = 1 */
-	sh_dmac->dmaor &= ~(DMAOR_NMIF | DMAOR_AE);
+	for (i = 0; i < MAX_DMAC_CHANNELS; i++) {
+		int irq = get_dmte_irq(i);
+
+		make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+
+		dma_info[i].ops = &sh_dmac_ops;
+		dma_info[i].tei_capable = 1;
+	}
 
-	for (i = 0; i < MAX_DMAC_CHANNELS; i++)
-		dma_info[i].ops  = &sh_dmac_ops;
+	sh_dmac->dmaor |= 0x8000 | DMAOR_DME;
 
 	return register_dmac(&sh_dmac_ops);
 }
diff -puN arch/sh/drivers/dma/dma-sh.h~sh-04-dma-mapping-api arch/sh/drivers/dma/dma-sh.h
--- 25/arch/sh/drivers/dma/dma-sh.h~sh-04-dma-mapping-api	2004-03-23 02:05:26.190121992 -0800
+++ 25-akpm/arch/sh/drivers/dma/dma-sh.h	2004-03-23 02:05:26.208119256 -0800
@@ -24,7 +24,6 @@
 #define DM_DEC	0x00008000
 #define SM_INC	0x00001000
 #define SM_DEC	0x00002000
-#define RS_DUAL	0x00000000
 #define RS_IN	0x00000200
 #define RS_OUT	0x00000300
 #define TM_BURST 0x0000080
@@ -37,6 +36,11 @@
 #define CHCR_TE 0x00000002
 #define CHCR_IE 0x00000004
 
+/* Define the default configuration for dual address memory-memory transfer.
+ * The 0x400 value represents auto-request, external->external.
+ */
+#define RS_DUAL	(DM_INC | SM_INC | 0x400 | TS_32)
+
 #define DMAOR_COD	0x00000008
 #define DMAOR_AE	0x00000004
 #define DMAOR_NMIF	0x00000002
diff -puN arch/sh/drivers/dma/Kconfig~sh-04-dma-mapping-api arch/sh/drivers/dma/Kconfig
--- 25/arch/sh/drivers/dma/Kconfig~sh-04-dma-mapping-api	2004-03-23 02:05:26.191121840 -0800
+++ 25-akpm/arch/sh/drivers/dma/Kconfig	2004-03-23 02:05:26.208119256 -0800
@@ -1,3 +1,5 @@
+menu "DMA support"
+
 config SH_DMA
 	bool "DMA controller (DMAC) support"
 	help
@@ -34,9 +36,20 @@ config NR_DMA_CHANNELS
 
 config DMA_PAGE_OPS
 	bool "Use DMAC for page copy/clear"
-	depends on SH_DMA
+	depends on SH_DMA && BROKEN
 	help
 	  Selecting this option will use a dual-address mode configured channel
 	  in the SH DMAC for copy_page()/clear_page(). Primarily a performance
 	  hack.
 
+config DMA_PAGE_OPS_CHANNEL
+	depends on DMA_PAGE_OPS
+	int "DMA channel for sh memory-manager page copy/clear"
+	default "3"
+	help
+	  This allows the specification of the dual address dma channel,
+	  in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
+	  are dual-address capable.
+
+endmenu
+
diff -puN arch/sh/drivers/pci/dma-dreamcast.c~sh-04-dma-mapping-api arch/sh/drivers/pci/dma-dreamcast.c
--- 25/arch/sh/drivers/pci/dma-dreamcast.c~sh-04-dma-mapping-api	2004-03-23 02:05:26.193121536 -0800
+++ 25-akpm/arch/sh/drivers/pci/dma-dreamcast.c	2004-03-23 02:05:26.208119256 -0800
@@ -30,7 +30,7 @@
 
 static int gapspci_dma_used = 0;
 
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 			   dma_addr_t * dma_handle)
 {
 	unsigned long buf;
@@ -52,7 +52,7 @@ void *pci_alloc_consistent(struct pci_de
 	return (void *)buf;
 }
 
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+void __pci_free_consistent(struct pci_dev *hwdev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
 	/* XXX */
diff -puN arch/sh/drivers/pci/Kconfig~sh-04-dma-mapping-api arch/sh/drivers/pci/Kconfig
--- 25/arch/sh/drivers/pci/Kconfig~sh-04-dma-mapping-api	2004-03-23 02:05:26.194121384 -0800
+++ 25-akpm/arch/sh/drivers/pci/Kconfig	2004-03-23 02:05:26.209119104 -0800
@@ -14,6 +14,7 @@ config PCI
 config SH_PCIDMA_NONCOHERENT
 	bool "Cache and PCI noncoherent"
 	depends on PCI
+	default y
 	help
 	  Enable this option if your platform does not have a CPU cache which
 	  remains coherent with PCI DMA. It is safest to say 'Y', although you
@@ -39,8 +40,3 @@ config PCI_AUTO_UPDATE_RESOURCES
 	  with its resources updated beyond what they are when the device
 	  is powered up, set this to N. Everyone else will want this as Y.
 
-config PCI_DMA
-	bool
-	depends on PCI
-	default y if !SH_DREAMCAST
-
diff -puN arch/sh/drivers/pci/Makefile~sh-04-dma-mapping-api arch/sh/drivers/pci/Makefile
--- 25/arch/sh/drivers/pci/Makefile~sh-04-dma-mapping-api	2004-03-23 02:05:26.196121080 -0800
+++ 25-akpm/arch/sh/drivers/pci/Makefile	2004-03-23 02:05:26.209119104 -0800
@@ -4,7 +4,6 @@
 
 obj-y					+= pci.o
 obj-$(CONFIG_PCI_AUTO)			+= pci-auto.o
-obj-$(CONFIG_PCI_DMA)			+= pci-dma.o
 
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)	+= pci-st40.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o 
diff -puN -L arch/sh/drivers/pci/pci-dma.c arch/sh/drivers/pci/pci-dma.c~sh-04-dma-mapping-api /dev/null
--- 25/arch/sh/drivers/pci/pci-dma.c
+++ /dev/null	2003-09-15 06:40:47.000000000 -0700
@@ -1,42 +0,0 @@
-/* 
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.                            
- *
- * Dynamic DMA mapping support.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-			   dma_addr_t * dma_handle)
-{
-	void *ret;
-	int gfp = GFP_ATOMIC;
-
-	ret = (void *) __get_free_pages(gfp, get_order(size));
-
-	if (ret != NULL) {
-	        /* Is it necessary to do the memset? */
-		memset(ret, 0, size);
-		*dma_handle = virt_to_phys(ret);
-	}
-	/* We must flush the cache before we pass it on to the device */
-	dma_cache_wback_inv(ret, size);
-	return  P2SEGADDR(ret);
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-        unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
-
-	free_pages(p1addr, get_order(size));
-}
diff -puN /dev/null arch/sh/mm/consistent.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/arch/sh/mm/consistent.c	2004-03-23 02:05:26.210118952 -0800
@@ -0,0 +1,79 @@
+/*
+ * arch/sh/mm/consistent.c
+ *
+ * Copyright (C) 2004  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle)
+{
+	struct page *page, *end, *free;
+	void *ret;
+	int order;
+
+	size = PAGE_ALIGN(size);
+	order = get_order(size);
+
+	page = alloc_pages(gfp, order);
+	if (!page)
+		return NULL;
+
+	ret = (void *)P2SEGADDR(page_to_bus(page));
+
+	/*
+	 * We must flush the cache before we pass it on to the device
+	 */
+	dma_cache_wback_inv(ret, size);
+
+	*handle = (unsigned long)ret;
+
+	free = page + (size >> PAGE_SHIFT);
+	end  = page + (1 << order);
+
+	do {
+		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++;
+	}
+
+	return ret;
+}
+
+void consistent_free(void *vaddr, size_t size)
+{
+	unsigned long addr = P1SEGADDR((unsigned long)vaddr);
+
+	free_pages(addr, get_order(size));
+}
+
+void consistent_sync(void *vaddr, size_t size, int direction)
+{
+	switch (direction) {
+	case DMA_FROM_DEVICE:		/* invalidate only */
+		dma_cache_inv(vaddr, size);
+		break;
+	case DMA_TO_DEVICE:		/* writeback only */
+		dma_cache_wback(vaddr, size);
+		break;
+	case DMA_BIDIRECTIONAL:		/* writeback and invalidate */
+		dma_cache_wback_inv(vaddr, size);
+		break;
+	default:
+		BUG();
+	}
+}
+
diff -puN arch/sh/mm/pg-dma.c~sh-04-dma-mapping-api arch/sh/mm/pg-dma.c
--- 25/arch/sh/mm/pg-dma.c~sh-04-dma-mapping-api	2004-03-23 02:05:26.199120624 -0800
+++ 25-akpm/arch/sh/mm/pg-dma.c	2004-03-23 02:05:26.210118952 -0800
@@ -21,7 +21,7 @@
 #include <asm/io.h>
 
 /* Channel to use for page ops, must be dual-address mode capable. */
-static int dma_channel = 3;
+static int dma_channel = CONFIG_DMA_PAGE_OPS_CHANNEL;
 
 static void copy_page_dma(void *to, void *from)
 {
diff -puN include/asm-sh/cpu-sh4/dma.h~sh-04-dma-mapping-api include/asm-sh/cpu-sh4/dma.h
--- 25/include/asm-sh/cpu-sh4/dma.h~sh-04-dma-mapping-api	2004-03-23 02:05:26.200120472 -0800
+++ 25-akpm/include/asm-sh/cpu-sh4/dma.h	2004-03-23 02:05:26.210118952 -0800
@@ -1,7 +1,7 @@
 #ifndef __ASM_CPU_SH4_DMA_H
 #define __ASM_CPU_SH4_DMA_H
 
-#define SH_DMAC_BASE	0xbfa00000
+#define SH_DMAC_BASE	0xffa00000
 
 #endif /* __ASM_CPU_SH4_DMA_H */
 
diff -puN include/asm-sh/dma.h~sh-04-dma-mapping-api include/asm-sh/dma.h
--- 25/include/asm-sh/dma.h~sh-04-dma-mapping-api	2004-03-23 02:05:26.201120320 -0800
+++ 25-akpm/include/asm-sh/dma.h	2004-03-23 02:05:26.211118800 -0800
@@ -12,6 +12,7 @@
 
 #include <linux/config.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 #include <asm/cpu/dma.h>
 #include <asm/semaphore.h>
 
@@ -63,11 +64,13 @@ struct dma_info {
 	unsigned long dar;
 
 	unsigned int configured:1;
+	unsigned int tei_capable:1;
 	atomic_t busy;
 
 	struct semaphore sem;
+	wait_queue_head_t wait_queue;
 	struct dma_ops *ops;
-} __attribute__ ((packed));
+};
 
 /* arch/sh/drivers/dma/dma-api.c */
 extern int dma_xfer(unsigned int chan, unsigned long from,
diff -puN include/asm-sh/dma-mapping.h~sh-04-dma-mapping-api include/asm-sh/dma-mapping.h
--- 25/include/asm-sh/dma-mapping.h~sh-04-dma-mapping-api	2004-03-23 02:05:26.202120168 -0800
+++ 25-akpm/include/asm-sh/dma-mapping.h	2004-03-23 02:05:26.212118648 -0800
@@ -1 +1,165 @@
-#include <asm-generic/dma-mapping.h>
+#ifndef __ASM_SH_DMA_MAPPING_H
+#define __ASM_SH_DMA_MAPPING_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+/* arch/sh/mm/consistent.c */
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
+extern void consistent_free(void *vaddr, size_t size);
+extern void consistent_sync(void *vaddr, size_t size, int direction);
+
+#ifdef CONFIG_SH_DREAMCAST
+struct pci_dev;
+extern struct bus_type pci_bus_type;
+extern void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				    dma_addr_t *dma_handle);
+extern void __pci_free_consistent(struct pci_dev *hwdev, size_t size,
+				  void *vaddr, dma_addr_t dma_handle);
+#endif
+
+#define dma_supported(dev, mask)	(1)
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, mask))
+		return -EIO;
+
+	*dev->dma_mask = mask;
+
+	return 0;
+}
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+			 dma_addr_t *dma_handle, int flag)
+{
+	/*
+	 * Some platforms have special pci_alloc_consistent() implementations,
+	 * in these instances we can't use the generic consistent_alloc().
+	 */
+#ifdef CONFIG_SH_DREAMCAST
+	if (dev && dev->bus == &pci_bus_type)
+		return __pci_alloc_consistent(NULL, size, dma_handle);
+#endif
+
+	return consistent_alloc(flag, size, dma_handle);
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+		       void *vaddr, dma_addr_t dma_handle)
+{
+	/*
+	 * Same note as above applies to pci_free_consistent()..
+	 */
+#ifdef CONFIG_SH_DREAMCAST
+	if (dev && dev->bus == &pci_bus_type) {
+		__pci_free_consistent(NULL, size, vaddr, dma_handle);
+		return;
+	}
+#endif
+
+	consistent_free(vaddr, size);
+}
+
+static inline void dma_cache_sync(void *vaddr, size_t size,
+				  enum dma_data_direction dir)
+{
+	consistent_sync(vaddr, size, (int)dir);
+}
+
+static inline dma_addr_t dma_map_single(struct device *dev,
+					void *ptr, size_t size,
+					enum dma_data_direction dir)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+	if (dev->bus == &pci_bus_type)
+		return virt_to_bus(ptr);
+#endif
+	dma_cache_sync(ptr, size, dir);
+
+	return virt_to_bus(ptr);
+}
+
+#define dma_unmap_single(dev, addr, size, dir)	do { } while (0)
+
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+			     int nents, enum dma_data_direction dir)
+{
+	int i;
+
+	for (i = 0; i < nents; i++) {
+#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+		dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+			       sg[i].length, dir);
+#endif
+		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+	}
+
+	return nents;
+}
+
+#define dma_unmap_sg(dev, sg, nents, dir)	do { } while (0)
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+				      unsigned long offset, size_t size,
+				      enum dma_data_direction dir)
+{
+	return dma_map_single(dev, page_address(page) + offset, size, dir);
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+				  size_t size, enum dma_data_direction dir)
+{
+	dma_unmap_single(dev, dma_address, size, dir);
+}
+
+static inline void dma_sync_single(struct device *dev, dma_addr_t dma_handle,
+				   size_t size, enum dma_data_direction dir)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+	if (dev->bus == &pci_bus_type)
+		return;
+#endif
+	dma_cache_sync(bus_to_virt(dma_handle), size, dir);
+}
+
+static inline void dma_sync_single_range(struct device *dev,
+					 dma_addr_t dma_handle,
+					 unsigned long offset, size_t size,
+					 enum dma_data_direction dir)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+	if (dev->bus == &pci_bus_type)
+		return;
+#endif
+	dma_cache_sync(bus_to_virt(dma_handle) + offset, size, dir);
+}
+
+static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
+			       int nelems, enum dma_data_direction dir)
+{
+	int i;
+
+	for (i = 0; i < nelems; i++) {
+#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+		dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+			       sg[i].length, dir);
+#endif
+		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+	}
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+	/*
+	 * Each processor family will define its own L1_CACHE_SHIFT,
+	 * L1_CACHE_BYTES wraps to this, so this is always safe.
+	 */
+	return L1_CACHE_BYTES;
+}
+
+#endif /* __ASM_SH_DMA_MAPPING_H */
+
diff -puN include/asm-sh/pci.h~sh-04-dma-mapping-api include/asm-sh/pci.h
--- 25/include/asm-sh/pci.h~sh-04-dma-mapping-api	2004-03-23 02:05:26.204119864 -0800
+++ 25-akpm/include/asm-sh/pci.h	2004-03-23 02:05:26.213118496 -0800
@@ -3,9 +3,7 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
-#include <linux/mm.h>		/* for struct page */
-#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
 
 /* Can be used to override the logic in pci_scan_bus for skipping
    already-configured bus numbers - to be used for buggy BIOSes
@@ -59,45 +57,6 @@ static inline void pcibios_penalize_isa_
 #include <linux/string.h>
 #include <asm/io.h>
 
-/* Allocate and map kernel buffer using consistent mode DMA for a device.
- * hwdev should be valid struct pci_dev pointer for PCI devices,
- * NULL for PCI-like buses (ISA, EISA).
- * Returns non-NULL cpu-view pointer to the buffer if successful and
- * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
- * is undefined.
- */
-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-				  dma_addr_t *dma_handle);
-
-/* Free and unmap a consistent DMA buffer.
- * cpu_addr is what was returned from pci_alloc_consistent,
- * size must be the same as what as passed into pci_alloc_consistent,
- * and likewise dma_addr must be the same as what *dma_addrp was set to.
- *
- * References to the memory and mappings associated with cpu_addr/dma_addr
- * past this call are illegal.
- */
-extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-				void *vaddr, dma_addr_t dma_handle);
-
-/* Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
- */
-static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-					size_t size, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	dma_cache_wback_inv(ptr, size);
-#endif
-	return virt_to_bus(ptr);
-}
-
 /* pci_unmap_{single,page} being a nop depends upon the
  * configuration.
  */
@@ -123,134 +82,6 @@ static inline dma_addr_t pci_map_single(
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 #endif
 
-/* Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-				    size_t size,int direction)
-{
-	/* Nothing to do */
-}
-
-/* Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
-static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-			     int nents, int direction)
-{
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	int i;
-
-	for (i=0; i<nents; i++) {
-		dma_cache_wback_inv(page_address(sg[i].page) + sg[i].offset, sg[i].length);
-		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
-	}
-#endif
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-	return nents;
-}
-
-/* Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-				int nents, int direction)
-{
-	/* Nothing to do */
-}
-
-/* Make physical memory consistent for a single
- * streaming mode DMA translation after a transfer.
- *
- * If you perform a pci_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, you
- * must first perform a pci_dma_sync_for_device, and then the device
- * again owns the buffer.
- */
-static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
-					       dma_addr_t dma_handle,
-					       size_t size, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-}
-
-static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
-						  dma_addr_t dma_handle,
-						  size_t size, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	dma_cache_wback_inv(bus_to_virt(dma_handle), size);
-#endif
-	
-}
-
-/* Make physical memory consistent for a set of streaming
- * mode DMA translations after a transfer.
- *
- * The same as pci_dma_sync_single_* but for a scatter-gather list,
- * same rules and usage.
- */
-static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
-					   struct scatterlist *sg,
-					   int nelems, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-}
-
-static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
-					      struct scatterlist *sg,
-					      int nelems, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	int i;
-
-	for (i=0; i<nelems; i++) {
-		dma_cache_wback_inv(page_address(sg[i].page) + sg[i].offset, sg[i].length);
-		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
-	}
-#endif
-}
-
-
-/* Return whether the given PCI device DMA address mask can
- * be supported properly.  For example, if your device can
- * only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
-{
-	return 1;
-}
-
 /* Not supporting more than 32-bit PCI bus addresses now, but
  * must satisfy references to this function.  Change if needed.
  */
@@ -282,5 +113,8 @@ static inline void pcibios_add_platform_
 /* generic pci stuff */
 #include <asm-generic/pci.h>
 
+/* generic DMA-mapping stuff */
+#include <asm-generic/pci-dma-compat.h>
+
 #endif /* __ASM_SH_PCI_H */
 

_