All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ralf Baechle <ralf@linux-mips.org>
To: Huacai Chen <chenhc@lemote.com>
Cc: John Crispin <john@phrozen.org>,
	"Steven J. Hill" <Steven.Hill@imgtec.com>,
	Aurelien Jarno <aurelien@aurel32.net>,
	linux-mips@linux-mips.org, Fuxin Zhang <zhangfx@lemote.com>,
	Zhangjin Wu <wuzhangjin@gmail.com>,
	Hongliang Tao <taohl@lemote.com>, Hua Yan <yanh@lemote.com>
Subject: Re: [PATCH V19 12/13] MIPS: Loongson 3: Add CPU hotplug support
Date: Tue, 18 Mar 2014 18:20:21 +0100	[thread overview]
Message-ID: <20140318172021.GG17197@linux-mips.org> (raw)
In-Reply-To: <1392537690-5961-13-git-send-email-chenhc@lemote.com>

On Sun, Feb 16, 2014 at 04:01:29PM +0800, Huacai Chen wrote:
> Date:   Sun, 16 Feb 2014 16:01:29 +0800
> From: Huacai Chen <chenhc@lemote.com>
> To: Ralf Baechle <ralf@linux-mips.org>
> Cc: John Crispin <john@phrozen.org>, "Steven J. Hill"
>  <Steven.Hill@imgtec.com>, Aurelien Jarno <aurelien@aurel32.net>,
>  linux-mips@linux-mips.org, Fuxin Zhang <zhangfx@lemote.com>, Zhangjin Wu
>  <wuzhangjin@gmail.com>, Huacai Chen <chenhc@lemote.com>, Hongliang Tao
>  <taohl@lemote.com>, Hua Yan <yanh@lemote.com>
> Subject: [PATCH V19 12/13] MIPS: Loongson 3: Add CPU hotplug support
> 
> Tips of Loongson's CPU hotplug:
> 1, To fully shutdown a core in Loongson 3, the target core should go to
>    CKSEG1 and flush all L1 cache entries at first. Then, another core
>    (usually Core 0) can safely disable the clock of the target core. So
>    play_dead() call loongson3_play_dead() via CKSEG1 (both uncached and
>    unmmaped).
> 2, The default clocksource of Loongson is MIPS. Since clock source is a
>    global device, timekeeping need the CP0' Count registers of each core
>    be synchronous. Thus, when a core is up, we use a SMP_ASK_C0COUNT IPI
>    to ask Core-0's Count.
> 
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Signed-off-by: Hongliang Tao <taohl@lemote.com>
> Signed-off-by: Hua Yan <yanh@lemote.com>
> Tested-by: Alex Smith <alex.smith@imgtec.com>
> Reviewed-by: Alex Smith <alex.smith@imgtec.com>
> ---
>  arch/mips/include/asm/mach-loongson/irq.h      |    1 +
>  arch/mips/include/asm/mach-loongson/loongson.h |    6 +-
>  arch/mips/include/asm/smp.h                    |    1 +
>  arch/mips/loongson/Kconfig                     |    1 +
>  arch/mips/loongson/loongson-3/irq.c            |   10 ++
>  arch/mips/loongson/loongson-3/smp.c            |  171 +++++++++++++++++++++++-
>  6 files changed, 185 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/mips/include/asm/mach-loongson/irq.h b/arch/mips/include/asm/mach-loongson/irq.h
> index e2568d6..e45e4f5 100644
> --- a/arch/mips/include/asm/mach-loongson/irq.h
> +++ b/arch/mips/include/asm/mach-loongson/irq.h
> @@ -37,6 +37,7 @@
>  
>  #endif
>  
> +extern void fixup_irqs(void);
>  extern void loongson3_ipi_interrupt(struct pt_regs *regs);
>  
>  #include_next <irq.h>
> diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
> index f185907..f3fd1eb 100644
> --- a/arch/mips/include/asm/mach-loongson/loongson.h
> +++ b/arch/mips/include/asm/mach-loongson/loongson.h
> @@ -249,6 +249,9 @@ static inline void do_perfcnt_IRQ(void)
>  #define LOONGSON_PXARB_CFG		LOONGSON_REG(LOONGSON_REGBASE + 0x68)
>  #define LOONGSON_PXARB_STATUS		LOONGSON_REG(LOONGSON_REGBASE + 0x6c)
>  
> +/* Chip Config */
> +#define LOONGSON_CHIPCFG0		LOONGSON_REG(LOONGSON_REGBASE + 0x80)
> +
>  /* pcimap */
>  
>  #define LOONGSON_PCIMAP_PCIMAP_LO0	0x0000003f
> @@ -264,9 +267,6 @@ static inline void do_perfcnt_IRQ(void)
>  #ifdef CONFIG_CPU_SUPPORTS_CPUFREQ
>  #include <linux/cpufreq.h>
>  extern struct cpufreq_frequency_table loongson2_clockmod_table[];
> -
> -/* Chip Config */
> -#define LOONGSON_CHIPCFG0		LOONGSON_REG(LOONGSON_REGBASE + 0x80)
>  #endif
>  
>  /*
> diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
> index eb60087..efa02ac 100644
> --- a/arch/mips/include/asm/smp.h
> +++ b/arch/mips/include/asm/smp.h
> @@ -42,6 +42,7 @@ extern int __cpu_logical_map[NR_CPUS];
>  #define SMP_ICACHE_FLUSH	0x4
>  /* Used by kexec crashdump to save all cpu's state */
>  #define SMP_DUMP		0x8
> +#define SMP_ASK_C0COUNT		0x10
>  
>  extern volatile cpumask_t cpu_callin_map;
>  
> diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
> index a5d46f5..7397be2 100644
> --- a/arch/mips/loongson/Kconfig
> +++ b/arch/mips/loongson/Kconfig
> @@ -79,6 +79,7 @@ config LEMOTE_MACH3A
>  	select SYS_HAS_CPU_LOONGSON3
>  	select SYS_HAS_EARLY_PRINTK
>  	select SYS_SUPPORTS_SMP
> +	select SYS_SUPPORTS_HOTPLUG_CPU
>  	select SYS_SUPPORTS_64BIT_KERNEL
>  	select SYS_SUPPORTS_HIGHMEM
>  	select SYS_SUPPORTS_LITTLE_ENDIAN
> diff --git a/arch/mips/loongson/loongson-3/irq.c b/arch/mips/loongson/loongson-3/irq.c
> index f26e68e..c76a740 100644
> --- a/arch/mips/loongson/loongson-3/irq.c
> +++ b/arch/mips/loongson/loongson-3/irq.c
> @@ -113,3 +113,13 @@ void __init mach_init_irq(void)
>  
>  	set_c0_status(STATUSF_IP2 | STATUSF_IP6);
>  }
> +
> +#ifdef CONFIG_HOTPLUG_CPU
> +
> +void fixup_irqs(void)
> +{
> +	irq_cpu_offline();
> +	clear_c0_status(ST0_IM);
> +}
> +
> +#endif
> diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c
> index 93483c2..83e6ea5 100644
> --- a/arch/mips/loongson/loongson-3/smp.c
> +++ b/arch/mips/loongson/loongson-3/smp.c
> @@ -23,10 +23,14 @@
>  #include <asm/time.h>
>  #include <asm/clock.h>
>  #include <asm/tlbflush.h>
> +#include <asm/cacheflush.h>
>  #include <loongson.h>
>  
>  #include "smp.h"
>  
> +DEFINE_PER_CPU(int, cpu_state);
> +DEFINE_PER_CPU(uint32_t, core0_c0count);
> +
>  /* read a 32bit value from ipi register */
>  #define loongson3_ipi_read32(addr) readl(addr)
>  /* read a 64bit value from ipi register */
> @@ -158,8 +162,8 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
>  
>  void loongson3_ipi_interrupt(struct pt_regs *regs)
>  {
> -	int cpu = smp_processor_id();
> -	unsigned int action;
> +	int i, cpu = smp_processor_id();
> +	unsigned int action, c0count;
>  
>  	/* Load the ipi register to figure out what we're supposed to do */
>  	action = loongson3_ipi_read32(ipi_status0_regs[cpu]);
> @@ -172,14 +176,24 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
>  
>  	if (action & SMP_CALL_FUNCTION)
>  		smp_call_function_interrupt();
> +
> +	if (action & SMP_ASK_C0COUNT) {
> +		BUG_ON(cpu != 0);
> +		c0count = read_c0_count();
> +		for (i = 1; i < loongson_sysconf.nr_cpus; i++)
> +			per_cpu(core0_c0count, i) = c0count;
> +	}
>  }
>  
> +#define MAX_LOOPS 1111
>  /*
>   * SMP init and finish on secondary CPUs
>   */
>  static void loongson3_init_secondary(void)
>  {
>  	int i;
> +	uint32_t initcount;
> +	unsigned int cpu = smp_processor_id();
>  	unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
>  			     STATUSF_IP3 | STATUSF_IP2;
>  
> @@ -188,6 +202,21 @@ static void loongson3_init_secondary(void)
>  
>  	for (i = 0; i < loongson_sysconf.nr_cpus; i++)
>  		loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]);
> +
> +	per_cpu(cpu_state, cpu) = CPU_ONLINE;
> +
> +	i = 0;
> +	__get_cpu_var(core0_c0count) = 0;
> +	loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
> +	while (!__get_cpu_var(core0_c0count)) {
> +		i++;
> +		cpu_relax();
> +	}
> +
> +	if (i > MAX_LOOPS)
> +		i = MAX_LOOPS;
> +	initcount = __get_cpu_var(core0_c0count) + i;
> +	write_c0_count(initcount);
>  }
>  
>  static void loongson3_smp_finish(void)
> @@ -222,6 +251,8 @@ static void __init loongson3_smp_setup(void)
>  
>  static void __init loongson3_prepare_cpus(unsigned int max_cpus)
>  {
> +	init_cpu_present(cpu_possible_mask);
> +	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
>  }
>  
>  /*
> @@ -255,6 +286,138 @@ static void __init loongson3_cpus_done(void)
>  {
>  }
>  
> +#ifdef CONFIG_HOTPLUG_CPU
> +
> +static int loongson3_cpu_disable(void)
> +{
> +	unsigned long flags;
> +	unsigned int cpu = smp_processor_id();
> +
> +	if (cpu == 0)
> +		return -EBUSY;
> +
> +	set_cpu_online(cpu, false);
> +	cpu_clear(cpu, cpu_callin_map);
> +	local_irq_save(flags);
> +	fixup_irqs();
> +	local_irq_restore(flags);
> +	flush_cache_all();
> +	local_flush_tlb_all();
> +
> +	return 0;
> +}
> +
> +
> +static void loongson3_cpu_die(unsigned int cpu)
> +{
> +	while (per_cpu(cpu_state, cpu) != CPU_DEAD)
> +		cpu_relax();
> +
> +	mb();
> +}
> +
> +/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
> + * flush all L1 entries at first. Then, another core (usually Core 0) can
> + * safely disable the clock of the target core. loongson3_play_dead() is
> + * called via CKSEG1 (uncached and unmmaped) */
> +static void loongson3_play_dead(int *state_addr)
> +{
> +	__asm__ __volatile__(
> +		"   .set push                     \n"
> +		"   .set noreorder                \n"
> +		"   li $t0, 0x80000000            \n" /* KSEG0 */
> +		"   move $t1, %0                  \n" /* num of L1 entries */
> +		"1: cache 0, 0($t0)               \n" /* flush L1 ICache */
> +		"   cache 0, 1($t0)               \n"
> +		"   cache 0, 2($t0)               \n"
> +		"   cache 0, 3($t0)               \n"
> +		"   cache 1, 0($t0)               \n" /* flush L1 DCache */
> +		"   cache 1, 1($t0)               \n"
> +		"   cache 1, 2($t0)               \n"
> +		"   cache 1, 3($t0)               \n"
> +		"   addiu $t0, $t0, 0x20          \n"
> +		"   bnez  $t1, 1b                 \n"
> +		"   addiu $t1, $t1, -1            \n"
> +		"   li    $t0, 0x7                \n" /* *state_addr = CPU_DEAD; */
> +		"   sw    $t0, 0($a0)             \n"
> +		"   sync                          \n"
> +		"   cache 21, 0($a0)              \n" /* flush entry of *state_addr */
> +		"   .set pop                      \n"
> +		: /* No Output */
> +		: "r" (cpu_data[smp_processor_id()].dcache.sets));
> +
> +	__asm__ __volatile__(
> +		"   .set push                     \n"
> +		"   .set noreorder                \n"
> +		"   .set mips64                   \n"
> +		"   mfc0  $t2, $15, 1             \n"
> +		"   andi  $t2, 0x3ff              \n"
> +		"   dli   $t0, 0x900000003ff01000 \n"
> +		"   andi  $t3, $t2, 0x3           \n"
> +		"   sll   $t3, 8                  \n"  /* get cpu id */
> +		"   or    $t0, $t0, $t3           \n"
> +		"   andi  $t1, $t2, 0xc           \n"
> +		"   dsll  $t1, 42                 \n"  /* get node id */
> +		"   or    $t0, $t0, $t1           \n"
> +		"1: li    $a0, 0x100              \n"  /* wait for init loop */
> +		"2: bnez  $a0, 2b                 \n"  /* limit mailbox access */
> +		"   addiu $a0, -1                 \n"
> +		"   lw    $v0, 0x20($t0)          \n"  /* get PC via mailbox */
> +		"   beqz  $v0, 1b                 \n"
> +		"   nop                           \n"
> +		"   ld    $sp, 0x28($t0)          \n"  /* get SP via mailbox */
> +		"   ld    $gp, 0x30($t0)          \n"  /* get GP via mailbox */
> +		"   ld    $a1, 0x38($t0)          \n"
> +		"   jr    $v0                     \n"  /* jump to initial PC */
> +		"   nop                           \n"
> +		"   .set pop                      \n");
> +}

