11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* pci-dma-nommu.c: Dynamic DMA mapping support for the FRV 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 444d1b980c72db0faf35adb082fb2208351803028David Woodhouse * Written by David Woodhouse (dwmw2@infradead.org) 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 14a5788caa269e446201018bb8879a1dd90f41d32bDavid Howells#include <linux/export.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DMA_SRAM_START dma_coherent_mem_start 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DMA_SRAM_END dma_coherent_mem_end 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else // Use video RAM on Matrox 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DMA_SRAM_START 0xe8900000 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DMA_SRAM_END 0xe8a00000 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dma_alloc_record { 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head list; 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long ofs; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long len; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(dma_alloc_lock); 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(dma_alloc_list); 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37a5da7d3c6e8fcd7aaab6c4e1e9101ba333248ffbAl Virovoid *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dma_alloc_record *new; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *this = &dma_alloc_list; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long start = DMA_SRAM_START; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long end; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!DMA_SRAM_START) { 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s called without any DMA area reserved!\n", __func__); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new = kmalloc(sizeof (*new), GFP_ATOMIC); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!new) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Round up to a reasonable alignment */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new->len = (size + 31) & ~31; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&dma_alloc_lock, flags); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (this, &dma_alloc_list) { 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dma_alloc_record *this_r = list_entry(this, struct dma_alloc_record, list); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = this_r->ofs; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (end - start >= size) 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto gotone; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = this_r->ofs + this_r->len; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reached end of list. */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = DMA_SRAM_END; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this = &dma_alloc_list; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (end - start >= size) { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gotone: 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new->ofs = start; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&new->list, this); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&dma_alloc_lock, flags); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dma_handle = start; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (void *)start; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(new); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&dma_alloc_lock, flags); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87402344012ebe696d9353bbf056889ddaaec83079David HowellsEXPORT_SYMBOL(dma_alloc_coherent); 88402344012ebe696d9353bbf056889ddaaec83079David Howells 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dma_alloc_record *rec; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&dma_alloc_lock, flags); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(rec, &dma_alloc_list, list) { 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rec->ofs == dma_handle) { 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&rec->list); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(rec); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&dma_alloc_lock, flags); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&dma_alloc_lock, flags); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108402344012ebe696d9353bbf056889ddaaec83079David HowellsEXPORT_SYMBOL(dma_free_coherent); 109402344012ebe696d9353bbf056889ddaaec83079David Howells 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum dma_data_direction direction) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 113db5c444eeb781788a0db36a2682b2417cf71f764Stoyan Gaydarov BUG_ON(direction == DMA_NONE); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return virt_to_bus(ptr); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120402344012ebe696d9353bbf056889ddaaec83079David HowellsEXPORT_SYMBOL(dma_map_single); 121402344012ebe696d9353bbf056889ddaaec83079David Howells 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum dma_data_direction direction) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<nents; i++) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frv_cache_wback_inv(sg_dma_address(&sg[i]), 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_dma_address(&sg[i]) + sg_dma_len(&sg[i])); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131db5c444eeb781788a0db36a2682b2417cf71f764Stoyan Gaydarov BUG_ON(direction == DMA_NONE); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return nents; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 135402344012ebe696d9353bbf056889ddaaec83079David Howells 136402344012ebe696d9353bbf056889ddaaec83079David HowellsEXPORT_SYMBOL(dma_map_sg); 137c9af956cf7548bc352557eb8356913e489fd8716David Howells 138c9af956cf7548bc352557eb8356913e489fd8716David Howellsdma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, 139c9af956cf7548bc352557eb8356913e489fd8716David Howells size_t size, enum dma_data_direction direction) 140c9af956cf7548bc352557eb8356913e489fd8716David Howells{ 141c9af956cf7548bc352557eb8356913e489fd8716David Howells BUG_ON(direction == DMA_NONE); 142c9af956cf7548bc352557eb8356913e489fd8716David Howells flush_dcache_page(page); 143c9af956cf7548bc352557eb8356913e489fd8716David Howells return (dma_addr_t) page_to_phys(page) + offset; 144c9af956cf7548bc352557eb8356913e489fd8716David Howells} 145c9af956cf7548bc352557eb8356913e489fd8716David Howells 146c9af956cf7548bc352557eb8356913e489fd8716David HowellsEXPORT_SYMBOL(dma_map_page); 147