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>
16 #include <asm/pci_x86.h>
18 struct pci_hostbridge_probe
{
25 static u64 __cpuinitdata fam10h_pci_mmconf_base
;
26 static int __cpuinitdata fam10h_pci_mmconf_base_status
;
28 static struct pci_hostbridge_probe pci_probes
[] __cpuinitdata
= {
29 { 0, 0x18, PCI_VENDOR_ID_AMD
, 0x1200 },
30 { 0xff, 0, PCI_VENDOR_ID_AMD
, 0x1200 },
38 static int __cpuinit
cmp_range(const void *x1
, const void *x2
)
40 const struct range
*r1
= x1
;
41 const struct range
*r2
= x2
;
44 start1
= r1
->start
>> 32;
45 start2
= r2
->start
>> 32;
47 return start1
- start2
;
51 /* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
52 #define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
53 #define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
54 static void __cpuinit
get_fam10h_pci_mmconf_base(void)
64 u64 base
= FAM10H_PCI_MMCONF_BASE
;
67 struct range range
[8];
69 /* only try to get setting from BSP */
71 if (fam10h_pci_mmconf_base_status
)
74 if (!early_pci_allowed())
78 for (i
= 0; i
< ARRAY_SIZE(pci_probes
); i
++) {
83 bus
= pci_probes
[i
].bus
;
84 slot
= pci_probes
[i
].slot
;
85 id
= read_pci_config(bus
, slot
, 0, PCI_VENDOR_ID
);
88 device
= (id
>>16) & 0xffff;
89 if (pci_probes
[i
].vendor
== vendor
&&
90 pci_probes
[i
].device
== device
) {
100 address
= MSR_K8_SYSCFG
;
101 rdmsrl(address
, val
);
103 /* TOP_MEM2 is not enabled? */
104 if (!(val
& (1<<21))) {
108 address
= MSR_K8_TOP_MEM2
;
109 rdmsrl(address
, val
);
110 tom2
= val
& (0xffffULL
<<32);
114 base
= tom2
+ (1ULL<<32);
117 * need to check if the range is in the high mmio range that is
121 for (i
= 0; i
< 8; i
++) {
125 reg
= read_pci_config(bus
, slot
, 1, 0x80 + (i
<< 3));
129 start
= (((u64
)reg
) << 8) & (0xffULL
<< 32); /* 39:16 on 31:8*/
130 reg
= read_pci_config(bus
, slot
, 1, 0x84 + (i
<< 3));
131 end
= (((u64
)reg
) << 8) & (0xffULL
<< 32); /* 39:16 on 31:8*/
136 range
[hi_mmio_num
].start
= start
;
137 range
[hi_mmio_num
].end
= end
;
145 sort(range
, hi_mmio_num
, sizeof(struct range
), cmp_range
, NULL
);
147 if (range
[hi_mmio_num
- 1].end
< base
)
149 if (range
[0].start
> base
)
152 /* need to find one window */
153 base
= range
[0].start
- (1ULL << 32);
154 if ((base
> tom2
) && BASE_VALID(base
))
156 base
= range
[hi_mmio_num
- 1].end
+ (1ULL << 32);
157 if ((base
> tom2
) && BASE_VALID(base
))
159 /* need to find window between ranges */
161 for (i
= 0; i
< hi_mmio_num
- 1; i
++) {
162 if (range
[i
+ 1].start
> (range
[i
].end
+ (1ULL << 32))) {
163 base
= range
[i
].end
+ (1ULL << 32);
164 if ((base
> tom2
) && BASE_VALID(base
))
170 fam10h_pci_mmconf_base_status
= -1;
173 fam10h_pci_mmconf_base
= base
;
174 fam10h_pci_mmconf_base_status
= 1;
177 void __cpuinit
fam10h_check_enable_mmcfg(void)
182 if (!(pci_probe
& PCI_CHECK_ENABLE_AMD_MMCONF
))
185 address
= MSR_FAM10H_MMIO_CONF_BASE
;
186 rdmsrl(address
, val
);
188 /* try to make sure that AP's setting is identical to BSP setting */
189 if (val
& FAM10H_MMIO_CONF_ENABLE
) {
191 busnbits
= (val
>> FAM10H_MMIO_CONF_BUSRANGE_SHIFT
) &
192 FAM10H_MMIO_CONF_BUSRANGE_MASK
;
194 /* only trust the one handle 256 buses, if acpi=off */
195 if (!acpi_pci_disabled
|| busnbits
>= 8) {
197 base
= val
& (0xffffULL
<< 32);
198 if (fam10h_pci_mmconf_base_status
<= 0) {
199 fam10h_pci_mmconf_base
= base
;
200 fam10h_pci_mmconf_base_status
= 1;
202 } else if (fam10h_pci_mmconf_base
== base
)
208 * if it is not enabled, try to enable it and assume only one segment
211 get_fam10h_pci_mmconf_base();
212 if (fam10h_pci_mmconf_base_status
<= 0)
215 printk(KERN_INFO
"Enable MMCONFIG on AMD Family 10h\n");
216 val
&= ~((FAM10H_MMIO_CONF_BASE_MASK
<<FAM10H_MMIO_CONF_BASE_SHIFT
) |
217 (FAM10H_MMIO_CONF_BUSRANGE_MASK
<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT
));
218 val
|= fam10h_pci_mmconf_base
| (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT
) |
219 FAM10H_MMIO_CONF_ENABLE
;
220 wrmsrl(address
, val
);
223 static int __devinit
set_check_enable_amd_mmconf(const struct dmi_system_id
*d
)
225 pci_probe
|= PCI_CHECK_ENABLE_AMD_MMCONF
;
229 static struct dmi_system_id __devinitdata mmconf_dmi_table
[] = {
231 .callback
= set_check_enable_amd_mmconf
,
232 .ident
= "Sun Microsystems Machine",
234 DMI_MATCH(DMI_SYS_VENDOR
, "Sun Microsystems"),
240 void __cpuinit
check_enable_amd_mmconf_dmi(void)
242 dmi_check_system(mmconf_dmi_table
);