Please don't use the $foo notation to allocate a register for use in this
function - gcc might ruin your day if it allocates the same register for
something else.  Something like:

static void somefunc(int blurb)
{
	int ptr;

	__asm__ __volatile__(
	"	cache	0, 0(%[ptr])		\n"
	"	cache	0, 1(%[ptr])		\n"
	"	cache	0, 2(%[ptr])		\n"
	"	cache	0, 3(%[ptr])		\n"
	: [ptr] "=&r" (ptr));
}

would be bulletproof against evil optimizations by GCC.

Or in plain C something like:

	unsigned long addr;

	for (addr = start; addr < end; addr += 0x20) {
		cache_op(0, ptr    );
		cache_op(0, ptr + 1);
		cache_op(0, ptr + 2);
		cache_op(0, ptr + 3);
		cache_op(1, ptr    );
		cache_op(1, ptr + 1);
		cache_op(1, ptr + 2);
		cache_op(1, ptr + 3);
	}
	...

  Ralf

  reply	other threads:[~2014-03-18 17:20 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-16  8:01 [PATCH V19 00/13] MIPS: Add Loongson-3 based machines support Huacai Chen
2014-02-16  8:01 ` [PATCH V19 01/13] MIPS: Loongson: Rename PRID_IMP_LOONGSON1 and PRID_IMP_LOONGSON2 Huacai Chen
2014-03-18 12:13   ` Ralf Baechle
2014-02-16  8:01 ` [PATCH V19 02/13] MIPS: Loongson: Add basic Loongson-3 definition Huacai Chen
2014-03-18 14:04   ` Ralf Baechle
2014-03-19  1:14     ` "陈华才"
2014-02-16  8:01 ` [PATCH V19 03/13] MIPS: Loongson: Add basic Loongson-3 CPU support Huacai Chen
2014-03-18 14:05   ` Ralf Baechle
2014-02-16  8:01 ` [PATCH V19 04/13] MIPS: Loongson 3: Add Lemote-3A machtypes definition Huacai Chen
2014-02-16  8:01 ` [PATCH V19 05/13] MIPS: Loongson: Add UEFI-like firmware interface (LEFI) support Huacai Chen
2014-02-16 21:12   ` Aurelien Jarno
2014-02-17  5:15     ` "陈华才"
2014-02-16  8:01 ` [PATCH V19 06/13] MIPS: Loongson 3: Add HT-linked PCI support Huacai Chen
2014-02-16  8:01 ` [PATCH V19 07/13] MIPS: Loongson 3: Add IRQ init and dispatch support Huacai Chen
2014-03-18 14:59   ` Ralf Baechle
2014-03-19  3:05     ` "陈华才"
2014-03-19 16:49       ` Ralf Baechle
2014-02-16  8:01 ` [PATCH V19 08/13] MIPS: Loongson 3: Add serial port support Huacai Chen
2014-02-16  8:01 ` [PATCH V19 09/13] MIPS: Loongson: Add swiotlb to support All-Memory DMA Huacai Chen
2014-02-16 21:12   ` Aurelien Jarno
2014-02-17  5:41     ` "陈华才"
2014-02-19 21:39       ` Aurelien Jarno
2014-02-20  1:00         ` "陈华才"
2014-02-16  8:01 ` [PATCH V19 10/13] MIPS: Loongson: Add Loongson-3 Kconfig options Huacai Chen
2014-02-16  8:01 ` [PATCH V19 11/13] MIPS: Loongson 3: Add Loongson-3 SMP support Huacai Chen
2014-03-18 15:52   ` Ralf Baechle
2014-02-16  8:01 ` [PATCH V19 12/13] MIPS: Loongson 3: Add CPU hotplug support Huacai Chen
2014-03-18 17:20   ` Ralf Baechle [this message]
2014-02-16  8:01 ` [PATCH V19 13/13] MIPS: Loongson: Add a Loongson-3 default config file Huacai Chen
2014-02-16 22:26 ` [PATCH V19 00/13] MIPS: Add Loongson-3 based machines support Andreas Barth
2014-03-06 10:30 ` Andreas Barth
2014-03-06 13:22   ` Huacai Chen
     [not found]   ` <532076A7.1040606@phrozen.org>
2014-03-12 23:31     ` Andreas Barth
2014-03-12 17:21 ` Aurelien Jarno

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140318172021.GG17197@linux-mips.org \
    --to=ralf@linux-mips.org \
    --cc=Steven.Hill@imgtec.com \
    --cc=aurelien@aurel32.net \
    --cc=chenhc@lemote.com \
    --cc=john@phrozen.org \
    --cc=linux-mips@linux-mips.org \
    --cc=taohl@lemote.com \
    --cc=wuzhangjin@gmail.com \
    --cc=yanh@lemote.com \
    --cc=zhangfx@lemote.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.