diff options
Diffstat (limited to 'arch/x86/pci/mmconfig-shared.c')
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 89bf9242c80a..d68dc1bb01b2 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
@@ -154,6 +154,68 @@ static const char __init *pci_mmcfg_amd_fam10h(void) | |||
154 | return "AMD Family 10h NB"; | 154 | return "AMD Family 10h NB"; |
155 | } | 155 | } |
156 | 156 | ||
157 | static bool __initdata mcp55_checked; | ||
158 | static const char __init *pci_mmcfg_nvidia_mcp55(void) | ||
159 | { | ||
160 | int bus; | ||
161 | int mcp55_mmconf_found = 0; | ||
162 | |||
163 | static const u32 extcfg_regnum = 0x90; | ||
164 | static const u32 extcfg_regsize = 4; | ||
165 | static const u32 extcfg_enable_mask = 1<<31; | ||
166 | static const u32 extcfg_start_mask = 0xff<<16; | ||
167 | static const int extcfg_start_shift = 16; | ||
168 | static const u32 extcfg_size_mask = 0x3<<28; | ||
169 | static const int extcfg_size_shift = 28; | ||
170 | static const int extcfg_sizebus[] = {0x100, 0x80, 0x40, 0x20}; | ||
171 | static const u32 extcfg_base_mask[] = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff}; | ||
172 | static const int extcfg_base_lshift = 25; | ||
173 | |||
174 | /* | ||
175 | * do check if amd fam10h already took over | ||
176 | */ | ||
177 | if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked) | ||
178 | return NULL; | ||
179 | |||
180 | mcp55_checked = true; | ||
181 | for (bus = 0; bus < 256; bus++) { | ||
182 | u64 base; | ||
183 | u32 l, extcfg; | ||
184 | u16 vendor, device; | ||
185 | int start, size_index, end; | ||
186 | |||
187 | raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l); | ||
188 | vendor = l & 0xffff; | ||
189 | device = (l >> 16) & 0xffff; | ||
190 | |||
191 | if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device) | ||
192 | continue; | ||
193 | |||
194 | raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum, | ||
195 | extcfg_regsize, &extcfg); | ||
196 | |||
197 | if (!(extcfg & extcfg_enable_mask)) | ||
198 | continue; | ||
199 | |||
200 | if (extend_mmcfg(1) == -1) | ||
201 | continue; | ||
202 | |||
203 | size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; | ||
204 | base = extcfg & extcfg_base_mask[size_index]; | ||
205 | /* base could > 4G */ | ||
206 | base <<= extcfg_base_lshift; | ||
207 | start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; | ||
208 | end = start + extcfg_sizebus[size_index] - 1; | ||
209 | fill_one_mmcfg(base, 0, start, end); | ||
210 | mcp55_mmconf_found++; | ||
211 | } | ||
212 | |||
213 | if (!mcp55_mmconf_found) | ||
214 | return NULL; | ||
215 | |||
216 | return "nVidia MCP55"; | ||
217 | } | ||
218 | |||
157 | struct pci_mmcfg_hostbridge_probe { | 219 | struct pci_mmcfg_hostbridge_probe { |
158 | u32 bus; | 220 | u32 bus; |
159 | u32 devfn; | 221 | u32 devfn; |
@@ -171,6 +233,8 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { | |||
171 | 0x1200, pci_mmcfg_amd_fam10h }, | 233 | 0x1200, pci_mmcfg_amd_fam10h }, |
172 | { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, | 234 | { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, |
173 | 0x1200, pci_mmcfg_amd_fam10h }, | 235 | 0x1200, pci_mmcfg_amd_fam10h }, |
236 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA, | ||
237 | 0x0369, pci_mmcfg_nvidia_mcp55 }, | ||
174 | }; | 238 | }; |
175 | 239 | ||
176 | static int __init pci_mmcfg_check_hostbridge(void) | 240 | static int __init pci_mmcfg_check_hostbridge(void) |