diff options
author | Imre Kaloz <kaloz@openwrt.org> | 2011-01-27 12:51:25 +0000 |
---|---|---|
committer | Imre Kaloz <kaloz@openwrt.org> | 2011-01-27 12:51:25 +0000 |
commit | 0f325459eae511f5f413b4e12af576214a30320c (patch) | |
tree | 682d14f882b81b6e936d4528cca719397b4f0164 /target/linux/leon/patches/015-dma_ops.patch | |
parent | a361eab890a4c5143d556e08d7e775c5175bad86 (diff) | |
download | mtk-20170518-0f325459eae511f5f413b4e12af576214a30320c.zip mtk-20170518-0f325459eae511f5f413b4e12af576214a30320c.tar.gz mtk-20170518-0f325459eae511f5f413b4e12af576214a30320c.tar.bz2 |
add preliminary LEON support
SVN-Revision: 25139
Diffstat (limited to 'target/linux/leon/patches/015-dma_ops.patch')
-rw-r--r-- | target/linux/leon/patches/015-dma_ops.patch | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/target/linux/leon/patches/015-dma_ops.patch b/target/linux/leon/patches/015-dma_ops.patch new file mode 100644 index 0000000..7f488e0 --- /dev/null +++ b/target/linux/leon/patches/015-dma_ops.patch @@ -0,0 +1,296 @@ +From c6d8f92cfd7f4f19eb3b16545b3b68c561978fe8 Mon Sep 17 00:00:00 2001 +From: Kristoffer Glembo <kristoffer@gaisler.com> +Date: Mon, 7 Jun 2010 14:00:30 +0200 +Subject: [PATCH] sparc32: Added LEON dma_ops. + +Added leon3_dma_ops and mmu_inval_dma_area. +--- + arch/sparc/kernel/ioport.c | 139 +++++++++++++++++++++++++++++++------------ + 1 files changed, 100 insertions(+), 39 deletions(-) + +--- a/arch/sparc/kernel/ioport.c ++++ b/arch/sparc/kernel/ioport.c +@@ -50,10 +50,15 @@ + #include <asm/io-unit.h> + #include <asm/leon.h> + +-#ifdef CONFIG_SPARC_LEON +-#define mmu_inval_dma_area(p, l) leon_flush_dcache_all() +-#else ++#ifndef CONFIG_SPARC_LEON + #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ ++#else ++static inline void mmu_inval_dma_area(unsigned long va, unsigned long len) ++{ ++ if (!sparc_leon3_snooping_enabled()) { ++ leon_flush_dcache_all(); ++ } ++} + #endif + + static struct resource *_sparc_find_resource(struct resource *r, +@@ -254,7 +259,7 @@ static void *sbus_alloc_coherent(struct + dma_addr_t *dma_addrp, gfp_t gfp) + { + struct platform_device *op = to_platform_device(dev); +- unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; ++ unsigned long len_total = PAGE_ALIGN(len); + unsigned long va; + struct resource *res; + int order; +@@ -287,15 +292,19 @@ static void *sbus_alloc_coherent(struct + * XXX That's where sdev would be used. Currently we load + * all iommu tables with the same translations. + */ +- if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) +- goto err_noiommu; +- +- res->name = op->dev.of_node->name; ++#ifdef CONFIG_SPARC_LEON ++ sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); ++ *dma_addrp = virt_to_phys(va); ++#else ++ if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) { ++ release_resource(res); ++ goto err_nova; ++ } ++#endif ++ res->name = op->node->name; + + return (void *)(unsigned long)res->start; + +-err_noiommu: +- release_resource(res); + err_nova: + free_pages(va, order); + err_nomem: +@@ -321,7 +330,7 @@ static void sbus_free_coherent(struct de + return; + } + +- n = (n + PAGE_SIZE-1) & PAGE_MASK; ++ n = PAGE_ALIGN(n); + if ((res->end-res->start)+1 != n) { + printk("sbus_free_consistent: region 0x%lx asked 0x%zx\n", + (long)((res->end-res->start)+1), n); +@@ -333,7 +342,12 @@ static void sbus_free_coherent(struct de + + /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ + pgv = virt_to_page(p); +- mmu_unmap_dma_area(dev, ba, n); ++ ++#ifdef CONFIG_SPARC_LEON ++ sparc_unmapiorange((unsigned long)p, n); ++#else ++ mmu_unmap_dma_area(dev, ba, n); ++#endif + + __free_pages(pgv, get_order(n)); + } +@@ -408,9 +422,6 @@ struct dma_map_ops sbus_dma_ops = { + .sync_sg_for_device = sbus_sync_sg_for_device, + }; + +-struct dma_map_ops *dma_ops = &sbus_dma_ops; +-EXPORT_SYMBOL(dma_ops); +- + static int __init sparc_register_ioport(void) + { + register_proc_sparc_ioport(); +@@ -422,7 +433,7 @@ arch_initcall(sparc_register_ioport); + + #endif /* CONFIG_SBUS */ + +-#ifdef CONFIG_PCI ++#if defined(CONFIG_PCI) || defined(CONFIG_SPARC_LEON) + + /* Allocate and map kernel buffer using consistent mode DMA for a device. + * hwdev should be valid struct pci_dev pointer for PCI devices. +@@ -430,7 +441,7 @@ arch_initcall(sparc_register_ioport); + static void *pci32_alloc_coherent(struct device *dev, size_t len, + dma_addr_t *pba, gfp_t gfp) + { +- unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; ++ unsigned long len_total = PAGE_ALIGN(len); + unsigned long va; + struct resource *res; + int order; +@@ -463,10 +474,6 @@ static void *pci32_alloc_coherent(struct + return NULL; + } + mmu_inval_dma_area(va, len_total); +-#if 0 +-/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %lx\n", +- (long)va, (long)res->start, (long)virt_to_phys(va), len_total); +-#endif + sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); + + *pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */ +@@ -498,7 +505,7 @@ static void pci32_free_coherent(struct d + return; + } + +- n = (n + PAGE_SIZE-1) & PAGE_MASK; ++ n = PAGE_ALIGN(n); + if ((res->end-res->start)+1 != n) { + printk("pci_free_consistent: region 0x%lx asked 0x%lx\n", + (long)((res->end-res->start)+1), (long)n); +@@ -515,6 +522,14 @@ static void pci32_free_coherent(struct d + free_pages(pgp, get_order(n)); + } + ++static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size, ++ enum dma_data_direction dir, struct dma_attrs *attrs) ++{ ++ if (dir != PCI_DMA_TODEVICE) { ++ mmu_inval_dma_area((unsigned long)phys_to_virt(ba), PAGE_ALIGN(size)); ++ } ++} ++ + /* + * Same as pci_map_single, but with pages. + */ +@@ -551,8 +566,7 @@ static int pci32_map_sg(struct device *d + + /* IIep is write-through, not flushing. */ + for_each_sg(sgl, sg, nents, n) { +- BUG_ON(page_address(sg_page(sg)) == NULL); +- sg->dma_address = virt_to_phys(sg_virt(sg)); ++ sg->dma_address = sg_phys(sg); + sg->dma_length = sg->length; + } + return nents; +@@ -571,10 +585,7 @@ static void pci32_unmap_sg(struct device + + if (dir != PCI_DMA_TODEVICE) { + for_each_sg(sgl, sg, nents, n) { +- BUG_ON(page_address(sg_page(sg)) == NULL); +- mmu_inval_dma_area( +- (unsigned long) page_address(sg_page(sg)), +- (sg->length + PAGE_SIZE-1) & PAGE_MASK); ++ mmu_inval_dma_area((unsigned long)sg_virt(sg), PAGE_ALIGN(sg->length)); + } + } + } +@@ -594,7 +605,7 @@ static void pci32_sync_single_for_cpu(st + { + if (dir != PCI_DMA_TODEVICE) { + mmu_inval_dma_area((unsigned long)phys_to_virt(ba), +- (size + PAGE_SIZE-1) & PAGE_MASK); ++ PAGE_ALIGN(size)); + } + } + +@@ -621,10 +632,7 @@ static void pci32_sync_sg_for_cpu(struct + + if (dir != PCI_DMA_TODEVICE) { + for_each_sg(sgl, sg, nents, n) { +- BUG_ON(page_address(sg_page(sg)) == NULL); +- mmu_inval_dma_area( +- (unsigned long) page_address(sg_page(sg)), +- (sg->length + PAGE_SIZE-1) & PAGE_MASK); ++ mmu_inval_dma_area((unsigned long)sg_virt(sg), PAGE_ALIGN(sg->length)); + } + } + } +@@ -637,18 +645,38 @@ static void pci32_sync_sg_for_device(str + + if (dir != PCI_DMA_TODEVICE) { + for_each_sg(sgl, sg, nents, n) { +- BUG_ON(page_address(sg_page(sg)) == NULL); +- mmu_inval_dma_area( +- (unsigned long) page_address(sg_page(sg)), +- (sg->length + PAGE_SIZE-1) & PAGE_MASK); ++ mmu_inval_dma_area((unsigned long)sg_virt(sg), PAGE_ALIGN(sg->length)); + } + } + } + ++/* LEON3 unmapping functions ++ * ++ * We can only invalidate the whole cache so unmap_page and unmap_sg do the same thing ++ */ ++static void leon3_unmap_page(struct device *dev, dma_addr_t ba, size_t size, ++ enum dma_data_direction dir, struct dma_attrs *attrs) ++{ ++ if (dir != PCI_DMA_TODEVICE) { ++ mmu_inval_dma_area(0, 0); ++ } ++} ++ ++static void leon3_unmap_sg(struct device *dev, struct scatterlist *sgl, ++ int nents, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ ++ if (dir != PCI_DMA_TODEVICE) { ++ mmu_inval_dma_area(0, 0); ++ } ++} ++ + struct dma_map_ops pci32_dma_ops = { + .alloc_coherent = pci32_alloc_coherent, + .free_coherent = pci32_free_coherent, + .map_page = pci32_map_page, ++ .unmap_page = pci32_unmap_page, + .map_sg = pci32_map_sg, + .unmap_sg = pci32_unmap_sg, + .sync_single_for_cpu = pci32_sync_single_for_cpu, +@@ -658,7 +686,30 @@ struct dma_map_ops pci32_dma_ops = { + }; + EXPORT_SYMBOL(pci32_dma_ops); + +-#endif /* CONFIG_PCI */ ++struct dma_map_ops leon3_dma_ops = { ++ .alloc_coherent = sbus_alloc_coherent, ++ .free_coherent = sbus_free_coherent, ++ .map_page = pci32_map_page, ++ .unmap_page = leon3_unmap_page, ++ .map_sg = pci32_map_sg, ++ .unmap_sg = leon3_unmap_sg, ++ .sync_single_for_cpu = pci32_sync_single_for_cpu, ++ .sync_single_for_device = pci32_sync_single_for_device, ++ .sync_sg_for_cpu = pci32_sync_sg_for_cpu, ++ .sync_sg_for_device = pci32_sync_sg_for_device, ++}; ++ ++#endif /* CONFIG_PCI || CONFIG_SPARC_LEON */ ++ ++#ifdef CONFIG_SPARC_LEON ++struct dma_map_ops *dma_ops = &leon3_dma_ops; ++#else ++struct dma_map_ops *dma_ops = &sbus_dma_ops; ++#endif ++ ++#ifdef CONFIG_SBUS ++EXPORT_SYMBOL(dma_ops); ++#endif + + /* + * Return whether the given PCI device DMA address mask can be +@@ -676,6 +727,16 @@ int dma_supported(struct device *dev, u6 + } + EXPORT_SYMBOL(dma_supported); + ++int dma_set_mask(struct device *dev, u64 dma_mask) ++{ ++#ifdef CONFIG_PCI ++ if (dev->bus == &pci_bus_type) ++ return pci_set_dma_mask(to_pci_dev(dev), dma_mask); ++#endif ++ return -EOPNOTSUPP; ++} ++EXPORT_SYMBOL(dma_set_mask); ++ + #ifdef CONFIG_PROC_FS + + static int sparc_io_proc_show(struct seq_file *m, void *v) +@@ -717,7 +778,7 @@ static const struct file_operations spar + static struct resource *_sparc_find_resource(struct resource *root, + unsigned long hit) + { +- struct resource *tmp; ++ struct resource *tmp; + + for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { + if (tmp->start <= hit && tmp->end >= hit) |