blob: aeb58748aeaa781b873606d34af5e599d5ffe378 [file] [log] [blame]
Damien Roth07a196e2016-01-19 20:20:15 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000014#include <console/console.h>
15#include <cpu/cpu.h>
16#include <cpu/x86/lapic.h>
17#include <cpu/intel/hyperthreading.h>
18#include <device/device.h>
19#include <pc80/mc146818rtc.h>
20#include <smp/spinlock.h>
Kyösti Mälkki8b28d502012-03-09 17:02:37 +020021#include <assert.h>
22
Kyösti Mälkki5c3f3842014-05-08 15:27:15 +030023#if CONFIG_PARALLEL_CPU_INIT
Elyes HAOUASd82be922016-07-28 18:58:27 +020024#error Intel hyper-threading requires serialized CPU init
Sven Schnelle51676b12012-07-29 19:18:03 +020025#endif
26
27static int first_time = 1;
28static int disable_siblings = !CONFIG_LOGICAL_CPUS;
29
Kyösti Mälkki9ed14562012-06-27 16:14:49 +030030/* Return true if running thread does not have the smallest lapic ID
31 * within a CPU core.
32 */
33int intel_ht_sibling(void)
34{
35 unsigned int core_ids, apic_ids, threads;
36
37 apic_ids = 1;
38 if (cpuid_eax(0) >= 1)
39 apic_ids = (cpuid_ebx(1) >> 16) & 0xff;
40 if (apic_ids < 1)
41 apic_ids = 1;
42
43 core_ids = 1;
Kyösti Mälkkidf0fbc72012-07-04 12:02:58 +030044 if (cpuid_eax(0) >= 4) {
45 struct cpuid_result result;
46 result = cpuid_ext(4, 0);
47 core_ids += (result.eax >> 26) & 0x3f;
48 }
Kyösti Mälkki9ed14562012-06-27 16:14:49 +030049
50 threads = (apic_ids / core_ids);
51 return !!(lapicid() & (threads-1));
52}
Sven Schnelle51676b12012-07-29 19:18:03 +020053
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110054void intel_sibling_init(struct device *cpu)
Sven Schnelle51676b12012-07-29 19:18:03 +020055{
56 unsigned i, siblings;
57 struct cpuid_result result;
58
59 /* On the bootstrap processor see if I want sibling cpus enabled */
60 if (first_time) {
61 first_time = 0;
62 get_option(&disable_siblings, "hyper_threading");
63 }
64 result = cpuid(1);
65 /* Is hyperthreading supported */
66 if (!(result.edx & (1 << 28))) {
67 return;
68 }
69 /* See how many sibling cpus we have */
70 siblings = (result.ebx >> 16) & 0xff;
71 if (siblings < 1) {
72 siblings = 1;
73 }
74
75 printk(BIOS_DEBUG, "CPU: %u %d siblings\n",
76 cpu->path.apic.apic_id,
77 siblings);
78
79 /* See if I am a sibling cpu */
80 if (cpu->path.apic.apic_id & (siblings -1)) {
81 if (disable_siblings) {
82 cpu->enabled = 0;
83 }
84 return;
85 }
86
Elyes HAOUASd82be922016-07-28 18:58:27 +020087 /* I am the primary CPU start up my siblings */
Elyes HAOUAScbe7464c2016-08-23 21:07:28 +020088 for (i = 1; i < siblings; i++) {
Sven Schnelle51676b12012-07-29 19:18:03 +020089 struct device_path cpu_path;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110090 struct device *new;
Elyes HAOUASd82be922016-07-28 18:58:27 +020091 /* Build the CPU device path */
Sven Schnelle51676b12012-07-29 19:18:03 +020092 cpu_path.type = DEVICE_PATH_APIC;
93 cpu_path.apic.apic_id = cpu->path.apic.apic_id + i;
94
95
Elyes HAOUASd82be922016-07-28 18:58:27 +020096 /* Allocate new CPU device structure iff sibling CPU
Sven Schnelle51676b12012-07-29 19:18:03 +020097 * was not in static device tree.
98 */
99 new = alloc_find_dev(cpu->bus, &cpu_path);
100
101 if (!new) {
102 continue;
103 }
104
105 printk(BIOS_DEBUG, "CPU: %u has sibling %u\n",
106 cpu->path.apic.apic_id,
107 new->path.apic.apic_id);
108 }
109}