Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ioremap_fixed.c
Go to the documentation of this file.
1 /*
2  * Re-map IO memory to kernel address space so that we can access it.
3  *
4  * These functions should only be used when it is necessary to map a
5  * physical address space into the kernel address space before ioremap()
6  * can be used, e.g. early in boot before paging_init().
7  *
8  * Copyright (C) 2009 Matt Fleming
9  */
10 
11 #include <linux/vmalloc.h>
12 #include <linux/ioport.h>
13 #include <linux/module.h>
14 #include <linux/mm.h>
15 #include <linux/io.h>
16 #include <linux/bootmem.h>
17 #include <linux/proc_fs.h>
18 #include <asm/fixmap.h>
19 #include <asm/page.h>
20 #include <asm/pgalloc.h>
21 #include <asm/addrspace.h>
22 #include <asm/cacheflush.h>
23 #include <asm/tlbflush.h>
24 #include <asm/mmu.h>
25 #include <asm/mmu_context.h>
26 
27 struct ioremap_map {
28  void __iomem *addr;
29  unsigned long size;
30  unsigned long fixmap_addr;
31 };
32 
33 static struct ioremap_map ioremap_maps[FIX_N_IOREMAPS];
34 
36 {
37  struct ioremap_map *map;
38  int i;
39 
40  for (i = 0; i < FIX_N_IOREMAPS; i++) {
41  map = &ioremap_maps[i];
43  }
44 }
45 
46 void __init __iomem *
48 {
49  enum fixed_addresses idx0, idx;
50  struct ioremap_map *map;
51  unsigned int nrpages;
52  unsigned long offset;
53  int i, slot;
54 
55  /*
56  * Mappings have to be page-aligned
57  */
58  offset = phys_addr & ~PAGE_MASK;
59  phys_addr &= PAGE_MASK;
60  size = PAGE_ALIGN(phys_addr + size) - phys_addr;
61 
62  slot = -1;
63  for (i = 0; i < FIX_N_IOREMAPS; i++) {
64  map = &ioremap_maps[i];
65  if (!map->addr) {
66  map->size = size;
67  slot = i;
68  break;
69  }
70  }
71 
72  if (slot < 0)
73  return NULL;
74 
75  /*
76  * Mappings have to fit in the FIX_IOREMAP area.
77  */
78  nrpages = size >> PAGE_SHIFT;
79  if (nrpages > FIX_N_IOREMAPS)
80  return NULL;
81 
82  /*
83  * Ok, go for it..
84  */
85  idx0 = FIX_IOREMAP_BEGIN + slot;
86  idx = idx0;
87  while (nrpages > 0) {
88  pgprot_val(prot) |= _PAGE_WIRED;
89  __set_fixmap(idx, phys_addr, prot);
90  phys_addr += PAGE_SIZE;
91  idx++;
92  --nrpages;
93  }
94 
95  map->addr = (void __iomem *)(offset + map->fixmap_addr);
96  return map->addr;
97 }
98 
100 {
101  enum fixed_addresses idx;
102  struct ioremap_map *map;
103  unsigned int nrpages;
104  int i, slot;
105 
106  slot = -1;
107  for (i = 0; i < FIX_N_IOREMAPS; i++) {
108  map = &ioremap_maps[i];
109  if (map->addr == addr) {
110  slot = i;
111  break;
112  }
113  }
114 
115  /*
116  * If we don't match, it's not for us.
117  */
118  if (slot < 0)
119  return -EINVAL;
120 
121  nrpages = map->size >> PAGE_SHIFT;
122 
123  idx = FIX_IOREMAP_BEGIN + slot + nrpages - 1;
124  while (nrpages > 0) {
126  --idx;
127  --nrpages;
128  }
129 
130  map->size = 0;
131  map->addr = NULL;
132 
133  return 0;
134 }