]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/ia64/ia64/physmem.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / ia64 / ia64 / physmem.c
1 /*-
2  * Copyright (c) 2012 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32
33 #include <machine/md_var.h>
34 #include <machine/vmparam.h>
35
36 static u_int phys_avail_segs;
37
38 vm_paddr_t phys_avail[2 * VM_PHYSSEG_MAX + 2];
39
40 vm_paddr_t paddr_max;
41
42 long realmem;
43
44 static u_int
45 ia64_physmem_find(vm_paddr_t base, vm_paddr_t lim)
46 {
47         u_int idx;
48
49         for (idx = 0; phys_avail[idx + 1] != 0; idx += 2) {
50                 if (phys_avail[idx] >= lim ||
51                     phys_avail[idx + 1] > base)
52                         break;
53         }
54         return (idx);
55 }
56
57 static int
58 ia64_physmem_insert(u_int idx, vm_paddr_t base, vm_paddr_t lim)
59 {
60         u_int ridx;
61
62         if (phys_avail_segs == VM_PHYSSEG_MAX)
63                 return (ENOMEM);
64
65         ridx = phys_avail_segs * 2;
66         while (idx < ridx) {
67                 phys_avail[ridx + 1] = phys_avail[ridx - 1];
68                 phys_avail[ridx] = phys_avail[ridx - 2];
69                 ridx -= 2;
70         }
71         phys_avail[idx] = base;
72         phys_avail[idx + 1] = lim;
73         phys_avail_segs++;
74         return (0);
75 }
76
77 static int
78 ia64_physmem_remove(u_int idx)
79 {
80
81         if (phys_avail_segs == 0)
82                 return (ENOENT);
83         do {
84                 phys_avail[idx] = phys_avail[idx + 2];
85                 phys_avail[idx + 1] = phys_avail[idx + 3];
86                 idx += 2;
87         } while (phys_avail[idx + 1] != 0);
88         phys_avail_segs--;
89         return (0);
90 }
91
92 int
93 ia64_physmem_add(vm_paddr_t base, vm_size_t len)
94 {
95         vm_paddr_t lim;
96         u_int idx;
97
98         realmem += len;
99
100         lim = base + len;
101         idx = ia64_physmem_find(base, lim);
102         if (phys_avail[idx] == lim) {
103                 phys_avail[idx] = base;
104                 return (0);
105         }
106         if (idx > 0 && phys_avail[idx - 1] == base) {
107                 phys_avail[idx - 1] = lim;
108                 return (0);
109         }
110         return (ia64_physmem_insert(idx, base, lim));
111 }
112
113 int
114 ia64_physmem_delete(vm_paddr_t base, vm_size_t len)
115 {
116         vm_paddr_t lim;
117         u_int idx;
118
119         lim = base + len;
120         idx = ia64_physmem_find(base, lim);
121         if (phys_avail[idx] >= lim || phys_avail[idx + 1] == 0)
122                 return (ENOENT);
123         if (phys_avail[idx] < base && phys_avail[idx + 1] > lim) {
124                 len = phys_avail[idx + 1] - lim;
125                 phys_avail[idx + 1] = base;
126                 base = lim;
127                 lim = base + len;
128                 return (ia64_physmem_insert(idx + 2, base, lim));
129         } else {
130                 if (phys_avail[idx] == base)
131                         phys_avail[idx] = lim;
132                 if (phys_avail[idx + 1] == lim)
133                         phys_avail[idx + 1] = base;
134                 if (phys_avail[idx] >= phys_avail[idx + 1])
135                         return (ia64_physmem_remove(idx));
136         }
137         return (0);
138 }
139
140 int
141 ia64_physmem_fini(void)
142 {
143         vm_paddr_t base, lim, size;
144         u_int idx;
145
146         idx = 0;
147         while (phys_avail[idx + 1] != 0) {
148                 base = round_page(phys_avail[idx]);
149                 lim = trunc_page(phys_avail[idx + 1]);
150                 if (base < lim) {
151                         phys_avail[idx] = base;
152                         phys_avail[idx + 1] = lim;
153                         size = lim - base;
154                         physmem += atop(size);
155                         paddr_max = lim;
156                         idx += 2;
157                 } else
158                         ia64_physmem_remove(idx);
159         }
160
161         /*
162          * Round realmem to a multple of 128MB. Hopefully that compensates
163          * for any loss of DRAM that isn't accounted for in the memory map.
164          * I'm thinking legacy BIOS or VGA here. In any case, it's ok if
165          * we got it wrong, because we don't actually use realmem. It's
166          * just for show...
167          */
168         size = 1U << 27;
169         realmem = (realmem + size - 1) & ~(size - 1);
170         realmem = atop(realmem);
171         return (0);
172 }
173
174 int
175 ia64_physmem_init(void)
176 {
177
178         /* Nothing to do just yet. */
179         return (0);
180 }
181
182 int
183 ia64_physmem_track(vm_paddr_t base, vm_size_t len)
184 {
185
186         realmem += len;
187         return (0);
188 }
189
190 void *
191 ia64_physmem_alloc(vm_size_t len, vm_size_t align)
192 {
193         vm_paddr_t base, lim, pa;
194         void *ptr;
195         u_int idx;
196
197         if (phys_avail_segs == 0)
198                 return (NULL);
199
200         len = round_page(len);
201
202         /*
203          * Try and allocate with least effort.
204          */
205         idx = phys_avail_segs * 2;
206         while (idx > 0) {
207                 idx -= 2;
208                 base = phys_avail[idx];
209                 lim = phys_avail[idx + 1];
210
211                 if (lim - base < len)
212                         continue;
213
214                 /* First try from the end. */
215                 pa = lim - len;
216                 if ((pa & (align - 1)) == 0) {
217                         if (pa == base)
218                                 ia64_physmem_remove(idx);
219                         else
220                                 phys_avail[idx + 1] = pa;
221                         goto gotit;
222                 }
223
224                 /* Try from the start next. */
225                 pa = base;
226                 if ((pa & (align - 1)) == 0) {
227                         if (pa + len == lim)
228                                 ia64_physmem_remove(idx);
229                         else
230                                 phys_avail[idx] += len;
231                         goto gotit;
232                 }
233         }
234
235         /*
236          * Find a good segment and split it up.
237          */
238         idx = phys_avail_segs * 2;
239         while (idx > 0) {
240                 idx -= 2;
241                 base = phys_avail[idx];
242                 lim = phys_avail[idx + 1];
243
244                 pa = (base + align - 1) & ~(align - 1);
245                 if (pa + len <= lim) {
246                         ia64_physmem_delete(pa, len);
247                         goto gotit;
248                 }
249         }
250
251         /* Out of luck. */
252         return (NULL);
253
254  gotit:
255         ptr = (void *)IA64_PHYS_TO_RR7(pa);
256         bzero(ptr, len);
257         return (ptr);
258 }