]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. | |
5 | * Copyright(c) 2014 6WIND S.A. | |
6 | * All rights reserved. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * * Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * * Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in | |
16 | * the documentation and/or other materials provided with the | |
17 | * distribution. | |
18 | * * Neither the name of Intel Corporation nor the names of its | |
19 | * contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #include <stdio.h> | |
36 | #include <stdlib.h> | |
37 | #include <stdint.h> | |
38 | #include <string.h> | |
39 | #include <stdarg.h> | |
40 | #include <unistd.h> | |
41 | #include <pthread.h> | |
42 | #include <syslog.h> | |
43 | #include <getopt.h> | |
44 | #include <sys/file.h> | |
45 | #include <stddef.h> | |
46 | #include <errno.h> | |
47 | #include <limits.h> | |
48 | #include <errno.h> | |
49 | #include <sys/mman.h> | |
50 | #include <sys/queue.h> | |
51 | ||
52 | #include <rte_common.h> | |
53 | #include <rte_debug.h> | |
54 | #include <rte_memory.h> | |
55 | #include <rte_memzone.h> | |
56 | #include <rte_launch.h> | |
57 | #include <rte_eal.h> | |
58 | #include <rte_eal_memconfig.h> | |
59 | #include <rte_per_lcore.h> | |
60 | #include <rte_lcore.h> | |
61 | #include <rte_log.h> | |
62 | #include <rte_random.h> | |
63 | #include <rte_cycles.h> | |
64 | #include <rte_string_fns.h> | |
65 | #include <rte_cpuflags.h> | |
66 | #include <rte_interrupts.h> | |
67 | #include <rte_pci.h> | |
68 | #include <rte_dev.h> | |
69 | #include <rte_devargs.h> | |
70 | #include <rte_common.h> | |
71 | #include <rte_version.h> | |
72 | #include <rte_atomic.h> | |
73 | #include <malloc_heap.h> | |
74 | ||
75 | #include "eal_private.h" | |
76 | #include "eal_thread.h" | |
77 | #include "eal_internal_cfg.h" | |
78 | #include "eal_filesystem.h" | |
79 | #include "eal_hugepages.h" | |
80 | #include "eal_options.h" | |
81 | ||
82 | #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL) | |
83 | ||
84 | /* Allow the application to print its usage message too if set */ | |
85 | static rte_usage_hook_t rte_application_usage_hook = NULL; | |
86 | /* early configuration structure, when memory config is not mmapped */ | |
87 | static struct rte_mem_config early_mem_config; | |
88 | ||
89 | /* define fd variable here, because file needs to be kept open for the | |
90 | * duration of the program, as we hold a write lock on it in the primary proc */ | |
91 | static int mem_cfg_fd = -1; | |
92 | ||
93 | static struct flock wr_lock = { | |
94 | .l_type = F_WRLCK, | |
95 | .l_whence = SEEK_SET, | |
96 | .l_start = offsetof(struct rte_mem_config, memseg), | |
97 | .l_len = sizeof(early_mem_config.memseg), | |
98 | }; | |
99 | ||
100 | /* Address of global and public configuration */ | |
101 | static struct rte_config rte_config = { | |
102 | .mem_config = &early_mem_config, | |
103 | }; | |
104 | ||
105 | /* internal configuration (per-core) */ | |
106 | struct lcore_config lcore_config[RTE_MAX_LCORE]; | |
107 | ||
108 | /* internal configuration */ | |
109 | struct internal_config internal_config; | |
110 | ||
111 | /* used by rte_rdtsc() */ | |
112 | int rte_cycles_vmware_tsc_map; | |
113 | ||
114 | /* Return a pointer to the configuration structure */ | |
115 | struct rte_config * | |
116 | rte_eal_get_configuration(void) | |
117 | { | |
118 | return &rte_config; | |
119 | } | |
120 | ||
121 | /* parse a sysfs (or other) file containing one integer value */ | |
122 | int | |
123 | eal_parse_sysfs_value(const char *filename, unsigned long *val) | |
124 | { | |
125 | FILE *f; | |
126 | char buf[BUFSIZ]; | |
127 | char *end = NULL; | |
128 | ||
129 | if ((f = fopen(filename, "r")) == NULL) { | |
130 | RTE_LOG(ERR, EAL, "%s(): cannot open sysfs value %s\n", | |
131 | __func__, filename); | |
132 | return -1; | |
133 | } | |
134 | ||
135 | if (fgets(buf, sizeof(buf), f) == NULL) { | |
136 | RTE_LOG(ERR, EAL, "%s(): cannot read sysfs value %s\n", | |
137 | __func__, filename); | |
138 | fclose(f); | |
139 | return -1; | |
140 | } | |
141 | *val = strtoul(buf, &end, 0); | |
142 | if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { | |
143 | RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs value %s\n", | |
144 | __func__, filename); | |
145 | fclose(f); | |
146 | return -1; | |
147 | } | |
148 | fclose(f); | |
149 | return 0; | |
150 | } | |
151 | ||
152 | ||
153 | /* create memory configuration in shared/mmap memory. Take out | |
154 | * a write lock on the memsegs, so we can auto-detect primary/secondary. | |
155 | * This means we never close the file while running (auto-close on exit). | |
156 | * We also don't lock the whole file, so that in future we can use read-locks | |
157 | * on other parts, e.g. memzones, to detect if there are running secondary | |
158 | * processes. */ | |
159 | static void | |
160 | rte_eal_config_create(void) | |
161 | { | |
162 | void *rte_mem_cfg_addr; | |
163 | int retval; | |
164 | ||
165 | const char *pathname = eal_runtime_config_path(); | |
166 | ||
167 | if (internal_config.no_shconf) | |
168 | return; | |
169 | ||
170 | if (mem_cfg_fd < 0){ | |
171 | mem_cfg_fd = open(pathname, O_RDWR | O_CREAT, 0660); | |
172 | if (mem_cfg_fd < 0) | |
173 | rte_panic("Cannot open '%s' for rte_mem_config\n", pathname); | |
174 | } | |
175 | ||
176 | retval = ftruncate(mem_cfg_fd, sizeof(*rte_config.mem_config)); | |
177 | if (retval < 0){ | |
178 | close(mem_cfg_fd); | |
179 | rte_panic("Cannot resize '%s' for rte_mem_config\n", pathname); | |
180 | } | |
181 | ||
182 | retval = fcntl(mem_cfg_fd, F_SETLK, &wr_lock); | |
183 | if (retval < 0){ | |
184 | close(mem_cfg_fd); | |
185 | rte_exit(EXIT_FAILURE, "Cannot create lock on '%s'. Is another primary " | |
186 | "process running?\n", pathname); | |
187 | } | |
188 | ||
189 | rte_mem_cfg_addr = mmap(NULL, sizeof(*rte_config.mem_config), | |
190 | PROT_READ | PROT_WRITE, MAP_SHARED, mem_cfg_fd, 0); | |
191 | ||
192 | if (rte_mem_cfg_addr == MAP_FAILED){ | |
193 | rte_panic("Cannot mmap memory for rte_config\n"); | |
194 | } | |
195 | memcpy(rte_mem_cfg_addr, &early_mem_config, sizeof(early_mem_config)); | |
196 | rte_config.mem_config = (struct rte_mem_config *) rte_mem_cfg_addr; | |
197 | } | |
198 | ||
199 | /* attach to an existing shared memory config */ | |
200 | static void | |
201 | rte_eal_config_attach(void) | |
202 | { | |
203 | void *rte_mem_cfg_addr; | |
204 | const char *pathname = eal_runtime_config_path(); | |
205 | ||
206 | if (internal_config.no_shconf) | |
207 | return; | |
208 | ||
209 | if (mem_cfg_fd < 0){ | |
210 | mem_cfg_fd = open(pathname, O_RDWR); | |
211 | if (mem_cfg_fd < 0) | |
212 | rte_panic("Cannot open '%s' for rte_mem_config\n", pathname); | |
213 | } | |
214 | ||
215 | rte_mem_cfg_addr = mmap(NULL, sizeof(*rte_config.mem_config), | |
216 | PROT_READ | PROT_WRITE, MAP_SHARED, mem_cfg_fd, 0); | |
217 | close(mem_cfg_fd); | |
218 | if (rte_mem_cfg_addr == MAP_FAILED) | |
219 | rte_panic("Cannot mmap memory for rte_config\n"); | |
220 | ||
221 | rte_config.mem_config = (struct rte_mem_config *) rte_mem_cfg_addr; | |
222 | } | |
223 | ||
224 | /* Detect if we are a primary or a secondary process */ | |
225 | enum rte_proc_type_t | |
226 | eal_proc_type_detect(void) | |
227 | { | |
228 | enum rte_proc_type_t ptype = RTE_PROC_PRIMARY; | |
229 | const char *pathname = eal_runtime_config_path(); | |
230 | ||
231 | /* if we can open the file but not get a write-lock we are a secondary | |
232 | * process. NOTE: if we get a file handle back, we keep that open | |
233 | * and don't close it to prevent a race condition between multiple opens */ | |
234 | if (((mem_cfg_fd = open(pathname, O_RDWR)) >= 0) && | |
235 | (fcntl(mem_cfg_fd, F_SETLK, &wr_lock) < 0)) | |
236 | ptype = RTE_PROC_SECONDARY; | |
237 | ||
238 | RTE_LOG(INFO, EAL, "Auto-detected process type: %s\n", | |
239 | ptype == RTE_PROC_PRIMARY ? "PRIMARY" : "SECONDARY"); | |
240 | ||
241 | return ptype; | |
242 | } | |
243 | ||
244 | /* Sets up rte_config structure with the pointer to shared memory config.*/ | |
245 | static void | |
246 | rte_config_init(void) | |
247 | { | |
248 | rte_config.process_type = internal_config.process_type; | |
249 | ||
250 | switch (rte_config.process_type){ | |
251 | case RTE_PROC_PRIMARY: | |
252 | rte_eal_config_create(); | |
253 | break; | |
254 | case RTE_PROC_SECONDARY: | |
255 | rte_eal_config_attach(); | |
256 | rte_eal_mcfg_wait_complete(rte_config.mem_config); | |
257 | break; | |
258 | case RTE_PROC_AUTO: | |
259 | case RTE_PROC_INVALID: | |
260 | rte_panic("Invalid process type\n"); | |
261 | } | |
262 | } | |
263 | ||
264 | /* display usage */ | |
265 | static void | |
266 | eal_usage(const char *prgname) | |
267 | { | |
268 | printf("\nUsage: %s ", prgname); | |
269 | eal_common_usage(); | |
270 | /* Allow the application to print its usage message too if hook is set */ | |
271 | if ( rte_application_usage_hook ) { | |
272 | printf("===== Application Usage =====\n\n"); | |
273 | rte_application_usage_hook(prgname); | |
274 | } | |
275 | } | |
276 | ||
277 | /* Set a per-application usage message */ | |
278 | rte_usage_hook_t | |
279 | rte_set_application_usage_hook( rte_usage_hook_t usage_func ) | |
280 | { | |
281 | rte_usage_hook_t old_func; | |
282 | ||
283 | /* Will be NULL on the first call to denote the last usage routine. */ | |
284 | old_func = rte_application_usage_hook; | |
285 | rte_application_usage_hook = usage_func; | |
286 | ||
287 | return old_func; | |
288 | } | |
289 | ||
290 | static inline size_t | |
291 | eal_get_hugepage_mem_size(void) | |
292 | { | |
293 | uint64_t size = 0; | |
294 | unsigned i, j; | |
295 | ||
296 | for (i = 0; i < internal_config.num_hugepage_sizes; i++) { | |
297 | struct hugepage_info *hpi = &internal_config.hugepage_info[i]; | |
298 | if (hpi->hugedir != NULL) { | |
299 | for (j = 0; j < RTE_MAX_NUMA_NODES; j++) { | |
300 | size += hpi->hugepage_sz * hpi->num_pages[j]; | |
301 | } | |
302 | } | |
303 | } | |
304 | ||
305 | return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; | |
306 | } | |
307 | ||
308 | /* Parse the arguments for --log-level only */ | |
309 | static void | |
310 | eal_log_level_parse(int argc, char **argv) | |
311 | { | |
312 | int opt; | |
313 | char **argvopt; | |
314 | int option_index; | |
315 | const int old_optind = optind; | |
316 | const int old_optopt = optopt; | |
317 | const int old_optreset = optreset; | |
318 | char * const old_optarg = optarg; | |
319 | ||
320 | argvopt = argv; | |
321 | optind = 1; | |
322 | optreset = 1; | |
323 | ||
324 | eal_reset_internal_config(&internal_config); | |
325 | ||
326 | while ((opt = getopt_long(argc, argvopt, eal_short_options, | |
327 | eal_long_options, &option_index)) != EOF) { | |
328 | ||
329 | int ret; | |
330 | ||
331 | /* getopt is not happy, stop right now */ | |
332 | if (opt == '?') | |
333 | break; | |
334 | ||
335 | ret = (opt == OPT_LOG_LEVEL_NUM) ? | |
336 | eal_parse_common_option(opt, optarg, &internal_config) : 0; | |
337 | ||
338 | /* common parser is not happy */ | |
339 | if (ret < 0) | |
340 | break; | |
341 | } | |
342 | ||
343 | /* restore getopt lib */ | |
344 | optind = old_optind; | |
345 | optopt = old_optopt; | |
346 | optreset = old_optreset; | |
347 | optarg = old_optarg; | |
348 | } | |
349 | ||
350 | /* Parse the argument given in the command line of the application */ | |
351 | static int | |
352 | eal_parse_args(int argc, char **argv) | |
353 | { | |
354 | int opt, ret; | |
355 | char **argvopt; | |
356 | int option_index; | |
357 | char *prgname = argv[0]; | |
358 | const int old_optind = optind; | |
359 | const int old_optopt = optopt; | |
360 | const int old_optreset = optreset; | |
361 | char * const old_optarg = optarg; | |
362 | ||
363 | argvopt = argv; | |
364 | optind = 1; | |
365 | optreset = 1; | |
366 | ||
367 | while ((opt = getopt_long(argc, argvopt, eal_short_options, | |
368 | eal_long_options, &option_index)) != EOF) { | |
369 | ||
370 | /* getopt is not happy, stop right now */ | |
371 | if (opt == '?') { | |
372 | eal_usage(prgname); | |
373 | ret = -1; | |
374 | goto out; | |
375 | } | |
376 | ||
377 | ret = eal_parse_common_option(opt, optarg, &internal_config); | |
378 | /* common parser is not happy */ | |
379 | if (ret < 0) { | |
380 | eal_usage(prgname); | |
381 | ret = -1; | |
382 | goto out; | |
383 | } | |
384 | /* common parser handled this option */ | |
385 | if (ret == 0) | |
386 | continue; | |
387 | ||
388 | switch (opt) { | |
389 | case 'h': | |
390 | eal_usage(prgname); | |
391 | exit(EXIT_SUCCESS); | |
392 | default: | |
393 | if (opt < OPT_LONG_MIN_NUM && isprint(opt)) { | |
394 | RTE_LOG(ERR, EAL, "Option %c is not supported " | |
395 | "on FreeBSD\n", opt); | |
396 | } else if (opt >= OPT_LONG_MIN_NUM && | |
397 | opt < OPT_LONG_MAX_NUM) { | |
398 | RTE_LOG(ERR, EAL, "Option %s is not supported " | |
399 | "on FreeBSD\n", | |
400 | eal_long_options[option_index].name); | |
401 | } else { | |
402 | RTE_LOG(ERR, EAL, "Option %d is not supported " | |
403 | "on FreeBSD\n", opt); | |
404 | } | |
405 | eal_usage(prgname); | |
406 | ret = -1; | |
407 | goto out; | |
408 | } | |
409 | } | |
410 | ||
411 | if (eal_adjust_config(&internal_config) != 0) { | |
412 | ret = -1; | |
413 | goto out; | |
414 | } | |
415 | ||
416 | /* sanity checks */ | |
417 | if (eal_check_common_options(&internal_config) != 0) { | |
418 | eal_usage(prgname); | |
419 | ret = -1; | |
420 | goto out; | |
421 | } | |
422 | ||
423 | if (optind >= 0) | |
424 | argv[optind-1] = prgname; | |
425 | ret = optind-1; | |
426 | ||
427 | out: | |
428 | /* restore getopt lib */ | |
429 | optind = old_optind; | |
430 | optopt = old_optopt; | |
431 | optreset = old_optreset; | |
432 | optarg = old_optarg; | |
433 | ||
434 | return ret; | |
435 | } | |
436 | ||
437 | static void | |
438 | eal_check_mem_on_local_socket(void) | |
439 | { | |
440 | const struct rte_memseg *ms; | |
441 | int i, socket_id; | |
442 | ||
443 | socket_id = rte_lcore_to_socket_id(rte_config.master_lcore); | |
444 | ||
445 | ms = rte_eal_get_physmem_layout(); | |
446 | ||
447 | for (i = 0; i < RTE_MAX_MEMSEG; i++) | |
448 | if (ms[i].socket_id == socket_id && | |
449 | ms[i].len > 0) | |
450 | return; | |
451 | ||
452 | RTE_LOG(WARNING, EAL, "WARNING: Master core has no " | |
453 | "memory on local socket!\n"); | |
454 | } | |
455 | ||
456 | static int | |
457 | sync_func(__attribute__((unused)) void *arg) | |
458 | { | |
459 | return 0; | |
460 | } | |
461 | ||
462 | inline static void | |
463 | rte_eal_mcfg_complete(void) | |
464 | { | |
465 | /* ALL shared mem_config related INIT DONE */ | |
466 | if (rte_config.process_type == RTE_PROC_PRIMARY) | |
467 | rte_config.mem_config->magic = RTE_MAGIC; | |
468 | } | |
469 | ||
470 | /* return non-zero if hugepages are enabled. */ | |
471 | int rte_eal_has_hugepages(void) | |
472 | { | |
473 | return !internal_config.no_hugetlbfs; | |
474 | } | |
475 | ||
476 | /* Abstraction for port I/0 privilege */ | |
477 | int | |
478 | rte_eal_iopl_init(void) | |
479 | { | |
480 | static int fd; | |
481 | ||
482 | fd = open("/dev/io", O_RDWR); | |
483 | if (fd < 0) | |
484 | return -1; | |
485 | /* keep fd open for iopl */ | |
486 | return 0; | |
487 | } | |
488 | ||
489 | /* Launch threads, called at application init(). */ | |
490 | int | |
491 | rte_eal_init(int argc, char **argv) | |
492 | { | |
493 | int i, fctret, ret; | |
494 | pthread_t thread_id; | |
495 | static rte_atomic32_t run_once = RTE_ATOMIC32_INIT(0); | |
496 | char cpuset[RTE_CPU_AFFINITY_STR_LEN]; | |
497 | char thread_name[RTE_MAX_THREAD_NAME_LEN]; | |
498 | ||
499 | /* checks if the machine is adequate */ | |
500 | rte_cpu_check_supported(); | |
501 | ||
502 | if (!rte_atomic32_test_and_set(&run_once)) | |
503 | return -1; | |
504 | ||
505 | thread_id = pthread_self(); | |
506 | ||
507 | eal_log_level_parse(argc, argv); | |
508 | ||
509 | /* set log level as early as possible */ | |
510 | rte_set_log_level(internal_config.log_level); | |
511 | ||
512 | if (rte_eal_cpu_init() < 0) | |
513 | rte_panic("Cannot detect lcores\n"); | |
514 | ||
515 | fctret = eal_parse_args(argc, argv); | |
516 | if (fctret < 0) | |
517 | exit(1); | |
518 | ||
519 | if (internal_config.no_hugetlbfs == 0 && | |
520 | internal_config.process_type != RTE_PROC_SECONDARY && | |
521 | eal_hugepage_info_init() < 0) | |
522 | rte_panic("Cannot get hugepage information\n"); | |
523 | ||
524 | if (internal_config.memory == 0 && internal_config.force_sockets == 0) { | |
525 | if (internal_config.no_hugetlbfs) | |
526 | internal_config.memory = MEMSIZE_IF_NO_HUGE_PAGE; | |
527 | else | |
528 | internal_config.memory = eal_get_hugepage_mem_size(); | |
529 | } | |
530 | ||
531 | if (internal_config.vmware_tsc_map == 1) { | |
532 | #ifdef RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT | |
533 | rte_cycles_vmware_tsc_map = 1; | |
534 | RTE_LOG (DEBUG, EAL, "Using VMWARE TSC MAP, " | |
535 | "you must have monitor_control.pseudo_perfctr = TRUE\n"); | |
536 | #else | |
537 | RTE_LOG (WARNING, EAL, "Ignoring --vmware-tsc-map because " | |
538 | "RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT is not set\n"); | |
539 | #endif | |
540 | } | |
541 | ||
542 | rte_srand(rte_rdtsc()); | |
543 | ||
544 | rte_config_init(); | |
545 | ||
546 | if (rte_eal_memory_init() < 0) | |
547 | rte_panic("Cannot init memory\n"); | |
548 | ||
549 | if (rte_eal_memzone_init() < 0) | |
550 | rte_panic("Cannot init memzone\n"); | |
551 | ||
552 | if (rte_eal_tailqs_init() < 0) | |
553 | rte_panic("Cannot init tail queues for objects\n"); | |
554 | ||
555 | if (rte_eal_alarm_init() < 0) | |
556 | rte_panic("Cannot init interrupt-handling thread\n"); | |
557 | ||
558 | if (rte_eal_intr_init() < 0) | |
559 | rte_panic("Cannot init interrupt-handling thread\n"); | |
560 | ||
561 | if (rte_eal_timer_init() < 0) | |
562 | rte_panic("Cannot init HPET or TSC timers\n"); | |
563 | ||
564 | if (rte_eal_pci_init() < 0) | |
565 | rte_panic("Cannot init PCI\n"); | |
566 | ||
567 | eal_check_mem_on_local_socket(); | |
568 | ||
569 | if (eal_plugins_init() < 0) | |
570 | rte_panic("Cannot init plugins\n"); | |
571 | ||
572 | eal_thread_init_master(rte_config.master_lcore); | |
573 | ||
574 | ret = eal_thread_dump_affinity(cpuset, RTE_CPU_AFFINITY_STR_LEN); | |
575 | ||
576 | RTE_LOG(DEBUG, EAL, "Master lcore %u is ready (tid=%p;cpuset=[%s%s])\n", | |
577 | rte_config.master_lcore, thread_id, cpuset, | |
578 | ret == 0 ? "" : "..."); | |
579 | ||
580 | if (rte_eal_dev_init() < 0) | |
581 | rte_panic("Cannot init pmd devices\n"); | |
582 | ||
583 | RTE_LCORE_FOREACH_SLAVE(i) { | |
584 | ||
585 | /* | |
586 | * create communication pipes between master thread | |
587 | * and children | |
588 | */ | |
589 | if (pipe(lcore_config[i].pipe_master2slave) < 0) | |
590 | rte_panic("Cannot create pipe\n"); | |
591 | if (pipe(lcore_config[i].pipe_slave2master) < 0) | |
592 | rte_panic("Cannot create pipe\n"); | |
593 | ||
594 | lcore_config[i].state = WAIT; | |
595 | ||
596 | /* create a thread for each lcore */ | |
597 | ret = pthread_create(&lcore_config[i].thread_id, NULL, | |
598 | eal_thread_loop, NULL); | |
599 | if (ret != 0) | |
600 | rte_panic("Cannot create thread\n"); | |
601 | ||
602 | /* Set thread_name for aid in debugging. */ | |
603 | snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, | |
604 | "lcore-slave-%d", i); | |
605 | rte_thread_setname(lcore_config[i].thread_id, thread_name); | |
606 | } | |
607 | ||
608 | /* | |
609 | * Launch a dummy function on all slave lcores, so that master lcore | |
610 | * knows they are all ready when this function returns. | |
611 | */ | |
612 | rte_eal_mp_remote_launch(sync_func, NULL, SKIP_MASTER); | |
613 | rte_eal_mp_wait_lcore(); | |
614 | ||
615 | /* Probe & Initialize PCI devices */ | |
616 | if (rte_eal_pci_probe()) | |
617 | rte_panic("Cannot probe PCI\n"); | |
618 | ||
619 | rte_eal_mcfg_complete(); | |
620 | ||
621 | return fctret; | |
622 | } | |
623 | ||
624 | /* get core role */ | |
625 | enum rte_lcore_role_t | |
626 | rte_eal_lcore_role(unsigned lcore_id) | |
627 | { | |
628 | return rte_config.lcore_role[lcore_id]; | |
629 | } | |
630 | ||
631 | enum rte_proc_type_t | |
632 | rte_eal_process_type(void) | |
633 | { | |
634 | return rte_config.process_type; | |
635 | } |