ip27-memory.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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 ([email protected])
  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 completely bogus but
  11. * alternate easier to use mechanisms are available.
  12. */
  13. #include <linux/init.h>
  14. #include <linux/kernel.h>
  15. #include <linux/memblock.h>
  16. #include <linux/mm.h>
  17. #include <linux/mmzone.h>
  18. #include <linux/export.h>
  19. #include <linux/nodemask.h>
  20. #include <linux/swap.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/agent.h>
  28. #include <asm/sn/klconfig.h>
  29. #include "ip27-common.h"
  30. #define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT)
  31. #define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT)
  32. struct node_data *__node_data[MAX_NUMNODES];
  33. EXPORT_SYMBOL(__node_data);
  34. static u64 gen_region_mask(void)
  35. {
  36. int region_shift;
  37. u64 region_mask;
  38. nasid_t nasid;
  39. region_shift = get_region_shift();
  40. region_mask = 0;
  41. for_each_online_node(nasid)
  42. region_mask |= BIT_ULL(nasid >> region_shift);
  43. return region_mask;
  44. }
  45. #define rou_rflag rou_flags
  46. static int router_distance;
  47. static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
  48. {
  49. klrou_t *router;
  50. lboard_t *brd;
  51. int port;
  52. if (router_a->rou_rflag == 1)
  53. return;
  54. if (depth >= router_distance)
  55. return;
  56. router_a->rou_rflag = 1;
  57. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  58. if (router_a->rou_port[port].port_nasid == INVALID_NASID)
  59. continue;
  60. brd = (lboard_t *)NODE_OFFSET_TO_K0(
  61. router_a->rou_port[port].port_nasid,
  62. router_a->rou_port[port].port_offset);
  63. if (brd->brd_type == KLTYPE_ROUTER) {
  64. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  65. if (router == router_b) {
  66. if (depth < router_distance)
  67. router_distance = depth;
  68. }
  69. else
  70. router_recurse(router, router_b, depth + 1);
  71. }
  72. }
  73. router_a->rou_rflag = 0;
  74. }
  75. unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
  76. EXPORT_SYMBOL(__node_distances);
  77. static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
  78. {
  79. klrou_t *router, *router_a = NULL, *router_b = NULL;
  80. lboard_t *brd, *dest_brd;
  81. nasid_t nasid;
  82. int port;
  83. /* Figure out which routers nodes in question are connected to */
  84. for_each_online_node(nasid) {
  85. brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
  86. KLTYPE_ROUTER);
  87. if (!brd)
  88. continue;
  89. do {
  90. if (brd->brd_flags & DUPLICATE_BOARD)
  91. continue;
  92. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  93. router->rou_rflag = 0;
  94. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  95. if (router->rou_port[port].port_nasid == INVALID_NASID)
  96. continue;
  97. dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
  98. router->rou_port[port].port_nasid,
  99. router->rou_port[port].port_offset);
  100. if (dest_brd->brd_type == KLTYPE_IP27) {
  101. if (dest_brd->brd_nasid == nasid_a)
  102. router_a = router;
  103. if (dest_brd->brd_nasid == nasid_b)
  104. router_b = router;
  105. }
  106. }
  107. } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
  108. }
  109. if (nasid_a == nasid_b)
  110. return LOCAL_DISTANCE;
  111. if (router_a == router_b)
  112. return LOCAL_DISTANCE + 1;
  113. if (router_a == NULL) {
  114. pr_info("node_distance: router_a NULL\n");
  115. return 255;
  116. }
  117. if (router_b == NULL) {
  118. pr_info("node_distance: router_b NULL\n");
  119. return 255;
  120. }
  121. router_distance = 100;
  122. router_recurse(router_a, router_b, 2);
  123. return LOCAL_DISTANCE + router_distance;
  124. }
  125. static void __init init_topology_matrix(void)
  126. {
  127. nasid_t row, col;
  128. for (row = 0; row < MAX_NUMNODES; row++)
  129. for (col = 0; col < MAX_NUMNODES; col++)
  130. __node_distances[row][col] = -1;
  131. for_each_online_node(row) {
  132. for_each_online_node(col) {
  133. __node_distances[row][col] =
  134. compute_node_distance(row, col);
  135. }
  136. }
  137. }
  138. static void __init dump_topology(void)
  139. {
  140. nasid_t nasid;
  141. lboard_t *brd, *dest_brd;
  142. int port;
  143. int router_num = 0;
  144. klrou_t *router;
  145. nasid_t row, col;
  146. pr_info("************** Topology ********************\n");
  147. pr_info(" ");
  148. for_each_online_node(col)
  149. pr_cont("%02d ", col);
  150. pr_cont("\n");
  151. for_each_online_node(row) {
  152. pr_info("%02d ", row);
  153. for_each_online_node(col)
  154. pr_cont("%2d ", node_distance(row, col));
  155. pr_cont("\n");
  156. }
  157. for_each_online_node(nasid) {
  158. brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
  159. KLTYPE_ROUTER);
  160. if (!brd)
  161. continue;
  162. do {
  163. if (brd->brd_flags & DUPLICATE_BOARD)
  164. continue;
  165. pr_cont("Router %d:", router_num);
  166. router_num++;
  167. router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
  168. for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
  169. if (router->rou_port[port].port_nasid == INVALID_NASID)
  170. continue;
  171. dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
  172. router->rou_port[port].port_nasid,
  173. router->rou_port[port].port_offset);
  174. if (dest_brd->brd_type == KLTYPE_IP27)
  175. pr_cont(" %d", dest_brd->brd_nasid);
  176. if (dest_brd->brd_type == KLTYPE_ROUTER)
  177. pr_cont(" r");
  178. }
  179. pr_cont("\n");
  180. } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
  181. }
  182. }
  183. static unsigned long __init slot_getbasepfn(nasid_t nasid, int slot)
  184. {
  185. return ((unsigned long)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT);
  186. }
  187. static unsigned long __init slot_psize_compute(nasid_t nasid, int slot)
  188. {
  189. lboard_t *brd;
  190. klmembnk_t *banks;
  191. unsigned long size;
  192. /* Find the node board */
  193. brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
  194. if (!brd)
  195. return 0;
  196. /* Get the memory bank structure */
  197. banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK);
  198. if (!banks)
  199. return 0;
  200. /* Size in _Megabytes_ */
  201. size = (unsigned long)banks->membnk_bnksz[slot/4];
  202. /* hack for 128 dimm banks */
  203. if (size <= 128) {
  204. if (slot % 4 == 0) {
  205. size <<= 20; /* size in bytes */
  206. return size >> PAGE_SHIFT;
  207. } else
  208. return 0;
  209. } else {
  210. size /= 4;
  211. size <<= 20;
  212. return size >> PAGE_SHIFT;
  213. }
  214. }
  215. static void __init mlreset(void)
  216. {
  217. u64 region_mask;
  218. nasid_t nasid;
  219. master_nasid = get_nasid();
  220. /*
  221. * Probe for all CPUs - this creates the cpumask and sets up the
  222. * mapping tables. We need to do this as early as possible.
  223. */
  224. #ifdef CONFIG_SMP
  225. cpu_node_probe();
  226. #endif
  227. init_topology_matrix();
  228. dump_topology();
  229. region_mask = gen_region_mask();
  230. setup_replication_mask();
  231. /*
  232. * Set all nodes' calias sizes to 8k
  233. */
  234. for_each_online_node(nasid) {
  235. /*
  236. * Always have node 0 in the region mask, otherwise
  237. * CALIAS accesses get exceptions since the hub
  238. * thinks it is a node 0 address.
  239. */
  240. REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
  241. REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
  242. #ifdef LATER
  243. /*
  244. * Set up all hubs to have a big window pointing at
  245. * widget 0. Memory mode, widget 0, offset 0
  246. */
  247. REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
  248. ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
  249. (0 << IIO_ITTE_WIDGET_SHIFT)));
  250. #endif
  251. }
  252. }
  253. static void __init szmem(void)
  254. {
  255. unsigned long slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */
  256. int slot;
  257. nasid_t node;
  258. for_each_online_node(node) {
  259. nodebytes = 0;
  260. for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
  261. slot_psize = slot_psize_compute(node, slot);
  262. if (slot == 0)
  263. slot0sz = slot_psize;
  264. /*
  265. * We need to refine the hack when we have replicated
  266. * kernel text.
  267. */
  268. nodebytes += (1LL << SLOT_SHIFT);
  269. if (!slot_psize)
  270. continue;
  271. if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
  272. (slot0sz << PAGE_SHIFT)) {
  273. pr_info("Ignoring slot %d onwards on node %d\n",
  274. slot, node);
  275. slot = MAX_MEM_SLOTS;
  276. continue;
  277. }
  278. memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)),
  279. PFN_PHYS(slot_psize), node,
  280. MEMBLOCK_NONE);
  281. }
  282. }
  283. }
  284. static void __init node_mem_init(nasid_t node)
  285. {
  286. unsigned long slot_firstpfn = slot_getbasepfn(node, 0);
  287. unsigned long slot_freepfn = node_getfirstfree(node);
  288. unsigned long start_pfn, end_pfn;
  289. get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
  290. /*
  291. * Allocate the node data structures on the node first.
  292. */
  293. __node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
  294. memset(__node_data[node], 0, PAGE_SIZE);
  295. NODE_DATA(node)->node_start_pfn = start_pfn;
  296. NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
  297. cpumask_clear(&hub_data(node)->h_cpus);
  298. slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
  299. sizeof(struct hub_data));
  300. memblock_reserve(slot_firstpfn << PAGE_SHIFT,
  301. ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT));
  302. }
  303. /*
  304. * A node with nothing. We use it to avoid any special casing in
  305. * cpumask_of_node
  306. */
  307. static struct node_data null_node = {
  308. .hub = {
  309. .h_cpus = CPU_MASK_NONE
  310. }
  311. };
  312. /*
  313. * Currently, the intranode memory hole support assumes that each slot
  314. * contains at least 32 MBytes of memory. We assume all bootmem data
  315. * fits on the first slot.
  316. */
  317. void __init prom_meminit(void)
  318. {
  319. nasid_t node;
  320. mlreset();
  321. szmem();
  322. max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
  323. for (node = 0; node < MAX_NUMNODES; node++) {
  324. if (node_online(node)) {
  325. node_mem_init(node);
  326. continue;
  327. }
  328. __node_data[node] = &null_node;
  329. }
  330. }
  331. extern void setup_zero_pages(void);
  332. void __init paging_init(void)
  333. {
  334. unsigned long zones_size[MAX_NR_ZONES] = {0, };
  335. pagetable_init();
  336. zones_size[ZONE_NORMAL] = max_low_pfn;
  337. free_area_init(zones_size);
  338. }
  339. void __init mem_init(void)
  340. {
  341. high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
  342. memblock_free_all();
  343. setup_zero_pages(); /* This comes from node 0 */
  344. }
  345. pg_data_t * __init arch_alloc_nodedata(int nid)
  346. {
  347. return memblock_alloc(sizeof(pg_data_t), SMP_CACHE_BYTES);
  348. }
  349. void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
  350. {
  351. __node_data[nid] = (struct node_data *)pgdat;
  352. }