| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- From c6d8f92cfd7f4f19eb3b16545b3b68c561978fe8 Mon Sep 17 00:00:00 2001
- From: Kristoffer Glembo <[email protected]>
- 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)
|