1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40 41 42 43 44 45/** 46 * @file 47 * Simple executive application initialization for Linux user space. This 48 * file should be used instead of cvmx-app-init.c for running simple executive 49 * applications under Linux in userspace. The following are some of the key 50 * points to remember when writing applications to run both under the 51 * standalone simple executive and userspace under Linux. 52 * 53 * -# Application main must be called "appmain" under Linux. Use and ifdef 54 * based on __linux__ to determine the proper name. 55 * -# Be careful to use cvmx_ptr_to_phys() and cvmx_phys_to_ptr. The simple 56 * executive 1-1 TLB mappings allow you to be sloppy and interchange 57 * hardware addresses with virtual address. This isn't true under Linux. 58 * -# If you're talking directly to hardware, be careful. The normal Linux 59 * protections are circumvented. If you do something bad, Linux won't 60 * save you. 61 * -# Most hardware can only be initialized once. Unless you're very careful, 62 * this also means you Linux application can only run once. 63 * 64 * <hr>$Revision: 70129 $<hr> 65 * 66 */ 67#define _GNU_SOURCE 68#include <stdint.h> 69#include <stdio.h> 70#include <stdlib.h> 71#include <stdarg.h> 72#include <string.h> 73#include <unistd.h> 74#include <errno.h> 75#include <fcntl.h> 76#include <sys/mman.h> 77#include <signal.h> 78#include <sys/statfs.h> 79#include <sys/wait.h> 80#include <sys/sysmips.h> 81#include <sched.h> 82#include <octeon-app-init.h> 83 84#include "cvmx-config.h" 85#include "cvmx.h" 86#include "cvmx-atomic.h" 87#include "cvmx-sysinfo.h" 88#include "cvmx-coremask.h" 89#include "cvmx-spinlock.h" 90#include "cvmx-bootmem.h" 91#include "cvmx-helper-cfg.h" 92 93int octeon_model_version_check(uint32_t chip_id); 94 95#define OCTEON_ECLOCK_MULT_INPUT_X16 ((int)(33.4*16)) 96 97/* Applications using the simple executive libraries under Linux userspace must 98 rename their "main" function to match the prototype below. This allows the 99 simple executive to perform needed memory initialization and process 100 creation before the application runs. */ 101extern int appmain(int argc, const char *argv[]); 102 103/* These two external addresses provide the beginning and end markers for the 104 CVMX_SHARED section. These are defined by the cvmx-shared.ld linker script. 105 If they aren't defined, you probably forgot to link using this script. */ 106extern void __cvmx_shared_start; 107extern void __cvmx_shared_end; 108extern uint64_t linux_mem32_min; 109extern uint64_t linux_mem32_max; 110extern uint64_t linux_mem32_wired; 111extern uint64_t linux_mem32_offset; 112 113/** 114 * This function performs some default initialization of the Octeon executive. It initializes 115 * the cvmx_bootmem memory allocator with the list of physical memory shared by the bootloader. 116 * This function should be called on all cores that will use the bootmem allocator. 117 * Applications which require a different configuration can replace this function with a suitable application 118 * specific one. 119 * 120 * @return 0 on success 121 * -1 on failure 122 */ 123int cvmx_user_app_init(void) 124{ 125 return 0; 126} 127 128 129/** 130 * Simulator magic is not supported in user mode under Linux. 131 * This version of simprintf simply calls the underlying C 132 * library printf for output. It also makes sure that two 133 * calls to simprintf provide atomic output. 134 * 135 * @param format Format string in the same format as printf. 136 */ 137void simprintf(const char *format, ...) 138{ 139 CVMX_SHARED static cvmx_spinlock_t simprintf_lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER; 140 va_list ap; 141 142 cvmx_spinlock_lock(&simprintf_lock); 143 printf("SIMPRINTF(%d): ", (int)cvmx_get_core_num()); 144 va_start(ap, format); 145 vprintf(format, ap); 146 va_end(ap); 147 cvmx_spinlock_unlock(&simprintf_lock); 148} 149 150 151/** 152 * Setup the CVMX_SHARED data section to be shared across 153 * all processors running this application. A memory mapped 154 * region is allocated using shm_open and mmap. The current 155 * contents of the CVMX_SHARED section are copied into the 156 * region. Then the new region is remapped to replace the 157 * existing CVMX_SHARED data. 158 * 159 * This function will display a message and abort the 160 * application under any error conditions. The Linux tmpfs 161 * filesystem must be mounted under /dev/shm. 162 */ 163static void setup_cvmx_shared(void) 164{ 165 const char *SHM_NAME = "cvmx_shared"; 166 unsigned long shared_size = &__cvmx_shared_end - &__cvmx_shared_start; 167 int fd; 168 169 /* If there isn't and shared data we can skip all this */ 170 if (shared_size) 171 { 172 char shm_name[30]; 173 printf("CVMX_SHARED: %p-%p\n", &__cvmx_shared_start, &__cvmx_shared_end); 174 175#ifdef __UCLIBC__ 176 const char *defaultdir = "/dev/shm/"; 177 struct statfs f; 178 int pid; 179 /* The canonical place is /dev/shm. */ 180 if (statfs (defaultdir, &f) == 0) 181 { 182 pid = getpid(); 183 sprintf (shm_name, "%s%s-%d", defaultdir, SHM_NAME, pid); 184 } 185 else 186 { 187 perror("/dev/shm is not mounted"); 188 exit(-1); 189 } 190 191 /* shm_open(), shm_unlink() are not implemented in uClibc. Do the 192 same thing using open() and close() system calls. */ 193 fd = open (shm_name, O_RDWR | O_CREAT | O_TRUNC, 0); 194 195 if (fd < 0) 196 { 197 perror("Failed to open CVMX_SHARED(shm_name)"); 198 exit(errno); 199 } 200 201 unlink (shm_name); 202#else 203 sprintf(shm_name, "%s-%d", SHM_NAME, getpid()); 204 /* Open a new shared memory region for use as CVMX_SHARED */ 205 fd = shm_open(shm_name, O_RDWR | O_CREAT | O_TRUNC, 0); 206 if (fd <0) 207 { 208 perror("Failed to setup CVMX_SHARED(shm_open)"); 209 exit(errno); 210 } 211 212 /* We don't want the file on the filesystem. Immediately unlink it so 213 another application can create its own shared region */ 214 shm_unlink(shm_name); 215#endif 216 217 /* Resize the region to match the size of CVMX_SHARED */ 218 ftruncate(fd, shared_size); 219 220 /* Map the region into some random location temporarily so we can 221 copy the shared data to it */ 222 void *ptr = mmap(NULL, shared_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 223 if (ptr == NULL) 224 { 225 perror("Failed to setup CVMX_SHARED(mmap copy)"); 226 exit(errno); 227 } 228 229 /* Copy CVMX_SHARED to the new shared region so we don't lose 230 initializers */ 231 memcpy(ptr, &__cvmx_shared_start, shared_size); 232 munmap(ptr, shared_size); 233 234 /* Remap the shared region to replace the old CVMX_SHARED region */ 235 ptr = mmap(&__cvmx_shared_start, shared_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0); 236 if (ptr == NULL) 237 { 238 perror("Failed to setup CVMX_SHARED(mmap final)"); 239 exit(errno); 240 } 241 242 /* Once mappings are setup, the file handle isn't needed anymore */ 243 close(fd); 244 } 245} 246 247 248/** 249 * Shutdown and free the shared CVMX_SHARED region setup by 250 * setup_cvmx_shared. 251 */ 252static void shutdown_cvmx_shared(void) 253{ 254 unsigned long shared_size = &__cvmx_shared_end - &__cvmx_shared_start; 255 if (shared_size) 256 munmap(&__cvmx_shared_start, shared_size); 257} 258 259 260/** 261 * Setup access to the CONFIG_CAVIUM_RESERVE32 memory section 262 * created by the kernel. This memory is used for shared 263 * hardware buffers with 32 bit userspace applications. 264 */ 265static void setup_reserve32(void) 266{ 267 if (linux_mem32_min && linux_mem32_max) 268 { 269 int region_size = linux_mem32_max - linux_mem32_min + 1; 270 int mmap_flags = MAP_SHARED; 271 void *linux_mem32_base_ptr = NULL; 272 273 /* Although not strictly necessary, we are going to mmap() the wired 274 TLB region so it is in the process page tables. These pages will 275 never fault in, but they will allow GDB to access the wired 276 region. We need the mappings to exactly match the wired TLB 277 entry. */ 278 if (linux_mem32_wired) 279 { 280 mmap_flags |= MAP_FIXED; 281 linux_mem32_base_ptr = CASTPTR(void, (1ull<<31) - region_size); 282 } 283 284 int fd = open("/dev/mem", O_RDWR); 285 if (fd < 0) 286 { 287 perror("ERROR opening /dev/mem"); 288 exit(-1); 289 } 290 291 linux_mem32_base_ptr = mmap64(linux_mem32_base_ptr, 292 region_size, 293 PROT_READ | PROT_WRITE, 294 mmap_flags, 295 fd, 296 linux_mem32_min); 297 close(fd); 298 299 if (MAP_FAILED == linux_mem32_base_ptr) 300 { 301 perror("Error mapping reserve32"); 302 exit(-1); 303 } 304 305 linux_mem32_offset = CAST64(linux_mem32_base_ptr) - linux_mem32_min; 306 } 307} 308 309 310/** 311 * Main entrypoint of the application. Here we setup shared 312 * memory and fork processes for each cpu. This simulates the 313 * normal simple executive environment of one process per 314 * cpu core. 315 * 316 * @param argc Number of command line arguments 317 * @param argv The command line arguments 318 * @return Return value for the process 319 */ 320int main(int argc, const char *argv[]) 321{ 322 CVMX_SHARED static cvmx_spinlock_t mask_lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER; 323 CVMX_SHARED static int32_t pending_fork; 324 unsigned long cpumask; 325 unsigned long cpu; 326 int firstcpu = 0; 327 int firstcore = 0; 328 329 cvmx_linux_enable_xkphys_access(0); 330 cvmx_sysinfo_linux_userspace_initialize(); 331 332 if (sizeof(void*) == 4) 333 { 334 if (linux_mem32_min) 335 setup_reserve32(); 336 else 337 { 338 printf("\nFailed to access 32bit shared memory region. Most likely the Kernel\n" 339 "has not been configured for 32bit shared memory access. Check the\n" 340 "kernel configuration.\n" 341 "Aborting...\n\n"); 342 exit(-1); 343 } 344 } 345 346 setup_cvmx_shared(); 347 cvmx_bootmem_init(cvmx_sysinfo_get()->phy_mem_desc_addr); 348 349 /* Check to make sure the Chip version matches the configured version */ 350 octeon_model_version_check(cvmx_get_proc_id()); 351 352 /* Initialize configuration to set bpid, pkind, pko_port for all the 353 available ports connected. */ 354 __cvmx_helper_cfg_init(); 355 356 /* Get the list of logical cpus we should run on */ 357 if (sched_getaffinity(0, sizeof(cpumask), (cpu_set_t*)&cpumask)) 358 { 359 perror("sched_getaffinity failed"); 360 exit(errno); 361 } 362 363 cvmx_sysinfo_t *system_info = cvmx_sysinfo_get(); 364 365 cvmx_atomic_set32(&pending_fork, 1); 366 367 /* Get the lowest logical cpu */ 368 firstcore = ffsl(cpumask) - 1; 369 cpumask ^= (1ull<<(firstcore)); 370 while (1) 371 { 372 if (cpumask == 0) 373 { 374 cpu = firstcore; 375 firstcpu = 1; 376 break; 377 } 378 cpu = ffsl(cpumask) - 1; 379 /* Turn off the bit for this CPU number. We've counted him */ 380 cpumask ^= (1ull<<cpu); 381 /* Increment the number of CPUs running this app */ 382 cvmx_atomic_add32(&pending_fork, 1); 383 /* Flush all IO streams before the fork. Otherwise any buffered 384 data in the C library will be duplicated. This results in 385 duplicate output from a single print */ 386 fflush(NULL); 387 /* Fork a process for the new CPU */ 388 int pid = fork(); 389 if (pid == 0) 390 { 391 break; 392 } 393 else if (pid == -1) 394 { 395 perror("Fork failed"); 396 exit(errno); 397 } 398 } 399 400 401 /* Set affinity to lock me to the correct CPU */ 402 cpumask = (1<<cpu); 403 if (sched_setaffinity(0, sizeof(cpumask), (cpu_set_t*)&cpumask)) 404 { 405 perror("sched_setaffinity failed"); 406 exit(errno); 407 } 408 409 cvmx_spinlock_lock(&mask_lock); 410 system_info->core_mask |= 1<<cvmx_get_core_num(); 411 cvmx_atomic_add32(&pending_fork, -1); 412 if (cvmx_atomic_get32(&pending_fork) == 0) 413 { 414 cvmx_dprintf("Active coremask = 0x%x\n", system_info->core_mask); 415 } 416 if (firstcpu) 417 system_info->init_core = cvmx_get_core_num(); 418 cvmx_spinlock_unlock(&mask_lock); 419 420 /* Spinning waiting for forks to complete */ 421 while (cvmx_atomic_get32(&pending_fork)) {} 422 423 cvmx_coremask_barrier_sync(system_info->core_mask); 424 425 cvmx_linux_enable_xkphys_access(1); 426 427 int result = appmain(argc, argv); 428 429 /* Wait for all forks to complete. This needs to be the core that started 430 all of the forks. It may not be the lowest numbered core! */ 431 if (cvmx_get_core_num() == system_info->init_core) 432 { 433 int num_waits; 434 CVMX_POP(num_waits, system_info->core_mask); 435 num_waits--; 436 while (num_waits--) 437 { 438 if (wait(NULL) == -1) 439 perror("CVMX: Wait for forked child failed\n"); 440 } 441 } 442 443 shutdown_cvmx_shared(); 444 445 return result; 446} 447