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 36static u_int phys_avail_segs; 37 38vm_paddr_t phys_avail[2 * VM_PHYSSEG_MAX + 2]; 39 40vm_paddr_t paddr_max; 41 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 return (0); 172} 173 174int 175ia64_physmem_init(void) 176{ 177 178 /* Nothing to do just yet. */ 179 return (0); 180} 181 182int 183ia64_physmem_track(vm_paddr_t base, vm_size_t len) 184{ 185 186 realmem += len; 187 return (0); 188} 189 190void * 191ia64_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} 259