From: Paul Mundt 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 -#include -#include -#include -#include -#include - - -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 +#include +#include + +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 /* 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 #include +#include #include #include @@ -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 +#ifndef __ASM_SH_DMA_MAPPING_H +#define __ASM_SH_DMA_MAPPING_H + +#include +#include +#include +#include +#include + +/* 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 -#include /* for struct page */ -#include +#include /* 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 #include -/* 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 +/* generic DMA-mapping stuff */ +#include + #endif /* __ASM_SH_PCI_H */ _