Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.17 97 lines 2.6 kB view raw
1/* 2 * arch/sh/mm/pg-dma.c 3 * 4 * Fast clear_page()/copy_page() implementation using the SH DMAC 5 * 6 * Copyright (C) 2003 Paul Mundt 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <asm/semaphore.h> 16#include <asm/mmu_context.h> 17#include <asm/addrspace.h> 18#include <asm/atomic.h> 19#include <asm/page.h> 20#include <asm/dma.h> 21#include <asm/io.h> 22 23/* Channel to use for page ops, must be dual-address mode capable. */ 24static int dma_channel = CONFIG_DMA_PAGE_OPS_CHANNEL; 25 26static void copy_page_dma(void *to, void *from) 27{ 28 /* 29 * This doesn't seem to get triggered until further along in the 30 * boot process, at which point the DMAC is already initialized. 31 * Fix this in the same fashion as clear_page_dma() in the event 32 * that this crashes due to the DMAC not being initialized. 33 */ 34 35 flush_icache_range((unsigned long)from, PAGE_SIZE); 36 dma_write_page(dma_channel, (unsigned long)from, (unsigned long)to); 37 dma_wait_for_completion(dma_channel); 38} 39 40static void clear_page_dma(void *to) 41{ 42 extern unsigned long empty_zero_page[1024]; 43 44 /* 45 * We get invoked quite early on, if the DMAC hasn't been initialized 46 * yet, fall back on the slow manual implementation. 47 */ 48 if (dma_info[dma_channel].chan != dma_channel) { 49 clear_page_slow(to); 50 return; 51 } 52 53 dma_write_page(dma_channel, (unsigned long)empty_zero_page, 54 (unsigned long)to); 55 56 /* 57 * FIXME: Something is a bit racy here, if we poll the counter right 58 * away, we seem to lock. flushing the page from the dcache doesn't 59 * seem to make a difference one way or the other, though either a full 60 * icache or dcache flush does. 61 * 62 * The location of this is important as well, and must happen prior to 63 * the completion loop but after the transfer was initiated. 64 * 65 * Oddly enough, this doesn't appear to be an issue for copy_page().. 66 */ 67 flush_icache_range((unsigned long)to, PAGE_SIZE); 68 69 dma_wait_for_completion(dma_channel); 70} 71 72static int __init pg_dma_init(void) 73{ 74 int ret; 75 76 ret = request_dma(dma_channel, "page ops"); 77 if (ret != 0) 78 return ret; 79 80 copy_page = copy_page_dma; 81 clear_page = clear_page_dma; 82 83 return ret; 84} 85 86static void __exit pg_dma_exit(void) 87{ 88 free_dma(dma_channel); 89} 90 91module_init(pg_dma_init); 92module_exit(pg_dma_exit); 93 94MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); 95MODULE_DESCRIPTION("Optimized page copy/clear routines using a dual-address mode capable DMAC channel"); 96MODULE_LICENSE("GPL"); 97