Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.21 182 lines 4.2 kB view raw
1/* 2 * AMD K8 NUMA support. 3 * Discover the memory map and associated nodes. 4 * 5 * This version reads it directly from the K8 northbridge. 6 * 7 * Copyright 2002,2003 Andi Kleen, SuSE Labs. 8 */ 9#include <linux/kernel.h> 10#include <linux/init.h> 11#include <linux/string.h> 12#include <linux/module.h> 13#include <linux/nodemask.h> 14#include <asm/io.h> 15#include <linux/pci_ids.h> 16#include <asm/types.h> 17#include <asm/mmzone.h> 18#include <asm/proto.h> 19#include <asm/e820.h> 20#include <asm/pci-direct.h> 21#include <asm/numa.h> 22 23static __init int find_northbridge(void) 24{ 25 int num; 26 27 for (num = 0; num < 32; num++) { 28 u32 header; 29 30 header = read_pci_config(0, num, 0, 0x00); 31 if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16))) 32 continue; 33 34 header = read_pci_config(0, num, 1, 0x00); 35 if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16))) 36 continue; 37 return num; 38 } 39 40 return -1; 41} 42 43int __init k8_scan_nodes(unsigned long start, unsigned long end) 44{ 45 unsigned long prevbase; 46 struct bootnode nodes[8]; 47 int nodeid, i, nb; 48 unsigned char nodeids[8]; 49 int found = 0; 50 u32 reg; 51 unsigned numnodes; 52 nodemask_t nodes_parsed; 53 unsigned dualcore = 0; 54 55 nodes_clear(nodes_parsed); 56 57 if (!early_pci_allowed()) 58 return -1; 59 60 nb = find_northbridge(); 61 if (nb < 0) 62 return nb; 63 64 printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); 65 66 reg = read_pci_config(0, nb, 0, 0x60); 67 numnodes = ((reg >> 4) & 0xF) + 1; 68 69 printk(KERN_INFO "Number of nodes %d\n", numnodes); 70 71 memset(&nodes,0,sizeof(nodes)); 72 prevbase = 0; 73 for (i = 0; i < 8; i++) { 74 unsigned long base,limit; 75 u32 nodeid; 76 77 /* Undefined before E stepping, but hopefully 0 */ 78 dualcore |= ((read_pci_config(0, nb, 3, 0xe8) >> 12) & 3) == 1; 79 base = read_pci_config(0, nb, 1, 0x40 + i*8); 80 limit = read_pci_config(0, nb, 1, 0x44 + i*8); 81 82 nodeid = limit & 7; 83 nodeids[i] = nodeid; 84 if ((base & 3) == 0) { 85 if (i < numnodes) 86 printk("Skipping disabled node %d\n", i); 87 continue; 88 } 89 if (nodeid >= numnodes) { 90 printk("Ignoring excess node %d (%lx:%lx)\n", nodeid, 91 base, limit); 92 continue; 93 } 94 95 if (!limit) { 96 printk(KERN_INFO "Skipping node entry %d (base %lx)\n", i, 97 base); 98 continue; 99 } 100 if ((base >> 8) & 3 || (limit >> 8) & 3) { 101 printk(KERN_ERR "Node %d using interleaving mode %lx/%lx\n", 102 nodeid, (base>>8)&3, (limit>>8) & 3); 103 return -1; 104 } 105 if (node_isset(nodeid, nodes_parsed)) { 106 printk(KERN_INFO "Node %d already present. Skipping\n", 107 nodeid); 108 continue; 109 } 110 111 limit >>= 16; 112 limit <<= 24; 113 limit |= (1<<24)-1; 114 limit++; 115 116 if (limit > end_pfn << PAGE_SHIFT) 117 limit = end_pfn << PAGE_SHIFT; 118 if (limit <= base) 119 continue; 120 121 base >>= 16; 122 base <<= 24; 123 124 if (base < start) 125 base = start; 126 if (limit > end) 127 limit = end; 128 if (limit == base) { 129 printk(KERN_ERR "Empty node %d\n", nodeid); 130 continue; 131 } 132 if (limit < base) { 133 printk(KERN_ERR "Node %d bogus settings %lx-%lx.\n", 134 nodeid, base, limit); 135 continue; 136 } 137 138 /* Could sort here, but pun for now. Should not happen anyroads. */ 139 if (prevbase > base) { 140 printk(KERN_ERR "Node map not sorted %lx,%lx\n", 141 prevbase,base); 142 return -1; 143 } 144 145 printk(KERN_INFO "Node %d MemBase %016lx Limit %016lx\n", 146 nodeid, base, limit); 147 148 found++; 149 150 nodes[nodeid].start = base; 151 nodes[nodeid].end = limit; 152 e820_register_active_regions(nodeid, 153 nodes[nodeid].start >> PAGE_SHIFT, 154 nodes[nodeid].end >> PAGE_SHIFT); 155 156 prevbase = base; 157 158 node_set(nodeid, nodes_parsed); 159 } 160 161 if (!found) 162 return -1; 163 164 memnode_shift = compute_hash_shift(nodes, 8); 165 if (memnode_shift < 0) { 166 printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n"); 167 return -1; 168 } 169 printk(KERN_INFO "Using node hash shift of %d\n", memnode_shift); 170 171 for (i = 0; i < 8; i++) { 172 if (nodes[i].start != nodes[i].end) { 173 nodeid = nodeids[i]; 174 apicid_to_node[nodeid << dualcore] = i; 175 apicid_to_node[(nodeid << dualcore) + dualcore] = i; 176 setup_node_bootmem(i, nodes[i].start, nodes[i].end); 177 } 178 } 179 180 numa_init_array(); 181 return 0; 182}