1 #include <linux/init.h>
3 #include <linux/topology.h>
5 #include <linux/range.h>
7 #include <asm/pci_x86.h>
9 #include <asm/pci-direct.h>
14 * This discovers the pcibus <-> node mapping on AMD K8.
15 * also get peer root bus resource for io,mmio
18 struct pci_hostbridge_probe
{
25 static struct pci_hostbridge_probe pci_probes
[] __initdata
= {
26 { 0, 0x18, PCI_VENDOR_ID_AMD
, 0x1100 },
27 { 0, 0x18, PCI_VENDOR_ID_AMD
, 0x1200 },
28 { 0xff, 0, PCI_VENDOR_ID_AMD
, 0x1200 },
29 { 0, 0x18, PCI_VENDOR_ID_AMD
, 0x1300 },
32 static u64 __initdata fam10h_mmconf_start
;
33 static u64 __initdata fam10h_mmconf_end
;
34 static void __init
get_pci_mmcfg_amd_fam10h_range(void)
38 unsigned segn_busn_bits
;
40 /* assume all cpus from fam10h have mmconf */
41 if (boot_cpu_data
.x86
< 0x10)
44 address
= MSR_FAM10H_MMIO_CONF_BASE
;
47 /* mmconfig is not enable */
48 if (!(msr
& FAM10H_MMIO_CONF_ENABLE
))
51 base
= msr
& (FAM10H_MMIO_CONF_BASE_MASK
<<FAM10H_MMIO_CONF_BASE_SHIFT
);
53 segn_busn_bits
= (msr
>> FAM10H_MMIO_CONF_BUSRANGE_SHIFT
) &
54 FAM10H_MMIO_CONF_BUSRANGE_MASK
;
56 fam10h_mmconf_start
= base
;
57 fam10h_mmconf_end
= base
+ (1ULL<<(segn_busn_bits
+ 20)) - 1;
63 * early_fill_mp_bus_to_node()
64 * called before pcibios_scan_root and pci_scan_bus
65 * fills the mp_bus_to_cpumask array based according to the LDT Bus Number
66 * Registers found in the K8 northbridge
68 static int __init
early_fill_mp_bus_info(void)
78 struct pci_root_info
*info
;
83 struct range range
[RANGE_NUM
];
88 if (!early_pci_allowed())
92 for (i
= 0; i
< ARRAY_SIZE(pci_probes
); i
++) {
97 bus
= pci_probes
[i
].bus
;
98 slot
= pci_probes
[i
].slot
;
99 id
= read_pci_config(bus
, slot
, 0, PCI_VENDOR_ID
);
101 vendor
= id
& 0xffff;
102 device
= (id
>>16) & 0xffff;
103 if (pci_probes
[i
].vendor
== vendor
&&
104 pci_probes
[i
].device
== device
) {
114 for (i
= 0; i
< 4; i
++) {
117 reg
= read_pci_config(bus
, slot
, 1, 0xe0 + (i
<< 2));
119 /* Check if that register is enabled for bus range */
123 min_bus
= (reg
>> 16) & 0xff;
124 max_bus
= (reg
>> 24) & 0xff;
125 node
= (reg
>> 4) & 0x07;
127 for (j
= min_bus
; j
<= max_bus
; j
++)
128 set_mp_bus_to_node(j
, node
);
130 link
= (reg
>> 8) & 0x03;
132 info
= &pci_root_info
[pci_root_num
];
133 info
->bus_min
= min_bus
;
134 info
->bus_max
= max_bus
;
137 sprintf(info
->name
, "PCI Bus #%02x", min_bus
);
141 /* get the default node and link for left over res */
142 reg
= read_pci_config(bus
, slot
, 0, 0x60);
143 def_node
= (reg
>> 8) & 0x07;
144 reg
= read_pci_config(bus
, slot
, 0, 0x64);
145 def_link
= (reg
>> 8) & 0x03;
147 memset(range
, 0, sizeof(range
));
148 add_range(range
, RANGE_NUM
, 0, 0, 0xffff + 1);
149 /* io port resource */
150 for (i
= 0; i
< 4; i
++) {
151 reg
= read_pci_config(bus
, slot
, 1, 0xc0 + (i
<< 3));
155 start
= reg
& 0xfff000;
156 reg
= read_pci_config(bus
, slot
, 1, 0xc4 + (i
<< 3));
158 link
= (reg
>> 4) & 0x03;
159 end
= (reg
& 0xfff000) | 0xfff;
161 /* find the position */
162 for (j
= 0; j
< pci_root_num
; j
++) {
163 info
= &pci_root_info
[j
];
164 if (info
->node
== node
&& info
->link
== link
)
167 if (j
== pci_root_num
)
168 continue; /* not found */
170 info
= &pci_root_info
[j
];
171 printk(KERN_DEBUG
"node %d link %d: io port [%llx, %llx]\n",
172 node
, link
, start
, end
);
174 /* kernel only handle 16 bit only */
177 update_res(info
, start
, end
, IORESOURCE_IO
, 1);
178 subtract_range(range
, RANGE_NUM
, start
, end
+ 1);
180 /* add left over io port range to def node/link, [0, 0xffff] */
181 /* find the position */
182 for (j
= 0; j
< pci_root_num
; j
++) {
183 info
= &pci_root_info
[j
];
184 if (info
->node
== def_node
&& info
->link
== def_link
)
187 if (j
< pci_root_num
) {
188 info
= &pci_root_info
[j
];
189 for (i
= 0; i
< RANGE_NUM
; i
++) {
193 update_res(info
, range
[i
].start
, range
[i
].end
- 1,
198 memset(range
, 0, sizeof(range
));
199 /* 0xfd00000000-0xffffffffff for HT */
200 end
= cap_resource((0xfdULL
<<32) - 1);
202 add_range(range
, RANGE_NUM
, 0, 0, end
);
204 /* need to take out [0, TOM) for RAM*/
205 address
= MSR_K8_TOP_MEM1
;
206 rdmsrl(address
, val
);
207 end
= (val
& 0xffffff800000ULL
);
208 printk(KERN_INFO
"TOM: %016llx aka %lldM\n", end
, end
>>20);
209 if (end
< (1ULL<<32))
210 subtract_range(range
, RANGE_NUM
, 0, end
);
213 get_pci_mmcfg_amd_fam10h_range();
214 /* need to take out mmconf range */
215 if (fam10h_mmconf_end
) {
216 printk(KERN_DEBUG
"Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start
, fam10h_mmconf_end
);
217 subtract_range(range
, RANGE_NUM
, fam10h_mmconf_start
,
218 fam10h_mmconf_end
+ 1);
222 for (i
= 0; i
< 8; i
++) {
223 reg
= read_pci_config(bus
, slot
, 1, 0x80 + (i
<< 3));
227 start
= reg
& 0xffffff00; /* 39:16 on 31:8*/
229 reg
= read_pci_config(bus
, slot
, 1, 0x84 + (i
<< 3));
231 link
= (reg
>> 4) & 0x03;
232 end
= (reg
& 0xffffff00);
236 /* find the position */
237 for (j
= 0; j
< pci_root_num
; j
++) {
238 info
= &pci_root_info
[j
];
239 if (info
->node
== node
&& info
->link
== link
)
242 if (j
== pci_root_num
)
243 continue; /* not found */
245 info
= &pci_root_info
[j
];
247 printk(KERN_DEBUG
"node %d link %d: mmio [%llx, %llx]",
248 node
, link
, start
, end
);
250 * some sick allocation would have range overlap with fam10h
251 * mmconf range, so need to update start and end.
253 if (fam10h_mmconf_end
) {
256 if (start
>= fam10h_mmconf_start
&&
257 start
<= fam10h_mmconf_end
) {
258 start
= fam10h_mmconf_end
+ 1;
262 if (end
>= fam10h_mmconf_start
&&
263 end
<= fam10h_mmconf_end
) {
264 end
= fam10h_mmconf_start
- 1;
268 if (start
< fam10h_mmconf_start
&&
269 end
> fam10h_mmconf_end
) {
271 endx
= fam10h_mmconf_start
- 1;
272 update_res(info
, start
, endx
, IORESOURCE_MEM
, 0);
273 subtract_range(range
, RANGE_NUM
, start
,
275 printk(KERN_CONT
" ==> [%llx, %llx]", start
, endx
);
276 start
= fam10h_mmconf_end
+ 1;
281 printk(KERN_CONT
" %s [%llx, %llx]", endx
? "and" : "==>", start
, end
);
283 printk(KERN_CONT
"%s\n", endx
?"":" ==> none");
289 update_res(info
, cap_resource(start
), cap_resource(end
),
291 subtract_range(range
, RANGE_NUM
, start
, end
+ 1);
292 printk(KERN_CONT
"\n");
295 /* need to take out [4G, TOM2) for RAM*/
297 address
= MSR_K8_SYSCFG
;
298 rdmsrl(address
, val
);
299 /* TOP_MEM2 is enabled? */
302 address
= MSR_K8_TOP_MEM2
;
303 rdmsrl(address
, val
);
304 end
= (val
& 0xffffff800000ULL
);
305 printk(KERN_INFO
"TOM2: %016llx aka %lldM\n", end
, end
>>20);
306 subtract_range(range
, RANGE_NUM
, 1ULL<<32, end
);
310 * add left over mmio range to def node/link ?
311 * that is tricky, just record range in from start_min to 4G
313 for (j
= 0; j
< pci_root_num
; j
++) {
314 info
= &pci_root_info
[j
];
315 if (info
->node
== def_node
&& info
->link
== def_link
)
318 if (j
< pci_root_num
) {
319 info
= &pci_root_info
[j
];
321 for (i
= 0; i
< RANGE_NUM
; i
++) {
325 update_res(info
, cap_resource(range
[i
].start
),
326 cap_resource(range
[i
].end
- 1),
331 for (i
= 0; i
< pci_root_num
; i
++) {
335 info
= &pci_root_info
[i
];
336 res_num
= info
->res_num
;
337 busnum
= info
->bus_min
;
338 printk(KERN_DEBUG
"bus: [%02x, %02x] on node %x link %x\n",
339 info
->bus_min
, info
->bus_max
, info
->node
, info
->link
);
340 for (j
= 0; j
< res_num
; j
++) {
342 printk(KERN_DEBUG
"bus: %02x index %x %pR\n",
350 #define ENABLE_CF8_EXT_CFG (1ULL << 46)
352 static void enable_pci_io_ecs(void *unused
)
355 rdmsrl(MSR_AMD64_NB_CFG
, reg
);
356 if (!(reg
& ENABLE_CF8_EXT_CFG
)) {
357 reg
|= ENABLE_CF8_EXT_CFG
;
358 wrmsrl(MSR_AMD64_NB_CFG
, reg
);
362 static int __cpuinit
amd_cpu_notify(struct notifier_block
*self
,
363 unsigned long action
, void *hcpu
)
365 int cpu
= (long)hcpu
;
368 case CPU_ONLINE_FROZEN
:
369 smp_call_function_single(cpu
, enable_pci_io_ecs
, NULL
, 0);
377 static struct notifier_block __cpuinitdata amd_cpu_notifier
= {
378 .notifier_call
= amd_cpu_notify
,
381 static int __init
pci_io_ecs_init(void)
385 /* assume all cpus from fam10h have IO ECS */
386 if (boot_cpu_data
.x86
< 0x10)
389 register_cpu_notifier(&amd_cpu_notifier
);
390 for_each_online_cpu(cpu
)
391 amd_cpu_notify(&amd_cpu_notifier
, (unsigned long)CPU_ONLINE
,
393 pci_probe
|= PCI_HAS_IO_ECS
;
398 static int __init
amd_postcore_init(void)
400 if (boot_cpu_data
.x86_vendor
!= X86_VENDOR_AMD
)
403 early_fill_mp_bus_info();
409 postcore_initcall(amd_postcore_init
);