blob: 7ec1bdb4f61c11913564e1880ac2378d5f10a698 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <arch/cpu.h>
#include <cpu/amd/msr.h>
#include <cpu/amd/multicore.h>
#include <device/pci_ops.h>
//called by bus_cpu_scan too
u32 read_nb_cfg_54(void)
{
msr_t msr;
msr = rdmsr(NB_CFG_MSR);
return (msr.hi >> (54-32)) & 1;
}
u32 get_initial_apicid(void)
{
return (cpuid_ebx(1) >> 24) & 0xff;
}
/* Called by amd_siblings (ramstage) as well */
struct node_core_id get_node_core_id(u32 nb_cfg_54)
{
struct node_core_id id;
uint8_t apicid;
uint8_t fam15h = 0;
uint8_t rev_gte_d = 0;
uint8_t dual_node = 0;
uint32_t f3xe8;
uint32_t family;
uint32_t model;
#if ENV_PCI_SIMPLE_DEVICE
f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
#else
f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
#endif
family = model = cpuid_eax(0x80000001);
model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
if (family >= 0x6f) {
/* Family 15h or later */
fam15h = 1;
nb_cfg_54 = 1;
}
if ((model >= 0x8) || fam15h)
/* Revision D or later */
rev_gte_d = 1;
if (rev_gte_d)
/* Check for dual node capability */
if (f3xe8 & 0x20000000)
dual_node = 1;
/* Get the apicid via cpuid(1) ebx[31:24]
* The apicid format varies based on processor revision
*/
apicid = (cpuid_ebx(1) >> 24) & 0xff;
if (nb_cfg_54) {
if (fam15h && dual_node) {
id.coreid = apicid & 0x1f;
id.nodeid = (apicid & 0x60) >> 5;
} else if (fam15h && !dual_node) {
id.coreid = apicid & 0xf;
id.nodeid = (apicid & 0x70) >> 4;
} else if (rev_gte_d && dual_node) {
id.coreid = apicid & 0xf;
id.nodeid = (apicid & 0x30) >> 4;
} else if (rev_gte_d && !dual_node) {
id.coreid = apicid & 0x7;
id.nodeid = (apicid & 0x38) >> 3;
} else {
id.coreid = apicid & 0x3;
id.nodeid = (apicid & 0x1c) >> 2;
}
} else {
if (rev_gte_d && dual_node) {
id.coreid = (apicid & 0xf0) >> 4;
id.nodeid = apicid & 0x3;
} else if (rev_gte_d && !dual_node) {
id.coreid = (apicid & 0xe0) >> 5;
id.nodeid = apicid & 0x7;
} else {
id.coreid = (apicid & 0x60) >> 5;
id.nodeid = apicid & 0x7;
}
}
if (fam15h && dual_node) {
/* coreboot expects each separate processor die to be on a
* different nodeid.
* Since the code above returns nodeid 0 even on
* internal node 1 some fixup is needed...
*/
uint32_t f5x84;
uint8_t core_count;
#if ENV_PCI_SIMPLE_DEVICE
f5x84 = pci_read_config32(NODE_PCI(0, 5), 0x84);
#else
f5x84 = pci_read_config32(get_node_pci(0, 5), 0x84);
#endif
core_count = (f5x84 & 0xff) + 1;
id.nodeid = id.nodeid * 2;
if (id.coreid >= core_count) {
id.nodeid += 1;
id.coreid = id.coreid - core_count;
}
} else if (rev_gte_d && dual_node) {
/* coreboot expects each separate processor die to be on a
* different nodeid.
* Since the code above returns nodeid 0 even on
* internal node 1 some fixup is needed...
*/
uint8_t core_count = (((f3xe8 & 0x00008000) >> 13) |
((f3xe8 & 0x00003000) >> 12)) + 1;
id.nodeid = id.nodeid * 2;
if (id.coreid >= core_count) {
id.nodeid += 1;
id.coreid = id.coreid - core_count;
}
}
return id;
}
#ifdef UNUSED_CODE
static u32 get_core_num(void)
{
return (cpuid_ecx(0x80000008) & 0xff);
}
#endif
struct node_core_id get_node_core_id_x(void)
{
return get_node_core_id(read_nb_cfg_54());
}