]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/ia64/ia64/physmem.c
MFC 349843:
[FreeBSD/stable/10.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 long Maxmem;
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
172         /*
173          * Maxmem isn't the "maximum memory", it's one larger than the
174          * highest page of the physical address space.
175          */
176         Maxmem = atop(paddr_max);
177         return (0);
178 }
179
180 int
181 ia64_physmem_init(void)
182 {
183
184         /* Nothing to do just yet. */
185         return (0);
186 }
187
188 int
189 ia64_physmem_track(vm_paddr_t base, vm_size_t len)
190 {
191
192         realmem += len;
193         return (0);
194 }
195
196 void *
197 ia64_physmem_alloc(vm_size_t len, vm_size_t align)
198 {
199         vm_paddr_t base, lim, pa;
200         void *ptr;
201         u_int idx;
202
203         if (phys_avail_segs == 0)
204                 return (NULL);
205
206         len = round_page(len);
207
208         /*
209          * Try and allocate with least effort.
210          */
211         idx = phys_avail_segs * 2;
212         while (idx > 0) {
213                 idx -= 2;
214                 base = phys_avail[idx];
215                 lim = phys_avail[idx + 1];
216
217                 if (lim - base < len)
218                         continue;
219
220                 /* First try from the end. */
221                 pa = lim - len;
222                 if ((pa & (align - 1)) == 0) {
223                         if (pa == base)
224                                 ia64_physmem_remove(idx);
225                         else
226                                 phys_avail[idx + 1] = pa;
227                         goto gotit;
228                 }
229
230                 /* Try from the start next. */
231                 pa = base;
232                 if ((pa & (align - 1)) == 0) {
233                         if (pa + len == lim)
234                                 ia64_physmem_remove(idx);
235                         else
236                                 phys_avail[idx] += len;
237                         goto gotit;
238                 }
239         }
240
241         /*
242          * Find a good segment and split it up.
243          */
244         idx = phys_avail_segs * 2;
245         while (idx > 0) {
246                 idx -= 2;
247                 base = phys_avail[idx];
248                 lim = phys_avail[idx + 1];
249
250                 pa = (base + align - 1) & ~(align - 1);
251                 if (pa + len <= lim) {
252                         ia64_physmem_delete(pa, len);
253                         goto gotit;
254                 }
255         }
256
257         /* Out of luck. */
258         return (NULL);
259
260  gotit:
261         ptr = (void *)IA64_PHYS_TO_RR7(pa);
262         bzero(ptr, len);
263         return (ptr);
264 }