early_res.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /*
  2. * early_res, could be used to replace bootmem
  3. */
  4. #include <linux/kernel.h>
  5. #include <linux/types.h>
  6. #include <linux/init.h>
  7. #include <linux/bootmem.h>
  8. #include <linux/mm.h>
  9. #include <asm/early_res.h>
  10. /*
  11. * Early reserved memory areas.
  12. */
  13. /*
  14. * need to make sure this one is bigger enough before
  15. * find_fw_memmap_area could be used
  16. */
  17. #define MAX_EARLY_RES_X 32
  18. struct early_res {
  19. u64 start, end;
  20. char name[15];
  21. char overlap_ok;
  22. };
  23. static struct early_res early_res_x[MAX_EARLY_RES_X] __initdata;
  24. static int max_early_res __initdata = MAX_EARLY_RES_X;
  25. static struct early_res *early_res __initdata = &early_res_x[0];
  26. static int early_res_count __initdata;
  27. static int __init find_overlapped_early(u64 start, u64 end)
  28. {
  29. int i;
  30. struct early_res *r;
  31. for (i = 0; i < max_early_res && early_res[i].end; i++) {
  32. r = &early_res[i];
  33. if (end > r->start && start < r->end)
  34. break;
  35. }
  36. return i;
  37. }
  38. /*
  39. * Drop the i-th range from the early reservation map,
  40. * by copying any higher ranges down one over it, and
  41. * clearing what had been the last slot.
  42. */
  43. static void __init drop_range(int i)
  44. {
  45. int j;
  46. for (j = i + 1; j < max_early_res && early_res[j].end; j++)
  47. ;
  48. memmove(&early_res[i], &early_res[i + 1],
  49. (j - 1 - i) * sizeof(struct early_res));
  50. early_res[j - 1].end = 0;
  51. early_res_count--;
  52. }
  53. /*
  54. * Split any existing ranges that:
  55. * 1) are marked 'overlap_ok', and
  56. * 2) overlap with the stated range [start, end)
  57. * into whatever portion (if any) of the existing range is entirely
  58. * below or entirely above the stated range. Drop the portion
  59. * of the existing range that overlaps with the stated range,
  60. * which will allow the caller of this routine to then add that
  61. * stated range without conflicting with any existing range.
  62. */
  63. static void __init drop_overlaps_that_are_ok(u64 start, u64 end)
  64. {
  65. int i;
  66. struct early_res *r;
  67. u64 lower_start, lower_end;
  68. u64 upper_start, upper_end;
  69. char name[15];
  70. for (i = 0; i < max_early_res && early_res[i].end; i++) {
  71. r = &early_res[i];
  72. /* Continue past non-overlapping ranges */
  73. if (end <= r->start || start >= r->end)
  74. continue;
  75. /*
  76. * Leave non-ok overlaps as is; let caller
  77. * panic "Overlapping early reservations"
  78. * when it hits this overlap.
  79. */
  80. if (!r->overlap_ok)
  81. return;
  82. /*
  83. * We have an ok overlap. We will drop it from the early
  84. * reservation map, and add back in any non-overlapping
  85. * portions (lower or upper) as separate, overlap_ok,
  86. * non-overlapping ranges.
  87. */
  88. /* 1. Note any non-overlapping (lower or upper) ranges. */
  89. strncpy(name, r->name, sizeof(name) - 1);
  90. lower_start = lower_end = 0;
  91. upper_start = upper_end = 0;
  92. if (r->start < start) {
  93. lower_start = r->start;
  94. lower_end = start;
  95. }
  96. if (r->end > end) {
  97. upper_start = end;
  98. upper_end = r->end;
  99. }
  100. /* 2. Drop the original ok overlapping range */
  101. drop_range(i);
  102. i--; /* resume for-loop on copied down entry */
  103. /* 3. Add back in any non-overlapping ranges. */
  104. if (lower_end)
  105. reserve_early_overlap_ok(lower_start, lower_end, name);
  106. if (upper_end)
  107. reserve_early_overlap_ok(upper_start, upper_end, name);
  108. }
  109. }
  110. static void __init __reserve_early(u64 start, u64 end, char *name,
  111. int overlap_ok)
  112. {
  113. int i;
  114. struct early_res *r;
  115. i = find_overlapped_early(start, end);
  116. if (i >= max_early_res)
  117. panic("Too many early reservations");
  118. r = &early_res[i];
  119. if (r->end)
  120. panic("Overlapping early reservations "
  121. "%llx-%llx %s to %llx-%llx %s\n",
  122. start, end - 1, name ? name : "", r->start,
  123. r->end - 1, r->name);
  124. r->start = start;
  125. r->end = end;
  126. r->overlap_ok = overlap_ok;
  127. if (name)
  128. strncpy(r->name, name, sizeof(r->name) - 1);
  129. early_res_count++;
  130. }
  131. /*
  132. * A few early reservtations come here.
  133. *
  134. * The 'overlap_ok' in the name of this routine does -not- mean it
  135. * is ok for these reservations to overlap an earlier reservation.
  136. * Rather it means that it is ok for subsequent reservations to
  137. * overlap this one.
  138. *
  139. * Use this entry point to reserve early ranges when you are doing
  140. * so out of "Paranoia", reserving perhaps more memory than you need,
  141. * just in case, and don't mind a subsequent overlapping reservation
  142. * that is known to be needed.
  143. *
  144. * The drop_overlaps_that_are_ok() call here isn't really needed.
  145. * It would be needed if we had two colliding 'overlap_ok'
  146. * reservations, so that the second such would not panic on the
  147. * overlap with the first. We don't have any such as of this
  148. * writing, but might as well tolerate such if it happens in
  149. * the future.
  150. */
  151. void __init reserve_early_overlap_ok(u64 start, u64 end, char *name)
  152. {
  153. drop_overlaps_that_are_ok(start, end);
  154. __reserve_early(start, end, name, 1);
  155. }
  156. u64 __init __weak find_fw_memmap_area(u64 start, u64 end, u64 size, u64 align)
  157. {
  158. panic("should have find_fw_memmap_area defined with arch");
  159. return -1ULL;
  160. }
  161. static void __init __check_and_double_early_res(u64 ex_start, u64 ex_end)
  162. {
  163. u64 start, end, size, mem;
  164. struct early_res *new;
  165. /* do we have enough slots left ? */
  166. if ((max_early_res - early_res_count) > max(max_early_res/8, 2))
  167. return;
  168. /* double it */
  169. mem = -1ULL;
  170. size = sizeof(struct early_res) * max_early_res * 2;
  171. if (early_res == early_res_x)
  172. start = 0;
  173. else
  174. start = early_res[0].end;
  175. end = ex_start;
  176. if (start + size < end)
  177. mem = find_fw_memmap_area(start, end, size,
  178. sizeof(struct early_res));
  179. if (mem == -1ULL) {
  180. start = ex_end;
  181. end = max_pfn_mapped << PAGE_SHIFT;
  182. if (start + size < end)
  183. mem = find_fw_memmap_area(start, end, size,
  184. sizeof(struct early_res));
  185. }
  186. if (mem == -1ULL)
  187. panic("can not find more space for early_res array");
  188. new = __va(mem);
  189. /* save the first one for own */
  190. new[0].start = mem;
  191. new[0].end = mem + size;
  192. new[0].overlap_ok = 0;
  193. /* copy old to new */
  194. if (early_res == early_res_x) {
  195. memcpy(&new[1], &early_res[0],
  196. sizeof(struct early_res) * max_early_res);
  197. memset(&new[max_early_res+1], 0,
  198. sizeof(struct early_res) * (max_early_res - 1));
  199. early_res_count++;
  200. } else {
  201. memcpy(&new[1], &early_res[1],
  202. sizeof(struct early_res) * (max_early_res - 1));
  203. memset(&new[max_early_res], 0,
  204. sizeof(struct early_res) * max_early_res);
  205. }
  206. memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
  207. early_res = new;
  208. max_early_res *= 2;
  209. printk(KERN_DEBUG "early_res array is doubled to %d at [%llx - %llx]\n",
  210. max_early_res, mem, mem + size - 1);
  211. }
  212. /*
  213. * Most early reservations come here.
  214. *
  215. * We first have drop_overlaps_that_are_ok() drop any pre-existing
  216. * 'overlap_ok' ranges, so that we can then reserve this memory
  217. * range without risk of panic'ing on an overlapping overlap_ok
  218. * early reservation.
  219. */
  220. void __init reserve_early(u64 start, u64 end, char *name)
  221. {
  222. if (start >= end)
  223. return;
  224. __check_and_double_early_res(start, end);
  225. drop_overlaps_that_are_ok(start, end);
  226. __reserve_early(start, end, name, 0);
  227. }
  228. void __init reserve_early_without_check(u64 start, u64 end, char *name)
  229. {
  230. struct early_res *r;
  231. if (start >= end)
  232. return;
  233. __check_and_double_early_res(start, end);
  234. r = &early_res[early_res_count];
  235. r->start = start;
  236. r->end = end;
  237. r->overlap_ok = 0;
  238. if (name)
  239. strncpy(r->name, name, sizeof(r->name) - 1);
  240. early_res_count++;
  241. }
  242. void __init free_early(u64 start, u64 end)
  243. {
  244. struct early_res *r;
  245. int i;
  246. i = find_overlapped_early(start, end);
  247. r = &early_res[i];
  248. if (i >= max_early_res || r->end != end || r->start != start)
  249. panic("free_early on not reserved area: %llx-%llx!",
  250. start, end - 1);
  251. drop_range(i);
  252. }
  253. #ifdef CONFIG_NO_BOOTMEM
  254. static void __init subtract_early_res(struct range *range, int az)
  255. {
  256. int i, count;
  257. u64 final_start, final_end;
  258. int idx = 0;
  259. count = 0;
  260. for (i = 0; i < max_early_res && early_res[i].end; i++)
  261. count++;
  262. /* need to skip first one ?*/
  263. if (early_res != early_res_x)
  264. idx = 1;
  265. #define DEBUG_PRINT_EARLY_RES 1
  266. #if DEBUG_PRINT_EARLY_RES
  267. printk(KERN_INFO "Subtract (%d early reservations)\n", count);
  268. #endif
  269. for (i = idx; i < count; i++) {
  270. struct early_res *r = &early_res[i];
  271. #if DEBUG_PRINT_EARLY_RES
  272. printk(KERN_INFO " #%d [%010llx - %010llx] %15s\n", i,
  273. r->start, r->end, r->name);
  274. #endif
  275. final_start = PFN_DOWN(r->start);
  276. final_end = PFN_UP(r->end);
  277. if (final_start >= final_end)
  278. continue;
  279. subtract_range(range, az, final_start, final_end);
  280. }
  281. }
  282. int __init get_free_all_memory_range(struct range **rangep, int nodeid)
  283. {
  284. int i, count;
  285. u64 start = 0, end;
  286. u64 size;
  287. u64 mem;
  288. struct range *range;
  289. int nr_range;
  290. count = 0;
  291. for (i = 0; i < max_early_res && early_res[i].end; i++)
  292. count++;
  293. count *= 2;
  294. size = sizeof(struct range) * count;
  295. #ifdef MAX_DMA32_PFN
  296. if (max_pfn_mapped > MAX_DMA32_PFN)
  297. start = MAX_DMA32_PFN << PAGE_SHIFT;
  298. #endif
  299. end = max_pfn_mapped << PAGE_SHIFT;
  300. mem = find_fw_memmap_area(start, end, size, sizeof(struct range));
  301. if (mem == -1ULL)
  302. panic("can not find more space for range free");
  303. range = __va(mem);
  304. /* use early_node_map[] and early_res to get range array at first */
  305. memset(range, 0, size);
  306. nr_range = 0;
  307. /* need to go over early_node_map to find out good range for node */
  308. nr_range = add_from_early_node_map(range, count, nr_range, nodeid);
  309. #ifdef CONFIG_X86_32
  310. subtract_range(range, count, max_low_pfn, -1ULL);
  311. #endif
  312. subtract_early_res(range, count);
  313. nr_range = clean_sort_range(range, count);
  314. /* need to clear it ? */
  315. if (nodeid == MAX_NUMNODES) {
  316. memset(&early_res[0], 0,
  317. sizeof(struct early_res) * max_early_res);
  318. early_res = NULL;
  319. max_early_res = 0;
  320. }
  321. *rangep = range;
  322. return nr_range;
  323. }
  324. #else
  325. void __init early_res_to_bootmem(u64 start, u64 end)
  326. {
  327. int i, count;
  328. u64 final_start, final_end;
  329. int idx = 0;
  330. count = 0;
  331. for (i = 0; i < max_early_res && early_res[i].end; i++)
  332. count++;
  333. /* need to skip first one ?*/
  334. if (early_res != early_res_x)
  335. idx = 1;
  336. printk(KERN_INFO "(%d/%d early reservations) ==> bootmem [%010llx - %010llx]\n",
  337. count - idx, max_early_res, start, end);
  338. for (i = idx; i < count; i++) {
  339. struct early_res *r = &early_res[i];
  340. printk(KERN_INFO " #%d [%010llx - %010llx] %16s", i,
  341. r->start, r->end, r->name);
  342. final_start = max(start, r->start);
  343. final_end = min(end, r->end);
  344. if (final_start >= final_end) {
  345. printk(KERN_CONT "\n");
  346. continue;
  347. }
  348. printk(KERN_CONT " ==> [%010llx - %010llx]\n",
  349. final_start, final_end);
  350. reserve_bootmem_generic(final_start, final_end - final_start,
  351. BOOTMEM_DEFAULT);
  352. }
  353. /* clear them */
  354. memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
  355. early_res = NULL;
  356. max_early_res = 0;
  357. early_res_count = 0;
  358. }
  359. #endif
  360. /* Check for already reserved areas */
  361. static inline int __init bad_addr(u64 *addrp, u64 size, u64 align)
  362. {
  363. int i;
  364. u64 addr = *addrp;
  365. int changed = 0;
  366. struct early_res *r;
  367. again:
  368. i = find_overlapped_early(addr, addr + size);
  369. r = &early_res[i];
  370. if (i < max_early_res && r->end) {
  371. *addrp = addr = round_up(r->end, align);
  372. changed = 1;
  373. goto again;
  374. }
  375. return changed;
  376. }
  377. /* Check for already reserved areas */
  378. static inline int __init bad_addr_size(u64 *addrp, u64 *sizep, u64 align)
  379. {
  380. int i;
  381. u64 addr = *addrp, last;
  382. u64 size = *sizep;
  383. int changed = 0;
  384. again:
  385. last = addr + size;
  386. for (i = 0; i < max_early_res && early_res[i].end; i++) {
  387. struct early_res *r = &early_res[i];
  388. if (last > r->start && addr < r->start) {
  389. size = r->start - addr;
  390. changed = 1;
  391. goto again;
  392. }
  393. if (last > r->end && addr < r->end) {
  394. addr = round_up(r->end, align);
  395. size = last - addr;
  396. changed = 1;
  397. goto again;
  398. }
  399. if (last <= r->end && addr >= r->start) {
  400. (*sizep)++;
  401. return 0;
  402. }
  403. }
  404. if (changed) {
  405. *addrp = addr;
  406. *sizep = size;
  407. }
  408. return changed;
  409. }
  410. /*
  411. * Find a free area with specified alignment in a specific range.
  412. * only with the area.between start to end is active range from early_node_map
  413. * so they are good as RAM
  414. */
  415. u64 __init find_early_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
  416. u64 size, u64 align)
  417. {
  418. u64 addr, last;
  419. addr = round_up(ei_start, align);
  420. if (addr < start)
  421. addr = round_up(start, align);
  422. if (addr >= ei_last)
  423. goto out;
  424. while (bad_addr(&addr, size, align) && addr+size <= ei_last)
  425. ;
  426. last = addr + size;
  427. if (last > ei_last)
  428. goto out;
  429. if (last > end)
  430. goto out;
  431. return addr;
  432. out:
  433. return -1ULL;
  434. }
  435. u64 __init find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
  436. u64 *sizep, u64 align)
  437. {
  438. u64 addr, last;
  439. addr = round_up(ei_start, align);
  440. if (addr < start)
  441. addr = round_up(start, align);
  442. if (addr >= ei_last)
  443. goto out;
  444. *sizep = ei_last - addr;
  445. while (bad_addr_size(&addr, sizep, align) && addr + *sizep <= ei_last)
  446. ;
  447. last = addr + *sizep;
  448. if (last > ei_last)
  449. goto out;
  450. return addr;
  451. out:
  452. return -1ULL;
  453. }