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