| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Shared support code for AMD K8 northbridges and derivates. |
|---|
| 3 | | - * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2. |
|---|
| 4 | + * Copyright 2006 Andi Kleen, SUSE Labs. |
|---|
| 4 | 5 | */ |
|---|
| 5 | 6 | |
|---|
| 6 | 7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 17 | 18 | #define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450 |
|---|
| 18 | 19 | #define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0 |
|---|
| 19 | 20 | #define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480 |
|---|
| 21 | +#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630 |
|---|
| 20 | 22 | #define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464 |
|---|
| 21 | 23 | #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec |
|---|
| 22 | 24 | #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494 |
|---|
| 25 | +#define PCI_DEVICE_ID_AMD_17H_M60H_DF_F4 0x144c |
|---|
| 23 | 26 | #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444 |
|---|
| 24 | 27 | #define PCI_DEVICE_ID_AMD_19H_DF_F4 0x1654 |
|---|
| 25 | 28 | |
|---|
| .. | .. |
|---|
| 32 | 35 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) }, |
|---|
| 33 | 36 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) }, |
|---|
| 34 | 37 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) }, |
|---|
| 38 | + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_ROOT) }, |
|---|
| 35 | 39 | {} |
|---|
| 36 | 40 | }; |
|---|
| 37 | 41 | |
|---|
| 38 | | - |
|---|
| 39 | 42 | #define PCI_DEVICE_ID_AMD_CNB17H_F4 0x1704 |
|---|
| 40 | 43 | |
|---|
| 41 | | -const struct pci_device_id amd_nb_misc_ids[] = { |
|---|
| 44 | +static const struct pci_device_id amd_nb_misc_ids[] = { |
|---|
| 42 | 45 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, |
|---|
| 43 | 46 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, |
|---|
| 44 | 47 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, |
|---|
| .. | .. |
|---|
| 50 | 53 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) }, |
|---|
| 51 | 54 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) }, |
|---|
| 52 | 55 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, |
|---|
| 56 | + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) }, |
|---|
| 53 | 57 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, |
|---|
| 54 | 58 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, |
|---|
| 55 | 59 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) }, |
|---|
| 56 | 60 | {} |
|---|
| 57 | 61 | }; |
|---|
| 58 | | -EXPORT_SYMBOL_GPL(amd_nb_misc_ids); |
|---|
| 59 | 62 | |
|---|
| 60 | 63 | static const struct pci_device_id amd_nb_link_ids[] = { |
|---|
| 61 | 64 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, |
|---|
| .. | .. |
|---|
| 66 | 69 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) }, |
|---|
| 67 | 70 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) }, |
|---|
| 68 | 71 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) }, |
|---|
| 72 | + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F4) }, |
|---|
| 69 | 73 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) }, |
|---|
| 70 | 74 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F4) }, |
|---|
| 71 | 75 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) }, |
|---|
| 76 | + {} |
|---|
| 77 | +}; |
|---|
| 78 | + |
|---|
| 79 | +static const struct pci_device_id hygon_root_ids[] = { |
|---|
| 80 | + { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_ROOT) }, |
|---|
| 81 | + {} |
|---|
| 82 | +}; |
|---|
| 83 | + |
|---|
| 84 | +static const struct pci_device_id hygon_nb_misc_ids[] = { |
|---|
| 85 | + { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, |
|---|
| 86 | + {} |
|---|
| 87 | +}; |
|---|
| 88 | + |
|---|
| 89 | +static const struct pci_device_id hygon_nb_link_ids[] = { |
|---|
| 90 | + { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F4) }, |
|---|
| 72 | 91 | {} |
|---|
| 73 | 92 | }; |
|---|
| 74 | 93 | |
|---|
| .. | .. |
|---|
| 205 | 224 | |
|---|
| 206 | 225 | int amd_cache_northbridges(void) |
|---|
| 207 | 226 | { |
|---|
| 208 | | - u16 i = 0; |
|---|
| 209 | | - struct amd_northbridge *nb; |
|---|
| 227 | + const struct pci_device_id *misc_ids = amd_nb_misc_ids; |
|---|
| 228 | + const struct pci_device_id *link_ids = amd_nb_link_ids; |
|---|
| 229 | + const struct pci_device_id *root_ids = amd_root_ids; |
|---|
| 210 | 230 | struct pci_dev *root, *misc, *link; |
|---|
| 231 | + struct amd_northbridge *nb; |
|---|
| 232 | + u16 roots_per_misc = 0; |
|---|
| 233 | + u16 misc_count = 0; |
|---|
| 234 | + u16 root_count = 0; |
|---|
| 235 | + u16 i, j; |
|---|
| 211 | 236 | |
|---|
| 212 | 237 | if (amd_northbridges.num) |
|---|
| 213 | 238 | return 0; |
|---|
| 214 | 239 | |
|---|
| 215 | | - misc = NULL; |
|---|
| 216 | | - while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL) |
|---|
| 217 | | - i++; |
|---|
| 240 | + if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) { |
|---|
| 241 | + root_ids = hygon_root_ids; |
|---|
| 242 | + misc_ids = hygon_nb_misc_ids; |
|---|
| 243 | + link_ids = hygon_nb_link_ids; |
|---|
| 244 | + } |
|---|
| 218 | 245 | |
|---|
| 219 | | - if (!i) |
|---|
| 246 | + misc = NULL; |
|---|
| 247 | + while ((misc = next_northbridge(misc, misc_ids)) != NULL) |
|---|
| 248 | + misc_count++; |
|---|
| 249 | + |
|---|
| 250 | + if (!misc_count) |
|---|
| 220 | 251 | return -ENODEV; |
|---|
| 221 | 252 | |
|---|
| 222 | | - nb = kcalloc(i, sizeof(struct amd_northbridge), GFP_KERNEL); |
|---|
| 253 | + root = NULL; |
|---|
| 254 | + while ((root = next_northbridge(root, root_ids)) != NULL) |
|---|
| 255 | + root_count++; |
|---|
| 256 | + |
|---|
| 257 | + if (root_count) { |
|---|
| 258 | + roots_per_misc = root_count / misc_count; |
|---|
| 259 | + |
|---|
| 260 | + /* |
|---|
| 261 | + * There should be _exactly_ N roots for each DF/SMN |
|---|
| 262 | + * interface. |
|---|
| 263 | + */ |
|---|
| 264 | + if (!roots_per_misc || (root_count % roots_per_misc)) { |
|---|
| 265 | + pr_info("Unsupported AMD DF/PCI configuration found\n"); |
|---|
| 266 | + return -ENODEV; |
|---|
| 267 | + } |
|---|
| 268 | + } |
|---|
| 269 | + |
|---|
| 270 | + nb = kcalloc(misc_count, sizeof(struct amd_northbridge), GFP_KERNEL); |
|---|
| 223 | 271 | if (!nb) |
|---|
| 224 | 272 | return -ENOMEM; |
|---|
| 225 | 273 | |
|---|
| 226 | 274 | amd_northbridges.nb = nb; |
|---|
| 227 | | - amd_northbridges.num = i; |
|---|
| 275 | + amd_northbridges.num = misc_count; |
|---|
| 228 | 276 | |
|---|
| 229 | 277 | link = misc = root = NULL; |
|---|
| 230 | | - for (i = 0; i != amd_northbridges.num; i++) { |
|---|
| 278 | + for (i = 0; i < amd_northbridges.num; i++) { |
|---|
| 231 | 279 | node_to_amd_nb(i)->root = root = |
|---|
| 232 | | - next_northbridge(root, amd_root_ids); |
|---|
| 280 | + next_northbridge(root, root_ids); |
|---|
| 233 | 281 | node_to_amd_nb(i)->misc = misc = |
|---|
| 234 | | - next_northbridge(misc, amd_nb_misc_ids); |
|---|
| 282 | + next_northbridge(misc, misc_ids); |
|---|
| 235 | 283 | node_to_amd_nb(i)->link = link = |
|---|
| 236 | | - next_northbridge(link, amd_nb_link_ids); |
|---|
| 284 | + next_northbridge(link, link_ids); |
|---|
| 285 | + |
|---|
| 286 | + /* |
|---|
| 287 | + * If there are more PCI root devices than data fabric/ |
|---|
| 288 | + * system management network interfaces, then the (N) |
|---|
| 289 | + * PCI roots per DF/SMN interface are functionally the |
|---|
| 290 | + * same (for DF/SMN access) and N-1 are redundant. N-1 |
|---|
| 291 | + * PCI roots should be skipped per DF/SMN interface so |
|---|
| 292 | + * the following DF/SMN interfaces get mapped to |
|---|
| 293 | + * correct PCI roots. |
|---|
| 294 | + */ |
|---|
| 295 | + for (j = 1; j < roots_per_misc; j++) |
|---|
| 296 | + root = next_northbridge(root, root_ids); |
|---|
| 237 | 297 | } |
|---|
| 238 | 298 | |
|---|
| 239 | 299 | if (amd_gart_present()) |
|---|
| .. | .. |
|---|
| 272 | 332 | */ |
|---|
| 273 | 333 | bool __init early_is_amd_nb(u32 device) |
|---|
| 274 | 334 | { |
|---|
| 335 | + const struct pci_device_id *misc_ids = amd_nb_misc_ids; |
|---|
| 275 | 336 | const struct pci_device_id *id; |
|---|
| 276 | 337 | u32 vendor = device & 0xffff; |
|---|
| 277 | 338 | |
|---|
| 339 | + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && |
|---|
| 340 | + boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) |
|---|
| 341 | + return false; |
|---|
| 342 | + |
|---|
| 343 | + if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) |
|---|
| 344 | + misc_ids = hygon_nb_misc_ids; |
|---|
| 345 | + |
|---|
| 278 | 346 | device >>= 16; |
|---|
| 279 | | - for (id = amd_nb_misc_ids; id->vendor; id++) |
|---|
| 347 | + for (id = misc_ids; id->vendor; id++) |
|---|
| 280 | 348 | if (vendor == id->vendor && device == id->device) |
|---|
| 281 | 349 | return true; |
|---|
| 282 | 350 | return false; |
|---|
| .. | .. |
|---|
| 288 | 356 | u64 base, msr; |
|---|
| 289 | 357 | unsigned int segn_busn_bits; |
|---|
| 290 | 358 | |
|---|
| 291 | | - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) |
|---|
| 359 | + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && |
|---|
| 360 | + boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) |
|---|
| 292 | 361 | return NULL; |
|---|
| 293 | 362 | |
|---|
| 294 | 363 | /* assume all cpus from fam10h have mmconfig */ |
|---|