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

Reply via email to