physmem.c revision 310508
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: stable/10/sys/ia64/ia64/physmem.c 310508 2016-12-24 13:28:39Z avg $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32 33#include <machine/md_var.h> 34#include <machine/vmparam.h> 35 36static u_int phys_avail_segs; 37 38vm_paddr_t phys_avail[2 * VM_PHYSSEG_MAX + 2]; 39 40vm_paddr_t paddr_max; 41long Maxmem; 42long realmem; 43 44static u_int 45ia64_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 57static int 58ia64_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 77static int 78ia64_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 92int 93ia64_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 113int 114ia64_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 140int 141ia64_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 180int 181ia64_physmem_init(void) 182{ 183 184 /* Nothing to do just yet. */ 185 return (0); 186} 187 188int 189ia64_physmem_track(vm_paddr_t base, vm_size_t len) 190{ 191 192 realmem += len; 193 return (0); 194} 195 196void * 197ia64_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} 265