mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	To be able to trace invocations of smp_send_reschedule(), rename the
arch-specific definitions of it to arch_smp_send_reschedule() and wrap it
into an smp_send_reschedule() that contains a tracepoint.
Changes to include the declaration of the tracepoint were driven by the
following coccinelle script:
  @func_use@
  @@
  smp_send_reschedule(...);
  @include@
  @@
  #include <trace/events/ipi.h>
  @no_include depends on func_use && !include@
  @@
    #include <...>
  +
  + #include <trace/events/ipi.h>
[csky bits]
[riscv bits]
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Guo Ren <guoren@kernel.org>
Acked-by: Palmer Dabbelt <palmer@rivosinc.com>
Link: https://lore.kernel.org/r/20230307143558.294354-6-vschneid@redhat.com
		
	
			
		
			
				
	
	
		
			154 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/*
 | 
						|
 * Actions Semi Leopard
 | 
						|
 *
 | 
						|
 * This file is based on arm realview smp platform.
 | 
						|
 *
 | 
						|
 * Copyright 2012 Actions Semi Inc.
 | 
						|
 * Author: Actions Semi, Inc.
 | 
						|
 *
 | 
						|
 * Copyright (c) 2017 Andreas Färber
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/delay.h>
 | 
						|
#include <linux/io.h>
 | 
						|
#include <linux/of.h>
 | 
						|
#include <linux/of_address.h>
 | 
						|
#include <linux/smp.h>
 | 
						|
#include <linux/soc/actions/owl-sps.h>
 | 
						|
#include <asm/cacheflush.h>
 | 
						|
#include <asm/smp_plat.h>
 | 
						|
#include <asm/smp_scu.h>
 | 
						|
 | 
						|
#include <trace/events/ipi.h>
 | 
						|
 | 
						|
#define OWL_CPU1_ADDR	0x50
 | 
						|
#define OWL_CPU1_FLAG	0x5c
 | 
						|
 | 
						|
#define OWL_CPUx_FLAG_BOOT	0x55aa
 | 
						|
 | 
						|
#define OWL_SPS_PG_CTL_PWR_CPU2	BIT(5)
 | 
						|
#define OWL_SPS_PG_CTL_PWR_CPU3	BIT(6)
 | 
						|
#define OWL_SPS_PG_CTL_ACK_CPU2	BIT(21)
 | 
						|
#define OWL_SPS_PG_CTL_ACK_CPU3	BIT(22)
 | 
						|
 | 
						|
static void __iomem *scu_base_addr;
 | 
						|
static void __iomem *sps_base_addr;
 | 
						|
static void __iomem *timer_base_addr;
 | 
						|
static int ncores;
 | 
						|
 | 
						|
static int s500_wakeup_secondary(unsigned int cpu)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	if (cpu > 3)
 | 
						|
		return -EINVAL;
 | 
						|
 | 
						|
	/* The generic PM domain driver is not available this early. */
 | 
						|
	switch (cpu) {
 | 
						|
	case 2:
 | 
						|
		ret = owl_sps_set_pg(sps_base_addr,
 | 
						|
		                     OWL_SPS_PG_CTL_PWR_CPU2,
 | 
						|
				     OWL_SPS_PG_CTL_ACK_CPU2, true);
 | 
						|
		if (ret)
 | 
						|
			return ret;
 | 
						|
		break;
 | 
						|
	case 3:
 | 
						|
		ret = owl_sps_set_pg(sps_base_addr,
 | 
						|
		                     OWL_SPS_PG_CTL_PWR_CPU3,
 | 
						|
				     OWL_SPS_PG_CTL_ACK_CPU3, true);
 | 
						|
		if (ret)
 | 
						|
			return ret;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* wait for CPUx to run to WFE instruction */
 | 
						|
	udelay(200);
 | 
						|
 | 
						|
	writel(__pa_symbol(secondary_startup),
 | 
						|
	       timer_base_addr + OWL_CPU1_ADDR + (cpu - 1) * 4);
 | 
						|
	writel(OWL_CPUx_FLAG_BOOT,
 | 
						|
	       timer_base_addr + OWL_CPU1_FLAG + (cpu - 1) * 4);
 | 
						|
 | 
						|
	dsb_sev();
 | 
						|
	mb();
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int s500_smp_boot_secondary(unsigned int cpu, struct task_struct *idle)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = s500_wakeup_secondary(cpu);
 | 
						|
	if (ret)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	udelay(10);
 | 
						|
 | 
						|
	smp_send_reschedule(cpu);
 | 
						|
 | 
						|
	writel(0, timer_base_addr + OWL_CPU1_ADDR + (cpu - 1) * 4);
 | 
						|
	writel(0, timer_base_addr + OWL_CPU1_FLAG + (cpu - 1) * 4);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void __init s500_smp_prepare_cpus(unsigned int max_cpus)
 | 
						|
{
 | 
						|
	struct device_node *node;
 | 
						|
 | 
						|
	node = of_find_compatible_node(NULL, NULL, "actions,s500-timer");
 | 
						|
	if (!node) {
 | 
						|
		pr_err("%s: missing timer\n", __func__);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	timer_base_addr = of_iomap(node, 0);
 | 
						|
	if (!timer_base_addr) {
 | 
						|
		pr_err("%s: could not map timer registers\n", __func__);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	node = of_find_compatible_node(NULL, NULL, "actions,s500-sps");
 | 
						|
	if (!node) {
 | 
						|
		pr_err("%s: missing sps\n", __func__);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	sps_base_addr = of_iomap(node, 0);
 | 
						|
	if (!sps_base_addr) {
 | 
						|
		pr_err("%s: could not map sps registers\n", __func__);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
 | 
						|
		node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
 | 
						|
		if (!node) {
 | 
						|
			pr_err("%s: missing scu\n", __func__);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		scu_base_addr = of_iomap(node, 0);
 | 
						|
		if (!scu_base_addr) {
 | 
						|
			pr_err("%s: could not map scu registers\n", __func__);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		/*
 | 
						|
		 * While the number of cpus is gathered from dt, also get the
 | 
						|
		 * number of cores from the scu to verify this value when
 | 
						|
		 * booting the cores.
 | 
						|
		 */
 | 
						|
		ncores = scu_get_core_count(scu_base_addr);
 | 
						|
		pr_debug("%s: ncores %d\n", __func__, ncores);
 | 
						|
 | 
						|
		scu_enable(scu_base_addr);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static const struct smp_operations s500_smp_ops __initconst = {
 | 
						|
	.smp_prepare_cpus = s500_smp_prepare_cpus,
 | 
						|
	.smp_boot_secondary = s500_smp_boot_secondary,
 | 
						|
};
 | 
						|
CPU_METHOD_OF_DECLARE(s500_smp, "actions,s500-smp", &s500_smp_ops);
 |