/** * Main entrypoint of the application. Here we setup shared * memory and fork processes for each cpu. This simulates the * normal simple executive environment of one process per * cpu core. * * @param argc Number of command line arguments * @param argv The command line arguments * @return Return value for the process */ int main(int argc, const char *argv[]) { CVMX_SHARED static cvmx_spinlock_t mask_lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER; CVMX_SHARED static int32_t pending_fork; unsigned long cpumask; unsigned long cpu; setup_system_info(); if (sizeof(void*) == 4) { if (linux_mem32_min) setup_reserve32(); else { printf("\nFailed to access 32bit shared memory region. Most likely the Kernel\n" "has not been configured for 32bit shared memory access. Check the\n" "kernel configuration.\n" "Aborting...\n\n"); exit(-1); } } setup_cvmx_shared(); /* Check to make sure the Chip version matches the configured version */ octeon_model_version_check(cvmx_app_init_processor_id); /* Get the list of logical cpus we should run on */ if (sched_getaffinity(0, sizeof(cpumask), (cpu_set_t*)&cpumask)) { perror("sched_getaffinity failed"); exit(errno); } cvmx_sysinfo_t *system_info = cvmx_sysinfo_get(); cvmx_atomic_set32(&pending_fork, 1); for (cpu=0; cpu<16; cpu++) { if (cpumask & (1<<cpu)) { /* Turn off the bit for this CPU number. We've counted him */ cpumask ^= (1<<cpu); /* If this is the last CPU to run on, use this process instead of forking another one */ if (cpumask == 0) break; /* Increment the number of CPUs running this app */ cvmx_atomic_add32(&pending_fork, 1); /* Fork a process for the new CPU */ int pid = fork(); if (pid == 0) { break; } else if (pid == -1) { perror("Fork failed"); exit(errno); } } } /* Set affinity to lock me to the correct CPU */ cpumask = (1<<cpu); if (sched_setaffinity(0, sizeof(cpumask), (cpu_set_t*)&cpumask)) { perror("sched_setaffinity failed"); exit(errno); } cvmx_spinlock_lock(&mask_lock); system_info->core_mask |= 1<<cvmx_get_core_num(); cvmx_atomic_add32(&pending_fork, -1); if (cvmx_atomic_get32(&pending_fork) == 0) cvmx_dprintf("Active coremask = 0x%x\n", system_info->core_mask); cvmx_spinlock_unlock(&mask_lock); /* Spinning waiting for forks to complete */ while (cvmx_atomic_get32(&pending_fork)) {} cvmx_coremask_barrier_sync(system_info->core_mask); int result = appmain(argc, argv); shutdown_cvmx_shared(); return result; }
void platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, __register_t a3) { const struct octeon_feature_description *ofd; uint64_t platform_counter_freq; int rv; mips_postboot_fixup(); /* * Initialize boot parameters so that we can determine things like * which console we shoud use, etc. */ octeon_boot_params_init(a3); /* Initialize pcpu stuff */ mips_pcpu0_init(); mips_timer_early_init(cvmx_sysinfo_get()->cpu_clock_hz); /* Initialize console. */ cninit(); /* * Display information about the CPU. */ #if !defined(OCTEON_MODEL) printf("Using runtime CPU model checks.\n"); #else printf("Compiled for CPU model: " __XSTRING(OCTEON_MODEL) "\n"); #endif strcpy(cpu_model, octeon_model_get_string(cvmx_get_proc_id())); printf("CPU Model: %s\n", cpu_model); printf("CPU clock: %uMHz Core Mask: %#x\n", cvmx_sysinfo_get()->cpu_clock_hz / 1000000, cvmx_sysinfo_get()->core_mask); rv = octeon_model_version_check(cvmx_get_proc_id()); if (rv == -1) panic("%s: kernel not compatible with this processor.", __func__); /* * Display information about the board. */ #if defined(OCTEON_BOARD_CAPK_0100ND) strcpy(cpu_board, "CAPK-0100ND"); if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CN3010_EVB_HS5) { panic("Compiled for %s, but board type is %s.", cpu_board, cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); } #else strcpy(cpu_board, cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); #endif printf("Board: %s\n", cpu_board); printf("Board Type: %u Revision: %u/%u\n", cvmx_sysinfo_get()->board_type, cvmx_sysinfo_get()->board_rev_major, cvmx_sysinfo_get()->board_rev_minor); printf("Serial number: %s\n", cvmx_sysinfo_get()->board_serial_number); /* * Additional on-chip hardware/settings. * * XXX Display PCI host/target? What else? */ printf("MAC address base: %6D (%u configured)\n", cvmx_sysinfo_get()->mac_addr_base, ":", cvmx_sysinfo_get()->mac_addr_count); octeon_ciu_reset(); /* * Convert U-Boot 'bootoctlinux' loader command line arguments into * boot flags and kernel environment variables. */ bootverbose = 1; octeon_init_kenv(a3); /* * For some reason on the cn38xx simulator ebase register is set to * 0x80001000 at bootup time. Move it back to the default, but * when we move to having support for multiple executives, we need * to rethink this. */ mips_wr_ebase(0x80000000); octeon_memory_init(); init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif cpu_clock = cvmx_sysinfo_get()->cpu_clock_hz; platform_counter_freq = cpu_clock; octeon_timecounter.tc_frequency = cpu_clock; platform_timecounter = &octeon_timecounter; mips_timer_init_params(platform_counter_freq, 0); set_cputicker(octeon_get_ticks, cpu_clock, 0); #ifdef SMP /* * Clear any pending IPIs. */ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(0), 0xffffffff); #endif printf("Octeon SDK: %s\n", OCTEON_SDK_VERSION_STRING); printf("Available Octeon features:"); for (ofd = octeon_feature_descriptions; ofd->ofd_string != NULL; ofd++) if (octeon_has_feature(ofd->ofd_feature)) printf(" %s", ofd->ofd_string); printf("\n"); }