2 * AMD Family 10h mmconfig enablement
5 #include <linux/types.h>
7 #include <linux/string.h>
10 #include <asm/pci-direct.h>
11 #include <linux/sort.h>
15 #include <asm/mmconfig.h>
17 #include "../pci/pci.h"
19 struct pci_hostbridge_probe
{
26 static u64 __cpuinitdata fam10h_pci_mmconf_base
;
27 static int __cpuinitdata fam10h_pci_mmconf_base_status
;
29 static struct pci_hostbridge_probe pci_probes
[] __cpuinitdata
= {
30 { 0, 0x18, PCI_VENDOR_ID_AMD
, 0x1200 },
31 { 0xff, 0, PCI_VENDOR_ID_AMD
, 0x1200 },
39 static int __cpuinit
cmp_range(const void *x1
, const void *x2
)
41 const struct range
*r1
= x1
;
42 const struct range
*r2
= x2
;
45 start1
= r1
->start
>> 32;
46 start2
= r2
->start
>> 32;
48 return start1
- start2
;
52 /* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
53 #define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
54 #define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
55 static void __cpuinit
get_fam10h_pci_mmconf_base(void)
65 u64 base
= FAM10H_PCI_MMCONF_BASE
;
68 struct range range
[8];
70 /* only try to get setting from BSP */
72 if (fam10h_pci_mmconf_base_status
)
75 if (!early_pci_allowed())
79 for (i
= 0; i
< ARRAY_SIZE(pci_probes
); i
++) {
84 bus
= pci_probes
[i
].bus
;
85 slot
= pci_probes
[i
].slot
;
86 id
= read_pci_config(bus
, slot
, 0, PCI_VENDOR_ID
);
89 device
= (id
>>16) & 0xffff;
90 if (pci_probes
[i
].vendor
== vendor
&&
91 pci_probes
[i
].device
== device
) {
101 address
= MSR_K8_SYSCFG
;
102 rdmsrl(address
, val
);
104 /* TOP_MEM2 is not enabled? */
105 if (!(val
& (1<<21))) {
109 address
= MSR_K8_TOP_MEM2
;
110 rdmsrl(address
, val
);
111 tom2
= val
& (0xffffULL
<<32);
115 base
= tom2
+ (1ULL<<32);
118 * need to check if the range is in the high mmio range that is
122 for (i
= 0; i
< 8; i
++) {
126 reg
= read_pci_config(bus
, slot
, 1, 0x80 + (i
<< 3));
130 start
= (((u64
)reg
) << 8) & (0xffULL
<< 32); /* 39:16 on 31:8*/
131 reg
= read_pci_config(bus
, slot
, 1, 0x84 + (i
<< 3));
132 end
= (((u64
)reg
) << 8) & (0xffULL
<< 32); /* 39:16 on 31:8*/
137 range
[hi_mmio_num
].start
= start
;
138 range
[hi_mmio_num
].end
= end
;
146 sort(range
, hi_mmio_num
, sizeof(struct range
), cmp_range
, NULL
);
148 if (range
[hi_mmio_num
- 1].end
< base
)
150 if (range
[0].start
> base
)
153 /* need to find one window */
154 base
= range
[0].start
- (1ULL << 32);
155 if ((base
> tom2
) && BASE_VALID(base
))
157 base
= range
[hi_mmio_num
- 1].end
+ (1ULL << 32);
158 if ((base
> tom2
) && BASE_VALID(base
))
160 /* need to find window between ranges */
162 for (i
= 0; i
< hi_mmio_num
- 1; i
++) {
163 if (range
[i
+ 1].start
> (range
[i
].end
+ (1ULL << 32))) {
164 base
= range
[i
].end
+ (1ULL << 32);
165 if ((base
> tom2
) && BASE_VALID(base
))
171 fam10h_pci_mmconf_base_status
= -1;
174 fam10h_pci_mmconf_base
= base
;
175 fam10h_pci_mmconf_base_status
= 1;
178 void __cpuinit
fam10h_check_enable_mmcfg(void)
183 if (!(pci_probe
& PCI_CHECK_ENABLE_AMD_MMCONF
))
186 address
= MSR_FAM10H_MMIO_CONF_BASE
;
187 rdmsrl(address
, val
);
189 /* try to make sure that AP's setting is identical to BSP setting */
190 if (val
& FAM10H_MMIO_CONF_ENABLE
) {
192 busnbits
= (val
>> FAM10H_MMIO_CONF_BUSRANGE_SHIFT
) &
193 FAM10H_MMIO_CONF_BUSRANGE_MASK
;
195 /* only trust the one handle 256 buses, if acpi=off */
196 if (!acpi_pci_disabled
|| busnbits
>= 8) {
198 base
= val
& (0xffffULL
<< 32);
199 if (fam10h_pci_mmconf_base_status
<= 0) {
200 fam10h_pci_mmconf_base
= base
;
201 fam10h_pci_mmconf_base_status
= 1;
203 } else if (fam10h_pci_mmconf_base
== base
)
209 * if it is not enabled, try to enable it and assume only one segment
212 get_fam10h_pci_mmconf_base();
213 if (fam10h_pci_mmconf_base_status
<= 0)
216 printk(KERN_INFO
"Enable MMCONFIG on AMD Family 10h\n");
217 val
&= ~((FAM10H_MMIO_CONF_BASE_MASK
<<FAM10H_MMIO_CONF_BASE_SHIFT
) |
218 (FAM10H_MMIO_CONF_BUSRANGE_MASK
<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT
));
219 val
|= fam10h_pci_mmconf_base
| (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT
) |
220 FAM10H_MMIO_CONF_ENABLE
;
221 wrmsrl(address
, val
);
224 static int __devinit
set_check_enable_amd_mmconf(const struct dmi_system_id
*d
)
226 pci_probe
|= PCI_CHECK_ENABLE_AMD_MMCONF
;
230 static struct dmi_system_id __devinitdata mmconf_dmi_table
[] = {
232 .callback
= set_check_enable_amd_mmconf
,
233 .ident
= "Sun Microsystems Machine",
235 DMI_MATCH(DMI_SYS_VENDOR
, "Sun Microsystems"),
241 void __init
check_enable_amd_mmconf_dmi(void)
243 dmi_check_system(mmconf_dmi_table
);