Hi Steven, Please find comments interspersed below. On Friday, 15 September 2017 10:30:13 PDT Steven J. Hill wrote: > From: David Daney <david.daney@xxxxxxxxxx> > This could use some explanation - how does this differ from the hotplug code that's already there? The subject says "working" which suggests the current hotplug code is broken - is it? If so, how? What happens when you try to use it? How about with this patch applied - what happens when you offline a CPU? What happens when you online it again? Does it require interaction with the bootloader? If so what does the bootloader need to provide? What happens if it doesn't? > Signed-off-by: David Daney <david.daney@xxxxxxxxxx> > Signed-off-by: Leonid Rosenboim <lrosenboim@xxxxxxxxxxxxxxxxxx> > Signed-off-by: Chandrakala Chavva <cchavva@xxxxxxxxxxxxxxxxxx> > Signed-off-by: Carlos Munoz <cmunoz@xxxxxxxxxxxxxxxxxx> > Signed-off-by: Corey Minyard <cminyard@xxxxxxxxxx> > --- > arch/mips/Kconfig | 10 +- > arch/mips/cavium-octeon/setup.c | 2 +- > arch/mips/cavium-octeon/smp.c | 213 > +++++++-------------- .../asm/mach-cavium-octeon/kernel-entry-init.h | > 129 ++++++++++++- arch/mips/include/asm/octeon/cvmx-coremask.h | 26 > ++- > arch/mips/include/asm/octeon/cvmx.h | 17 +- > drivers/watchdog/Kconfig | 1 + > 7 files changed, 249 insertions(+), 149 deletions(-) > > diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig > index ed35fd1..3e19353 100644 > --- a/arch/mips/Kconfig > +++ b/arch/mips/Kconfig > @@ -904,7 +904,7 @@ config CAVIUM_OCTEON_SOC > select EDAC_SUPPORT > select EDAC_ATOMIC_SCRUB > select SYS_SUPPORTS_LITTLE_ENDIAN > - select SYS_SUPPORTS_HOTPLUG_CPU if CPU_BIG_ENDIAN > + select SYS_SUPPORTS_HOTPLUG_CPU Why did hotplug depend on big endian before? Why doesn't it now? More things the commit message could explain. > select SYS_HAS_EARLY_PRINTK > select SYS_HAS_CPU_CAVIUM_OCTEON > select HW_HAS_PCI > @@ -2737,6 +2737,14 @@ config NR_CPUS > config MIPS_PERF_SHARED_TC_COUNTERS > bool > > +config MIPS_NR_CPU_NR_MAP_1024 > + bool > + > +config MIPS_NR_CPU_NR_MAP > + int > + default 1024 if MIPS_NR_CPU_NR_MAP_1024 > + default NR_CPUS if !MIPS_NR_CPU_NR_MAP_1024 > + This belongs in patch 1. > # > # Timer Interrupt Frequency Configuration > # > diff --git a/arch/mips/cavium-octeon/setup.c > b/arch/mips/cavium-octeon/setup.c index 2855d8d..068787d 100644 > --- a/arch/mips/cavium-octeon/setup.c > +++ b/arch/mips/cavium-octeon/setup.c > @@ -756,7 +756,7 @@ void __init prom_init(void) > if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2) || > OCTEON_IS_MODEL(OCTEON_CN31XX)) > cvmx_write_csr(CVMX_CIU_SOFT_BIST, 0); > - else > + else if (!OCTEON_IS_MODEL(OCTEON_CN78XX)) > cvmx_write_csr(CVMX_CIU_SOFT_BIST, 1); > > /* Default to 64MB in the simulator to speed things up */ > diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c > index 3de7865..ef6c5ec 100644 > --- a/arch/mips/cavium-octeon/smp.c > +++ b/arch/mips/cavium-octeon/smp.c > @@ -3,26 +3,26 @@ > * License. See the file "COPYING" in the main directory of this archive > * for more details. > * > - * Copyright (C) 2004-2008, 2009, 2010 Cavium Networks > + * Copyright (C) 2004-2017 Cavium, Inc. > */ > #include <linux/cpu.h> > #include <linux/delay.h> > #include <linux/smp.h> > #include <linux/interrupt.h> > -#include <linux/kernel_stat.h> > #include <linux/sched.h> > #include <linux/sched/hotplug.h> > #include <linux/sched/task_stack.h> > #include <linux/init.h> > #include <linux/export.h> > > -#include <asm/mmu_context.h> > #include <asm/time.h> > #include <asm/setup.h> > +#include <asm/cacheflush.h> > +#include <asm/tlbflush.h> > > #include <asm/octeon/octeon.h> > - > -#include "octeon_boot.h" > +#include <asm/octeon/cvmx-sysinfo.h> > +#include <asm/octeon/cvmx-boot-vector.h> > > volatile unsigned long octeon_processor_boot = 0xff; > volatile unsigned long octeon_processor_sp; > @@ -32,10 +32,14 @@ volatile unsigned long > octeon_processor_relocated_kernel_entry; #endif /* CONFIG_RELOCATABLE */ > > #ifdef CONFIG_HOTPLUG_CPU > -uint64_t octeon_bootloader_entry_addr; > -EXPORT_SYMBOL(octeon_bootloader_entry_addr); > +static struct cvmx_boot_vector_element *octeon_bootvector; > +static void *octeon_hotplug_entry_raw; > +extern asmlinkage void octeon_hotplug_entry(void); > #endif > > +/* State of each CPU. */ > +DEFINE_PER_CPU(int, cpu_state); > + > extern void kernel_entry(unsigned long arg1, ...); > > static void octeon_icache_flush(void) > @@ -108,44 +112,22 @@ void octeon_send_ipi_single(int cpu, unsigned int > action) static inline void octeon_send_ipi_mask(const struct cpumask *mask, > unsigned int action) > { > - unsigned int i; > - > - for_each_cpu(i, mask) > - octeon_send_ipi_single(i, action); > -} > - > -/** > - * Detect available CPUs, populate cpu_possible_mask > - */ > -static void octeon_smp_hotplug_setup(void) > -{ > -#ifdef CONFIG_HOTPLUG_CPU > - struct linux_app_boot_info *labi; > + int cpu; > > - 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 > + for_each_cpu(cpu, mask) > + octeon_send_ipi_single(cpu, action); > } > > -static void __init octeon_smp_setup(void) > +static void octeon_smp_setup(void) > { > const int coreid = cvmx_get_core_num(); > int cpus; > int id; > - struct cvmx_sysinfo *sysinfo = cvmx_sysinfo_get(); > - > #ifdef CONFIG_HOTPLUG_CPU > - int core_mask = octeon_get_boot_coremask(); > unsigned int num_cores = cvmx_octeon_num_cores(); > + unsigned long t; > #endif > + struct cvmx_sysinfo *sysinfo = cvmx_sysinfo_get(); > > /* The present CPUs are initially just the boot cpu (CPU 0). */ > for (id = 0; id < NR_CPUS; id++) { > @@ -158,7 +140,7 @@ static void __init octeon_smp_setup(void) > > /* The present CPUs get the lowest CPU numbers. */ > cpus = 1; > - for (id = 0; id < NR_CPUS; id++) { > + for (id = 0; id < CONFIG_MIPS_NR_CPU_NR_MAP; id++) { > if ((id != coreid) && cvmx_coremask_is_core_set(&sysinfo->core_mask, id)) > { set_cpu_possible(cpus, true); > set_cpu_present(cpus, true); > @@ -169,14 +151,22 @@ static void __init octeon_smp_setup(void) > } > > #ifdef CONFIG_HOTPLUG_CPU > + > + octeon_bootvector = cvmx_boot_vector_get(); > + if (!octeon_bootvector) { > + pr_err("Error: Cannot allocate boot vector.\n"); > + return; > + } > + t = __pa_symbol(octeon_hotplug_entry); > + octeon_hotplug_entry_raw = phys_to_virt(t); > + > /* > * The possible CPUs are all those present on the chip. We > * will assign CPU numbers for possible cores as well. Cores > * are always consecutively numberd from 0. > */ > - for (id = 0; setup_max_cpus && octeon_bootloader_entry_addr && > - id < num_cores && id < NR_CPUS; id++) { > - if (!(core_mask & (1 << id))) { > + for (id = 0; id < num_cores && id < NR_CPUS; id++) { > + if (!(cvmx_coremask_is_core_set(&sysinfo->core_mask, id))) { > set_cpu_possible(cpus, true); > __cpu_number_map[id] = cpus; > __cpu_logical_map[cpus] = id; > @@ -184,8 +174,6 @@ static void __init octeon_smp_setup(void) > } > } > #endif > - > - octeon_smp_hotplug_setup(); > } > > > @@ -208,13 +196,31 @@ int plat_post_relocation(long offset) > static void octeon_boot_secondary(int cpu, struct task_struct *idle) > { > int count; > + int node; > + int coreid = cpu_logical_map(cpu); > > + per_cpu(cpu_state, smp_processor_id()) = CPU_UP_PREPARE; > + octeon_bootvector[coreid].target_ptr = (uint64_t)octeon_hotplug_entry_raw; > + mb(); > + /* Convert coreid to node,core spair and send NMI to target core */ > + node = cvmx_coremask_core_to_node(coreid); > + coreid = cvmx_coremask_core_on_node(coreid); > + if (octeon_has_feature(OCTEON_FEATURE_CIU3)) > + cvmx_write_csr_node(node, CVMX_CIU3_NMI, (1ull << coreid)); > + else > + cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid)); > pr_info("SMP: Booting CPU%02d (CoreId %2d)...\n", cpu, > cpu_logical_map(cpu)); > > octeon_processor_sp = __KSTK_TOS(idle); > octeon_processor_gp = (unsigned long)(task_thread_info(idle)); > - octeon_processor_boot = cpu_logical_map(cpu); > + /* This barrier is needed to guarangee the following is done last */ s/guarangee/guarantee/ > + mb(); > + > + /* Indicate which core is being brought up out of pan */ > + octeon_processor_boot = coreid; > + > + /* Push the last update out before polling */ > mb(); > > count = 10000; > @@ -222,9 +228,13 @@ static void octeon_boot_secondary(int cpu, struct > task_struct *idle) /* Waiting for processor to get the SP and GP */ > udelay(1); > count--; > + mb(); Why this barrier? I presume it's to cause octeon_processor_sp to be re-read on each iteration? If so why not use READ_ONCE()? There are other uncommented memory barriers too - checkpatch spots 4. > } > if (count == 0) > pr_err("Secondary boot timeout\n"); > + > + octeon_processor_boot = ~0ul; > + mb(); > } > > /** > @@ -251,11 +261,24 @@ static void octeon_init_secondary(void) > */ > static void __init octeon_prepare_cpus(unsigned int max_cpus) > { > + u64 mask; > + u64 coreid; > + > /* > * 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 (OCTEON_IS_MODEL(OCTEON_CN68XX)) > + mask = 0xff; > + else > + mask = 0xffff; > + > + coreid = cvmx_get_core_num(); > + > + /* Clear pending mailbox interrupts */ > + cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), mask); > + > + /* Attach mailbox interrupt handler */ > if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, > IRQF_PERCPU | IRQF_NO_THREAD, "SMP-IPI", > mailbox_interrupt)) { > @@ -270,6 +293,8 @@ static void __init octeon_prepare_cpus(unsigned int > max_cpus) static void octeon_smp_finish(void) > { > octeon_user_io_init(); > + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; > + mb(); > > /* to generate the first CPU timer interrupt */ > write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); > @@ -278,9 +303,6 @@ static void octeon_smp_finish(void) > > #ifdef CONFIG_HOTPLUG_CPU > > -/* State of each CPU. */ > -DEFINE_PER_CPU(int, cpu_state); > - > static int octeon_cpu_disable(void) > { > unsigned int cpu = smp_processor_id(); > @@ -288,9 +310,6 @@ static int octeon_cpu_disable(void) > if (cpu == 0) > return -EBUSY; > > - if (!octeon_bootloader_entry_addr) > - return -ENOTSUPP; > - > set_cpu_online(cpu, false); > calculate_cpu_foreign_map(); > octeon_fixup_irqs(); > @@ -303,40 +322,8 @@ static int octeon_cpu_disable(void) > > 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); > } > > void play_dead(void) > @@ -344,71 +331,19 @@ void play_dead(void) > int cpu = cpu_number_map(cvmx_get_core_num()); > > idle_task_exit(); > - octeon_processor_boot = 0xff; > per_cpu(cpu_state, cpu) = CPU_DEAD; > - > mb(); > - > - while (1) /* core will be reset here */ > - ; > -} > - > -static void start_after_reset(void) > -{ > - kernel_entry(0, 0, 0); /* set a2 = 0 for secondary core */ > -} > - > -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); > + local_irq_disable(); > + while (1) { /* core will be reset here */ > + asm volatile ("nop\n" > + " wait\n" > + " nop\n"); Are the nops necessary? If so could you add a comment saying why? > } > - > - 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 int register_cavium_notifier(void) > -{ > - return cpuhp_setup_state_nocalls(CPUHP_MIPS_SOC_PREPARE, > - "mips/cavium:prepare", > - octeon_update_boot_vector, NULL); > } > -late_initcall(register_cavium_notifier); > > #endif /* CONFIG_HOTPLUG_CPU */ > > -struct plat_smp_ops octeon_smp_ops = { > +static struct plat_smp_ops octeon_smp_ops = { > .send_ipi_single = octeon_send_ipi_single, > .send_ipi_mask = octeon_send_ipi_mask, > .init_secondary = octeon_init_secondary, > diff --git a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h > b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h index > c38b38c..5093a2f 100644 > --- a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h > +++ b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h > @@ -3,11 +3,13 @@ > * License. See the file "COPYING" in the main directory of this archive > * for more details. > * > - * Copyright (C) 2005-2008 Cavium Networks, Inc > + * Copyright (C) 2005-2017 Cavium, Inc > */ > #ifndef __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H > #define __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H > > +#include <asm/octeon/cvmx-asm.h> > + > #define CP0_CVMCTL_REG $9, 7 > #define CP0_CVMMEMCTL_REG $11,7 > #define CP0_PRID_REG $15, 0 > @@ -26,6 +28,131 @@ > # a3 = address of boot descriptor block > .set push > .set arch=octeon > +#ifdef CONFIG_HOTPLUG_CPU > + b 7f > +FEXPORT(octeon_hotplug_entry) > + move a0, zero > + move a1, zero > + move a2, zero > + move a3, zero > +7: > +#endif /* CONFIG_HOTPLUG_CPU */ > + mfc0 v0, CP0_STATUS > + /* Force 64-bit addressing enabled */ > + ori v0, v0, (ST0_UX | ST0_SX | ST0_KX) > + /* Clear NMI and SR as they are sometimes restored and 0 -> 1 > + * transitions are not allowed > + */ > + li v1, ~(ST0_NMI | ST0_SR) > + and v0, v1 > + mtc0 v0, CP0_STATUS > + > + # Clear the TLB. > + mfc0 v0, $16, 1 # Config1 s/$16/CP0_CONFIG/ ? Below too. > + dsrl v0, v0, 25 > + andi v0, v0, 0x3f ext v0, v0, MIPS_CONF1_TLBS_SHIFT, MIPS_CONF1_TLBS_SIZE? Or at least use the field macros with your shift & and. > + mfc0 v1, $16, 3 # Config3 > + bgez v1, 1f > + mfc0 v1, $16, 4 # Config4 > + andi v1, 0x7f Is this reading MMUSizeExt? Note that's 8 bits, not 7. Why not: andi v1, v1, MIPS_CONF4_MMUSIZEEXT > + dsll v1, 6 > + or v0, v0, v1 ins v0, v1, MIPS_CONF1_TLBS_SIZE, MIPS_CONF4_MMUSIZEEXT_SIZE? Would need to add MIPS_CONF4_MMUSIZEEXT_SIZE for that. > +1: # Number of TLBs in v0 > + > + dmtc0 zero, $2, 0 # EntryLo0 > + dmtc0 zero, $3, 0 # EntryLo1 > + dmtc0 zero, $5, 0 # PageMask > + dla t0, 0xffffffff90000000 > +10: > + dmtc0 t0, $10, 0 # EntryHi > + tlbp > + mfc0 t1, $0, 0 # Index > + bltz t1, 1f > + tlbr > + dmtc0 zero, $2, 0 # EntryLo0 > + dmtc0 zero, $3, 0 # EntryLo1 > + dmtc0 zero, $5, 0 # PageMask > + tlbwi # Make it a 'normal' sized page > + daddiu t0, t0, 8192 > + b 10b > +1: > + mtc0 v0, $0, 0 # Index > + tlbwi > + .set noreorder > + bne v0, zero, 10b > + addiu v0, v0, -1 > + .set reorder > + > + mtc0 zero, $0, 0 # Index > + dmtc0 zero, $10, 0 # EntryHi > + > +#ifdef CONFIG_MAPPED_KERNEL Octeon doesn't support CONFIG_MAPPED_KERNEL, at least not upstream. Please remove this - it can be added later if you submit CONFIG_MAPPED_KERNEL support upstream. > + # Set up the TLB index 0 for wired access to kernel. > + # Assume we were loaded with sufficient alignment so that we > + # can cover the image with two pages. > + dla v0, _end > + dla s0, _text > + dsubu v0, v0, s0 # size of image > + move v1, zero > + li t1, -1 # shift count. > +1: dsrl v0, v0, 1 # mask into v1 > + dsll v1, v1, 1 > + daddiu t1, t1, 1 > + ori v1, v1, 1 > + bne v0, zero, 1b > + daddiu t2, t1, -6 > + mtc0 v1, $5, 0 # PageMask > + dla t3, 0xffffffffc0000000 # kernel address > + dmtc0 t3, $10, 0 # EntryHi > + .set push > + .set noreorder > + .set nomacro > + bal 1f > + nop > +1: > + .set pop > + > + dsra v0, ra, 31 > + daddiu v0, v0, 1 # if it were a ckseg0 address v0 will be zero. > + beqz v0, 3f > + dli v0, 0x07ffffffffffffff # Otherwise assume xkphys. > + b 2f > +3: > + dli v0, 0x7fffffff > + > +2: and ra, ra, v0 # physical address of pc in ra > + dla v0, 1b > + dsubu v0, v0, s0 # distance from _text to 1: in v0 > + dsubu ra, ra, v0 # ra is physical address of _text > + dsrl v1, v1, 1 > + nor v1, v1, zero > + and ra, ra, v1 # mask it with the page mask > + dsubu v1, t3, ra # virtual to physical offset into v1 > + dsrlv v0, ra, t1 > + dsllv v0, v0, t2 > + ori v0, v0, 0x1f > + dmtc0 v0, $2, 0 # EntryLo1 > + dsrlv v0, ra, t1 > + daddiu v0, v0, 1 > + dsllv v0, v0, t2 > + ori v0, v0, 0x1f > + dmtc0 v0, $3, 0 # EntryLo2 > + mtc0 $0, $0, 0 # Set index to zero > + tlbwi > + li v0, 1 > + mtc0 v0, $6, 0 # Wired > + dla v0, phys_to_kernel_offset > + sd v1, 0(v0) > + dla v0, kernel_image_end > + li v1, 2 > + dsllv v1, v1, t1 > + daddu v1, v1, t3 > + sd v1, 0(v0) > +#endif > + dla v0, continue_in_mapped_space > + jr v0 > + > +continue_in_mapped_space: > # Read the cavium mem control register > dmfc0 v0, CP0_CVMMEMCTL_REG > # Clear the lower 6 bits, the CVMSEG size > diff --git a/arch/mips/include/asm/octeon/cvmx-coremask.h > b/arch/mips/include/asm/octeon/cvmx-coremask.h index 097dc09..a4de3c2 > 100644 > --- a/arch/mips/include/asm/octeon/cvmx-coremask.h > +++ b/arch/mips/include/asm/octeon/cvmx-coremask.h > @@ -29,7 +29,6 @@ > #ifndef __CVMX_COREMASK_H__ > #define __CVMX_COREMASK_H__ > > -#define CVMX_MIPS_MAX_CORES 1024 > /* bits per holder */ > #define CVMX_COREMASK_ELTSZ 64 > > @@ -86,4 +85,29 @@ static inline void cvmx_coremask_clear_core(struct > cvmx_coremask *pcm, int core) pcm->coremask_bitmap[i] &= ~(1ull << n); > } > > +/** > + * For multi-node systems, return the node a core belongs to. > + * > + * @param core - core number (0-1023) > + * > + * @return node number core belongs to > + */ > +static inline int cvmx_coremask_core_to_node(int core) > +{ > + return (core >> CVMX_NODE_NO_SHIFT) & CVMX_NODE_MASK; > +} > + > +/** > + * Given a core number on a multi-node system, return the core number for a > + * particular node. > + * > + * @param core - global core number > + * > + * @returns core number local to the node. > + */ > +static inline int cvmx_coremask_core_on_node(int core) > +{ > + return (core & ((1 << CVMX_NODE_NO_SHIFT) - 1)); core & GENMASK(CVMX_NODE_NO_SHIFT - 1, 0) ? > +} > + > #endif /* __CVMX_COREMASK_H__ */ > diff --git a/arch/mips/include/asm/octeon/cvmx.h > b/arch/mips/include/asm/octeon/cvmx.h index 1c0a929..455d4f54 100644 > --- a/arch/mips/include/asm/octeon/cvmx.h > +++ b/arch/mips/include/asm/octeon/cvmx.h > @@ -53,6 +53,17 @@ enum cvmx_mips_space { > #define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add)) > #endif > > +#define CVMX_MAX_CORES (48) > +#define CVMX_MIPS_MAX_CORE_BITS (10) /** Maximum # of bits to define > cores */ +#define CVMX_MIPS_MAX_CORES (1 << CVMX_MIPS_MAX_CORE_BITS) > +#define CVMX_NODE_NO_SHIFT (7) /* Maximum # of bits to define core in > node */ +#define CVMX_NODE_BITS (2) /* Number of bits to define a node > */ +#define CVMX_NODE_MASK (CVMX_MAX_NODES - 1) > +#define CVMX_MAX_NODES (1 << CVMX_NODE_BITS) > +#define CVMX_NODE_IO_SHIFT (36) > +#define CVMX_NODE_MEM_SHIFT (40) > +#define CVMX_NODE_IO_MASK ((uint64_t)CVMX_NODE_MASK << CVMX_NODE_IO_SHIFT) > + > #include <asm/octeon/cvmx-asm.h> > #include <asm/octeon/octeon-model.h> > > @@ -83,7 +94,6 @@ enum cvmx_mips_space { > #define cvmx_dprintf(...) {} > #endif > > -#define CVMX_MAX_CORES (16) > #define CVMX_CACHE_LINE_SIZE (128) /* In bytes */ > #define CVMX_CACHE_LINE_MASK (CVMX_CACHE_LINE_SIZE - 1) /* In bytes */ > #define CVMX_CACHE_LINE_ALIGNED __attribute__ > ((aligned(CVMX_CACHE_LINE_SIZE))) @@ -361,16 +371,11 @@ static inline > unsigned int cvmx_get_core_num(void) return core_num; > } > > -/* Maximum # of bits to define core in node */ > -#define CVMX_NODE_NO_SHIFT 7 > -#define CVMX_NODE_MASK 0x3 > static inline unsigned int cvmx_get_node_num(void) > { > unsigned int core_num = cvmx_get_core_num(); > - > return (core_num >> CVMX_NODE_NO_SHIFT) & CVMX_NODE_MASK; > } > - > static inline unsigned int cvmx_get_local_core_num(void) > { > return cvmx_get_core_num() & ((1 << CVMX_NODE_NO_SHIFT) - 1); > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig > index c722cbf..b68708e 100644 > --- a/drivers/watchdog/Kconfig > +++ b/drivers/watchdog/Kconfig > @@ -1511,6 +1511,7 @@ config TXX9_WDT > config OCTEON_WDT > tristate "Cavium OCTEON SOC family Watchdog Timer" > depends on CAVIUM_OCTEON_SOC > + depends on CPU_BIG_ENDIAN || !HOTPLUG_CPU This could at least use a mention in the commit message explaining why the watchdog doesn't work with little endian & hotplug. > default y > select WATCHDOG_CORE > select EXPORT_UASM if OCTEON_WDT = m Thanks, Paul
Attachment:
signature.asc
Description: This is a digitally signed message part.