ip27-memory.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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/init.h>
  14. #include <linux/kernel.h>
  15. #include <linux/mm.h>
  16. #include <linux/mmzone.h>
  17. #include <linux/module.h>
  18. #include <linux/nodemask.h>
  19. #include <linux/swap.h>
  20. #include <linux/bootmem.h>
  21. #include <linux/pfn.h>
  22. #include <linux/highmem.h>
  23. #include <asm/page.h>
  24. #include <asm/pgalloc.h>
  25. #include <asm/sections.h>
  26. #include <asm/sn/arch.h>
  27. #include <asm/sn/hub.h>
  28. #include <asm/sn/klconfig.h>
  29. #include <asm/sn/sn_private.h>
  30. #define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT)
  31. #define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT)
  32. struct node_data *__node_data[MAX_COMPACT_NODES];
  33. EXPORT_SYMBOL(__node_data);
  34. static int fine_mode;
  35. static int is_fine_dirmode(void)
  36. {
  37. return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
  38. >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
  39. }
  40. static hubreg_t get_region(cnodeid_t cnode)
  41. {
  42. if (fine_mode)
  43. return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
  44. else
  45. return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
  46. }
  47. static hubreg_t region_mask;
  48. static void gen_region_mask(hubreg_t *region_mask)
  49. {
  50. cnodeid_t cnode;
  51. (*region_mask) = 0;
  52. for_each_online_node(cnode) {
  53. (*region_mask) |= 1ULL << get_region(cnode);
  54. }
  55. }
  56. #define rou_rflag rou_flags
  57. static int router_distance;
  58. static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
  59. {
  60. klrou_t *router;
  61. lboard_t *brd;
  62. int port;
  63. if (router_a->rou_rflag == 1)
  64. return;
  65. if (depth >= router_distance)
  66. return;
  67. router_a->rou_rflag = 1;
  68. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  69. if (router_a->rou_port[port].port_nasid == INVALID_NASID)
  70. continue;
  71. brd = (lboard_t *)NODE_OFFSET_TO_K0(
  72. router_a->rou_port[port].port_nasid,
  73. router_a->rou_port[port].port_offset);
  74. if (brd->brd_type == KLTYPE_ROUTER) {
  75. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  76. if (router == router_b) {
  77. if (depth < router_distance)
  78. router_distance = depth;
  79. }
  80. else
  81. router_recurse(router, router_b, depth + 1);
  82. }
  83. }
  84. router_a->rou_rflag = 0;
  85. }
  86. unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
  87. static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
  88. {
  89. klrou_t *router, *router_a = NULL, *router_b = NULL;
  90. lboard_t *brd, *dest_brd;
  91. cnodeid_t cnode;
  92. nasid_t nasid;
  93. int port;
  94. /* Figure out which routers nodes in question are connected to */
  95. for_each_online_node(cnode) {
  96. nasid = COMPACT_TO_NASID_NODEID(cnode);
  97. if (nasid == -1) continue;
  98. brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
  99. KLTYPE_ROUTER);
  100. if (!brd)
  101. continue;
  102. do {
  103. if (brd->brd_flags & DUPLICATE_BOARD)
  104. continue;
  105. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  106. router->rou_rflag = 0;
  107. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  108. if (router->rou_port[port].port_nasid == INVALID_NASID)
  109. continue;
  110. dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
  111. router->rou_port[port].port_nasid,
  112. router->rou_port[port].port_offset);
  113. if (dest_brd->brd_type == KLTYPE_IP27) {
  114. if (dest_brd->brd_nasid == nasid_a)
  115. router_a = router;
  116. if (dest_brd->brd_nasid == nasid_b)
  117. router_b = router;
  118. }
  119. }
  120. } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
  121. }
  122. if (router_a == NULL) {
  123. printk("node_distance: router_a NULL\n");
  124. return -1;
  125. }
  126. if (router_b == NULL) {
  127. printk("node_distance: router_b NULL\n");
  128. return -1;
  129. }
  130. if (nasid_a == nasid_b)
  131. return 0;
  132. if (router_a == router_b)
  133. return 1;
  134. router_distance = 100;
  135. router_recurse(router_a, router_b, 2);
  136. return router_distance;
  137. }
  138. static void __init init_topology_matrix(void)
  139. {
  140. nasid_t nasid, nasid2;
  141. cnodeid_t row, col;
  142. for (row = 0; row < MAX_COMPACT_NODES; row++)
  143. for (col = 0; col < MAX_COMPACT_NODES; col++)
  144. __node_distances[row][col] = -1;
  145. for_each_online_node(row) {
  146. nasid = COMPACT_TO_NASID_NODEID(row);
  147. for_each_online_node(col) {
  148. nasid2 = COMPACT_TO_NASID_NODEID(col);
  149. __node_distances[row][col] =
  150. compute_node_distance(nasid, nasid2);
  151. }
  152. }
  153. }
  154. static void __init dump_topology(void)
  155. {
  156. nasid_t nasid;
  157. cnodeid_t cnode;
  158. lboard_t *brd, *dest_brd;
  159. int port;
  160. int router_num = 0;
  161. klrou_t *router;
  162. cnodeid_t row, col;
  163. printk("************** Topology ********************\n");
  164. printk(" ");
  165. for_each_online_node(col)
  166. printk("%02d ", col);
  167. printk("\n");
  168. for_each_online_node(row) {
  169. printk("%02d ", row);
  170. for_each_online_node(col)
  171. printk("%2d ", node_distance(row, col));
  172. printk("\n");
  173. }
  174. for_each_online_node(cnode) {
  175. nasid = COMPACT_TO_NASID_NODEID(cnode);
  176. if (nasid == -1) continue;
  177. brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
  178. KLTYPE_ROUTER);
  179. if (!brd)
  180. continue;
  181. do {
  182. if (brd->brd_flags & DUPLICATE_BOARD)
  183. continue;
  184. printk("Router %d:", router_num);
  185. router_num++;
  186. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  187. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  188. if (router->rou_port[port].port_nasid == INVALID_NASID)
  189. continue;
  190. dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
  191. router->rou_port[port].port_nasid,
  192. router->rou_port[port].port_offset);
  193. if (dest_brd->brd_type == KLTYPE_IP27)
  194. printk(" %d", dest_brd->brd_nasid);
  195. if (dest_brd->brd_type == KLTYPE_ROUTER)
  196. printk(" r");
  197. }
  198. printk("\n");
  199. } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
  200. }
  201. }
  202. static pfn_t __init slot_getbasepfn(cnodeid_t cnode, int slot)
  203. {
  204. nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
  205. return ((pfn_t)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT);
  206. }
  207. static pfn_t __init slot_psize_compute(cnodeid_t node, int slot)
  208. {
  209. nasid_t nasid;
  210. lboard_t *brd;
  211. klmembnk_t *banks;
  212. unsigned long size;
  213. nasid = COMPACT_TO_NASID_NODEID(node);
  214. /* Find the node board */
  215. brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
  216. if (!brd)
  217. return 0;
  218. /* Get the memory bank structure */
  219. banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK);
  220. if (!banks)
  221. return 0;
  222. /* Size in _Megabytes_ */
  223. size = (unsigned long)banks->membnk_bnksz[slot/4];
  224. /* hack for 128 dimm banks */
  225. if (size <= 128) {
  226. if (slot % 4 == 0) {
  227. size <<= 20; /* size in bytes */
  228. return(size >> PAGE_SHIFT);
  229. } else
  230. return 0;
  231. } else {
  232. size /= 4;
  233. size <<= 20;
  234. return size >> PAGE_SHIFT;
  235. }
  236. }
  237. static void __init mlreset(void)
  238. {
  239. int i;
  240. master_nasid = get_nasid();
  241. fine_mode = is_fine_dirmode();
  242. /*
  243. * Probe for all CPUs - this creates the cpumask and sets up the
  244. * mapping tables. We need to do this as early as possible.
  245. */
  246. #ifdef CONFIG_SMP
  247. cpu_node_probe();
  248. #endif
  249. init_topology_matrix();
  250. dump_topology();
  251. gen_region_mask(&region_mask);
  252. setup_replication_mask();
  253. /*
  254. * Set all nodes' calias sizes to 8k
  255. */
  256. for_each_online_node(i) {
  257. nasid_t nasid;
  258. nasid = COMPACT_TO_NASID_NODEID(i);
  259. /*
  260. * Always have node 0 in the region mask, otherwise
  261. * CALIAS accesses get exceptions since the hub
  262. * thinks it is a node 0 address.
  263. */
  264. REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
  265. #ifdef CONFIG_REPLICATE_EXHANDLERS
  266. REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
  267. #else
  268. REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
  269. #endif
  270. #ifdef LATER
  271. /*
  272. * Set up all hubs to have a big window pointing at
  273. * widget 0. Memory mode, widget 0, offset 0
  274. */
  275. REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
  276. ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
  277. (0 << IIO_ITTE_WIDGET_SHIFT)));
  278. #endif
  279. }
  280. }
  281. static void __init szmem(void)
  282. {
  283. pfn_t slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */
  284. int slot;
  285. cnodeid_t node;
  286. num_physpages = 0;
  287. for_each_online_node(node) {
  288. nodebytes = 0;
  289. for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
  290. slot_psize = slot_psize_compute(node, slot);
  291. if (slot == 0)
  292. slot0sz = slot_psize;
  293. /*
  294. * We need to refine the hack when we have replicated
  295. * kernel text.
  296. */
  297. nodebytes += (1LL << SLOT_SHIFT);
  298. if (!slot_psize)
  299. continue;
  300. if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
  301. (slot0sz << PAGE_SHIFT)) {
  302. printk("Ignoring slot %d onwards on node %d\n",
  303. slot, node);
  304. slot = MAX_MEM_SLOTS;
  305. continue;
  306. }
  307. num_physpages += slot_psize;
  308. add_active_range(node, slot_getbasepfn(node, slot),
  309. slot_getbasepfn(node, slot) + slot_psize);
  310. }
  311. }
  312. }
  313. static void __init node_mem_init(cnodeid_t node)
  314. {
  315. pfn_t slot_firstpfn = slot_getbasepfn(node, 0);
  316. pfn_t slot_freepfn = node_getfirstfree(node);
  317. unsigned long bootmap_size;
  318. pfn_t start_pfn, end_pfn;
  319. get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
  320. /*
  321. * Allocate the node data structures on the node first.
  322. */
  323. __node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
  324. NODE_DATA(node)->bdata = &bootmem_node_data[node];
  325. NODE_DATA(node)->node_start_pfn = start_pfn;
  326. NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
  327. cpus_clear(hub_data(node)->h_cpus);
  328. slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
  329. sizeof(struct hub_data));
  330. bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
  331. start_pfn, end_pfn);
  332. free_bootmem_with_active_regions(node, end_pfn);
  333. reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
  334. ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size,
  335. BOOTMEM_DEFAULT);
  336. sparse_memory_present_with_active_regions(node);
  337. }
  338. /*
  339. * A node with nothing. We use it to avoid any special casing in
  340. * cpumask_of_node
  341. */
  342. static struct node_data null_node = {
  343. .hub = {
  344. .h_cpus = CPU_MASK_NONE
  345. }
  346. };
  347. /*
  348. * Currently, the intranode memory hole support assumes that each slot
  349. * contains at least 32 MBytes of memory. We assume all bootmem data
  350. * fits on the first slot.
  351. */
  352. void __init prom_meminit(void)
  353. {
  354. cnodeid_t node;
  355. mlreset();
  356. szmem();
  357. for (node = 0; node < MAX_COMPACT_NODES; node++) {
  358. if (node_online(node)) {
  359. node_mem_init(node);
  360. continue;
  361. }
  362. __node_data[node] = &null_node;
  363. }
  364. }
  365. void __init prom_free_prom_memory(void)
  366. {
  367. /* We got nothing to free here ... */
  368. }
  369. extern unsigned long setup_zero_pages(void);
  370. void __init paging_init(void)
  371. {
  372. unsigned long zones_size[MAX_NR_ZONES] = {0, };
  373. unsigned node;
  374. pagetable_init();
  375. for_each_online_node(node) {
  376. pfn_t start_pfn, end_pfn;
  377. get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
  378. if (end_pfn > max_low_pfn)
  379. max_low_pfn = end_pfn;
  380. }
  381. zones_size[ZONE_NORMAL] = max_low_pfn;
  382. free_area_init_nodes(zones_size);
  383. }
  384. void __init mem_init(void)
  385. {
  386. unsigned long codesize, datasize, initsize, tmp;
  387. unsigned node;
  388. high_memory = (void *) __va(num_physpages << PAGE_SHIFT);
  389. for_each_online_node(node) {
  390. /*
  391. * This will free up the bootmem, ie, slot 0 memory.
  392. */
  393. totalram_pages += free_all_bootmem_node(NODE_DATA(node));
  394. }
  395. totalram_pages -= setup_zero_pages(); /* This comes from node 0 */
  396. codesize = (unsigned long) &_etext - (unsigned long) &_text;
  397. datasize = (unsigned long) &_edata - (unsigned long) &_etext;
  398. initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
  399. tmp = nr_free_pages();
  400. printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
  401. "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
  402. tmp << (PAGE_SHIFT-10),
  403. num_physpages << (PAGE_SHIFT-10),
  404. codesize >> 10,
  405. (num_physpages - tmp) << (PAGE_SHIFT-10),
  406. datasize >> 10,
  407. initsize >> 10,
  408. totalhigh_pages << (PAGE_SHIFT-10));
  409. }