ip27-memory.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2000, 05 by Ralf Baechle (ralf@linux-mips.org)
  7. * Copyright (C) 2000 by Silicon Graphics, Inc.
  8. * Copyright (C) 2004 by Christoph Hellwig
  9. *
  10. * On SGI IP27 the ARC memory configuration data is completly bogus but
  11. * alternate easier to use mechanisms are available.
  12. */
  13. #include <linux/config.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/mm.h>
  17. #include <linux/mmzone.h>
  18. #include <linux/module.h>
  19. #include <linux/nodemask.h>
  20. #include <linux/swap.h>
  21. #include <linux/bootmem.h>
  22. #include <asm/page.h>
  23. #include <asm/sections.h>
  24. #include <asm/sn/arch.h>
  25. #include <asm/sn/hub.h>
  26. #include <asm/sn/klconfig.h>
  27. #include <asm/sn/sn_private.h>
  28. #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
  29. #define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT)
  30. #define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT)
  31. #define SLOT_IGNORED 0xffff
  32. static short __initdata slot_lastfilled_cache[MAX_COMPACT_NODES];
  33. static unsigned short __initdata slot_psize_cache[MAX_COMPACT_NODES][MAX_MEM_SLOTS];
  34. static struct bootmem_data __initdata plat_node_bdata[MAX_COMPACT_NODES];
  35. struct node_data *__node_data[MAX_COMPACT_NODES];
  36. EXPORT_SYMBOL(__node_data);
  37. static int fine_mode;
  38. static int is_fine_dirmode(void)
  39. {
  40. return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
  41. >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
  42. }
  43. static hubreg_t get_region(cnodeid_t cnode)
  44. {
  45. if (fine_mode)
  46. return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
  47. else
  48. return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
  49. }
  50. static hubreg_t region_mask;
  51. static void gen_region_mask(hubreg_t *region_mask)
  52. {
  53. cnodeid_t cnode;
  54. (*region_mask) = 0;
  55. for_each_online_node(cnode) {
  56. (*region_mask) |= 1ULL << get_region(cnode);
  57. }
  58. }
  59. #define rou_rflag rou_flags
  60. static int router_distance;
  61. static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
  62. {
  63. klrou_t *router;
  64. lboard_t *brd;
  65. int port;
  66. if (router_a->rou_rflag == 1)
  67. return;
  68. if (depth >= router_distance)
  69. return;
  70. router_a->rou_rflag = 1;
  71. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  72. if (router_a->rou_port[port].port_nasid == INVALID_NASID)
  73. continue;
  74. brd = (lboard_t *)NODE_OFFSET_TO_K0(
  75. router_a->rou_port[port].port_nasid,
  76. router_a->rou_port[port].port_offset);
  77. if (brd->brd_type == KLTYPE_ROUTER) {
  78. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  79. if (router == router_b) {
  80. if (depth < router_distance)
  81. router_distance = depth;
  82. }
  83. else
  84. router_recurse(router, router_b, depth + 1);
  85. }
  86. }
  87. router_a->rou_rflag = 0;
  88. }
  89. unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
  90. static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
  91. {
  92. klrou_t *router, *router_a = NULL, *router_b = NULL;
  93. lboard_t *brd, *dest_brd;
  94. cnodeid_t cnode;
  95. nasid_t nasid;
  96. int port;
  97. /* Figure out which routers nodes in question are connected to */
  98. for_each_online_node(cnode) {
  99. nasid = COMPACT_TO_NASID_NODEID(cnode);
  100. if (nasid == -1) continue;
  101. brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
  102. KLTYPE_ROUTER);
  103. if (!brd)
  104. continue;
  105. do {
  106. if (brd->brd_flags & DUPLICATE_BOARD)
  107. continue;
  108. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  109. router->rou_rflag = 0;
  110. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  111. if (router->rou_port[port].port_nasid == INVALID_NASID)
  112. continue;
  113. dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
  114. router->rou_port[port].port_nasid,
  115. router->rou_port[port].port_offset);
  116. if (dest_brd->brd_type == KLTYPE_IP27) {
  117. if (dest_brd->brd_nasid == nasid_a)
  118. router_a = router;
  119. if (dest_brd->brd_nasid == nasid_b)
  120. router_b = router;
  121. }
  122. }
  123. } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
  124. }
  125. if (router_a == NULL) {
  126. printk("node_distance: router_a NULL\n");
  127. return -1;
  128. }
  129. if (router_b == NULL) {
  130. printk("node_distance: router_b NULL\n");
  131. return -1;
  132. }
  133. if (nasid_a == nasid_b)
  134. return 0;
  135. if (router_a == router_b)
  136. return 1;
  137. router_distance = 100;
  138. router_recurse(router_a, router_b, 2);
  139. return router_distance;
  140. }
  141. static void __init init_topology_matrix(void)
  142. {
  143. nasid_t nasid, nasid2;
  144. cnodeid_t row, col;
  145. for (row = 0; row < MAX_COMPACT_NODES; row++)
  146. for (col = 0; col < MAX_COMPACT_NODES; col++)
  147. __node_distances[row][col] = -1;
  148. for_each_online_node(row) {
  149. nasid = COMPACT_TO_NASID_NODEID(row);
  150. for_each_online_node(col) {
  151. nasid2 = COMPACT_TO_NASID_NODEID(col);
  152. __node_distances[row][col] =
  153. compute_node_distance(nasid, nasid2);
  154. }
  155. }
  156. }
  157. static void __init dump_topology(void)
  158. {
  159. nasid_t nasid;
  160. cnodeid_t cnode;
  161. lboard_t *brd, *dest_brd;
  162. int port;
  163. int router_num = 0;
  164. klrou_t *router;
  165. cnodeid_t row, col;
  166. printk("************** Topology ********************\n");
  167. printk(" ");
  168. for_each_online_node(col)
  169. printk("%02d ", col);
  170. printk("\n");
  171. for_each_online_node(row) {
  172. printk("%02d ", row);
  173. for_each_online_node(col)
  174. printk("%2d ", node_distance(row, col));
  175. printk("\n");
  176. }
  177. for_each_online_node(cnode) {
  178. nasid = COMPACT_TO_NASID_NODEID(cnode);
  179. if (nasid == -1) continue;
  180. brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
  181. KLTYPE_ROUTER);
  182. if (!brd)
  183. continue;
  184. do {
  185. if (brd->brd_flags & DUPLICATE_BOARD)
  186. continue;
  187. printk("Router %d:", router_num);
  188. router_num++;
  189. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  190. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  191. if (router->rou_port[port].port_nasid == INVALID_NASID)
  192. continue;
  193. dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
  194. router->rou_port[port].port_nasid,
  195. router->rou_port[port].port_offset);
  196. if (dest_brd->brd_type == KLTYPE_IP27)
  197. printk(" %d", dest_brd->brd_nasid);
  198. if (dest_brd->brd_type == KLTYPE_ROUTER)
  199. printk(" r");
  200. }
  201. printk("\n");
  202. } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
  203. }
  204. }
  205. static pfn_t __init slot_getbasepfn(cnodeid_t cnode, int slot)
  206. {
  207. nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
  208. return ((pfn_t)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT);
  209. }
  210. /*
  211. * Return the number of pages of memory provided by the given slot
  212. * on the specified node.
  213. */
  214. static pfn_t __init slot_getsize(cnodeid_t node, int slot)
  215. {
  216. return (pfn_t) slot_psize_cache[node][slot];
  217. }
  218. /*
  219. * Return highest slot filled
  220. */
  221. static int __init node_getlastslot(cnodeid_t node)
  222. {
  223. return (int) slot_lastfilled_cache[node];
  224. }
  225. /*
  226. * Return the pfn of the last free page of memory on a node.
  227. */
  228. static pfn_t __init node_getmaxclick(cnodeid_t node)
  229. {
  230. pfn_t slot_psize;
  231. int slot;
  232. /*
  233. * Start at the top slot. When we find a slot with memory in it,
  234. * that's the winner.
  235. */
  236. for (slot = (MAX_MEM_SLOTS - 1); slot >= 0; slot--) {
  237. if ((slot_psize = slot_getsize(node, slot))) {
  238. if (slot_psize == SLOT_IGNORED)
  239. continue;
  240. /* Return the basepfn + the slot size, minus 1. */
  241. return slot_getbasepfn(node, slot) + slot_psize - 1;
  242. }
  243. }
  244. /*
  245. * If there's no memory on the node, return 0. This is likely
  246. * to cause problems.
  247. */
  248. return 0;
  249. }
  250. static pfn_t __init slot_psize_compute(cnodeid_t node, int slot)
  251. {
  252. nasid_t nasid;
  253. lboard_t *brd;
  254. klmembnk_t *banks;
  255. unsigned long size;
  256. nasid = COMPACT_TO_NASID_NODEID(node);
  257. /* Find the node board */
  258. brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
  259. if (!brd)
  260. return 0;
  261. /* Get the memory bank structure */
  262. banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK);
  263. if (!banks)
  264. return 0;
  265. /* Size in _Megabytes_ */
  266. size = (unsigned long)banks->membnk_bnksz[slot/4];
  267. /* hack for 128 dimm banks */
  268. if (size <= 128) {
  269. if (slot % 4 == 0) {
  270. size <<= 20; /* size in bytes */
  271. return(size >> PAGE_SHIFT);
  272. } else
  273. return 0;
  274. } else {
  275. size /= 4;
  276. size <<= 20;
  277. return size >> PAGE_SHIFT;
  278. }
  279. }
  280. static void __init mlreset(void)
  281. {
  282. int i;
  283. master_nasid = get_nasid();
  284. fine_mode = is_fine_dirmode();
  285. /*
  286. * Probe for all CPUs - this creates the cpumask and sets up the
  287. * mapping tables. We need to do this as early as possible.
  288. */
  289. #ifdef CONFIG_SMP
  290. cpu_node_probe();
  291. #endif
  292. init_topology_matrix();
  293. dump_topology();
  294. gen_region_mask(&region_mask);
  295. setup_replication_mask();
  296. /*
  297. * Set all nodes' calias sizes to 8k
  298. */
  299. for_each_online_node(i) {
  300. nasid_t nasid;
  301. nasid = COMPACT_TO_NASID_NODEID(i);
  302. /*
  303. * Always have node 0 in the region mask, otherwise
  304. * CALIAS accesses get exceptions since the hub
  305. * thinks it is a node 0 address.
  306. */
  307. REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
  308. #ifdef CONFIG_REPLICATE_EXHANDLERS
  309. REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
  310. #else
  311. REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
  312. #endif
  313. #ifdef LATER
  314. /*
  315. * Set up all hubs to have a big window pointing at
  316. * widget 0. Memory mode, widget 0, offset 0
  317. */
  318. REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
  319. ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
  320. (0 << IIO_ITTE_WIDGET_SHIFT)));
  321. #endif
  322. }
  323. }
  324. static void __init szmem(void)
  325. {
  326. pfn_t slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */
  327. int slot, ignore;
  328. cnodeid_t node;
  329. num_physpages = 0;
  330. for_each_online_node(node) {
  331. ignore = nodebytes = 0;
  332. for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
  333. slot_psize = slot_psize_compute(node, slot);
  334. if (slot == 0)
  335. slot0sz = slot_psize;
  336. /*
  337. * We need to refine the hack when we have replicated
  338. * kernel text.
  339. */
  340. nodebytes += (1LL << SLOT_SHIFT);
  341. if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
  342. (slot0sz << PAGE_SHIFT))
  343. ignore = 1;
  344. if (ignore && slot_psize) {
  345. printk("Ignoring slot %d onwards on node %d\n",
  346. slot, node);
  347. slot_psize_cache[node][slot] = SLOT_IGNORED;
  348. slot = MAX_MEM_SLOTS;
  349. continue;
  350. }
  351. num_physpages += slot_psize;
  352. slot_psize_cache[node][slot] =
  353. (unsigned short) slot_psize;
  354. if (slot_psize)
  355. slot_lastfilled_cache[node] = slot;
  356. }
  357. }
  358. }
  359. static void __init node_mem_init(cnodeid_t node)
  360. {
  361. pfn_t slot_firstpfn = slot_getbasepfn(node, 0);
  362. pfn_t slot_lastpfn = slot_firstpfn + slot_getsize(node, 0);
  363. pfn_t slot_freepfn = node_getfirstfree(node);
  364. struct pglist_data *pd;
  365. unsigned long bootmap_size;
  366. /*
  367. * Allocate the node data structures on the node first.
  368. */
  369. __node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
  370. pd = NODE_DATA(node);
  371. pd->bdata = &plat_node_bdata[node];
  372. cpus_clear(hub_data(node)->h_cpus);
  373. slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
  374. sizeof(struct hub_data));
  375. bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
  376. slot_firstpfn, slot_lastpfn);
  377. free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
  378. (slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
  379. reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
  380. ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
  381. }
  382. /*
  383. * A node with nothing. We use it to avoid any special casing in
  384. * node_to_cpumask
  385. */
  386. static struct node_data null_node = {
  387. .hub = {
  388. .h_cpus = CPU_MASK_NONE
  389. }
  390. };
  391. /*
  392. * Currently, the intranode memory hole support assumes that each slot
  393. * contains at least 32 MBytes of memory. We assume all bootmem data
  394. * fits on the first slot.
  395. */
  396. void __init prom_meminit(void)
  397. {
  398. cnodeid_t node;
  399. mlreset();
  400. szmem();
  401. for (node = 0; node < MAX_COMPACT_NODES; node++) {
  402. if (node_online(node)) {
  403. node_mem_init(node);
  404. continue;
  405. }
  406. __node_data[node] = &null_node;
  407. }
  408. }
  409. unsigned long __init prom_free_prom_memory(void)
  410. {
  411. /* We got nothing to free here ... */
  412. return 0;
  413. }
  414. extern void pagetable_init(void);
  415. extern unsigned long setup_zero_pages(void);
  416. void __init paging_init(void)
  417. {
  418. unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
  419. unsigned node;
  420. pagetable_init();
  421. for_each_online_node(node) {
  422. pfn_t start_pfn = slot_getbasepfn(node, 0);
  423. pfn_t end_pfn = node_getmaxclick(node) + 1;
  424. zones_size[ZONE_DMA] = end_pfn - start_pfn;
  425. free_area_init_node(node, NODE_DATA(node),
  426. zones_size, start_pfn, NULL);
  427. if (end_pfn > max_low_pfn)
  428. max_low_pfn = end_pfn;
  429. }
  430. }
  431. void __init mem_init(void)
  432. {
  433. unsigned long codesize, datasize, initsize, tmp;
  434. unsigned node;
  435. high_memory = (void *) __va(num_physpages << PAGE_SHIFT);
  436. for_each_online_node(node) {
  437. unsigned slot, numslots;
  438. struct page *end, *p;
  439. /*
  440. * This will free up the bootmem, ie, slot 0 memory.
  441. */
  442. totalram_pages += free_all_bootmem_node(NODE_DATA(node));
  443. /*
  444. * We need to manually do the other slots.
  445. */
  446. numslots = node_getlastslot(node);
  447. for (slot = 1; slot <= numslots; slot++) {
  448. p = nid_page_nr(node, slot_getbasepfn(node, slot) -
  449. slot_getbasepfn(node, 0));
  450. /*
  451. * Free valid memory in current slot.
  452. */
  453. for (end = p + slot_getsize(node, slot); p < end; p++) {
  454. /* if (!page_is_ram(pgnr)) continue; */
  455. /* commented out until page_is_ram works */
  456. ClearPageReserved(p);
  457. set_page_count(p, 1);
  458. __free_page(p);
  459. totalram_pages++;
  460. }
  461. }
  462. }
  463. totalram_pages -= setup_zero_pages(); /* This comes from node 0 */
  464. codesize = (unsigned long) &_etext - (unsigned long) &_text;
  465. datasize = (unsigned long) &_edata - (unsigned long) &_etext;
  466. initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
  467. tmp = nr_free_pages();
  468. printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
  469. "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
  470. tmp << (PAGE_SHIFT-10),
  471. num_physpages << (PAGE_SHIFT-10),
  472. codesize >> 10,
  473. (num_physpages - tmp) << (PAGE_SHIFT-10),
  474. datasize >> 10,
  475. initsize >> 10,
  476. (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
  477. }