Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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/vmalloc.h>
  9 #include <linux/mm.h>
 10 #include <linux/sched.h>
 11 #include <linux/io.h>
 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         start = addr;
 80         phys_addr -= addr;
 81         pgd = pgd_offset_k(addr);
 82         do {
 83                 next = pgd_addr_end(addr, end);
 84                 err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
 85                 if (err)
 86                         break;
 87         } while (pgd++, addr = next, addr != end);
 88 
 89         flush_cache_vmap(start, end);
 90 
 91         return err;
 92 }
 93 
  This page was automatically generated by the LXR engine.