1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
224bfdca7SRobert Richter #include <linux/init.h>
324bfdca7SRobert Richter #include <linux/pci.h>
4d199a048SRobert Richter #include <linux/topology.h>
591ede005SRobert Richter #include <linux/cpu.h>
627811d8cSYinghai Lu #include <linux/range.h>
727811d8cSYinghai Lu
824d9b70bSJan Beulich #include <asm/amd_nb.h>
982487711SJaswinder Singh Rajput #include <asm/pci_x86.h>
103a27dd1cSRobert Richter
1124bfdca7SRobert Richter #include <asm/pci-direct.h>
1224bfdca7SRobert Richter
1399935a7aSYinghai Lu #include "bus_numa.h"
1499935a7aSYinghai Lu
159e7f7231SSuravee Suthikulpanit #define AMD_NB_F0_NODE_ID 0x60
169e7f7231SSuravee Suthikulpanit #define AMD_NB_F0_UNIT_ID 0x64
179e7f7231SSuravee Suthikulpanit #define AMD_NB_F1_CONFIG_MAP_REG 0xe0
1824bfdca7SRobert Richter
199e7f7231SSuravee Suthikulpanit #define RANGE_NUM 16
209e7f7231SSuravee Suthikulpanit #define AMD_NB_F1_CONFIG_MAP_RANGES 4
219e7f7231SSuravee Suthikulpanit
229e7f7231SSuravee Suthikulpanit struct amd_hostbridge {
2324bfdca7SRobert Richter u32 bus;
2424bfdca7SRobert Richter u32 slot;
2524bfdca7SRobert Richter u32 device;
2624bfdca7SRobert Richter };
2724bfdca7SRobert Richter
289e7f7231SSuravee Suthikulpanit /*
299e7f7231SSuravee Suthikulpanit * IMPORTANT NOTE:
309e7f7231SSuravee Suthikulpanit * hb_probes[] and early_root_info_init() is in maintenance mode.
319e7f7231SSuravee Suthikulpanit * It only supports K8, Fam10h, Fam11h, and Fam15h_00h-0fh .
329e7f7231SSuravee Suthikulpanit * Future processor will rely on information in ACPI.
339e7f7231SSuravee Suthikulpanit */
349e7f7231SSuravee Suthikulpanit static struct amd_hostbridge hb_probes[] __initdata = {
359e7f7231SSuravee Suthikulpanit { 0, 0x18, 0x1100 }, /* K8 */
369e7f7231SSuravee Suthikulpanit { 0, 0x18, 0x1200 }, /* Family10h */
379e7f7231SSuravee Suthikulpanit { 0xff, 0, 0x1200 }, /* Family10h */
389e7f7231SSuravee Suthikulpanit { 0, 0x18, 0x1300 }, /* Family11h */
399e7f7231SSuravee Suthikulpanit { 0, 0x18, 0x1600 }, /* Family15h */
4024bfdca7SRobert Richter };
4124bfdca7SRobert Richter
find_pci_root_info(int node,int link)42d28e5ac2SYinghai Lu static struct pci_root_info __init *find_pci_root_info(int node, int link)
43d28e5ac2SYinghai Lu {
44d28e5ac2SYinghai Lu struct pci_root_info *info;
45d28e5ac2SYinghai Lu
46d28e5ac2SYinghai Lu /* find the position */
47d28e5ac2SYinghai Lu list_for_each_entry(info, &pci_root_infos, list)
48d28e5ac2SYinghai Lu if (info->node == node && info->link == link)
49d28e5ac2SYinghai Lu return info;
50d28e5ac2SYinghai Lu
51d28e5ac2SYinghai Lu return NULL;
52d28e5ac2SYinghai Lu }
53d28e5ac2SYinghai Lu
cap_resource(u64 val)54*3c9d017cSAndy Shevchenko static inline resource_size_t cap_resource(u64 val)
55*3c9d017cSAndy Shevchenko {
56*3c9d017cSAndy Shevchenko if (val > RESOURCE_SIZE_MAX)
57*3c9d017cSAndy Shevchenko return RESOURCE_SIZE_MAX;
58*3c9d017cSAndy Shevchenko
59*3c9d017cSAndy Shevchenko return val;
60*3c9d017cSAndy Shevchenko }
61*3c9d017cSAndy Shevchenko
6224bfdca7SRobert Richter /**
639e7f7231SSuravee Suthikulpanit * early_root_info_init()
6424bfdca7SRobert Richter * called before pcibios_scan_root and pci_scan_bus
659e7f7231SSuravee Suthikulpanit * fills the mp_bus_to_cpumask array based according
669e7f7231SSuravee Suthikulpanit * to the LDT Bus Number Registers found in the northbridge.
6724bfdca7SRobert Richter */
early_root_info_init(void)689e7f7231SSuravee Suthikulpanit static int __init early_root_info_init(void)
6924bfdca7SRobert Richter {
7024bfdca7SRobert Richter int i;
7124bfdca7SRobert Richter unsigned bus;
7224bfdca7SRobert Richter unsigned slot;
7324bfdca7SRobert Richter int node;
7424bfdca7SRobert Richter int link;
7524bfdca7SRobert Richter int def_node;
7624bfdca7SRobert Richter int def_link;
7724bfdca7SRobert Richter struct pci_root_info *info;
7824bfdca7SRobert Richter u32 reg;
7997445c3bSYinghai Lu u64 start;
8097445c3bSYinghai Lu u64 end;
8127811d8cSYinghai Lu struct range range[RANGE_NUM];
8224bfdca7SRobert Richter u64 val;
8324bfdca7SRobert Richter u32 address;
843e3da00cSYinghai Lu bool found;
8524d25dbfSBjorn Helgaas struct resource fam10h_mmconf_res, *fam10h_mmconf;
8624d25dbfSBjorn Helgaas u64 fam10h_mmconf_start;
8724d25dbfSBjorn Helgaas u64 fam10h_mmconf_end;
8824bfdca7SRobert Richter
8924bfdca7SRobert Richter if (!early_pci_allowed())
9024bfdca7SRobert Richter return -1;
9124bfdca7SRobert Richter
923e3da00cSYinghai Lu found = false;
939e7f7231SSuravee Suthikulpanit for (i = 0; i < ARRAY_SIZE(hb_probes); i++) {
9424bfdca7SRobert Richter u32 id;
9524bfdca7SRobert Richter u16 device;
9624bfdca7SRobert Richter u16 vendor;
9724bfdca7SRobert Richter
989e7f7231SSuravee Suthikulpanit bus = hb_probes[i].bus;
999e7f7231SSuravee Suthikulpanit slot = hb_probes[i].slot;
10024bfdca7SRobert Richter id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
10124bfdca7SRobert Richter vendor = id & 0xffff;
10224bfdca7SRobert Richter device = (id>>16) & 0xffff;
1039e7f7231SSuravee Suthikulpanit
104c6babb58SPu Wen if (vendor != PCI_VENDOR_ID_AMD &&
105c6babb58SPu Wen vendor != PCI_VENDOR_ID_HYGON)
1069e7f7231SSuravee Suthikulpanit continue;
1079e7f7231SSuravee Suthikulpanit
1089e7f7231SSuravee Suthikulpanit if (hb_probes[i].device == device) {
1093e3da00cSYinghai Lu found = true;
11024bfdca7SRobert Richter break;
11124bfdca7SRobert Richter }
11224bfdca7SRobert Richter }
11324bfdca7SRobert Richter
1143e3da00cSYinghai Lu if (!found)
11524bfdca7SRobert Richter return 0;
11624bfdca7SRobert Richter
11794d4bb5bSSuravee Suthikulpanit /*
11894d4bb5bSSuravee Suthikulpanit * We should learn topology and routing information from _PXM and
11994d4bb5bSSuravee Suthikulpanit * _CRS methods in the ACPI namespace. We extract node numbers
12094d4bb5bSSuravee Suthikulpanit * here to work around BIOSes that don't supply _PXM.
12194d4bb5bSSuravee Suthikulpanit */
1229e7f7231SSuravee Suthikulpanit for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) {
12324bfdca7SRobert Richter int min_bus;
12424bfdca7SRobert Richter int max_bus;
1259e7f7231SSuravee Suthikulpanit reg = read_pci_config(bus, slot, 1,
1269e7f7231SSuravee Suthikulpanit AMD_NB_F1_CONFIG_MAP_REG + (i << 2));
12724bfdca7SRobert Richter
12824bfdca7SRobert Richter /* Check if that register is enabled for bus range */
12924bfdca7SRobert Richter if ((reg & 7) != 3)
13024bfdca7SRobert Richter continue;
13124bfdca7SRobert Richter
13224bfdca7SRobert Richter min_bus = (reg >> 16) & 0xff;
13324bfdca7SRobert Richter max_bus = (reg >> 24) & 0xff;
13424bfdca7SRobert Richter node = (reg >> 4) & 0x07;
13524bfdca7SRobert Richter link = (reg >> 8) & 0x03;
13624bfdca7SRobert Richter
137ccd61f07SKrzysztof Wilczyński alloc_pci_root_info(min_bus, max_bus, node, link);
13824bfdca7SRobert Richter }
13924bfdca7SRobert Richter
14094d4bb5bSSuravee Suthikulpanit /*
14194d4bb5bSSuravee Suthikulpanit * The following code extracts routing information for use on old
14294d4bb5bSSuravee Suthikulpanit * systems where Linux doesn't automatically use host bridge _CRS
14394d4bb5bSSuravee Suthikulpanit * methods (or when the user specifies "pci=nocrs").
14494d4bb5bSSuravee Suthikulpanit *
14594d4bb5bSSuravee Suthikulpanit * We only do this through Fam11h, because _CRS should be enough on
14694d4bb5bSSuravee Suthikulpanit * newer systems.
14794d4bb5bSSuravee Suthikulpanit */
14894d4bb5bSSuravee Suthikulpanit if (boot_cpu_data.x86 > 0x11)
14994d4bb5bSSuravee Suthikulpanit return 0;
15094d4bb5bSSuravee Suthikulpanit
15124bfdca7SRobert Richter /* get the default node and link for left over res */
1529e7f7231SSuravee Suthikulpanit reg = read_pci_config(bus, slot, 0, AMD_NB_F0_NODE_ID);
15324bfdca7SRobert Richter def_node = (reg >> 8) & 0x07;
1549e7f7231SSuravee Suthikulpanit reg = read_pci_config(bus, slot, 0, AMD_NB_F0_UNIT_ID);
15524bfdca7SRobert Richter def_link = (reg >> 8) & 0x03;
15624bfdca7SRobert Richter
15724bfdca7SRobert Richter memset(range, 0, sizeof(range));
158e9a0064aSYinghai Lu add_range(range, RANGE_NUM, 0, 0, 0xffff + 1);
15924bfdca7SRobert Richter /* io port resource */
16024bfdca7SRobert Richter for (i = 0; i < 4; i++) {
16124bfdca7SRobert Richter reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3));
16224bfdca7SRobert Richter if (!(reg & 3))
16324bfdca7SRobert Richter continue;
16424bfdca7SRobert Richter
16524bfdca7SRobert Richter start = reg & 0xfff000;
16624bfdca7SRobert Richter reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3));
16724bfdca7SRobert Richter node = reg & 0x07;
16824bfdca7SRobert Richter link = (reg >> 4) & 0x03;
16924bfdca7SRobert Richter end = (reg & 0xfff000) | 0xfff;
17024bfdca7SRobert Richter
171d28e5ac2SYinghai Lu info = find_pci_root_info(node, link);
172d28e5ac2SYinghai Lu if (!info)
17324bfdca7SRobert Richter continue; /* not found */
17424bfdca7SRobert Richter
17524bfdca7SRobert Richter printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n",
17697445c3bSYinghai Lu node, link, start, end);
17724bfdca7SRobert Richter
17824bfdca7SRobert Richter /* kernel only handle 16 bit only */
17924bfdca7SRobert Richter if (end > 0xffff)
18024bfdca7SRobert Richter end = 0xffff;
18124bfdca7SRobert Richter update_res(info, start, end, IORESOURCE_IO, 1);
182e9a0064aSYinghai Lu subtract_range(range, RANGE_NUM, start, end + 1);
18324bfdca7SRobert Richter }
18424bfdca7SRobert Richter /* add left over io port range to def node/link, [0, 0xffff] */
18524bfdca7SRobert Richter /* find the position */
186d28e5ac2SYinghai Lu info = find_pci_root_info(def_node, def_link);
187d28e5ac2SYinghai Lu if (info) {
18824bfdca7SRobert Richter for (i = 0; i < RANGE_NUM; i++) {
18924bfdca7SRobert Richter if (!range[i].end)
19024bfdca7SRobert Richter continue;
19124bfdca7SRobert Richter
192e9a0064aSYinghai Lu update_res(info, range[i].start, range[i].end - 1,
19324bfdca7SRobert Richter IORESOURCE_IO, 1);
19424bfdca7SRobert Richter }
19524bfdca7SRobert Richter }
19624bfdca7SRobert Richter
19724bfdca7SRobert Richter memset(range, 0, sizeof(range));
19824bfdca7SRobert Richter /* 0xfd00000000-0xffffffffff for HT */
199e9a0064aSYinghai Lu end = cap_resource((0xfdULL<<32) - 1);
200e9a0064aSYinghai Lu end++;
201e9a0064aSYinghai Lu add_range(range, RANGE_NUM, 0, 0, end);
20224bfdca7SRobert Richter
20324bfdca7SRobert Richter /* need to take out [0, TOM) for RAM*/
20424bfdca7SRobert Richter address = MSR_K8_TOP_MEM1;
20524bfdca7SRobert Richter rdmsrl(address, val);
2063de352bbSIngo Molnar end = (val & 0xffffff800000ULL);
20797445c3bSYinghai Lu printk(KERN_INFO "TOM: %016llx aka %lldM\n", end, end>>20);
20824bfdca7SRobert Richter if (end < (1ULL<<32))
209e9a0064aSYinghai Lu subtract_range(range, RANGE_NUM, 0, end);
21024bfdca7SRobert Richter
21124bfdca7SRobert Richter /* get mmconfig */
21224d25dbfSBjorn Helgaas fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res);
21324bfdca7SRobert Richter /* need to take out mmconf range */
21424d25dbfSBjorn Helgaas if (fam10h_mmconf) {
21524d25dbfSBjorn Helgaas printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf);
21624d25dbfSBjorn Helgaas fam10h_mmconf_start = fam10h_mmconf->start;
21724d25dbfSBjorn Helgaas fam10h_mmconf_end = fam10h_mmconf->end;
218e9a0064aSYinghai Lu subtract_range(range, RANGE_NUM, fam10h_mmconf_start,
219e9a0064aSYinghai Lu fam10h_mmconf_end + 1);
22024d25dbfSBjorn Helgaas } else {
22124d25dbfSBjorn Helgaas fam10h_mmconf_start = 0;
22224d25dbfSBjorn Helgaas fam10h_mmconf_end = 0;
22324bfdca7SRobert Richter }
22424bfdca7SRobert Richter
22524bfdca7SRobert Richter /* mmio resource */
22624bfdca7SRobert Richter for (i = 0; i < 8; i++) {
22724bfdca7SRobert Richter reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
22824bfdca7SRobert Richter if (!(reg & 3))
22924bfdca7SRobert Richter continue;
23024bfdca7SRobert Richter
23124bfdca7SRobert Richter start = reg & 0xffffff00; /* 39:16 on 31:8*/
23224bfdca7SRobert Richter start <<= 8;
23324bfdca7SRobert Richter reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
23424bfdca7SRobert Richter node = reg & 0x07;
23524bfdca7SRobert Richter link = (reg >> 4) & 0x03;
23624bfdca7SRobert Richter end = (reg & 0xffffff00);
23724bfdca7SRobert Richter end <<= 8;
23824bfdca7SRobert Richter end |= 0xffff;
23924bfdca7SRobert Richter
240d28e5ac2SYinghai Lu info = find_pci_root_info(node, link);
24124bfdca7SRobert Richter
242d28e5ac2SYinghai Lu if (!info)
243d28e5ac2SYinghai Lu continue;
24424bfdca7SRobert Richter
24524bfdca7SRobert Richter printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]",
24697445c3bSYinghai Lu node, link, start, end);
24724bfdca7SRobert Richter /*
24824bfdca7SRobert Richter * some sick allocation would have range overlap with fam10h
24924bfdca7SRobert Richter * mmconf range, so need to update start and end.
25024bfdca7SRobert Richter */
25124bfdca7SRobert Richter if (fam10h_mmconf_end) {
25224bfdca7SRobert Richter int changed = 0;
25324bfdca7SRobert Richter u64 endx = 0;
25424bfdca7SRobert Richter if (start >= fam10h_mmconf_start &&
25524bfdca7SRobert Richter start <= fam10h_mmconf_end) {
25624bfdca7SRobert Richter start = fam10h_mmconf_end + 1;
25724bfdca7SRobert Richter changed = 1;
25824bfdca7SRobert Richter }
25924bfdca7SRobert Richter
26024bfdca7SRobert Richter if (end >= fam10h_mmconf_start &&
26124bfdca7SRobert Richter end <= fam10h_mmconf_end) {
26224bfdca7SRobert Richter end = fam10h_mmconf_start - 1;
26324bfdca7SRobert Richter changed = 1;
26424bfdca7SRobert Richter }
26524bfdca7SRobert Richter
26624bfdca7SRobert Richter if (start < fam10h_mmconf_start &&
26724bfdca7SRobert Richter end > fam10h_mmconf_end) {
26824bfdca7SRobert Richter /* we got a hole */
26924bfdca7SRobert Richter endx = fam10h_mmconf_start - 1;
27024bfdca7SRobert Richter update_res(info, start, endx, IORESOURCE_MEM, 0);
271e9a0064aSYinghai Lu subtract_range(range, RANGE_NUM, start,
272e9a0064aSYinghai Lu endx + 1);
27397445c3bSYinghai Lu printk(KERN_CONT " ==> [%llx, %llx]", start, endx);
27424bfdca7SRobert Richter start = fam10h_mmconf_end + 1;
27524bfdca7SRobert Richter changed = 1;
27624bfdca7SRobert Richter }
27724bfdca7SRobert Richter if (changed) {
27824bfdca7SRobert Richter if (start <= end) {
27997445c3bSYinghai Lu printk(KERN_CONT " %s [%llx, %llx]", endx ? "and" : "==>", start, end);
28024bfdca7SRobert Richter } else {
28124bfdca7SRobert Richter printk(KERN_CONT "%s\n", endx?"":" ==> none");
28224bfdca7SRobert Richter continue;
28324bfdca7SRobert Richter }
28424bfdca7SRobert Richter }
28524bfdca7SRobert Richter }
28624bfdca7SRobert Richter
2879ad3f2c7SYinghai Lu update_res(info, cap_resource(start), cap_resource(end),
2889ad3f2c7SYinghai Lu IORESOURCE_MEM, 1);
289e9a0064aSYinghai Lu subtract_range(range, RANGE_NUM, start, end + 1);
29024bfdca7SRobert Richter printk(KERN_CONT "\n");
29124bfdca7SRobert Richter }
29224bfdca7SRobert Richter
29324bfdca7SRobert Richter /* need to take out [4G, TOM2) for RAM*/
29424bfdca7SRobert Richter /* SYS_CFG */
295059e5c32SBrijesh Singh address = MSR_AMD64_SYSCFG;
29624bfdca7SRobert Richter rdmsrl(address, val);
29724bfdca7SRobert Richter /* TOP_MEM2 is enabled? */
29824bfdca7SRobert Richter if (val & (1<<21)) {
29924bfdca7SRobert Richter /* TOP_MEM2 */
30024bfdca7SRobert Richter address = MSR_K8_TOP_MEM2;
30124bfdca7SRobert Richter rdmsrl(address, val);
3023de352bbSIngo Molnar end = (val & 0xffffff800000ULL);
30397445c3bSYinghai Lu printk(KERN_INFO "TOM2: %016llx aka %lldM\n", end, end>>20);
304e9a0064aSYinghai Lu subtract_range(range, RANGE_NUM, 1ULL<<32, end);
30524bfdca7SRobert Richter }
30624bfdca7SRobert Richter
30724bfdca7SRobert Richter /*
30824bfdca7SRobert Richter * add left over mmio range to def node/link ?
30924bfdca7SRobert Richter * that is tricky, just record range in from start_min to 4G
31024bfdca7SRobert Richter */
311d28e5ac2SYinghai Lu info = find_pci_root_info(def_node, def_link);
312d28e5ac2SYinghai Lu if (info) {
31324bfdca7SRobert Richter for (i = 0; i < RANGE_NUM; i++) {
31424bfdca7SRobert Richter if (!range[i].end)
31524bfdca7SRobert Richter continue;
31624bfdca7SRobert Richter
3179ad3f2c7SYinghai Lu update_res(info, cap_resource(range[i].start),
318e9a0064aSYinghai Lu cap_resource(range[i].end - 1),
31924bfdca7SRobert Richter IORESOURCE_MEM, 1);
32024bfdca7SRobert Richter }
32124bfdca7SRobert Richter }
32224bfdca7SRobert Richter
323d28e5ac2SYinghai Lu list_for_each_entry(info, &pci_root_infos, list) {
32424bfdca7SRobert Richter int busnum;
325d28e5ac2SYinghai Lu struct pci_root_res *root_res;
32624bfdca7SRobert Richter
327a10bb128SYinghai Lu busnum = info->busn.start;
328a10bb128SYinghai Lu printk(KERN_DEBUG "bus: %pR on node %x link %x\n",
329a10bb128SYinghai Lu &info->busn, info->node, info->link);
330d28e5ac2SYinghai Lu list_for_each_entry(root_res, &info->resources, list)
331d28e5ac2SYinghai Lu printk(KERN_DEBUG "bus: %02x %pR\n",
332d28e5ac2SYinghai Lu busnum, &root_res->res);
33324bfdca7SRobert Richter }
33424bfdca7SRobert Richter
33524bfdca7SRobert Richter return 0;
33624bfdca7SRobert Richter }
33724bfdca7SRobert Richter
3383a27dd1cSRobert Richter #define ENABLE_CF8_EXT_CFG (1ULL << 46)
3393a27dd1cSRobert Richter
amd_bus_cpu_online(unsigned int cpu)340c8b877a5SSebastian Andrzej Siewior static int amd_bus_cpu_online(unsigned int cpu)
3413a27dd1cSRobert Richter {
3423a27dd1cSRobert Richter u64 reg;
343c8b877a5SSebastian Andrzej Siewior
3443a27dd1cSRobert Richter rdmsrl(MSR_AMD64_NB_CFG, reg);
3453a27dd1cSRobert Richter if (!(reg & ENABLE_CF8_EXT_CFG)) {
3463a27dd1cSRobert Richter reg |= ENABLE_CF8_EXT_CFG;
3473a27dd1cSRobert Richter wrmsrl(MSR_AMD64_NB_CFG, reg);
3483a27dd1cSRobert Richter }
349c8b877a5SSebastian Andrzej Siewior return 0;
3503a27dd1cSRobert Richter }
3513a27dd1cSRobert Richter
pci_enable_pci_io_ecs(void)35224d9b70bSJan Beulich static void __init pci_enable_pci_io_ecs(void)
35324d9b70bSJan Beulich {
35424d9b70bSJan Beulich #ifdef CONFIG_AMD_NB
35524d9b70bSJan Beulich unsigned int i, n;
35624d9b70bSJan Beulich
35724d9b70bSJan Beulich for (n = i = 0; !n && amd_nb_bus_dev_ranges[i].dev_limit; ++i) {
35824d9b70bSJan Beulich u8 bus = amd_nb_bus_dev_ranges[i].bus;
35924d9b70bSJan Beulich u8 slot = amd_nb_bus_dev_ranges[i].dev_base;
36024d9b70bSJan Beulich u8 limit = amd_nb_bus_dev_ranges[i].dev_limit;
36124d9b70bSJan Beulich
36224d9b70bSJan Beulich for (; slot < limit; ++slot) {
36324d9b70bSJan Beulich u32 val = read_pci_config(bus, slot, 3, 0);
36424d9b70bSJan Beulich
36524d9b70bSJan Beulich if (!early_is_amd_nb(val))
36624d9b70bSJan Beulich continue;
36724d9b70bSJan Beulich
36824d9b70bSJan Beulich val = read_pci_config(bus, slot, 3, 0x8c);
36924d9b70bSJan Beulich if (!(val & (ENABLE_CF8_EXT_CFG >> 32))) {
37024d9b70bSJan Beulich val |= ENABLE_CF8_EXT_CFG >> 32;
37124d9b70bSJan Beulich write_pci_config(bus, slot, 3, 0x8c, val);
37224d9b70bSJan Beulich }
37324d9b70bSJan Beulich ++n;
37424d9b70bSJan Beulich }
37524d9b70bSJan Beulich }
37624d9b70bSJan Beulich #endif
37724d9b70bSJan Beulich }
37824d9b70bSJan Beulich
pci_io_ecs_init(void)37991ede005SRobert Richter static int __init pci_io_ecs_init(void)
38091ede005SRobert Richter {
381c8b877a5SSebastian Andrzej Siewior int ret;
38291ede005SRobert Richter
3833a27dd1cSRobert Richter /* assume all cpus from fam10h have IO ECS */
3843a27dd1cSRobert Richter if (boot_cpu_data.x86 < 0x10)
3853a27dd1cSRobert Richter return 0;
38691ede005SRobert Richter
38724d9b70bSJan Beulich /* Try the PCI method first. */
38824d9b70bSJan Beulich if (early_pci_allowed())
38924d9b70bSJan Beulich pci_enable_pci_io_ecs();
39024d9b70bSJan Beulich
391c8b877a5SSebastian Andrzej Siewior ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "pci/amd_bus:online",
392c8b877a5SSebastian Andrzej Siewior amd_bus_cpu_online, NULL);
393c8b877a5SSebastian Andrzej Siewior WARN_ON(ret < 0);
3949f668f66SSrivatsa S. Bhat
3953a27dd1cSRobert Richter pci_probe |= PCI_HAS_IO_ECS;
39691ede005SRobert Richter
3973a27dd1cSRobert Richter return 0;
3983a27dd1cSRobert Richter }
3993a27dd1cSRobert Richter
amd_postcore_init(void)4009b4e27b5SRobert Richter static int __init amd_postcore_init(void)
4019b4e27b5SRobert Richter {
402c6babb58SPu Wen if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
403c6babb58SPu Wen boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
4049b4e27b5SRobert Richter return 0;
4059b4e27b5SRobert Richter
4069e7f7231SSuravee Suthikulpanit early_root_info_init();
40791ede005SRobert Richter pci_io_ecs_init();
4089b4e27b5SRobert Richter
4099b4e27b5SRobert Richter return 0;
4109b4e27b5SRobert Richter }
4119b4e27b5SRobert Richter
4129b4e27b5SRobert Richter postcore_initcall(amd_postcore_init);
413