xref: /openbmc/linux/arch/hexagon/kernel/dma.c (revision 2209fda3)
1 /*
2  * DMA implementation for Hexagon
3  *
4  * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 and
8  * only version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA.
19  */
20 
21 #include <linux/dma-noncoherent.h>
22 #include <linux/bootmem.h>
23 #include <linux/genalloc.h>
24 #include <linux/module.h>
25 #include <asm/page.h>
26 
27 static struct gen_pool *coherent_pool;
28 
29 
30 /* Allocates from a pool of uncached memory that was reserved at boot time */
31 
32 void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_addr,
33 		gfp_t flag, unsigned long attrs)
34 {
35 	void *ret;
36 
37 	/*
38 	 * Our max_low_pfn should have been backed off by 16MB in
39 	 * mm/init.c to create DMA coherent space.  Use that as the VA
40 	 * for the pool.
41 	 */
42 
43 	if (coherent_pool == NULL) {
44 		coherent_pool = gen_pool_create(PAGE_SHIFT, -1);
45 
46 		if (coherent_pool == NULL)
47 			panic("Can't create %s() memory pool!", __func__);
48 		else
49 			gen_pool_add(coherent_pool,
50 				(unsigned long)pfn_to_virt(max_low_pfn),
51 				hexagon_coherent_pool_size, -1);
52 	}
53 
54 	ret = (void *) gen_pool_alloc(coherent_pool, size);
55 
56 	if (ret) {
57 		memset(ret, 0, size);
58 		*dma_addr = (dma_addr_t) virt_to_phys(ret);
59 	} else
60 		*dma_addr = ~0;
61 
62 	return ret;
63 }
64 
65 void arch_dma_free(struct device *dev, size_t size, void *vaddr,
66 		dma_addr_t dma_addr, unsigned long attrs)
67 {
68 	gen_pool_free(coherent_pool, (unsigned long) vaddr, size);
69 }
70 
71 void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
72 		size_t size, enum dma_data_direction dir)
73 {
74 	void *addr = phys_to_virt(paddr);
75 
76 	switch (dir) {
77 	case DMA_TO_DEVICE:
78 		hexagon_clean_dcache_range((unsigned long) addr,
79 		(unsigned long) addr + size);
80 		break;
81 	case DMA_FROM_DEVICE:
82 		hexagon_inv_dcache_range((unsigned long) addr,
83 		(unsigned long) addr + size);
84 		break;
85 	case DMA_BIDIRECTIONAL:
86 		flush_dcache_range((unsigned long) addr,
87 		(unsigned long) addr + size);
88 		break;
89 	default:
90 		BUG();
91 	}
92 }
93