diff options
| author | Richard Henderson <rth@twiddle.net> | 2004-08-30 03:14:53 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-08-30 03:14:53 -0700 |
| commit | a90ee89e25ef0b8919afc945ee4e940d9418196f (patch) | |
| tree | a8e3c65918d5b52e6c8b0ea59b6bda0bf058918b | |
| parent | 7ef56c665fd9ab640cff405d1408fa52154c9a1c (diff) | |
[PATCH] Alpha: generic dma mapping
From: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
- big functions moved out of line;
- handle dev == NULL case, which apparently means the isa device.
As before, this is needed for Jensen. This also makes the isa sound
drivers working again with recent kernels.
| -rw-r--r-- | arch/alpha/kernel/alpha_ksyms.c | 3 | ||||
| -rw-r--r-- | arch/alpha/kernel/pci-noop.c | 63 | ||||
| -rw-r--r-- | arch/alpha/kernel/pci_iommu.c | 39 | ||||
| -rw-r--r-- | include/asm-alpha/cache.h | 2 | ||||
| -rw-r--r-- | include/asm-alpha/dma-mapping.h | 64 | ||||
| -rw-r--r-- | include/asm-alpha/pci.h | 2 |
6 files changed, 170 insertions, 3 deletions
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index c901914a393d..9473cd26803a 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -18,6 +18,7 @@ #include <linux/tty.h> #include <linux/mm.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/console.h> @@ -136,7 +137,9 @@ EXPORT_SYMBOL(pci_dac_dma_supported); EXPORT_SYMBOL(pci_dac_page_to_dma); EXPORT_SYMBOL(pci_dac_dma_to_page); EXPORT_SYMBOL(pci_dac_dma_to_offset); +EXPORT_SYMBOL(alpha_gendev_to_pci); #endif +EXPORT_SYMBOL(dma_set_mask); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_elf_thread); diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c index b8a7e3ff8ade..1fa496d32c7c 100644 --- a/arch/alpha/kernel/pci-noop.c +++ b/arch/alpha/kernel/pci-noop.c @@ -7,8 +7,10 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/bootmem.h> +#include <linux/mm.h> #include <linux/errno.h> #include <linux/sched.h> +#include <linux/dma-mapping.h> #include "proto.h" @@ -101,41 +103,100 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, else return -ENODEV; } -/* stubs for the routines in pci_iommu.c */ + +/* Stubs for the routines in pci_iommu.c: */ + void * pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) { return NULL; } + void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr, dma_addr_t dma_addr) { } + dma_addr_t pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int direction) { return (dma_addr_t) 0; } + void pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, int direction) { } + int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) { return 0; } + void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) { } + int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) { return 0; } + +/* Generic DMA mapping functions: */ + +void * +dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, int gfp) +{ + void *ret; + + if (!dev || *dev->dma_mask >= 0xffffffffUL) + gfp &= ~GFP_DMA; + ret = (void *)__get_free_pages(gfp, get_order(size)); + if (ret) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} + +EXPORT_SYMBOL(dma_alloc_coherent); + +int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + int i; + + for (i = 0; i < nents; i++ ) { + void *va; + + BUG_ON(!sg[i].page); + va = page_address(sg[i].page) + sg[i].offset; + sg_dma_address(sg + i) = (dma_addr_t)virt_to_bus(va); + sg_dma_len(sg + i) = sg[i].length; + } + + return nents; +} + +EXPORT_SYMBOL(dma_map_sg); + +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; +} diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index b47c35679e87..7cb23f12ecbd 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -930,3 +930,42 @@ pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) { return (dma_addr & ~PAGE_MASK); } + + +/* Helper for generic DMA-mapping functions. */ + +struct pci_dev * +alpha_gendev_to_pci(struct device *dev) +{ + if (dev && dev->bus == &pci_bus_type) + return to_pci_dev(dev); + + /* Assume that non-PCI devices asking for DMA are either ISA or EISA, + BUG() otherwise. */ + BUG_ON(!isa_bridge); + + /* Assume non-busmaster ISA DMA when dma_mask is not set (the ISA + bridge is bus master then). */ + if (!dev || !dev->dma_mask || !*dev->dma_mask) + return isa_bridge; + + /* For EISA bus masters, return isa_bridge (it might have smaller + dma_mask due to wiring limitations). */ + if (*dev->dma_mask >= isa_bridge->dma_mask) + return isa_bridge; + + /* This assumes ISA bus master with dma_mask 0xffffff. */ + return NULL; +} + +int +dma_set_mask(struct device *dev, u64 mask) +{ + if (!dev->dma_mask || + !pci_dma_supported(alpha_gendev_to_pci(dev), mask)) + return -EIO; + + *dev->dma_mask = mask; + + return 0; +} diff --git a/include/asm-alpha/cache.h b/include/asm-alpha/cache.h index f74d7ece132e..e69b29501a5f 100644 --- a/include/asm-alpha/cache.h +++ b/include/asm-alpha/cache.h @@ -20,6 +20,6 @@ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define L1_CACHE_SHIFT_MAX 6 /* largest L1 which this arch supports */ +#define L1_CACHE_SHIFT_MAX L1_CACHE_SHIFT #endif diff --git a/include/asm-alpha/dma-mapping.h b/include/asm-alpha/dma-mapping.h index e7e16901f686..0faad459ad12 100644 --- a/include/asm-alpha/dma-mapping.h +++ b/include/asm-alpha/dma-mapping.h @@ -1 +1,63 @@ -#include <asm-generic/dma-mapping.h> +#ifndef _ALPHA_DMA_MAPPING_H +#define _ALPHA_DMA_MAPPING_H + +#include <linux/config.h> + +#ifdef CONFIG_PCI + +#include <linux/pci.h> + +#define dma_map_single(dev, va, size, dir) \ + pci_map_single(alpha_gendev_to_pci(dev), va, size, dir) +#define dma_unmap_single(dev, addr, size, dir) \ + pci_unmap_single(alpha_gendev_to_pci(dev), addr, size, dir) +#define dma_alloc_coherent(dev, size, addr, gfp) \ + pci_alloc_consistent(alpha_gendev_to_pci(dev), size, addr) +#define dma_free_coherent(dev, size, va, addr) \ + pci_free_consistent(alpha_gendev_to_pci(dev), size, va, addr) +#define dma_map_page(dev, page, off, size, dir) \ + pci_map_single(alpha_gendev_to_pci(dev), page, off, size, dir) +#define dma_unmap_page(dev, addr, size, dir) \ + pci_unmap_page(alpha_gendev_to_pci(dev), addr, size, dir) +#define dma_map_sg(dev, sg, nents, dir) \ + pci_map_sg(alpha_gendev_to_pci(dev), sg, nents, dir) +#define dma_unmap_sg(dev, sg, nents, dir) \ + pci_unmap_sg(alpha_gendev_to_pci(dev), sg, nents, dir) +#define dma_supported(dev, mask) \ + pci_dma_supported(alpha_gendev_to_pci(dev), mask) + +#else /* no PCI - no IOMMU. */ + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, int gfp); +int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction); + +#define dma_free_coherent(dev, size, va, addr) \ + free_pages((unsigned long)va, get_order(size)) +#define dma_supported(dev, mask) (mask < 0x00ffffffUL ? 0 : 1) +#define dma_map_single(dev, va, size, dir) virt_to_phys(va) +#define dma_map_page(dev, page, off, size, dir) (page_to_pa(page) + off) + +#define dma_unmap_single(dev, addr, size, dir) do { } while (0) +#define dma_unmap_page(dev, addr, size, dir) do { } while (0) +#define dma_unmap_sg(dev, sg, nents, dir) do { } while (0) + +#endif /* !CONFIG_PCI */ + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(dev) (1) + +int dma_set_mask(struct device *dev, u64 mask); + +#define dma_sync_single_for_cpu(dev, addr, size, dir) do { } while (0) +#define dma_sync_single_for_device(dev, addr, size, dir) do { } while (0) +#define dma_sync_single_range(dev, addr, off, size, dir) do { } while (0) +#define dma_sync_sg_for_cpu(dev, sg, nents, dir) do { } while (0) +#define dma_sync_sg_for_device(dev, sg, nents, dir) do { } while (0) +#define dma_cache_sync(va, size, dir) do { } while (0) + +#define dma_get_cache_alignment() L1_CACHE_BYTES + +#endif /* _ALPHA_DMA_MAPPING_H */ diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index 5cd3779b0e0d..2d1e0fd6d7db 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -246,6 +246,8 @@ pcibios_add_platform_entries(struct pci_dev *dev) { } +struct pci_dev *alpha_gendev_to_pci(struct device *dev); + #endif /* __KERNEL__ */ /* Values for the `which' argument to sys_pciconfig_iobase. */ |
