k8topology.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:4k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* 
  2.  * AMD K8 NUMA support.
  3.  * Discover the memory map and associated nodes.
  4.  * 
  5.  * Doesn't use the ACPI SRAT table because it has a questionable license.
  6.  * Instead the northbridge registers are read directly. 
  7.  * 
  8.  * Copyright 2002 Andi Kleen, SuSE Labs.
  9.  * $Id: k8topology.c,v 1.3 2002/09/12 12:51:39 ak Exp $
  10.  */
  11. #include <linux/kernel.h>
  12. #include <linux/init.h>
  13. #include <linux/string.h>
  14. #include <linux/module.h>
  15. #include <asm/io.h>
  16. #include <linux/pci_ids.h>
  17. #include <asm/types.h>
  18. #include <asm/mmzone.h>
  19. #include <asm/proto.h>
  20. #include <asm/e820.h>
  21. #include <asm/pci-direct.h>
  22. int memnode_shift;
  23. u8  memnodemap[NODEMAPSIZE];
  24. static int find_northbridge(void)
  25. {
  26. int num; 
  27. for (num = 0; num < 32; num++) { 
  28. u32 header;
  29. header = read_pci_config(0, num, 0, 0x00);  
  30. if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)))
  31. continue; 
  32. header = read_pci_config(0, num, 1, 0x00); 
  33. if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)))
  34. continue;
  35. return num; 
  36. return -1; 
  37. }
  38. #define MAXNODE 8 
  39. #define NODEMASK 0xff
  40. struct node { 
  41. u64 start,end; 
  42. };
  43. #define for_all_nodes(n) 
  44. for (n=0; n<MAXNODE;n++) if (nodes[n].start!=nodes[n].end)
  45. static int compute_hash_shift(struct node *nodes, int numnodes, u64 maxmem)
  46. {
  47. int i; 
  48. int shift = 24;
  49. u64 addr;
  50. /* When in doubt use brute force. */
  51. while (shift < 48) { 
  52. memset(memnodemap,0xff,sizeof(*memnodemap) * NODEMAPSIZE); 
  53. for_all_nodes (i) { 
  54. for (addr = nodes[i].start; 
  55.      addr < nodes[i].end; 
  56.      addr += (1UL << shift)) {
  57. if (memnodemap[addr >> shift] != 0xff) { 
  58. printk("node %d shift %d addr %Lx conflict %dn", 
  59.        i, shift, addr, memnodemap[addr>>shift]);
  60. goto next; 
  61. memnodemap[addr >> shift] = i; 
  62. return shift; 
  63. next:
  64. shift++; 
  65. memset(memnodemap,0,sizeof(*memnodemap) * NODEMAPSIZE); 
  66. return -1; 
  67. }
  68. extern unsigned long nodes_present;
  69. extern unsigned long end_pfn;
  70. int __init k8_scan_nodes(unsigned long start, unsigned long end)
  71. unsigned long prevbase;
  72. struct node nodes[MAXNODE];
  73. int nodeid, numnodes, maxnode, i, nb; 
  74. nb = find_northbridge(); 
  75. if (nb < 0) 
  76. return nb;
  77. printk(KERN_INFO "Scanning NUMA topology in Northbridge %dn", nb); 
  78. numnodes = (read_pci_config(0, nb, 0, 0x60 ) >> 4) & 3; 
  79. memset(&nodes,0,sizeof(nodes)); 
  80. prevbase = 0;
  81. maxnode = -1; 
  82. for (i = 0; i < MAXNODE; i++) { 
  83. unsigned long base,limit; 
  84. base = read_pci_config(0, nb, 1, 0x40 + i*8);
  85. limit = read_pci_config(0, nb, 1, 0x44 + i*8);
  86. nodeid = limit & 3; 
  87. if (!limit) { 
  88. printk(KERN_INFO "Skipping node entry %d (base %lx)n", i,        base);
  89. continue;
  90. }
  91. if ((base >> 8) & 3 || (limit >> 8) & 3) {
  92. printk(KERN_ERR "Node %d using interleaving mode %lx/%lxn", 
  93.        nodeid, (base>>8)&3, (limit>>8) & 3); 
  94. return -1; 
  95. }
  96. if (nodeid > maxnode) 
  97. maxnode = nodeid; 
  98. if ((1UL << nodeid) & nodes_present) { 
  99. printk("Node %d already present. Skippingn", nodeid);
  100. continue;
  101. }
  102. limit >>= 16; 
  103. limit <<= 24; 
  104. if (limit > end_pfn << PAGE_SHIFT) 
  105. limit = end_pfn << PAGE_SHIFT; 
  106. if (limit <= base) { 
  107. printk(KERN_INFO "Node %d beyond memory mapn", nodeid);
  108. continue; 
  109. base >>= 16;
  110. base <<= 24; 
  111. if (base < start) 
  112. base = start; 
  113. if (limit > end) 
  114. limit = end; 
  115. if (limit == base) 
  116. continue; 
  117. if (limit < base) { 
  118. printk(KERN_INFO"Node %d bogus settings %lx-%lx. Ignored.n",
  119.        nodeid, base, limit);         
  120. continue; 
  121. /* Could sort here, but pun for now. Should not happen anyroads. */
  122. if (prevbase > base) { 
  123. printk(KERN_INFO "Node map not sorted %lx,%lxn",
  124.        prevbase,base);
  125. return -1;
  126. }
  127. printk(KERN_INFO "Node %d MemBase %016lx Limit %016lxn", 
  128.        nodeid, base, limit); 
  129. nodes[nodeid].start = base; 
  130. nodes[nodeid].end = limit;
  131. prevbase = base;
  132. if (maxnode <= 0)
  133. return -1; 
  134. memnode_shift = compute_hash_shift(nodes,maxnode,end);
  135. if (memnode_shift < 0) { 
  136. printk(KERN_ERR "No NUMA node hash function found. Contact maintainern"); 
  137. return -1; 
  138. printk(KERN_INFO "Using node hash shift of %dn", memnode_shift); 
  139. for_all_nodes(i) { 
  140. setup_node_bootmem(i, nodes[i].start, nodes[i].end); 
  141. return 0;