1238184Smarcel/*- 2238184Smarcel * Copyright (c) 2012 Marcel Moolenaar 3238184Smarcel * All rights reserved. 4238184Smarcel * 5238184Smarcel * Redistribution and use in source and binary forms, with or without 6238184Smarcel * modification, are permitted provided that the following conditions 7238184Smarcel * are met: 8238184Smarcel * 1. Redistributions of source code must retain the above copyright 9238184Smarcel * notice, this list of conditions and the following disclaimer. 10238184Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11238184Smarcel * notice, this list of conditions and the following disclaimer in the 12238184Smarcel * documentation and/or other materials provided with the distribution. 13238184Smarcel * 14238184Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15238184Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16238184Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17238184Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18238184Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19238184Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20238184Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21238184Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22238184Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23238184Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24238184Smarcel * SUCH DAMAGE. 25238184Smarcel */ 26238184Smarcel 27238184Smarcel#include <sys/cdefs.h> 28238184Smarcel__FBSDID("$FreeBSD$"); 29238184Smarcel 30238184Smarcel#include <sys/param.h> 31238184Smarcel#include <sys/systm.h> 32238184Smarcel 33238184Smarcel#include <machine/md_var.h> 34238184Smarcel#include <machine/vmparam.h> 35238184Smarcel 36238184Smarcelstatic u_int phys_avail_segs; 37238184Smarcel 38238184Smarcelvm_paddr_t phys_avail[2 * VM_PHYSSEG_MAX + 2]; 39238184Smarcel 40238184Smarcelvm_paddr_t paddr_max; 41238184Smarcel 42238184Smarcellong realmem; 43238184Smarcel 44238184Smarcelstatic u_int 45238184Smarcelia64_physmem_find(vm_paddr_t base, vm_paddr_t lim) 46238184Smarcel{ 47238184Smarcel u_int idx; 48238184Smarcel 49238184Smarcel for (idx = 0; phys_avail[idx + 1] != 0; idx += 2) { 50238184Smarcel if (phys_avail[idx] >= lim || 51238184Smarcel phys_avail[idx + 1] > base) 52238184Smarcel break; 53238184Smarcel } 54238184Smarcel return (idx); 55238184Smarcel} 56238184Smarcel 57238184Smarcelstatic int 58238184Smarcelia64_physmem_insert(u_int idx, vm_paddr_t base, vm_paddr_t lim) 59238184Smarcel{ 60238184Smarcel u_int ridx; 61238184Smarcel 62238184Smarcel if (phys_avail_segs == VM_PHYSSEG_MAX) 63238184Smarcel return (ENOMEM); 64238184Smarcel 65238184Smarcel ridx = phys_avail_segs * 2; 66238184Smarcel while (idx < ridx) { 67238184Smarcel phys_avail[ridx + 1] = phys_avail[ridx - 1]; 68238184Smarcel phys_avail[ridx] = phys_avail[ridx - 2]; 69238184Smarcel ridx -= 2; 70238184Smarcel } 71238184Smarcel phys_avail[idx] = base; 72238184Smarcel phys_avail[idx + 1] = lim; 73238184Smarcel phys_avail_segs++; 74238184Smarcel return (0); 75238184Smarcel} 76238184Smarcel 77238184Smarcelstatic int 78238184Smarcelia64_physmem_remove(u_int idx) 79238184Smarcel{ 80238184Smarcel 81238184Smarcel if (phys_avail_segs == 0) 82238184Smarcel return (ENOENT); 83238184Smarcel do { 84238184Smarcel phys_avail[idx] = phys_avail[idx + 2]; 85238184Smarcel phys_avail[idx + 1] = phys_avail[idx + 3]; 86238184Smarcel idx += 2; 87238184Smarcel } while (phys_avail[idx + 1] != 0); 88238184Smarcel phys_avail_segs--; 89238184Smarcel return (0); 90238184Smarcel} 91238184Smarcel 92238184Smarcelint 93238184Smarcelia64_physmem_add(vm_paddr_t base, vm_size_t len) 94238184Smarcel{ 95238184Smarcel vm_paddr_t lim; 96238184Smarcel u_int idx; 97238184Smarcel 98238184Smarcel realmem += len; 99238184Smarcel 100238184Smarcel lim = base + len; 101238184Smarcel idx = ia64_physmem_find(base, lim); 102238184Smarcel if (phys_avail[idx] == lim) { 103238184Smarcel phys_avail[idx] = base; 104238184Smarcel return (0); 105238184Smarcel } 106238184Smarcel if (idx > 0 && phys_avail[idx - 1] == base) { 107238184Smarcel phys_avail[idx - 1] = lim; 108238184Smarcel return (0); 109238184Smarcel } 110238184Smarcel return (ia64_physmem_insert(idx, base, lim)); 111238184Smarcel} 112238184Smarcel 113238184Smarcelint 114238184Smarcelia64_physmem_delete(vm_paddr_t base, vm_size_t len) 115238184Smarcel{ 116238184Smarcel vm_paddr_t lim; 117238184Smarcel u_int idx; 118238184Smarcel 119238184Smarcel lim = base + len; 120238184Smarcel idx = ia64_physmem_find(base, lim); 121238184Smarcel if (phys_avail[idx] >= lim || phys_avail[idx + 1] == 0) 122238184Smarcel return (ENOENT); 123238184Smarcel if (phys_avail[idx] < base && phys_avail[idx + 1] > lim) { 124238184Smarcel len = phys_avail[idx + 1] - lim; 125238184Smarcel phys_avail[idx + 1] = base; 126238184Smarcel base = lim; 127238184Smarcel lim = base + len; 128238184Smarcel return (ia64_physmem_insert(idx + 2, base, lim)); 129238184Smarcel } else { 130238184Smarcel if (phys_avail[idx] == base) 131238184Smarcel phys_avail[idx] = lim; 132238184Smarcel if (phys_avail[idx + 1] == lim) 133238184Smarcel phys_avail[idx + 1] = base; 134238184Smarcel if (phys_avail[idx] >= phys_avail[idx + 1]) 135238184Smarcel return (ia64_physmem_remove(idx)); 136238184Smarcel } 137238184Smarcel return (0); 138238184Smarcel} 139238184Smarcel 140238184Smarcelint 141238184Smarcelia64_physmem_fini(void) 142238184Smarcel{ 143238184Smarcel vm_paddr_t base, lim, size; 144238184Smarcel u_int idx; 145238184Smarcel 146238184Smarcel idx = 0; 147238184Smarcel while (phys_avail[idx + 1] != 0) { 148238184Smarcel base = round_page(phys_avail[idx]); 149238184Smarcel lim = trunc_page(phys_avail[idx + 1]); 150238184Smarcel if (base < lim) { 151238184Smarcel phys_avail[idx] = base; 152238184Smarcel phys_avail[idx + 1] = lim; 153238184Smarcel size = lim - base; 154238184Smarcel physmem += atop(size); 155238184Smarcel paddr_max = lim; 156238184Smarcel idx += 2; 157238184Smarcel } else 158238184Smarcel ia64_physmem_remove(idx); 159238184Smarcel } 160238184Smarcel 161238184Smarcel /* 162238184Smarcel * Round realmem to a multple of 128MB. Hopefully that compensates 163238184Smarcel * for any loss of DRAM that isn't accounted for in the memory map. 164238184Smarcel * I'm thinking legacy BIOS or VGA here. In any case, it's ok if 165238184Smarcel * we got it wrong, because we don't actually use realmem. It's 166238184Smarcel * just for show... 167238184Smarcel */ 168238184Smarcel size = 1U << 27; 169238184Smarcel realmem = (realmem + size - 1) & ~(size - 1); 170238184Smarcel realmem = atop(realmem); 171238184Smarcel return (0); 172238184Smarcel} 173238184Smarcel 174238184Smarcelint 175238184Smarcelia64_physmem_init(void) 176238184Smarcel{ 177238184Smarcel 178238184Smarcel /* Nothing to do just yet. */ 179238184Smarcel return (0); 180238184Smarcel} 181238184Smarcel 182238184Smarcelint 183238184Smarcelia64_physmem_track(vm_paddr_t base, vm_size_t len) 184238184Smarcel{ 185238184Smarcel 186238184Smarcel realmem += len; 187238184Smarcel return (0); 188238184Smarcel} 189238184Smarcel 190251963Smariusvoid * 191238184Smarcelia64_physmem_alloc(vm_size_t len, vm_size_t align) 192238184Smarcel{ 193251963Smarius vm_paddr_t base, lim, pa; 194251963Smarius void *ptr; 195251963Smarius u_int idx; 196238184Smarcel 197251963Smarius if (phys_avail_segs == 0) 198251963Smarius return (NULL); 199251963Smarius 200251963Smarius len = round_page(len); 201251963Smarius 202251963Smarius /* 203251963Smarius * Try and allocate with least effort. 204251963Smarius */ 205251963Smarius idx = phys_avail_segs * 2; 206251963Smarius while (idx > 0) { 207251963Smarius idx -= 2; 208251963Smarius base = phys_avail[idx]; 209251963Smarius lim = phys_avail[idx + 1]; 210251963Smarius 211251963Smarius if (lim - base < len) 212251963Smarius continue; 213251963Smarius 214251963Smarius /* First try from the end. */ 215251963Smarius pa = lim - len; 216251963Smarius if ((pa & (align - 1)) == 0) { 217251963Smarius if (pa == base) 218251963Smarius ia64_physmem_remove(idx); 219251963Smarius else 220251963Smarius phys_avail[idx + 1] = pa; 221251963Smarius goto gotit; 222251963Smarius } 223251963Smarius 224251963Smarius /* Try from the start next. */ 225251963Smarius pa = base; 226251963Smarius if ((pa & (align - 1)) == 0) { 227251963Smarius if (pa + len == lim) 228251963Smarius ia64_physmem_remove(idx); 229251963Smarius else 230251963Smarius phys_avail[idx] += len; 231251963Smarius goto gotit; 232251963Smarius } 233251963Smarius } 234251963Smarius 235251963Smarius /* 236251963Smarius * Find a good segment and split it up. 237251963Smarius */ 238251963Smarius idx = phys_avail_segs * 2; 239251963Smarius while (idx > 0) { 240251963Smarius idx -= 2; 241251963Smarius base = phys_avail[idx]; 242251963Smarius lim = phys_avail[idx + 1]; 243251963Smarius 244251963Smarius pa = (base + align - 1) & ~(align - 1); 245251963Smarius if (pa + len <= lim) { 246251963Smarius ia64_physmem_delete(pa, len); 247251963Smarius goto gotit; 248251963Smarius } 249251963Smarius } 250251963Smarius 251251963Smarius /* Out of luck. */ 252251963Smarius return (NULL); 253251963Smarius 254251963Smarius gotit: 255251963Smarius ptr = (void *)IA64_PHYS_TO_RR7(pa); 256251963Smarius bzero(ptr, len); 257251963Smarius return (ptr); 258238184Smarcel} 259