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