summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2004-08-30 03:14:53 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-08-30 03:14:53 -0700
commita90ee89e25ef0b8919afc945ee4e940d9418196f (patch)
treea8e3c65918d5b52e6c8b0ea59b6bda0bf058918b
parent7ef56c665fd9ab640cff405d1408fa52154c9a1c (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.c3
-rw-r--r--arch/alpha/kernel/pci-noop.c63
-rw-r--r--arch/alpha/kernel/pci_iommu.c39
-rw-r--r--include/asm-alpha/cache.h2
-rw-r--r--include/asm-alpha/dma-mapping.h64
-rw-r--r--include/asm-alpha/pci.h2
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. */