162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef __ASM_ARC_SMP_H 762306a36Sopenharmony_ci#define __ASM_ARC_SMP_H 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifdef CONFIG_SMP 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/types.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/threads.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define raw_smp_processor_id() (current_thread_info()->cpu) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* including cpumask.h leads to cyclic deps hence this Forward declaration */ 1862306a36Sopenharmony_cistruct cpumask; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * APIs provided by arch SMP code to generic code 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ciextern void arch_send_call_function_single_ipi(int cpu); 2462306a36Sopenharmony_ciextern void arch_send_call_function_ipi_mask(const struct cpumask *mask); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * APIs provided by arch SMP code to rest of arch code 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ciextern void __init smp_init_cpus(void); 3062306a36Sopenharmony_ciextern void first_lines_of_secondary(void); 3162306a36Sopenharmony_ciextern const char *arc_platform_smp_cpuinfo(void); 3262306a36Sopenharmony_ciextern void arc_platform_smp_wait_to_boot(int); 3362306a36Sopenharmony_ciextern void start_kernel_secondary(void); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * API expected BY platform smp code (FROM arch smp code) 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * smp_ipi_irq_setup: 3962306a36Sopenharmony_ci * Takes @cpu and @hwirq to which the arch-common ISR is hooked up 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ciextern int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* 4462306a36Sopenharmony_ci * struct plat_smp_ops - SMP callbacks provided by platform to ARC SMP 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * @info: SoC SMP specific info for /proc/cpuinfo etc 4762306a36Sopenharmony_ci * @init_early_smp: A SMP specific h/w block can init itself 4862306a36Sopenharmony_ci * Could be common across platforms so not covered by 4962306a36Sopenharmony_ci * mach_desc->init_early() 5062306a36Sopenharmony_ci * @init_per_cpu: Called for each core so SMP h/w block driver can do 5162306a36Sopenharmony_ci * any needed setup per cpu (e.g. IPI request) 5262306a36Sopenharmony_ci * @cpu_kick: For Master to kickstart a cpu (optionally at a PC) 5362306a36Sopenharmony_ci * @ipi_send: To send IPI to a @cpu 5462306a36Sopenharmony_ci * @ips_clear: To clear IPI received at @irq 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistruct plat_smp_ops { 5762306a36Sopenharmony_ci const char *info; 5862306a36Sopenharmony_ci void (*init_early_smp)(void); 5962306a36Sopenharmony_ci void (*init_per_cpu)(int cpu); 6062306a36Sopenharmony_ci void (*cpu_kick)(int cpu, unsigned long pc); 6162306a36Sopenharmony_ci void (*ipi_send)(int cpu); 6262306a36Sopenharmony_ci void (*ipi_clear)(int irq); 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* TBD: stop exporting it for direct population by platform */ 6662306a36Sopenharmony_ciextern struct plat_smp_ops plat_smp_ops; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#else /* CONFIG_SMP */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline void smp_init_cpus(void) {} 7162306a36Sopenharmony_cistatic inline const char *arc_platform_smp_cpuinfo(void) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return ""; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#endif /* !CONFIG_SMP */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * ARC700 doesn't support atomic Read-Modify-Write ops. 8062306a36Sopenharmony_ci * Originally Interrupts had to be disabled around code to gaurantee atomicity. 8162306a36Sopenharmony_ci * The LLOCK/SCOND insns allow writing interrupt-hassle-free based atomic ops 8262306a36Sopenharmony_ci * based on retry-if-irq-in-atomic (with hardware assist). 8362306a36Sopenharmony_ci * However despite these, we provide the IRQ disabling variant 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * (1) These insn were introduced only in 4.10 release. So for older released 8662306a36Sopenharmony_ci * support needed. 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * (2) In a SMP setup, the LLOCK/SCOND atomicity across CPUs needs to be 8962306a36Sopenharmony_ci * gaurantted by the platform (not something which core handles). 9062306a36Sopenharmony_ci * Assuming a platform won't, SMP Linux needs to use spinlocks + local IRQ 9162306a36Sopenharmony_ci * disabling for atomicity. 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * However exported spinlock API is not usable due to cyclic hdr deps 9462306a36Sopenharmony_ci * (even after system.h disintegration upstream) 9562306a36Sopenharmony_ci * asm/bitops.h -> linux/spinlock.h -> linux/preempt.h 9662306a36Sopenharmony_ci * -> linux/thread_info.h -> linux/bitops.h -> asm/bitops.h 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * So the workaround is to use the lowest level arch spinlock API. 9962306a36Sopenharmony_ci * The exported spinlock API is smart enough to be NOP for !CONFIG_SMP, 10062306a36Sopenharmony_ci * but same is not true for ARCH backend, hence the need for 2 variants 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci#ifndef CONFIG_ARC_HAS_LLSC 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#include <linux/irqflags.h> 10562306a36Sopenharmony_ci#ifdef CONFIG_SMP 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#include <asm/spinlock.h> 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ciextern arch_spinlock_t smp_atomic_ops_lock; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define atomic_ops_lock(flags) do { \ 11262306a36Sopenharmony_ci local_irq_save(flags); \ 11362306a36Sopenharmony_ci arch_spin_lock(&smp_atomic_ops_lock); \ 11462306a36Sopenharmony_ci} while (0) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define atomic_ops_unlock(flags) do { \ 11762306a36Sopenharmony_ci arch_spin_unlock(&smp_atomic_ops_lock); \ 11862306a36Sopenharmony_ci local_irq_restore(flags); \ 11962306a36Sopenharmony_ci} while (0) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#else /* !CONFIG_SMP */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define atomic_ops_lock(flags) local_irq_save(flags) 12462306a36Sopenharmony_ci#define atomic_ops_unlock(flags) local_irq_restore(flags) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#endif /* !CONFIG_SMP */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#endif /* !CONFIG_ARC_HAS_LLSC */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#endif 131