1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/config.h>
18#include <linux/kernel.h>
19#include <linux/stddef.h>
20#include <linux/blk.h>
21#include <linux/init.h>
22
23#include "mem_pieces.h"
24
25extern struct mem_pieces phys_avail;
26
27static void mem_pieces_print(struct mem_pieces *);
28
29
30
31
32void __init *
33mem_pieces_find(unsigned int size, unsigned int align)
34{
35 int i;
36 unsigned a, e;
37 struct mem_pieces *mp = &phys_avail;
38
39 for (i = 0; i < mp->n_regions; ++i) {
40 a = mp->regions[i].address;
41 e = a + mp->regions[i].size;
42 a = (a + align - 1) & -align;
43 if (a + size <= e) {
44 mem_pieces_remove(mp, a, size, 1);
45 return __va(a);
46 }
47 }
48 panic("Couldn't find %u bytes at %u alignment\n", size, align);
49
50 return NULL;
51}
52
53
54
55
56void __init
57mem_pieces_remove(struct mem_pieces *mp, unsigned int start, unsigned int size,
58 int must_exist)
59{
60 int i, j;
61 unsigned int end, rs, re;
62 struct reg_property *rp;
63
64 end = start + size;
65 for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
66 if (end > rp->address && start < rp->address + rp->size)
67 break;
68 }
69 if (i >= mp->n_regions) {
70 if (must_exist)
71 printk("mem_pieces_remove: [%x,%x) not in any region\n",
72 start, end);
73 return;
74 }
75 for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
76 rs = rp->address;
77 re = rs + rp->size;
78 if (must_exist && (start < rs || end > re)) {
79 printk("mem_pieces_remove: bad overlap [%x,%x) with",
80 start, end);
81 mem_pieces_print(mp);
82 must_exist = 0;
83 }
84 if (start > rs) {
85 rp->size = start - rs;
86 if (end < re) {
87
88 if (mp->n_regions >= MEM_PIECES_MAX)
89 panic("eek... mem_pieces overflow");
90 for (j = mp->n_regions; j > i + 1; --j)
91 mp->regions[j] = mp->regions[j-1];
92 ++mp->n_regions;
93 rp[1].address = end;
94 rp[1].size = re - end;
95 }
96 } else {
97 if (end < re) {
98 rp->address = end;
99 rp->size = re - end;
100 } else {
101
102 for (j = i; j < mp->n_regions - 1; ++j)
103 mp->regions[j] = mp->regions[j+1];
104 --mp->n_regions;
105 --i;
106 --rp;
107 }
108 }
109 }
110}
111
112static void __init
113mem_pieces_print(struct mem_pieces *mp)
114{
115 int i;
116
117 for (i = 0; i < mp->n_regions; ++i)
118 printk(" [%x, %x)", mp->regions[i].address,
119 mp->regions[i].address + mp->regions[i].size);
120 printk("\n");
121}
122
123#if defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
124
125
126
127void __init
128mem_pieces_append(struct mem_pieces *mp, unsigned int start, unsigned int size)
129{
130 struct reg_property *rp;
131
132 if (mp->n_regions >= MEM_PIECES_MAX)
133 return;
134 rp = &mp->regions[mp->n_regions++];
135 rp->address = start;
136 rp->size = size;
137}
138#endif
139
140void __init
141mem_pieces_sort(struct mem_pieces *mp)
142{
143 unsigned long a, s;
144 int i, j;
145
146 for (i = 1; i < mp->n_regions; ++i) {
147 a = mp->regions[i].address;
148 s = mp->regions[i].size;
149 for (j = i - 1; j >= 0; --j) {
150 if (a >= mp->regions[j].address)
151 break;
152 mp->regions[j+1] = mp->regions[j];
153 }
154 mp->regions[j+1].address = a;
155 mp->regions[j+1].size = s;
156 }
157}
158
159void __init
160mem_pieces_coalesce(struct mem_pieces *mp)
161{
162 unsigned long a, s, ns;
163 int i, j, d;
164
165 d = 0;
166 for (i = 0; i < mp->n_regions; i = j) {
167 a = mp->regions[i].address;
168 s = mp->regions[i].size;
169 for (j = i + 1; j < mp->n_regions
170 && mp->regions[j].address - a <= s; ++j) {
171 ns = mp->regions[j].address + mp->regions[j].size - a;
172 if (ns > s)
173 s = ns;
174 }
175 mp->regions[d].address = a;
176 mp->regions[d].size = s;
177 ++d;
178 }
179 mp->n_regions = d;
180}
181