On Thu, Aug 16, 2018 at 5:26 AM, Atish Patra <atish.pa...@wdc.com> wrote: > Setup the cpu_logical_map during boot. Moreover, every SBI call > and PLIC context are based on the physical hartid. Use the logical > cpu to hartid mapping to pass correct hartid to respective functions. > > Signed-off-by: Atish Patra <atish.pa...@wdc.com> > --- > arch/riscv/include/asm/tlbflush.h | 17 +++++++++++++---- > arch/riscv/kernel/cpu.c | 4 +++- > arch/riscv/kernel/setup.c | 10 ++++++++++ > arch/riscv/kernel/smp.c | 24 +++++++++++++++--------- > arch/riscv/kernel/smpboot.c | 30 ++++++++++++++++++------------ > drivers/clocksource/riscv_timer.c | 12 ++++++++---- > drivers/irqchip/irq-sifive-plic.c | 11 +++++++---- > 7 files changed, 74 insertions(+), 34 deletions(-) > > diff --git a/arch/riscv/include/asm/tlbflush.h > b/arch/riscv/include/asm/tlbflush.h > index 85c2d8ba..ecfd9b0e 100644 > --- a/arch/riscv/include/asm/tlbflush.h > +++ b/arch/riscv/include/asm/tlbflush.h > @@ -16,6 +16,7 @@ > #define _ASM_RISCV_TLBFLUSH_H > > #include <linux/mm_types.h> > +#include <asm/smp.h> > > /* > * Flush entire local TLB. 'sfence.vma' implicitly fences with the > instruction > @@ -49,13 +50,21 @@ static inline void flush_tlb_range(struct vm_area_struct > *vma, > > #include <asm/sbi.h> > > -#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1) > +static inline void remote_sfence_vma(struct cpumask *cmask, unsigned long > start, > + unsigned long size) > +{ > + struct cpumask hmask; > + > + cpuid_to_hartid_mask(cmask, &hmask); > + sbi_remote_sfence_vma(hmask.bits, start, size); > +} > + > +#define flush_tlb_all() remote_sfence_vma(NULL, 0, -1) > #define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0) > #define flush_tlb_range(vma, start, end) \ > - sbi_remote_sfence_vma(mm_cpumask((vma)->vm_mm)->bits, \ > - start, (end) - (start)) > + remote_sfence_vma(mm_cpumask((vma)->vm_mm), start, (end) - (start)) > #define flush_tlb_mm(mm) \ > - sbi_remote_sfence_vma(mm_cpumask(mm)->bits, 0, -1) > + remote_sfence_vma(mm_cpumask(mm), 0, -1) > > #endif /* CONFIG_SMP */ > > diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c > index ca6c81e5..f8a18ace 100644 > --- a/arch/riscv/kernel/cpu.c > +++ b/arch/riscv/kernel/cpu.c > @@ -14,6 +14,7 @@ > #include <linux/init.h> > #include <linux/seq_file.h> > #include <linux/of.h> > +#include <asm/smp.h> > > /* Return -1 if not a valid hart */ > int riscv_of_processor_hart(struct device_node *node) > @@ -79,7 +80,8 @@ static void c_stop(struct seq_file *m, void *v) > static int c_show(struct seq_file *m, void *v) > { > unsigned long hart_id = (unsigned long)v - 1; > - struct device_node *node = of_get_cpu_node(hart_id, NULL); > + struct device_node *node = of_get_cpu_node(cpu_logical_map(hart_id), > + NULL);
The hart_id is misleading name here. It should be cpu_id. Please replace all instances of hart_id with cpu_id and where hard ID is to be displayed use cpu_logical_map(cpu_id). > const char *compat, *isa, *mmu; > > seq_printf(m, "hart\t: %lu\n", hart_id); > diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c > index e21ed481..97b586f8 100644 > --- a/arch/riscv/kernel/setup.c > +++ b/arch/riscv/kernel/setup.c > @@ -84,6 +84,16 @@ atomic_t hart_lottery; > > u64 __cpu_logical_map[NR_CPUS]; > > +void __init smp_setup_processor_id(void) > +{ > + int cpu = smp_processor_id(); > + > + cpu_logical_map(0) = cpu; I think this should be: cpu_logical_map(cpu) = hart_id; Here hart_id for boot CPU will be value of a0 register passed at boot-time. > + > + /* Change the boot cpu ID in thread_info */ > + current->thread_info.cpu = 0; > +} > + > #ifdef CONFIG_BLK_DEV_INITRD > static void __init setup_initrd(void) > { > diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c > index d55379ee..4ab70480 100644 > --- a/arch/riscv/kernel/smp.c > +++ b/arch/riscv/kernel/smp.c > @@ -97,14 +97,18 @@ void riscv_software_interrupt(void) > static void > send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type > operation) > { > - int i; > + int cpuid, hartid; > + struct cpumask hartid_mask; > > + cpumask_clear(&hartid_mask); > mb(); > - for_each_cpu(i, to_whom) > - set_bit(operation, &ipi_data[i].bits); > - > + for_each_cpu(cpuid, to_whom) { > + set_bit(operation, &ipi_data[cpuid].bits); > + hartid = cpu_logical_map(cpuid); > + cpumask_set_cpu(hartid, &hartid_mask); > + } > mb(); > - sbi_send_ipi(cpumask_bits(to_whom)); > + sbi_send_ipi(cpumask_bits(&hartid_mask)); > } > > void arch_send_call_function_ipi_mask(struct cpumask *mask) > @@ -146,7 +150,7 @@ void smp_send_reschedule(int cpu) > void flush_icache_mm(struct mm_struct *mm, bool local) > { > unsigned int cpu; > - cpumask_t others, *mask; > + cpumask_t others, hmask, *mask; > > preempt_disable(); > > @@ -164,9 +168,11 @@ void flush_icache_mm(struct mm_struct *mm, bool local) > */ > cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); > local |= cpumask_empty(&others); > - if (mm != current->active_mm || !local) > - sbi_remote_fence_i(others.bits); > - else { > + if (mm != current->active_mm || !local) { > + cpumask_clear(&hmask); > + cpuid_to_hartid_mask(&others, &hmask); > + sbi_remote_fence_i(hmask.bits); > + } else { > /* > * It's assumed that at least one strongly ordered operation > is > * performed on this hart between setting a hart's cpumask bit > diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c > index 56abab6a..6ab2bb1b 100644 > --- a/arch/riscv/kernel/smpboot.c > +++ b/arch/riscv/kernel/smpboot.c > @@ -50,27 +50,33 @@ void __init smp_prepare_cpus(unsigned int max_cpus) > void __init setup_smp(void) > { > struct device_node *dn = NULL; > - int hart, im_okay_therefore_i_am = 0; > + int hart, found_boot_cpu = 0; > + int cpuid = 1; > > while ((dn = of_find_node_by_type(dn, "cpu"))) { > hart = riscv_of_processor_hart(dn); > - if (hart >= 0) { > - set_cpu_possible(hart, true); > - set_cpu_present(hart, true); > - if (hart == smp_processor_id()) { > - BUG_ON(im_okay_therefore_i_am); > - im_okay_therefore_i_am = 1; > - } > + > + if (hart < 0) > + continue; > + if (hart == cpu_logical_map(0)) { > + BUG_ON(found_boot_cpu); > + found_boot_cpu = 1; > + continue; > } > + > + cpu_logical_map(cpuid) = hart; > + set_cpu_possible(cpuid, true); > + set_cpu_present(cpuid, true); > + cpuid++; > } > > - BUG_ON(!im_okay_therefore_i_am); > + BUG_ON(!found_boot_cpu); > } > > int __cpu_up(unsigned int cpu, struct task_struct *tidle) > { > + int hartid = cpu_logical_map(cpu); > tidle->thread_info.cpu = cpu; > - > /* > * On RISC-V systems, all harts boot on their own accord. Our _start > * selects the first hart to boot the kernel and causes the remainder > @@ -79,8 +85,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) > * the spinning harts that they can continue the boot process. > */ > smp_mb(); > - __cpu_up_stack_pointer[cpu] = task_stack_page(tidle) + THREAD_SIZE; > - __cpu_up_task_pointer[cpu] = tidle; > + __cpu_up_stack_pointer[hartid] = task_stack_page(tidle) + THREAD_SIZE; > + __cpu_up_task_pointer[hartid] = tidle; > > while (!cpu_online(cpu)) > cpu_relax(); > diff --git a/drivers/clocksource/riscv_timer.c > b/drivers/clocksource/riscv_timer.c > index 4e8b347e..f1f205e5 100644 > --- a/drivers/clocksource/riscv_timer.c > +++ b/drivers/clocksource/riscv_timer.c > @@ -8,6 +8,7 @@ > #include <linux/cpu.h> > #include <linux/delay.h> > #include <linux/irq.h> > +#include <asm/smp.h> > #include <asm/sbi.h> > > /* > @@ -84,13 +85,16 @@ void riscv_timer_interrupt(void) > > static int __init riscv_timer_init_dt(struct device_node *n) > { > - int cpu_id = riscv_of_processor_hart(n), error; > + int cpuid, hartid, error; > struct clocksource *cs; > > - if (cpu_id != smp_processor_id()) > + hartid = riscv_of_processor_hart(n); > + cpuid = riscv_hartid_to_cpuid(hartid); > + > + if (cpuid != smp_processor_id()) > return 0; > > - cs = per_cpu_ptr(&riscv_clocksource, cpu_id); > + cs = per_cpu_ptr(&riscv_clocksource, cpuid); > clocksource_register_hz(cs, riscv_timebase); > > error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING, > @@ -98,7 +102,7 @@ static int __init riscv_timer_init_dt(struct device_node > *n) > riscv_timer_starting_cpu, riscv_timer_dying_cpu); > if (error) > pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", > - error, cpu_id); > + error, cpuid); > return error; > } > > diff --git a/drivers/irqchip/irq-sifive-plic.c > b/drivers/irqchip/irq-sifive-plic.c > index 298685e5..2eb2e78c 100644 > --- a/drivers/irqchip/irq-sifive-plic.c > +++ b/drivers/irqchip/irq-sifive-plic.c > @@ -15,6 +15,7 @@ > #include <linux/of_irq.h> > #include <linux/platform_device.h> > #include <linux/spinlock.h> > +#include <asm/smp.h> > > /* > * This driver implements a version of the RISC-V PLIC with the actual layout > @@ -93,10 +94,11 @@ static inline void plic_toggle(int ctxid, int hwirq, int > enable) > static inline void plic_irq_toggle(struct irq_data *d, int enable) > { > int cpu; > + struct plic_handler *handler; > > writel(enable, plic_regs + PRIORITY_BASE + d->hwirq * > PRIORITY_PER_ID); > for_each_cpu(cpu, irq_data_get_affinity_mask(d)) { > - struct plic_handler *handler = per_cpu_ptr(&plic_handlers, > cpu); > + handler = per_cpu_ptr(&plic_handlers, cpu); > > if (handler->present) > plic_toggle(handler->ctxid, d->hwirq, enable); > @@ -217,7 +219,7 @@ static int __init plic_init(struct device_node *node, > struct of_phandle_args parent; > struct plic_handler *handler; > irq_hw_number_t hwirq; > - int cpu; > + int cpu, hartid; > > if (of_irq_parse_one(node, i, &parent)) { > pr_err("failed to parse parent for context %d.\n", i); > @@ -228,12 +230,13 @@ static int __init plic_init(struct device_node *node, > if (parent.args[0] == -1) > continue; > > - cpu = plic_find_hart_id(parent.np); > - if (cpu < 0) { > + hartid = plic_find_hart_id(parent.np); > + if (hartid < 0) { > pr_warn("failed to parse hart ID for context %d.\n", > i); > continue; > } > > + cpu = riscv_hartid_to_cpuid(hartid); > handler = per_cpu_ptr(&plic_handlers, cpu); > handler->present = true; > handler->ctxid = i; > -- > 2.7.4 > Regards, Anup