ip27-memory.c 9.4 KB

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