summaryrefslogtreecommitdiff
path: root/src/cpu/amd/quadcore/quadcore_id.c
blob: f3e9f4b3467e4a0f9a7c2c4a1eb4c6f9fd3f887c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>,
 *		      Raptor Engineering
 * Copyright (C) 2007 Advanced Micro Devices, Inc.
 *
 * 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;

#ifdef __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;

#ifdef __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());
}