1 /***********************license start***************
2 * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
18 * * Neither the name of Cavium Networks nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
23 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
45 * Simple executive application initialization for Linux user space. This
46 * file should be used instead of cvmx-app-init.c for running simple executive
47 * applications under Linux in userspace. The following are some of the key
48 * points to remember when writing applications to run both under the
49 * standalone simple executive and userspace under Linux.
51 * -# Application main must be called "appmain" under Linux. Use and ifdef
52 * based on __linux__ to determine the proper name.
53 * -# Be careful to use cvmx_ptr_to_phys() and cvmx_phys_to_ptr. The simple
54 * executive 1-1 TLB mappings allow you to be sloppy and interchange
55 * hardware addresses with virtual address. This isn't true under Linux.
56 * -# If you're talking directly to hardware, be careful. The normal Linux
57 * protections are circumvented. If you do something bad, Linux won't
59 * -# Most hardware can only be initialized once. Unless you're very careful,
60 * this also means you Linux application can only run once.
62 * <hr>$Revision: 41757 $<hr>
76 #include <sys/statfs.h>
78 #include <sys/sysmips.h>
80 #include <octeon-app-init.h>
82 #include "cvmx-config.h"
84 #include "cvmx-atomic.h"
85 #include "cvmx-sysinfo.h"
86 #include "cvmx-coremask.h"
87 #include "cvmx-spinlock.h"
88 #include "cvmx-bootmem.h"
90 int octeon_model_version_check(uint32_t chip_id);
92 #define OCTEON_ECLOCK_MULT_INPUT_X16 ((int)(33.4*16))
94 /* Applications using the simple executive libraries under Linux userspace must
95 rename their "main" function to match the prototype below. This allows the
96 simple executive to perform needed memory initialization and process
97 creation before the application runs. */
98 extern int appmain(int argc, const char *argv[]);
100 /* These two external addresses provide the beginning and end markers for the
101 CVMX_SHARED section. These are defined by the cvmx-shared.ld linker script.
102 If they aren't defined, you probably forgot to link using this script. */
103 extern void __cvmx_shared_start;
104 extern void __cvmx_shared_end;
105 extern uint64_t linux_mem32_min;
106 extern uint64_t linux_mem32_max;
107 extern uint64_t linux_mem32_wired;
108 extern uint64_t linux_mem32_offset;
110 #define MIPS_CAVIUM_XKPHYS_READ 2010 /* XKPHYS */
111 #define MIPS_CAVIUM_XKPHYS_WRITE 2011 /* XKPHYS */
113 static CVMX_SHARED int32_t warn_count;
116 * This function performs some default initialization of the Octeon executive. It initializes
117 * the cvmx_bootmem memory allocator with the list of physical memory shared by the bootloader.
118 * This function should be called on all cores that will use the bootmem allocator.
119 * Applications which require a different configuration can replace this function with a suitable application
122 * @return 0 on success
125 int cvmx_user_app_init(void)
132 * Simulator magic is not supported in user mode under Linux.
133 * This version of simprintf simply calls the underlying C
134 * library printf for output. It also makes sure that two
135 * calls to simprintf provide atomic output.
137 * @param fmt Format string in the same format as printf.
139 void simprintf(const char *fmt, ...)
141 CVMX_SHARED static cvmx_spinlock_t simprintf_lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER;
144 cvmx_spinlock_lock(&simprintf_lock);
145 printf("SIMPRINTF(%d): ", (int)cvmx_get_core_num());
149 cvmx_spinlock_unlock(&simprintf_lock);
154 * Setup the CVMX_SHARED data section to be shared across
155 * all processors running this application. A memory mapped
156 * region is allocated using shm_open and mmap. The current
157 * contents of the CVMX_SHARED section are copied into the
158 * region. Then the new region is remapped to replace the
159 * existing CVMX_SHARED data.
161 * This function will display a message and abort the
162 * application under any error conditions. The Linux tmpfs
163 * filesystem must be mounted under /dev/shm.
165 static void setup_cvmx_shared(void)
167 const char *SHM_NAME = "cvmx_shared";
168 unsigned long shared_size = &__cvmx_shared_end - &__cvmx_shared_start;
171 /* If there isn't and shared data we can skip all this */
175 printf("CVMX_SHARED: %p-%p\n", &__cvmx_shared_start, &__cvmx_shared_end);
178 const char *defaultdir = "/dev/shm/";
181 /* The canonical place is /dev/shm. */
182 if (statfs (defaultdir, &f) == 0)
185 sprintf (shm_name, "%s%s-%d", defaultdir, SHM_NAME, pid);
189 perror("/dev/shm is not mounted");
193 /* shm_open(), shm_unlink() are not implemented in uClibc. Do the
194 same thing using open() and close() system calls. */
195 fd = open (shm_name, O_RDWR | O_CREAT | O_TRUNC, 0);
199 perror("Failed to open CVMX_SHARED(shm_name)");
205 sprintf(shm_name, "%s-%d", SHM_NAME, getpid());
206 /* Open a new shared memory region for use as CVMX_SHARED */
207 fd = shm_open(shm_name, O_RDWR | O_CREAT | O_TRUNC, 0);
210 perror("Failed to setup CVMX_SHARED(shm_open)");
214 /* We don't want the file on the filesystem. Immediately unlink it so
215 another application can create its own shared region */
216 shm_unlink(shm_name);
219 /* Resize the region to match the size of CVMX_SHARED */
220 ftruncate(fd, shared_size);
222 /* Map the region into some random location temporarily so we can
223 copy the shared data to it */
224 void *ptr = mmap(NULL, shared_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
227 perror("Failed to setup CVMX_SHARED(mmap copy)");
231 /* Copy CVMX_SHARED to the new shared region so we don't lose
233 memcpy(ptr, &__cvmx_shared_start, shared_size);
234 munmap(ptr, shared_size);
236 /* Remap the shared region to replace the old CVMX_SHARED region */
237 ptr = mmap(&__cvmx_shared_start, shared_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
240 perror("Failed to setup CVMX_SHARED(mmap final)");
244 /* Once mappings are setup, the file handle isn't needed anymore */
251 * Shutdown and free the shared CVMX_SHARED region setup by
254 static void shutdown_cvmx_shared(void)
256 unsigned long shared_size = &__cvmx_shared_end - &__cvmx_shared_start;
258 munmap(&__cvmx_shared_start, shared_size);
263 * Setup access to the CONFIG_CAVIUM_RESERVE32 memory section
264 * created by the kernel. This memory is used for shared
265 * hardware buffers with 32 bit userspace applications.
267 static void setup_reserve32(void)
269 if (linux_mem32_min && linux_mem32_max)
271 int region_size = linux_mem32_max - linux_mem32_min + 1;
272 int mmap_flags = MAP_SHARED;
273 void *linux_mem32_base_ptr = NULL;
275 /* Although not strictly necessary, we are going to mmap() the wired
276 TLB region so it is in the process page tables. These pages will
277 never fault in, but they will allow GDB to access the wired
278 region. We need the mappings to exactly match the wired TLB
280 if (linux_mem32_wired)
282 mmap_flags |= MAP_FIXED;
283 linux_mem32_base_ptr = CASTPTR(void, (1ull<<31) - region_size);
286 int fd = open("/dev/mem", O_RDWR);
289 perror("ERROR opening /dev/mem");
293 linux_mem32_base_ptr = mmap64(linux_mem32_base_ptr,
295 PROT_READ | PROT_WRITE,
301 if (MAP_FAILED == linux_mem32_base_ptr)
303 perror("Error mapping reserve32");
307 linux_mem32_offset = CAST64(linux_mem32_base_ptr) - linux_mem32_min;
313 * Main entrypoint of the application. Here we setup shared
314 * memory and fork processes for each cpu. This simulates the
315 * normal simple executive environment of one process per
318 * @param argc Number of command line arguments
319 * @param argv The command line arguments
320 * @return Return value for the process
322 int main(int argc, const char *argv[])
324 CVMX_SHARED static cvmx_spinlock_t mask_lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER;
325 CVMX_SHARED static int32_t pending_fork;
326 unsigned long cpumask;
330 cvmx_sysinfo_linux_userspace_initialize();
332 if (sizeof(void*) == 4)
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"
347 cvmx_bootmem_init(cvmx_sysinfo_get()->phy_mem_desc_ptr);
349 /* Check to make sure the Chip version matches the configured version */
350 octeon_model_version_check(cvmx_get_proc_id());
352 /* Get the list of logical cpus we should run on */
353 if (sched_getaffinity(0, sizeof(cpumask), (cpu_set_t*)&cpumask))
355 perror("sched_getaffinity failed");
359 cvmx_sysinfo_t *system_info = cvmx_sysinfo_get();
361 cvmx_atomic_set32(&pending_fork, 1);
362 for (cpu=0; cpu<16; cpu++)
364 if (cpumask & (1<<cpu))
366 /* Turn off the bit for this CPU number. We've counted him */
368 /* If this is the last CPU to run on, use this process instead of forking another one */
374 /* Increment the number of CPUs running this app */
375 cvmx_atomic_add32(&pending_fork, 1);
376 /* Flush all IO streams before the fork. Otherwise any buffered
377 data in the C library will be duplicated. This results in
378 duplicate output from a single print */
380 /* Fork a process for the new CPU */
388 perror("Fork failed");
394 /* Set affinity to lock me to the correct CPU */
396 if (sched_setaffinity(0, sizeof(cpumask), (cpu_set_t*)&cpumask))
398 perror("sched_setaffinity failed");
402 cvmx_spinlock_lock(&mask_lock);
403 system_info->core_mask |= 1<<cvmx_get_core_num();
404 cvmx_atomic_add32(&pending_fork, -1);
405 if (cvmx_atomic_get32(&pending_fork) == 0)
406 cvmx_dprintf("Active coremask = 0x%x\n", system_info->core_mask);
408 system_info->init_core = cvmx_get_core_num();
409 cvmx_spinlock_unlock(&mask_lock);
411 /* Spinning waiting for forks to complete */
412 while (cvmx_atomic_get32(&pending_fork)) {}
414 cvmx_coremask_barrier_sync(system_info->core_mask);
416 int ret = sysmips(MIPS_CAVIUM_XKPHYS_WRITE, getpid(), 3, 0);
418 int32_t w = cvmx_atomic_fetch_and_add32(&warn_count, 1);
422 perror("sysmips(MIPS_CAVIUM_XKPHYS_WRITE) failed.\n"
423 " Did you configure your kernel with both:\n"
424 " CONFIG_CAVIUM_OCTEON_USER_MEM_PER_PROCESS *and*\n"
425 " CONFIG_CAVIUM_OCTEON_USER_IO_PER_PROCESS?");
428 perror("sysmips(MIPS_CAVIUM_XKPHYS_WRITE) failed.\n"
429 " Are you running as root?");
432 perror("sysmips(MIPS_CAVIUM_XKPHYS_WRITE) failed");
438 int result = appmain(argc, argv);
440 /* Wait for all forks to complete. This needs to be the core that started
441 all of the forks. It may not be the lowest numbered core! */
442 if (cvmx_get_core_num() == system_info->init_core)
445 CVMX_POP(num_waits, system_info->core_mask);
449 if (wait(NULL) == -1)
450 perror("CVMX: Wait for forked child failed\n");
454 shutdown_cvmx_shared();