]>
Commit | Line | Data |
---|---|---|
247c9de1 EH |
1 | /* |
2 | * x86 CPU topology data structures and functions | |
3 | * | |
4 | * Copyright (c) 2012 Red Hat Inc. | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | * of this software and associated documentation files (the "Software"), to deal | |
8 | * in the Software without restriction, including without limitation the rights | |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | * copies of the Software, and to permit persons to whom the Software is | |
11 | * furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | * THE SOFTWARE. | |
23 | */ | |
24 | #ifndef TARGET_I386_TOPOLOGY_H | |
25 | #define TARGET_I386_TOPOLOGY_H | |
26 | ||
27 | /* This file implements the APIC-ID-based CPU topology enumeration logic, | |
28 | * documented at the following document: | |
29 | * IntelĀ® 64 Architecture Processor Topology Enumeration | |
30 | * http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ | |
31 | * | |
32 | * This code should be compatible with AMD's "Extended Method" described at: | |
33 | * AMD CPUID Specification (Publication #25481) | |
34 | * Section 3: Multiple Core Calcuation | |
35 | * as long as: | |
36 | * nr_threads is set to 1; | |
37 | * OFFSET_IDX is assumed to be 0; | |
38 | * CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). | |
39 | */ | |
40 | ||
41 | #include <stdint.h> | |
42 | #include <string.h> | |
43 | ||
44 | #include "qemu/bitops.h" | |
45 | ||
46 | /* APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support | |
47 | */ | |
48 | typedef uint32_t apic_id_t; | |
49 | ||
50 | /* Return the bit width needed for 'count' IDs | |
51 | */ | |
52 | static unsigned apicid_bitwidth_for_count(unsigned count) | |
53 | { | |
54 | g_assert(count >= 1); | |
14e53426 RH |
55 | count -= 1; |
56 | return count ? 32 - clz32(count) : 0; | |
247c9de1 EH |
57 | } |
58 | ||
59 | /* Bit width of the SMT_ID (thread ID) field on the APIC ID | |
60 | */ | |
61 | static inline unsigned apicid_smt_width(unsigned nr_cores, unsigned nr_threads) | |
62 | { | |
63 | return apicid_bitwidth_for_count(nr_threads); | |
64 | } | |
65 | ||
66 | /* Bit width of the Core_ID field | |
67 | */ | |
68 | static inline unsigned apicid_core_width(unsigned nr_cores, unsigned nr_threads) | |
69 | { | |
70 | return apicid_bitwidth_for_count(nr_cores); | |
71 | } | |
72 | ||
73 | /* Bit offset of the Core_ID field | |
74 | */ | |
75 | static inline unsigned apicid_core_offset(unsigned nr_cores, | |
76 | unsigned nr_threads) | |
77 | { | |
78 | return apicid_smt_width(nr_cores, nr_threads); | |
79 | } | |
80 | ||
81 | /* Bit offset of the Pkg_ID (socket ID) field | |
82 | */ | |
83 | static inline unsigned apicid_pkg_offset(unsigned nr_cores, unsigned nr_threads) | |
84 | { | |
85 | return apicid_core_offset(nr_cores, nr_threads) + | |
86 | apicid_core_width(nr_cores, nr_threads); | |
87 | } | |
88 | ||
89 | /* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID | |
90 | * | |
91 | * The caller must make sure core_id < nr_cores and smt_id < nr_threads. | |
92 | */ | |
93 | static inline apic_id_t apicid_from_topo_ids(unsigned nr_cores, | |
94 | unsigned nr_threads, | |
95 | unsigned pkg_id, | |
96 | unsigned core_id, | |
97 | unsigned smt_id) | |
98 | { | |
99 | return (pkg_id << apicid_pkg_offset(nr_cores, nr_threads)) | | |
100 | (core_id << apicid_core_offset(nr_cores, nr_threads)) | | |
101 | smt_id; | |
102 | } | |
103 | ||
104 | /* Calculate thread/core/package IDs for a specific topology, | |
105 | * based on (contiguous) CPU index | |
106 | */ | |
107 | static inline void x86_topo_ids_from_idx(unsigned nr_cores, | |
108 | unsigned nr_threads, | |
109 | unsigned cpu_index, | |
110 | unsigned *pkg_id, | |
111 | unsigned *core_id, | |
112 | unsigned *smt_id) | |
113 | { | |
114 | unsigned core_index = cpu_index / nr_threads; | |
115 | *smt_id = cpu_index % nr_threads; | |
116 | *core_id = core_index % nr_cores; | |
117 | *pkg_id = core_index / nr_cores; | |
118 | } | |
119 | ||
120 | /* Make APIC ID for the CPU 'cpu_index' | |
121 | * | |
122 | * 'cpu_index' is a sequential, contiguous ID for the CPU. | |
123 | */ | |
124 | static inline apic_id_t x86_apicid_from_cpu_idx(unsigned nr_cores, | |
125 | unsigned nr_threads, | |
126 | unsigned cpu_index) | |
127 | { | |
128 | unsigned pkg_id, core_id, smt_id; | |
129 | x86_topo_ids_from_idx(nr_cores, nr_threads, cpu_index, | |
130 | &pkg_id, &core_id, &smt_id); | |
131 | return apicid_from_topo_ids(nr_cores, nr_threads, pkg_id, core_id, smt_id); | |
132 | } | |
133 | ||
134 | #endif /* TARGET_I386_TOPOLOGY_H */ |