1*78acc472SPeter Tyser /* 2*78acc472SPeter Tyser * Procedures for maintaining information about logical memory blocks. 3*78acc472SPeter Tyser * 4*78acc472SPeter Tyser * Peter Bergner, IBM Corp. June 2001. 5*78acc472SPeter Tyser * Copyright (C) 2001 Peter Bergner. 6*78acc472SPeter Tyser * 7*78acc472SPeter Tyser * This program is free software; you can redistribute it and/or 8*78acc472SPeter Tyser * modify it under the terms of the GNU General Public License 9*78acc472SPeter Tyser * as published by the Free Software Foundation; either version 10*78acc472SPeter Tyser * 2 of the License, or (at your option) any later version. 11*78acc472SPeter Tyser */ 12*78acc472SPeter Tyser 13*78acc472SPeter Tyser #include <common.h> 14*78acc472SPeter Tyser #include <lmb.h> 15*78acc472SPeter Tyser 16*78acc472SPeter Tyser #define LMB_ALLOC_ANYWHERE 0 17*78acc472SPeter Tyser 18*78acc472SPeter Tyser void lmb_dump_all(struct lmb *lmb) 19*78acc472SPeter Tyser { 20*78acc472SPeter Tyser #ifdef DEBUG 21*78acc472SPeter Tyser unsigned long i; 22*78acc472SPeter Tyser 23*78acc472SPeter Tyser debug("lmb_dump_all:\n"); 24*78acc472SPeter Tyser debug(" memory.cnt = 0x%lx\n", lmb->memory.cnt); 25*78acc472SPeter Tyser debug(" memory.size = 0x%llx\n", 26*78acc472SPeter Tyser (unsigned long long)lmb->memory.size); 27*78acc472SPeter Tyser for (i=0; i < lmb->memory.cnt ;i++) { 28*78acc472SPeter Tyser debug(" memory.reg[0x%lx].base = 0x%llx\n", i, 29*78acc472SPeter Tyser (long long unsigned)lmb->memory.region[i].base); 30*78acc472SPeter Tyser debug(" .size = 0x%llx\n", 31*78acc472SPeter Tyser (long long unsigned)lmb->memory.region[i].size); 32*78acc472SPeter Tyser } 33*78acc472SPeter Tyser 34*78acc472SPeter Tyser debug("\n reserved.cnt = 0x%lx\n", 35*78acc472SPeter Tyser lmb->reserved.cnt); 36*78acc472SPeter Tyser debug(" reserved.size = 0x%llx\n", 37*78acc472SPeter Tyser (long long unsigned)lmb->reserved.size); 38*78acc472SPeter Tyser for (i=0; i < lmb->reserved.cnt ;i++) { 39*78acc472SPeter Tyser debug(" reserved.reg[0x%lx].base = 0x%llx\n", i, 40*78acc472SPeter Tyser (long long unsigned)lmb->reserved.region[i].base); 41*78acc472SPeter Tyser debug(" .size = 0x%llx\n", 42*78acc472SPeter Tyser (long long unsigned)lmb->reserved.region[i].size); 43*78acc472SPeter Tyser } 44*78acc472SPeter Tyser #endif /* DEBUG */ 45*78acc472SPeter Tyser } 46*78acc472SPeter Tyser 47*78acc472SPeter Tyser static long lmb_addrs_overlap(phys_addr_t base1, 48*78acc472SPeter Tyser phys_size_t size1, phys_addr_t base2, phys_size_t size2) 49*78acc472SPeter Tyser { 50*78acc472SPeter Tyser return ((base1 < (base2+size2)) && (base2 < (base1+size1))); 51*78acc472SPeter Tyser } 52*78acc472SPeter Tyser 53*78acc472SPeter Tyser static long lmb_addrs_adjacent(phys_addr_t base1, phys_size_t size1, 54*78acc472SPeter Tyser phys_addr_t base2, phys_size_t size2) 55*78acc472SPeter Tyser { 56*78acc472SPeter Tyser if (base2 == base1 + size1) 57*78acc472SPeter Tyser return 1; 58*78acc472SPeter Tyser else if (base1 == base2 + size2) 59*78acc472SPeter Tyser return -1; 60*78acc472SPeter Tyser 61*78acc472SPeter Tyser return 0; 62*78acc472SPeter Tyser } 63*78acc472SPeter Tyser 64*78acc472SPeter Tyser static long lmb_regions_adjacent(struct lmb_region *rgn, 65*78acc472SPeter Tyser unsigned long r1, unsigned long r2) 66*78acc472SPeter Tyser { 67*78acc472SPeter Tyser phys_addr_t base1 = rgn->region[r1].base; 68*78acc472SPeter Tyser phys_size_t size1 = rgn->region[r1].size; 69*78acc472SPeter Tyser phys_addr_t base2 = rgn->region[r2].base; 70*78acc472SPeter Tyser phys_size_t size2 = rgn->region[r2].size; 71*78acc472SPeter Tyser 72*78acc472SPeter Tyser return lmb_addrs_adjacent(base1, size1, base2, size2); 73*78acc472SPeter Tyser } 74*78acc472SPeter Tyser 75*78acc472SPeter Tyser static void lmb_remove_region(struct lmb_region *rgn, unsigned long r) 76*78acc472SPeter Tyser { 77*78acc472SPeter Tyser unsigned long i; 78*78acc472SPeter Tyser 79*78acc472SPeter Tyser for (i = r; i < rgn->cnt - 1; i++) { 80*78acc472SPeter Tyser rgn->region[i].base = rgn->region[i + 1].base; 81*78acc472SPeter Tyser rgn->region[i].size = rgn->region[i + 1].size; 82*78acc472SPeter Tyser } 83*78acc472SPeter Tyser rgn->cnt--; 84*78acc472SPeter Tyser } 85*78acc472SPeter Tyser 86*78acc472SPeter Tyser /* Assumption: base addr of region 1 < base addr of region 2 */ 87*78acc472SPeter Tyser static void lmb_coalesce_regions(struct lmb_region *rgn, 88*78acc472SPeter Tyser unsigned long r1, unsigned long r2) 89*78acc472SPeter Tyser { 90*78acc472SPeter Tyser rgn->region[r1].size += rgn->region[r2].size; 91*78acc472SPeter Tyser lmb_remove_region(rgn, r2); 92*78acc472SPeter Tyser } 93*78acc472SPeter Tyser 94*78acc472SPeter Tyser void lmb_init(struct lmb *lmb) 95*78acc472SPeter Tyser { 96*78acc472SPeter Tyser /* Create a dummy zero size LMB which will get coalesced away later. 97*78acc472SPeter Tyser * This simplifies the lmb_add() code below... 98*78acc472SPeter Tyser */ 99*78acc472SPeter Tyser lmb->memory.region[0].base = 0; 100*78acc472SPeter Tyser lmb->memory.region[0].size = 0; 101*78acc472SPeter Tyser lmb->memory.cnt = 1; 102*78acc472SPeter Tyser lmb->memory.size = 0; 103*78acc472SPeter Tyser 104*78acc472SPeter Tyser /* Ditto. */ 105*78acc472SPeter Tyser lmb->reserved.region[0].base = 0; 106*78acc472SPeter Tyser lmb->reserved.region[0].size = 0; 107*78acc472SPeter Tyser lmb->reserved.cnt = 1; 108*78acc472SPeter Tyser lmb->reserved.size = 0; 109*78acc472SPeter Tyser } 110*78acc472SPeter Tyser 111*78acc472SPeter Tyser /* This routine called with relocation disabled. */ 112*78acc472SPeter Tyser static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t size) 113*78acc472SPeter Tyser { 114*78acc472SPeter Tyser unsigned long coalesced = 0; 115*78acc472SPeter Tyser long adjacent, i; 116*78acc472SPeter Tyser 117*78acc472SPeter Tyser if ((rgn->cnt == 1) && (rgn->region[0].size == 0)) { 118*78acc472SPeter Tyser rgn->region[0].base = base; 119*78acc472SPeter Tyser rgn->region[0].size = size; 120*78acc472SPeter Tyser return 0; 121*78acc472SPeter Tyser } 122*78acc472SPeter Tyser 123*78acc472SPeter Tyser /* First try and coalesce this LMB with another. */ 124*78acc472SPeter Tyser for (i=0; i < rgn->cnt; i++) { 125*78acc472SPeter Tyser phys_addr_t rgnbase = rgn->region[i].base; 126*78acc472SPeter Tyser phys_size_t rgnsize = rgn->region[i].size; 127*78acc472SPeter Tyser 128*78acc472SPeter Tyser if ((rgnbase == base) && (rgnsize == size)) 129*78acc472SPeter Tyser /* Already have this region, so we're done */ 130*78acc472SPeter Tyser return 0; 131*78acc472SPeter Tyser 132*78acc472SPeter Tyser adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); 133*78acc472SPeter Tyser if ( adjacent > 0 ) { 134*78acc472SPeter Tyser rgn->region[i].base -= size; 135*78acc472SPeter Tyser rgn->region[i].size += size; 136*78acc472SPeter Tyser coalesced++; 137*78acc472SPeter Tyser break; 138*78acc472SPeter Tyser } 139*78acc472SPeter Tyser else if ( adjacent < 0 ) { 140*78acc472SPeter Tyser rgn->region[i].size += size; 141*78acc472SPeter Tyser coalesced++; 142*78acc472SPeter Tyser break; 143*78acc472SPeter Tyser } 144*78acc472SPeter Tyser } 145*78acc472SPeter Tyser 146*78acc472SPeter Tyser if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) { 147*78acc472SPeter Tyser lmb_coalesce_regions(rgn, i, i+1); 148*78acc472SPeter Tyser coalesced++; 149*78acc472SPeter Tyser } 150*78acc472SPeter Tyser 151*78acc472SPeter Tyser if (coalesced) 152*78acc472SPeter Tyser return coalesced; 153*78acc472SPeter Tyser if (rgn->cnt >= MAX_LMB_REGIONS) 154*78acc472SPeter Tyser return -1; 155*78acc472SPeter Tyser 156*78acc472SPeter Tyser /* Couldn't coalesce the LMB, so add it to the sorted table. */ 157*78acc472SPeter Tyser for (i = rgn->cnt-1; i >= 0; i--) { 158*78acc472SPeter Tyser if (base < rgn->region[i].base) { 159*78acc472SPeter Tyser rgn->region[i+1].base = rgn->region[i].base; 160*78acc472SPeter Tyser rgn->region[i+1].size = rgn->region[i].size; 161*78acc472SPeter Tyser } else { 162*78acc472SPeter Tyser rgn->region[i+1].base = base; 163*78acc472SPeter Tyser rgn->region[i+1].size = size; 164*78acc472SPeter Tyser break; 165*78acc472SPeter Tyser } 166*78acc472SPeter Tyser } 167*78acc472SPeter Tyser 168*78acc472SPeter Tyser if (base < rgn->region[0].base) { 169*78acc472SPeter Tyser rgn->region[0].base = base; 170*78acc472SPeter Tyser rgn->region[0].size = size; 171*78acc472SPeter Tyser } 172*78acc472SPeter Tyser 173*78acc472SPeter Tyser rgn->cnt++; 174*78acc472SPeter Tyser 175*78acc472SPeter Tyser return 0; 176*78acc472SPeter Tyser } 177*78acc472SPeter Tyser 178*78acc472SPeter Tyser /* This routine may be called with relocation disabled. */ 179*78acc472SPeter Tyser long lmb_add(struct lmb *lmb, phys_addr_t base, phys_size_t size) 180*78acc472SPeter Tyser { 181*78acc472SPeter Tyser struct lmb_region *_rgn = &(lmb->memory); 182*78acc472SPeter Tyser 183*78acc472SPeter Tyser return lmb_add_region(_rgn, base, size); 184*78acc472SPeter Tyser } 185*78acc472SPeter Tyser 186*78acc472SPeter Tyser long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size) 187*78acc472SPeter Tyser { 188*78acc472SPeter Tyser struct lmb_region *rgn = &(lmb->reserved); 189*78acc472SPeter Tyser phys_addr_t rgnbegin, rgnend; 190*78acc472SPeter Tyser phys_addr_t end = base + size; 191*78acc472SPeter Tyser int i; 192*78acc472SPeter Tyser 193*78acc472SPeter Tyser rgnbegin = rgnend = 0; /* supress gcc warnings */ 194*78acc472SPeter Tyser 195*78acc472SPeter Tyser /* Find the region where (base, size) belongs to */ 196*78acc472SPeter Tyser for (i=0; i < rgn->cnt; i++) { 197*78acc472SPeter Tyser rgnbegin = rgn->region[i].base; 198*78acc472SPeter Tyser rgnend = rgnbegin + rgn->region[i].size; 199*78acc472SPeter Tyser 200*78acc472SPeter Tyser if ((rgnbegin <= base) && (end <= rgnend)) 201*78acc472SPeter Tyser break; 202*78acc472SPeter Tyser } 203*78acc472SPeter Tyser 204*78acc472SPeter Tyser /* Didn't find the region */ 205*78acc472SPeter Tyser if (i == rgn->cnt) 206*78acc472SPeter Tyser return -1; 207*78acc472SPeter Tyser 208*78acc472SPeter Tyser /* Check to see if we are removing entire region */ 209*78acc472SPeter Tyser if ((rgnbegin == base) && (rgnend == end)) { 210*78acc472SPeter Tyser lmb_remove_region(rgn, i); 211*78acc472SPeter Tyser return 0; 212*78acc472SPeter Tyser } 213*78acc472SPeter Tyser 214*78acc472SPeter Tyser /* Check to see if region is matching at the front */ 215*78acc472SPeter Tyser if (rgnbegin == base) { 216*78acc472SPeter Tyser rgn->region[i].base = end; 217*78acc472SPeter Tyser rgn->region[i].size -= size; 218*78acc472SPeter Tyser return 0; 219*78acc472SPeter Tyser } 220*78acc472SPeter Tyser 221*78acc472SPeter Tyser /* Check to see if the region is matching at the end */ 222*78acc472SPeter Tyser if (rgnend == end) { 223*78acc472SPeter Tyser rgn->region[i].size -= size; 224*78acc472SPeter Tyser return 0; 225*78acc472SPeter Tyser } 226*78acc472SPeter Tyser 227*78acc472SPeter Tyser /* 228*78acc472SPeter Tyser * We need to split the entry - adjust the current one to the 229*78acc472SPeter Tyser * beginging of the hole and add the region after hole. 230*78acc472SPeter Tyser */ 231*78acc472SPeter Tyser rgn->region[i].size = base - rgn->region[i].base; 232*78acc472SPeter Tyser return lmb_add_region(rgn, end, rgnend - end); 233*78acc472SPeter Tyser } 234*78acc472SPeter Tyser 235*78acc472SPeter Tyser long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size) 236*78acc472SPeter Tyser { 237*78acc472SPeter Tyser struct lmb_region *_rgn = &(lmb->reserved); 238*78acc472SPeter Tyser 239*78acc472SPeter Tyser return lmb_add_region(_rgn, base, size); 240*78acc472SPeter Tyser } 241*78acc472SPeter Tyser 242*78acc472SPeter Tyser long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base, 243*78acc472SPeter Tyser phys_size_t size) 244*78acc472SPeter Tyser { 245*78acc472SPeter Tyser unsigned long i; 246*78acc472SPeter Tyser 247*78acc472SPeter Tyser for (i=0; i < rgn->cnt; i++) { 248*78acc472SPeter Tyser phys_addr_t rgnbase = rgn->region[i].base; 249*78acc472SPeter Tyser phys_size_t rgnsize = rgn->region[i].size; 250*78acc472SPeter Tyser if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) { 251*78acc472SPeter Tyser break; 252*78acc472SPeter Tyser } 253*78acc472SPeter Tyser } 254*78acc472SPeter Tyser 255*78acc472SPeter Tyser return (i < rgn->cnt) ? i : -1; 256*78acc472SPeter Tyser } 257*78acc472SPeter Tyser 258*78acc472SPeter Tyser phys_addr_t lmb_alloc(struct lmb *lmb, phys_size_t size, ulong align) 259*78acc472SPeter Tyser { 260*78acc472SPeter Tyser return lmb_alloc_base(lmb, size, align, LMB_ALLOC_ANYWHERE); 261*78acc472SPeter Tyser } 262*78acc472SPeter Tyser 263*78acc472SPeter Tyser phys_addr_t lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phys_addr_t max_addr) 264*78acc472SPeter Tyser { 265*78acc472SPeter Tyser phys_addr_t alloc; 266*78acc472SPeter Tyser 267*78acc472SPeter Tyser alloc = __lmb_alloc_base(lmb, size, align, max_addr); 268*78acc472SPeter Tyser 269*78acc472SPeter Tyser if (alloc == 0) 270*78acc472SPeter Tyser printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n", 271*78acc472SPeter Tyser (ulong)size, (ulong)max_addr); 272*78acc472SPeter Tyser 273*78acc472SPeter Tyser return alloc; 274*78acc472SPeter Tyser } 275*78acc472SPeter Tyser 276*78acc472SPeter Tyser static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size) 277*78acc472SPeter Tyser { 278*78acc472SPeter Tyser return addr & ~(size - 1); 279*78acc472SPeter Tyser } 280*78acc472SPeter Tyser 281*78acc472SPeter Tyser static phys_addr_t lmb_align_up(phys_addr_t addr, ulong size) 282*78acc472SPeter Tyser { 283*78acc472SPeter Tyser return (addr + (size - 1)) & ~(size - 1); 284*78acc472SPeter Tyser } 285*78acc472SPeter Tyser 286*78acc472SPeter Tyser phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phys_addr_t max_addr) 287*78acc472SPeter Tyser { 288*78acc472SPeter Tyser long i, j; 289*78acc472SPeter Tyser phys_addr_t base = 0; 290*78acc472SPeter Tyser phys_addr_t res_base; 291*78acc472SPeter Tyser 292*78acc472SPeter Tyser for (i = lmb->memory.cnt-1; i >= 0; i--) { 293*78acc472SPeter Tyser phys_addr_t lmbbase = lmb->memory.region[i].base; 294*78acc472SPeter Tyser phys_size_t lmbsize = lmb->memory.region[i].size; 295*78acc472SPeter Tyser 296*78acc472SPeter Tyser if (lmbsize < size) 297*78acc472SPeter Tyser continue; 298*78acc472SPeter Tyser if (max_addr == LMB_ALLOC_ANYWHERE) 299*78acc472SPeter Tyser base = lmb_align_down(lmbbase + lmbsize - size, align); 300*78acc472SPeter Tyser else if (lmbbase < max_addr) { 301*78acc472SPeter Tyser base = min(lmbbase + lmbsize, max_addr); 302*78acc472SPeter Tyser base = lmb_align_down(base - size, align); 303*78acc472SPeter Tyser } else 304*78acc472SPeter Tyser continue; 305*78acc472SPeter Tyser 306*78acc472SPeter Tyser while (base && lmbbase <= base) { 307*78acc472SPeter Tyser j = lmb_overlaps_region(&lmb->reserved, base, size); 308*78acc472SPeter Tyser if (j < 0) { 309*78acc472SPeter Tyser /* This area isn't reserved, take it */ 310*78acc472SPeter Tyser if (lmb_add_region(&lmb->reserved, base, 311*78acc472SPeter Tyser lmb_align_up(size, 312*78acc472SPeter Tyser align)) < 0) 313*78acc472SPeter Tyser return 0; 314*78acc472SPeter Tyser return base; 315*78acc472SPeter Tyser } 316*78acc472SPeter Tyser res_base = lmb->reserved.region[j].base; 317*78acc472SPeter Tyser if (res_base < size) 318*78acc472SPeter Tyser break; 319*78acc472SPeter Tyser base = lmb_align_down(res_base - size, align); 320*78acc472SPeter Tyser } 321*78acc472SPeter Tyser } 322*78acc472SPeter Tyser return 0; 323*78acc472SPeter Tyser } 324*78acc472SPeter Tyser 325*78acc472SPeter Tyser int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr) 326*78acc472SPeter Tyser { 327*78acc472SPeter Tyser int i; 328*78acc472SPeter Tyser 329*78acc472SPeter Tyser for (i = 0; i < lmb->reserved.cnt; i++) { 330*78acc472SPeter Tyser phys_addr_t upper = lmb->reserved.region[i].base + 331*78acc472SPeter Tyser lmb->reserved.region[i].size - 1; 332*78acc472SPeter Tyser if ((addr >= lmb->reserved.region[i].base) && (addr <= upper)) 333*78acc472SPeter Tyser return 1; 334*78acc472SPeter Tyser } 335*78acc472SPeter Tyser return 0; 336*78acc472SPeter Tyser } 337*78acc472SPeter Tyser 338*78acc472SPeter Tyser void __board_lmb_reserve(struct lmb *lmb) 339*78acc472SPeter Tyser { 340*78acc472SPeter Tyser /* please define platform specific board_lmb_reserve() */ 341*78acc472SPeter Tyser } 342*78acc472SPeter Tyser void board_lmb_reserve(struct lmb *lmb) __attribute__((weak, alias("__board_lmb_reserve"))); 343*78acc472SPeter Tyser 344*78acc472SPeter Tyser void __arch_lmb_reserve(struct lmb *lmb) 345*78acc472SPeter Tyser { 346*78acc472SPeter Tyser /* please define platform specific arch_lmb_reserve() */ 347*78acc472SPeter Tyser } 348*78acc472SPeter Tyser void arch_lmb_reserve(struct lmb *lmb) __attribute__((weak, alias("__arch_lmb_reserve"))); 349