Commit 74588d8ba34ff1bda027cfa737972af01ab00c8b

Authored by Haavard Skinnemoen
Committed by Linus Torvalds
1 parent bc03613dec

[PATCH] Generic ioremap_page_range: implementation

This patch adds a generic implementation of ioremap_page_range() in
lib/ioremap.c based on the i386 implementation. It differs from the
i386 version in the following ways:

  * The PTE flags are passed as a pgprot_t argument and must be
    determined up front by the arch-specific code. No additional
    PTE flags are added.
  * Uses set_pte_at() instead of set_pte()

[bunk@stusta.de: warning fix]
]dhowells@redhat.com: nommu build fix]
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Andi Kleen <ak@suse.de>
Cc: <linux-m32r@ml.linux-m32r.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Kyle McMartin <kyle@parisc-linux.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 3 changed files with 99 additions and 0 deletions Side-by-side Diff

... ... @@ -19,9 +19,13 @@
19 19 #define _LINUX_IO_H
20 20  
21 21 #include <asm/io.h>
  22 +#include <asm/page.h>
22 23  
23 24 void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
24 25 void __iowrite64_copy(void __iomem *to, const void *from, size_t count);
  26 +
  27 +int ioremap_page_range(unsigned long addr, unsigned long end,
  28 + unsigned long phys_addr, pgprot_t prot);
25 29  
26 30 #endif /* _LINUX_IO_H */
... ... @@ -7,6 +7,7 @@
7 7 idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \
8 8 sha1.o
9 9  
  10 +lib-$(CONFIG_MMU) += ioremap.o
10 11 lib-$(CONFIG_SMP) += cpumask.o
11 12  
12 13 lib-y += kobject.o kref.o kobject_uevent.o klist.o
  1 +/*
  2 + * Re-map IO memory to kernel address space so that we can access it.
  3 + * This is needed for high PCI addresses that aren't mapped in the
  4 + * 640k-1MB IO memory area on PC's
  5 + *
  6 + * (C) Copyright 1995 1996 Linus Torvalds
  7 + */
  8 +#include <linux/io.h>
  9 +#include <linux/vmalloc.h>
  10 +#include <linux/mm.h>
  11 +
  12 +#include <asm/cacheflush.h>
  13 +#include <asm/pgtable.h>
  14 +
  15 +static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
  16 + unsigned long end, unsigned long phys_addr, pgprot_t prot)
  17 +{
  18 + pte_t *pte;
  19 + unsigned long pfn;
  20 +
  21 + pfn = phys_addr >> PAGE_SHIFT;
  22 + pte = pte_alloc_kernel(pmd, addr);
  23 + if (!pte)
  24 + return -ENOMEM;
  25 + do {
  26 + BUG_ON(!pte_none(*pte));
  27 + set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
  28 + pfn++;
  29 + } while (pte++, addr += PAGE_SIZE, addr != end);
  30 + return 0;
  31 +}
  32 +
  33 +static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
  34 + unsigned long end, unsigned long phys_addr, pgprot_t prot)
  35 +{
  36 + pmd_t *pmd;
  37 + unsigned long next;
  38 +
  39 + phys_addr -= addr;
  40 + pmd = pmd_alloc(&init_mm, pud, addr);
  41 + if (!pmd)
  42 + return -ENOMEM;
  43 + do {
  44 + next = pmd_addr_end(addr, end);
  45 + if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, prot))
  46 + return -ENOMEM;
  47 + } while (pmd++, addr = next, addr != end);
  48 + return 0;
  49 +}
  50 +
  51 +static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
  52 + unsigned long end, unsigned long phys_addr, pgprot_t prot)
  53 +{
  54 + pud_t *pud;
  55 + unsigned long next;
  56 +
  57 + phys_addr -= addr;
  58 + pud = pud_alloc(&init_mm, pgd, addr);
  59 + if (!pud)
  60 + return -ENOMEM;
  61 + do {
  62 + next = pud_addr_end(addr, end);
  63 + if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
  64 + return -ENOMEM;
  65 + } while (pud++, addr = next, addr != end);
  66 + return 0;
  67 +}
  68 +
  69 +int ioremap_page_range(unsigned long addr,
  70 + unsigned long end, unsigned long phys_addr, pgprot_t prot)
  71 +{
  72 + pgd_t *pgd;
  73 + unsigned long start;
  74 + unsigned long next;
  75 + int err;
  76 +
  77 + BUG_ON(addr >= end);
  78 +
  79 + flush_cache_all();
  80 +
  81 + start = addr;
  82 + phys_addr -= addr;
  83 + pgd = pgd_offset_k(addr);
  84 + do {
  85 + next = pgd_addr_end(addr, end);
  86 + err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
  87 + if (err)
  88 + break;
  89 + } while (pgd++, addr = next, addr != end);
  90 +
  91 + flush_tlb_all();
  92 +
  93 + return err;
  94 +}