eal/riscv: support RISC-V architecture
[dpdk.git] / lib / eal / windows / eal_lcore.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  * Copyright (C) 2022 Microsoft Corporation
4  */
5
6 #include <stdbool.h>
7 #include <stdint.h>
8
9 #include <rte_common.h>
10 #include <rte_debug.h>
11 #include <rte_lcore.h>
12
13 #include "eal_private.h"
14 #include "eal_thread.h"
15 #include "eal_windows.h"
16
17 /** Number of logical processors (cores) in a processor group (32 or 64). */
18 #define EAL_PROCESSOR_GROUP_SIZE (sizeof(KAFFINITY) * CHAR_BIT)
19
20 struct lcore_map {
21         uint8_t socket_id;
22         uint8_t core_id;
23 };
24
25 struct socket_map {
26         uint16_t node_id;
27 };
28
29 struct cpu_map {
30         unsigned int lcore_count;
31         unsigned int socket_count;
32         unsigned int cpu_count;
33         struct lcore_map lcores[RTE_MAX_LCORE];
34         struct socket_map sockets[RTE_MAX_NUMA_NODES];
35         GROUP_AFFINITY cpus[CPU_SETSIZE];
36 };
37
38 static struct cpu_map cpu_map;
39
40 /* eal_create_cpu_map() is called before logging is initialized */
41 static void
42 __rte_format_printf(1, 2)
43 log_early(const char *format, ...)
44 {
45         va_list va;
46
47         va_start(va, format);
48         vfprintf(stderr, format, va);
49         va_end(va);
50 }
51
52 static int
53 eal_query_group_affinity(void)
54 {
55         SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infos = NULL;
56         unsigned int *cpu_count = &cpu_map.cpu_count;
57         DWORD infos_size = 0;
58         int ret = 0;
59         USHORT group_count;
60         KAFFINITY affinity;
61         USHORT group_no;
62         unsigned int i;
63
64         if (!GetLogicalProcessorInformationEx(RelationGroup, NULL,
65                         &infos_size)) {
66                 DWORD error = GetLastError();
67                 if (error != ERROR_INSUFFICIENT_BUFFER) {
68                         RTE_LOG(ERR, EAL, "Cannot get group information size, error %lu\n", error);
69                         rte_errno = EINVAL;
70                         ret = -1;
71                         goto cleanup;
72                 }
73         }
74
75         infos = malloc(infos_size);
76         if (infos == NULL) {
77                 RTE_LOG(ERR, EAL, "Cannot allocate memory for NUMA node information\n");
78                 rte_errno = ENOMEM;
79                 ret = -1;
80                 goto cleanup;
81         }
82
83         if (!GetLogicalProcessorInformationEx(RelationGroup, infos,
84                         &infos_size)) {
85                 RTE_LOG(ERR, EAL, "Cannot get group information, error %lu\n",
86                         GetLastError());
87                 rte_errno = EINVAL;
88                 ret = -1;
89                 goto cleanup;
90         }
91
92         *cpu_count = 0;
93         group_count = infos->Group.ActiveGroupCount;
94         for (group_no = 0; group_no < group_count; group_no++) {
95                 affinity = infos->Group.GroupInfo[group_no].ActiveProcessorMask;
96                 for (i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) {
97                         if ((affinity & ((KAFFINITY)1 << i)) == 0)
98                                 continue;
99                         cpu_map.cpus[*cpu_count].Group = group_no;
100                         cpu_map.cpus[*cpu_count].Mask = (KAFFINITY)1 << i;
101                         (*cpu_count)++;
102                 }
103         }
104
105 cleanup:
106         free(infos);
107         return ret;
108 }
109
110 static bool
111 eal_create_lcore_map(const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info)
112 {
113         const unsigned int node_id = info->NumaNode.NodeNumber;
114         const GROUP_AFFINITY *cores = &info->NumaNode.GroupMask;
115         struct lcore_map *lcore;
116         unsigned int socket_id;
117         unsigned int i;
118
119         /*
120          * NUMA node may be reported multiple times if it includes
121          * cores from different processor groups, e. g. 80 cores
122          * of a physical processor comprise one NUMA node, but two
123          * processor groups, because group size is limited by 32/64.
124          */
125         for (socket_id = 0; socket_id < cpu_map.socket_count; socket_id++)
126                 if (cpu_map.sockets[socket_id].node_id == node_id)
127                         break;
128
129         if (socket_id == cpu_map.socket_count) {
130                 if (socket_id == RTE_DIM(cpu_map.sockets))
131                         return true;
132
133                 cpu_map.sockets[socket_id].node_id = node_id;
134                 cpu_map.socket_count++;
135         }
136
137         for (i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) {
138                 if ((cores->Mask & ((KAFFINITY)1 << i)) == 0)
139                         continue;
140
141                 if (cpu_map.lcore_count == RTE_DIM(cpu_map.lcores))
142                         return true;
143
144                 lcore = &cpu_map.lcores[cpu_map.lcore_count];
145                 lcore->socket_id = socket_id;
146                 lcore->core_id = cores->Group * EAL_PROCESSOR_GROUP_SIZE + i;
147                 cpu_map.lcore_count++;
148         }
149         return false;
150 }
151
152 int
153 eal_create_cpu_map(void)
154 {
155         SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infos, *info;
156         DWORD infos_size;
157         bool full = false;
158         int ret = 0;
159
160         infos = NULL;
161         infos_size = 0;
162         if (!GetLogicalProcessorInformationEx(
163                         RelationNumaNode, NULL, &infos_size)) {
164                 DWORD error = GetLastError();
165                 if (error != ERROR_INSUFFICIENT_BUFFER) {
166                         log_early("Cannot get NUMA node info size, error %lu\n",
167                                 GetLastError());
168                         rte_errno = ENOMEM;
169                         ret = -1;
170                         goto exit;
171                 }
172         }
173
174         infos = malloc(infos_size);
175         if (infos == NULL) {
176                 log_early("Cannot allocate memory for NUMA node information\n");
177                 rte_errno = ENOMEM;
178                 ret = -1;
179                 goto exit;
180         }
181
182         if (!GetLogicalProcessorInformationEx(
183                         RelationNumaNode, infos, &infos_size)) {
184                 log_early("Cannot get NUMA node information, error %lu\n",
185                         GetLastError());
186                 rte_errno = EINVAL;
187                 ret = -1;
188                 goto exit;
189         }
190
191         info = infos;
192         while ((uint8_t *)info - (uint8_t *)infos < infos_size) {
193                 if (eal_create_lcore_map(info)) {
194                         full = true;
195                         break;
196                 }
197
198                 info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(
199                         (uint8_t *)info + info->Size);
200         }
201
202         if (eal_query_group_affinity()) {
203                 /*
204                  * No need to set rte_errno here.
205                  * It is set by eal_query_group_affinity().
206                  */
207                 ret = -1;
208                 goto exit;
209         }
210
211 exit:
212         if (full) {
213                 /* Not a fatal error, but important for troubleshooting. */
214                 log_early("Enumerated maximum of %u NUMA nodes and %u cores\n",
215                         cpu_map.socket_count, cpu_map.lcore_count);
216         }
217
218         free(infos);
219
220         return ret;
221 }
222
223 int
224 eal_cpu_detected(unsigned int lcore_id)
225 {
226         return lcore_id < cpu_map.lcore_count;
227 }
228
229 unsigned
230 eal_cpu_socket_id(unsigned int lcore_id)
231 {
232         return cpu_map.lcores[lcore_id].socket_id;
233 }
234
235 unsigned
236 eal_cpu_core_id(unsigned int lcore_id)
237 {
238         return cpu_map.lcores[lcore_id].core_id;
239 }
240
241 unsigned int
242 eal_socket_numa_node(unsigned int socket_id)
243 {
244         return cpu_map.sockets[socket_id].node_id;
245 }
246
247 PGROUP_AFFINITY
248 eal_get_cpu_affinity(size_t cpu_index)
249 {
250         RTE_VERIFY(cpu_index < CPU_SETSIZE);
251
252         return &cpu_map.cpus[cpu_index];
253 }