1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/init.h> 3 #include <linux/pci.h> 4 #include <linux/topology.h> 5 #include <linux/cpu.h> 6 #include <linux/range.h> 7 8 #include <asm/amd_nb.h> 9 #include <asm/pci_x86.h> 10 11 #include <asm/pci-direct.h> 12 13 #include "bus_numa.h" 14 15 #define AMD_NB_F0_NODE_ID 0x60 16 #define AMD_NB_F0_UNIT_ID 0x64 17 #define AMD_NB_F1_CONFIG_MAP_REG 0xe0 18 19 #define RANGE_NUM 16 20 #define AMD_NB_F1_CONFIG_MAP_RANGES 4 21 22 struct amd_hostbridge { 23 u32 bus; 24 u32 slot; 25 u32 device; 26 }; 27 28 /* 29 * IMPORTANT NOTE: 30 * hb_probes[] and early_root_info_init() is in maintenance mode. 31 * It only supports K8, Fam10h, Fam11h, and Fam15h_00h-0fh . 32 * Future processor will rely on information in ACPI. 33 */ 34 static struct amd_hostbridge hb_probes[] __initdata = { 35 { 0, 0x18, 0x1100 }, /* K8 */ 36 { 0, 0x18, 0x1200 }, /* Family10h */ 37 { 0xff, 0, 0x1200 }, /* Family10h */ 38 { 0, 0x18, 0x1300 }, /* Family11h */ 39 { 0, 0x18, 0x1600 }, /* Family15h */ 40 }; 41 42 static struct pci_root_info __init *find_pci_root_info(int node, int link) 43 { 44 struct pci_root_info *info; 45 46 /* find the position */ 47 list_for_each_entry(info, &pci_root_infos, list) 48 if (info->node == node && info->link == link) 49 return info; 50 51 return NULL; 52 } 53 54 static inline resource_size_t cap_resource(u64 val) 55 { 56 if (val > RESOURCE_SIZE_MAX) 57 return RESOURCE_SIZE_MAX; 58 59 return val; 60 } 61 62 /** 63 * early_root_info_init() 64 * called before pcibios_scan_root and pci_scan_bus 65 * fills the mp_bus_to_cpumask array based according 66 * to the LDT Bus Number Registers found in the northbridge. 67 */ 68 static int __init early_root_info_init(void) 69 { 70 int i; 71 unsigned bus; 72 unsigned slot; 73 int node; 74 int link; 75 int def_node; 76 int def_link; 77 struct pci_root_info *info; 78 u32 reg; 79 u64 start; 80 u64 end; 81 struct range range[RANGE_NUM]; 82 u64 val; 83 u32 address; 84 bool found; 85 struct resource fam10h_mmconf_res, *fam10h_mmconf; 86 u64 fam10h_mmconf_start; 87 u64 fam10h_mmconf_end; 88 89 if (!early_pci_allowed()) 90 return -1; 91 92 found = false; 93 for (i = 0; i < ARRAY_SIZE(hb_probes); i++) { 94 u32 id; 95 u16 device; 96 u16 vendor; 97 98 bus = hb_probes[i].bus; 99 slot = hb_probes[i].slot; 100 id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID); 101 vendor = id & 0xffff; 102 device = (id>>16) & 0xffff; 103 104 if (vendor != PCI_VENDOR_ID_AMD && 105 vendor != PCI_VENDOR_ID_HYGON) 106 continue; 107 108 if (hb_probes[i].device == device) { 109 found = true; 110 break; 111 } 112 } 113 114 if (!found) 115 return 0; 116 117 /* 118 * We should learn topology and routing information from _PXM and 119 * _CRS methods in the ACPI namespace. We extract node numbers 120 * here to work around BIOSes that don't supply _PXM. 121 */ 122 for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) { 123 int min_bus; 124 int max_bus; 125 reg = read_pci_config(bus, slot, 1, 126 AMD_NB_F1_CONFIG_MAP_REG + (i << 2)); 127 128 /* Check if that register is enabled for bus range */ 129 if ((reg & 7) != 3) 130 continue; 131 132 min_bus = (reg >> 16) & 0xff; 133 max_bus = (reg >> 24) & 0xff; 134 node = (reg >> 4) & 0x07; 135 link = (reg >> 8) & 0x03; 136 137 alloc_pci_root_info(min_bus, max_bus, node, link); 138 } 139 140 /* 141 * The following code extracts routing information for use on old 142 * systems where Linux doesn't automatically use host bridge _CRS 143 * methods (or when the user specifies "pci=nocrs"). 144 * 145 * We only do this through Fam11h, because _CRS should be enough on 146 * newer systems. 147 */ 148 if (boot_cpu_data.x86 > 0x11) 149 return 0; 150 151 /* get the default node and link for left over res */ 152 reg = read_pci_config(bus, slot, 0, AMD_NB_F0_NODE_ID); 153 def_node = (reg >> 8) & 0x07; 154 reg = read_pci_config(bus, slot, 0, AMD_NB_F0_UNIT_ID); 155 def_link = (reg >> 8) & 0x03; 156 157 memset(range, 0, sizeof(range)); 158 add_range(range, RANGE_NUM, 0, 0, 0xffff + 1); 159 /* io port resource */ 160 for (i = 0; i < 4; i++) { 161 reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); 162 if (!(reg & 3)) 163 continue; 164 165 start = reg & 0xfff000; 166 reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3)); 167 node = reg & 0x07; 168 link = (reg >> 4) & 0x03; 169 end = (reg & 0xfff000) | 0xfff; 170 171 info = find_pci_root_info(node, link); 172 if (!info) 173 continue; /* not found */ 174 175 printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", 176 node, link, start, end); 177 178 /* kernel only handle 16 bit only */ 179 if (end > 0xffff) 180 end = 0xffff; 181 update_res(info, start, end, IORESOURCE_IO, 1); 182 subtract_range(range, RANGE_NUM, start, end + 1); 183 } 184 /* add left over io port range to def node/link, [0, 0xffff] */ 185 /* find the position */ 186 info = find_pci_root_info(def_node, def_link); 187 if (info) { 188 for (i = 0; i < RANGE_NUM; i++) { 189 if (!range[i].end) 190 continue; 191 192 update_res(info, range[i].start, range[i].end - 1, 193 IORESOURCE_IO, 1); 194 } 195 } 196 197 memset(range, 0, sizeof(range)); 198 /* 0xfd00000000-0xffffffffff for HT */ 199 end = cap_resource((0xfdULL<<32) - 1); 200 end++; 201 add_range(range, RANGE_NUM, 0, 0, end); 202 203 /* need to take out [0, TOM) for RAM*/ 204 address = MSR_K8_TOP_MEM1; 205 rdmsrl(address, val); 206 end = (val & 0xffffff800000ULL); 207 printk(KERN_INFO "TOM: %016llx aka %lldM\n", end, end>>20); 208 if (end < (1ULL<<32)) 209 subtract_range(range, RANGE_NUM, 0, end); 210 211 /* get mmconfig */ 212 fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res); 213 /* need to take out mmconf range */ 214 if (fam10h_mmconf) { 215 printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf); 216 fam10h_mmconf_start = fam10h_mmconf->start; 217 fam10h_mmconf_end = fam10h_mmconf->end; 218 subtract_range(range, RANGE_NUM, fam10h_mmconf_start, 219 fam10h_mmconf_end + 1); 220 } else { 221 fam10h_mmconf_start = 0; 222 fam10h_mmconf_end = 0; 223 } 224 225 /* mmio resource */ 226 for (i = 0; i < 8; i++) { 227 reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3)); 228 if (!(reg & 3)) 229 continue; 230 231 start = reg & 0xffffff00; /* 39:16 on 31:8*/ 232 start <<= 8; 233 reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3)); 234 node = reg & 0x07; 235 link = (reg >> 4) & 0x03; 236 end = (reg & 0xffffff00); 237 end <<= 8; 238 end |= 0xffff; 239 240 info = find_pci_root_info(node, link); 241 242 if (!info) 243 continue; 244 245 printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", 246 node, link, start, end); 247 /* 248 * some sick allocation would have range overlap with fam10h 249 * mmconf range, so need to update start and end. 250 */ 251 if (fam10h_mmconf_end) { 252 int changed = 0; 253 u64 endx = 0; 254 if (start >= fam10h_mmconf_start && 255 start <= fam10h_mmconf_end) { 256 start = fam10h_mmconf_end + 1; 257 changed = 1; 258 } 259 260 if (end >= fam10h_mmconf_start && 261 end <= fam10h_mmconf_end) { 262 end = fam10h_mmconf_start - 1; 263 changed = 1; 264 } 265 266 if (start < fam10h_mmconf_start && 267 end > fam10h_mmconf_end) { 268 /* we got a hole */ 269 endx = fam10h_mmconf_start - 1; 270 update_res(info, start, endx, IORESOURCE_MEM, 0); 271 subtract_range(range, RANGE_NUM, start, 272 endx + 1); 273 printk(KERN_CONT " ==> [%llx, %llx]", start, endx); 274 start = fam10h_mmconf_end + 1; 275 changed = 1; 276 } 277 if (changed) { 278 if (start <= end) { 279 printk(KERN_CONT " %s [%llx, %llx]", endx ? "and" : "==>", start, end); 280 } else { 281 printk(KERN_CONT "%s\n", endx?"":" ==> none"); 282 continue; 283 } 284 } 285 } 286 287 update_res(info, cap_resource(start), cap_resource(end), 288 IORESOURCE_MEM, 1); 289 subtract_range(range, RANGE_NUM, start, end + 1); 290 printk(KERN_CONT "\n"); 291 } 292 293 /* need to take out [4G, TOM2) for RAM*/ 294 /* SYS_CFG */ 295 address = MSR_AMD64_SYSCFG; 296 rdmsrl(address, val); 297 /* TOP_MEM2 is enabled? */ 298 if (val & (1<<21)) { 299 /* TOP_MEM2 */ 300 address = MSR_K8_TOP_MEM2; 301 rdmsrl(address, val); 302 end = (val & 0xffffff800000ULL); 303 printk(KERN_INFO "TOM2: %016llx aka %lldM\n", end, end>>20); 304 subtract_range(range, RANGE_NUM, 1ULL<<32, end); 305 } 306 307 /* 308 * add left over mmio range to def node/link ? 309 * that is tricky, just record range in from start_min to 4G 310 */ 311 info = find_pci_root_info(def_node, def_link); 312 if (info) { 313 for (i = 0; i < RANGE_NUM; i++) { 314 if (!range[i].end) 315 continue; 316 317 update_res(info, cap_resource(range[i].start), 318 cap_resource(range[i].end - 1), 319 IORESOURCE_MEM, 1); 320 } 321 } 322 323 list_for_each_entry(info, &pci_root_infos, list) { 324 int busnum; 325 struct pci_root_res *root_res; 326 327 busnum = info->busn.start; 328 printk(KERN_DEBUG "bus: %pR on node %x link %x\n", 329 &info->busn, info->node, info->link); 330 list_for_each_entry(root_res, &info->resources, list) 331 printk(KERN_DEBUG "bus: %02x %pR\n", 332 busnum, &root_res->res); 333 } 334 335 return 0; 336 } 337 338 #define ENABLE_CF8_EXT_CFG (1ULL << 46) 339 340 static int amd_bus_cpu_online(unsigned int cpu) 341 { 342 u64 reg; 343 344 rdmsrl(MSR_AMD64_NB_CFG, reg); 345 if (!(reg & ENABLE_CF8_EXT_CFG)) { 346 reg |= ENABLE_CF8_EXT_CFG; 347 wrmsrl(MSR_AMD64_NB_CFG, reg); 348 } 349 return 0; 350 } 351 352 static void __init pci_enable_pci_io_ecs(void) 353 { 354 #ifdef CONFIG_AMD_NB 355 unsigned int i, n; 356 357 for (n = i = 0; !n && amd_nb_bus_dev_ranges[i].dev_limit; ++i) { 358 u8 bus = amd_nb_bus_dev_ranges[i].bus; 359 u8 slot = amd_nb_bus_dev_ranges[i].dev_base; 360 u8 limit = amd_nb_bus_dev_ranges[i].dev_limit; 361 362 for (; slot < limit; ++slot) { 363 u32 val = read_pci_config(bus, slot, 3, 0); 364 365 if (!early_is_amd_nb(val)) 366 continue; 367 368 val = read_pci_config(bus, slot, 3, 0x8c); 369 if (!(val & (ENABLE_CF8_EXT_CFG >> 32))) { 370 val |= ENABLE_CF8_EXT_CFG >> 32; 371 write_pci_config(bus, slot, 3, 0x8c, val); 372 } 373 ++n; 374 } 375 } 376 #endif 377 } 378 379 static int __init pci_io_ecs_init(void) 380 { 381 int ret; 382 383 /* assume all cpus from fam10h have IO ECS */ 384 if (boot_cpu_data.x86 < 0x10) 385 return 0; 386 387 /* Try the PCI method first. */ 388 if (early_pci_allowed()) 389 pci_enable_pci_io_ecs(); 390 391 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "pci/amd_bus:online", 392 amd_bus_cpu_online, NULL); 393 WARN_ON(ret < 0); 394 395 pci_probe |= PCI_HAS_IO_ECS; 396 397 return 0; 398 } 399 400 static int __init amd_postcore_init(void) 401 { 402 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && 403 boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) 404 return 0; 405 406 early_root_info_init(); 407 pci_io_ecs_init(); 408 409 return 0; 410 } 411 412 postcore_initcall(amd_postcore_init); 413
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.