/** * Detect available CPUs, populate cpu_possible_mask */ static void octeon_smp_hotplug_setup(void) { #ifdef CONFIG_HOTPLUG_CPU struct linux_app_boot_info *labi; labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); if (labi->labi_signature != LABI_SIGNATURE) panic("The bootloader version on this board is incorrect."); octeon_bootloader_entry_addr = labi->InitTLBStart_addr; #endif }
static int octeon_update_boot_vector(unsigned int cpu) { int coreid = cpu_logical_map(cpu); uint32_t avail_coremask; const struct cvmx_bootmem_named_block_desc *block_desc; struct boot_init_vector *boot_vect = (struct boot_init_vector *)PHYS_TO_XKSEG_CACHED(BOOTLOADER_BOOT_VECTOR); block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME); if (!block_desc) { struct linux_app_boot_info *labi; labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); avail_coremask = labi->avail_coremask; labi->avail_coremask &= ~(1 << coreid); } else { /* alternative, already initialized */ avail_coremask = *(uint32_t *)PHYS_TO_XKSEG_CACHED( block_desc->base_addr + AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK); } if (!(avail_coremask & (1 << coreid))) { /* core not available, assume, that caught by simple-executive */ cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid); cvmx_write_csr(CVMX_CIU_PP_RST, 0); } boot_vect[coreid].app_start_func_addr = (uint32_t) (unsigned long) start_after_reset; boot_vect[coreid].code_addr = octeon_bootloader_entry_addr; mb(); cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid) & avail_coremask); return 0; }
static void octeon_cpu_die(unsigned int cpu) { int coreid = cpu_logical_map(cpu); uint32_t mask, new_mask; const struct cvmx_bootmem_named_block_desc *block_desc; while (per_cpu(cpu_state, cpu) != CPU_DEAD) cpu_relax(); /* * This is a bit complicated strategics of getting/settig available * cores mask, copied from bootloader */ mask = 1 << coreid; /* LINUX_APP_BOOT_BLOCK is initialized in bootoct binary */ block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME); if (!block_desc) { struct linux_app_boot_info *labi; labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); labi->avail_coremask |= mask; new_mask = labi->avail_coremask; } else { /* alternative, already initialized */ uint32_t *p = (uint32_t *)PHYS_TO_XKSEG_CACHED(block_desc->base_addr + AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK); *p |= mask; new_mask = *p; } pr_info("Reset core %d. Available Coremask = 0x%x \n", coreid, new_mask); mb(); cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid); cvmx_write_csr(CVMX_CIU_PP_RST, 0); }
/** * Detect available CPUs, populate cpu_possible_mask */ static void octeon_smp_hotplug_setup(void) { #ifdef CONFIG_HOTPLUG_CPU struct linux_app_boot_info *labi; if (!setup_max_cpus) return; labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); if (labi->labi_signature != LABI_SIGNATURE) { pr_info("The bootloader on this board does not support HOTPLUG_CPU."); return; } octeon_bootloader_entry_addr = labi->InitTLBStart_addr; #endif }
/** * Callout to firmware before smp_init * */ void octeon_prepare_cpus(unsigned int max_cpus) { #ifdef CONFIG_HOTPLUG_CPU struct linux_app_boot_info *labi; labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); if (labi->labi_signature != LABI_SIGNATURE) panic("The bootloader version on this board is incorrect."); #endif /* * Only the low order mailbox bits are used for IPIs, leave * the other bits alone. */ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff); if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_PERCPU | IRQF_NO_THREAD, "SMP-IPI", mailbox_interrupt)) { panic("Cannot request_irq(OCTEON_IRQ_MBOX0)"); } }