===== arch/ppc/mm/pgtable.c 1.19 vs edited ===== --- 1.19/arch/ppc/mm/pgtable.c Sat May 22 14:56:23 2004 +++ edited/arch/ppc/mm/pgtable.c Fri Jun 4 16:28:44 2004 @@ -10,6 +10,8 @@ * Copyright (C) 1996 Paul Mackerras * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). * + * Simple ioremap cache added by Eugene Surovegin , 2004 + * * Derived from "arch/i386/mm/init.c" * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * @@ -59,6 +61,17 @@ #define p_mapped_by_bats(x) (0UL) #endif /* HAVE_BATS */ +/* simple ioremap cache */ +#define IOREMAP_CACHE_SIZE 10 +static spinlock_t ioremap_cache_lock = SPIN_LOCK_UNLOCKED; +static int ioremap_cache_active_slots; +static struct ioremap_cache_entry { + phys_addr_t pa; + unsigned long va; + unsigned long flags; + int users; +} ioremap_cache[IOREMAP_CACHE_SIZE]; + #ifdef CONFIG_44x /* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */ #define PGDIR_ORDER 1 @@ -137,6 +150,84 @@ __free_page(ptepage); } +static unsigned long ioremap_cache_check(phys_addr_t pa, unsigned long size, + unsigned long flags) +{ + unsigned long va = 0; + int i; + + if (size != 0x1000) + return 0; + + spin_lock(&ioremap_cache_lock); + if (!ioremap_cache_active_slots) + goto out; + + for (i = 0; i < IOREMAP_CACHE_SIZE; ++i) + if (ioremap_cache[i].pa == pa && + ioremap_cache[i].flags == flags) + { + va = ioremap_cache[i].va; + ++ioremap_cache[i].users; + break; + } +out: + spin_unlock(&ioremap_cache_lock); + + return va; +} + +static void ioremap_cache_add(phys_addr_t pa, unsigned long va, unsigned long size, + unsigned long flags) +{ + int i; + + if (size != 0x1000) + return; + + spin_lock(&ioremap_cache_lock); + if (ioremap_cache_active_slots == IOREMAP_CACHE_SIZE) + goto out; + + for (i = 0; i < IOREMAP_CACHE_SIZE; ++i) + if (!ioremap_cache[i].pa){ + ioremap_cache[i].pa = pa; + ioremap_cache[i].va = va; + ioremap_cache[i].flags = flags; + ioremap_cache[i].users = 1; + ++ioremap_cache_active_slots; + break; + } +out: + spin_unlock(&ioremap_cache_lock); +} + +static int ioremap_cache_del(unsigned long va) +{ + int i, res = 0; + va &= PAGE_MASK; + + spin_lock(&ioremap_cache_lock); + if (!ioremap_cache_active_slots) + goto out; + + for (i = 0; i < IOREMAP_CACHE_SIZE; ++i) + if (ioremap_cache[i].va == va){ + res = --ioremap_cache[i].users; + if (!res){ + ioremap_cache[i].pa = 0; + ioremap_cache[i].va = 0; + ioremap_cache[i].flags = 0; + --ioremap_cache_active_slots; + } + break; + } +out: + spin_unlock(&ioremap_cache_lock); + + return res; +} + #ifndef CONFIG_44x void * ioremap(phys_addr_t addr, unsigned long size) @@ -210,6 +301,14 @@ if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ ) goto out; + if ((flags & _PAGE_PRESENT) == 0) + flags |= _PAGE_KERNEL; + if (flags & _PAGE_NO_CACHE) + flags |= _PAGE_GUARDED; + + if ((v = ioremap_cache_check(p, size, flags))) + goto out; + if (mem_init_done) { struct vm_struct *area; area = get_vm_area(size, VM_IOREMAP); @@ -220,11 +319,6 @@ v = (ioremap_bot -= size); } - if ((flags & _PAGE_PRESENT) == 0) - flags |= _PAGE_KERNEL; - if (flags & _PAGE_NO_CACHE) - flags |= _PAGE_GUARDED; - /* * Should check if it is a candidate for a BAT mapping */ @@ -238,6 +332,7 @@ return NULL; } + ioremap_cache_add(p, v, size, flags); out: return (void *) (v + ((unsigned long)addr & ~PAGE_MASK)); } @@ -250,8 +345,9 @@ */ if (v_mapped_by_bats((unsigned long)addr)) return; - if (addr > high_memory && (unsigned long) addr < ioremap_bot) - vunmap((void *) (PAGE_MASK & (unsigned long)addr)); + if (!ioremap_cache_del((unsigned long)addr)) + if (addr > high_memory && (unsigned long) addr < ioremap_bot) + vunmap((void *) (PAGE_MASK & (unsigned long)addr)); } int