2 * AMD Family 10h mmconfig enablement
5 #include <linux/types.h>
7 #include <linux/string.h>
10 #include <linux/range.h>
12 #include <asm/pci-direct.h>
13 #include <linux/sort.h>
17 #include <asm/mmconfig.h>
18 #include <asm/pci_x86.h>
20 struct pci_hostbridge_probe
{
27 static u64 __cpuinitdata fam10h_pci_mmconf_base
;
28 static int __cpuinitdata fam10h_pci_mmconf_base_status
;
30 static struct pci_hostbridge_probe pci_probes
[] __cpuinitdata
= {
31 { 0, 0x18, PCI_VENDOR_ID_AMD
, 0x1200 },
32 { 0xff, 0, PCI_VENDOR_ID_AMD
, 0x1200 },
35 static int __cpuinit
cmp_range(const void *x1
, const void *x2
)
37 const struct range
*r1
= x1
;
38 const struct range
*r2
= x2
;
41 start1
= r1
->start
>> 32;
42 start2
= r2
->start
>> 32;
44 return start1
- start2
;
48 /* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
49 #define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
50 #define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
51 static void __cpuinit
get_fam10h_pci_mmconf_base(void)
61 u64 base
= FAM10H_PCI_MMCONF_BASE
;
64 struct range range
[8];
66 /* only try to get setting from BSP */
68 if (fam10h_pci_mmconf_base_status
)
71 if (!early_pci_allowed())
75 for (i
= 0; i
< ARRAY_SIZE(pci_probes
); i
++) {
80 bus
= pci_probes
[i
].bus
;
81 slot
= pci_probes
[i
].slot
;
82 id
= read_pci_config(bus
, slot
, 0, PCI_VENDOR_ID
);
85 device
= (id
>>16) & 0xffff;
86 if (pci_probes
[i
].vendor
== vendor
&&
87 pci_probes
[i
].device
== device
) {
97 address
= MSR_K8_SYSCFG
;
100 /* TOP_MEM2 is not enabled? */
101 if (!(val
& (1<<21))) {
105 address
= MSR_K8_TOP_MEM2
;
106 rdmsrl(address
, val
);
107 tom2
= val
& (0xffffULL
<<32);
111 base
= tom2
+ (1ULL<<32);
114 * need to check if the range is in the high mmio range that is
118 for (i
= 0; i
< 8; i
++) {
122 reg
= read_pci_config(bus
, slot
, 1, 0x80 + (i
<< 3));
126 start
= (((u64
)reg
) << 8) & (0xffULL
<< 32); /* 39:16 on 31:8*/
127 reg
= read_pci_config(bus
, slot
, 1, 0x84 + (i
<< 3));
128 end
= (((u64
)reg
) << 8) & (0xffULL
<< 32); /* 39:16 on 31:8*/
133 range
[hi_mmio_num
].start
= start
;
134 range
[hi_mmio_num
].end
= end
;
142 sort(range
, hi_mmio_num
, sizeof(struct range
), cmp_range
, NULL
);
144 if (range
[hi_mmio_num
- 1].end
< base
)
146 if (range
[0].start
> base
)
149 /* need to find one window */
150 base
= range
[0].start
- (1ULL << 32);
151 if ((base
> tom2
) && BASE_VALID(base
))
153 base
= range
[hi_mmio_num
- 1].end
+ (1ULL << 32);
154 if ((base
> tom2
) && BASE_VALID(base
))
156 /* need to find window between ranges */
158 for (i
= 0; i
< hi_mmio_num
- 1; i
++) {
159 if (range
[i
+ 1].start
> (range
[i
].end
+ (1ULL << 32))) {
160 base
= range
[i
].end
+ (1ULL << 32);
161 if ((base
> tom2
) && BASE_VALID(base
))
167 fam10h_pci_mmconf_base_status
= -1;
170 fam10h_pci_mmconf_base
= base
;
171 fam10h_pci_mmconf_base_status
= 1;
174 void __cpuinit
fam10h_check_enable_mmcfg(void)
179 if (!(pci_probe
& PCI_CHECK_ENABLE_AMD_MMCONF
))
182 address
= MSR_FAM10H_MMIO_CONF_BASE
;
183 rdmsrl(address
, val
);
185 /* try to make sure that AP's setting is identical to BSP setting */
186 if (val
& FAM10H_MMIO_CONF_ENABLE
) {
188 busnbits
= (val
>> FAM10H_MMIO_CONF_BUSRANGE_SHIFT
) &
189 FAM10H_MMIO_CONF_BUSRANGE_MASK
;
191 /* only trust the one handle 256 buses, if acpi=off */
192 if (!acpi_pci_disabled
|| busnbits
>= 8) {
194 base
= val
& (0xffffULL
<< 32);
195 if (fam10h_pci_mmconf_base_status
<= 0) {
196 fam10h_pci_mmconf_base
= base
;
197 fam10h_pci_mmconf_base_status
= 1;
199 } else if (fam10h_pci_mmconf_base
== base
)
205 * if it is not enabled, try to enable it and assume only one segment
208 get_fam10h_pci_mmconf_base();
209 if (fam10h_pci_mmconf_base_status
<= 0)
212 printk(KERN_INFO
"Enable MMCONFIG on AMD Family 10h\n");
213 val
&= ~((FAM10H_MMIO_CONF_BASE_MASK
<<FAM10H_MMIO_CONF_BASE_SHIFT
) |
214 (FAM10H_MMIO_CONF_BUSRANGE_MASK
<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT
));
215 val
|= fam10h_pci_mmconf_base
| (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT
) |
216 FAM10H_MMIO_CONF_ENABLE
;
217 wrmsrl(address
, val
);
220 static int __init
set_check_enable_amd_mmconf(const struct dmi_system_id
*d
)
222 pci_probe
|= PCI_CHECK_ENABLE_AMD_MMCONF
;
226 static const struct dmi_system_id __initconst mmconf_dmi_table
[] = {
228 .callback
= set_check_enable_amd_mmconf
,
229 .ident
= "Sun Microsystems Machine",
231 DMI_MATCH(DMI_SYS_VENDOR
, "Sun Microsystems"),
237 /* Called from a __cpuinit function, but only on the BSP. */
238 void __ref
check_enable_amd_mmconf_dmi(void)
240 dmi_check_system(mmconf_dmi_table
);