/** * early_root_info_init() * called before pcibios_scan_root and pci_scan_bus * fills the mp_bus_to_cpumask array based according * to the LDT Bus Number Registers found in the northbridge.
*/ staticint __init early_root_info_init(void)
{ int i; unsigned bus; unsigned slot; int node; int link; int def_node; int def_link; struct pci_root_info *info;
u32 reg;
u64 start;
u64 end; struct range range[RANGE_NUM];
u64 val;
u32 address; bool found; struct resource fam10h_mmconf_res, *fam10h_mmconf;
u64 fam10h_mmconf_start;
u64 fam10h_mmconf_end;
if (!early_pci_allowed()) return -1;
found = false; for (i = 0; i < ARRAY_SIZE(hb_probes); i++) {
u32 id;
u16 device;
u16 vendor;
bus = hb_probes[i].bus;
slot = hb_probes[i].slot;
id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
vendor = id & 0xffff;
device = (id>>16) & 0xffff;
if (vendor != PCI_VENDOR_ID_AMD &&
vendor != PCI_VENDOR_ID_HYGON) continue;
if (hb_probes[i].device == device) {
found = true; break;
}
}
if (!found) return 0;
/* * We should learn topology and routing information from _PXM and * _CRS methods in the ACPI namespace. We extract node numbers * here to work around BIOSes that don't supply _PXM.
*/ for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) { int min_bus; int max_bus;
reg = read_pci_config(bus, slot, 1,
AMD_NB_F1_CONFIG_MAP_REG + (i << 2));
/* Check if that register is enabled for bus range */ if ((reg & 7) != 3) continue;
/* * The following code extracts routing information for use on old * systems where Linux doesn't automatically use host bridge _CRS * methods (or when the user specifies "pci=nocrs"). * * We only do this through Fam11h, because _CRS should be enough on * newer systems.
*/ if (boot_cpu_data.x86 > 0x11) return 0;
/* get the default node and link for left over res */
reg = read_pci_config(bus, slot, 0, AMD_NB_F0_NODE_ID);
def_node = (reg >> 8) & 0x07;
reg = read_pci_config(bus, slot, 0, AMD_NB_F0_UNIT_ID);
def_link = (reg >> 8) & 0x03;
memset(range, 0, sizeof(range));
add_range(range, RANGE_NUM, 0, 0, 0xffff + 1); /* io port resource */ for (i = 0; i < 4; i++) {
reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); if (!(reg & 3)) continue;
info = find_pci_root_info(node, link); if (!info) continue; /* not found */
printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n",
node, link, start, end);
/* kernel only handle 16 bit only */ if (end > 0xffff)
end = 0xffff;
update_res(info, start, end, IORESOURCE_IO, 1);
subtract_range(range, RANGE_NUM, start, end + 1);
} /* add left over io port range to def node/link, [0, 0xffff] */ /* find the position */
info = find_pci_root_info(def_node, def_link); if (info) { for (i = 0; i < RANGE_NUM; i++) { if (!range[i].end) continue;
memset(range, 0, sizeof(range)); /* 0xfd00000000-0xffffffffff for HT */
end = cap_resource((0xfdULL<<32) - 1);
end++;
add_range(range, RANGE_NUM, 0, 0, end);
/* need to take out [0, TOM) for RAM*/
address = MSR_K8_TOP_MEM1;
rdmsrq(address, val);
end = (val & 0xffffff800000ULL);
printk(KERN_INFO "TOM: %016llx aka %lldM\n", end, end>>20); if (end < (1ULL<<32))
subtract_range(range, RANGE_NUM, 0, end);
/* get mmconfig */
fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res); /* need to take out mmconf range */ if (fam10h_mmconf) {
printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf);
fam10h_mmconf_start = fam10h_mmconf->start;
fam10h_mmconf_end = fam10h_mmconf->end;
subtract_range(range, RANGE_NUM, fam10h_mmconf_start,
fam10h_mmconf_end + 1);
} else {
fam10h_mmconf_start = 0;
fam10h_mmconf_end = 0;
}
/* mmio resource */ for (i = 0; i < 8; i++) {
reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3)); if (!(reg & 3)) continue;
start = reg & 0xffffff00; /* 39:16 on 31:8*/
start <<= 8;
reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
node = reg & 0x07;
link = (reg >> 4) & 0x03;
end = (reg & 0xffffff00);
end <<= 8;
end |= 0xffff;
info = find_pci_root_info(node, link);
if (!info) continue;
printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]",
node, link, start, end); /* * some sick allocation would have range overlap with fam10h * mmconf range, so need to update start and end.
*/ if (fam10h_mmconf_end) { int changed = 0;
u64 endx = 0; if (start >= fam10h_mmconf_start &&
start <= fam10h_mmconf_end) {
start = fam10h_mmconf_end + 1;
changed = 1;
}
if (end >= fam10h_mmconf_start &&
end <= fam10h_mmconf_end) {
end = fam10h_mmconf_start - 1;
changed = 1;
}
/* need to take out [4G, TOM2) for RAM*/ /* SYS_CFG */
address = MSR_AMD64_SYSCFG;
rdmsrq(address, val); /* TOP_MEM2 is enabled? */ if (val & (1<<21)) { /* TOP_MEM2 */
address = MSR_K8_TOP_MEM2;
rdmsrq(address, val);
end = (val & 0xffffff800000ULL);
printk(KERN_INFO "TOM2: %016llx aka %lldM\n", end, end>>20);
subtract_range(range, RANGE_NUM, 1ULL<<32, end);
}
/* * add left over mmio range to def node/link ? * that is tricky, just record range in from start_min to 4G
*/
info = find_pci_root_info(def_node, def_link); if (info) { for (i = 0; i < RANGE_NUM; i++) { if (!range[i].end) continue;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.10Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.