162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  arch/arm/include/asm/proc-fns.h
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 1997-1999 Russell King
662306a36Sopenharmony_ci *  Copyright (C) 2000 Deep Blue Solutions Ltd
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#ifndef __ASM_PROCFNS_H
962306a36Sopenharmony_ci#define __ASM_PROCFNS_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#ifdef __KERNEL__
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <asm/glue-proc.h>
1462306a36Sopenharmony_ci#include <asm/page.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#ifndef __ASSEMBLY__
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct mm_struct;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * Don't change this structure - ASM code relies on it.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_cistruct processor {
2462306a36Sopenharmony_ci	/* MISC
2562306a36Sopenharmony_ci	 * get data abort address/flags
2662306a36Sopenharmony_ci	 */
2762306a36Sopenharmony_ci	void (*_data_abort)(unsigned long pc);
2862306a36Sopenharmony_ci	/*
2962306a36Sopenharmony_ci	 * Retrieve prefetch fault address
3062306a36Sopenharmony_ci	 */
3162306a36Sopenharmony_ci	unsigned long (*_prefetch_abort)(unsigned long lr);
3262306a36Sopenharmony_ci	/*
3362306a36Sopenharmony_ci	 * Set up any processor specifics
3462306a36Sopenharmony_ci	 */
3562306a36Sopenharmony_ci	void (*_proc_init)(void);
3662306a36Sopenharmony_ci	/*
3762306a36Sopenharmony_ci	 * Check for processor bugs
3862306a36Sopenharmony_ci	 */
3962306a36Sopenharmony_ci	void (*check_bugs)(void);
4062306a36Sopenharmony_ci	/*
4162306a36Sopenharmony_ci	 * Disable any processor specifics
4262306a36Sopenharmony_ci	 */
4362306a36Sopenharmony_ci	void (*_proc_fin)(void);
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * Special stuff for a reset
4662306a36Sopenharmony_ci	 */
4762306a36Sopenharmony_ci	void (*reset)(unsigned long addr, bool hvc) __attribute__((noreturn));
4862306a36Sopenharmony_ci	/*
4962306a36Sopenharmony_ci	 * Idle the processor
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci	int (*_do_idle)(void);
5262306a36Sopenharmony_ci	/*
5362306a36Sopenharmony_ci	 * Processor architecture specific
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	/*
5662306a36Sopenharmony_ci	 * clean a virtual address range from the
5762306a36Sopenharmony_ci	 * D-cache without flushing the cache.
5862306a36Sopenharmony_ci	 */
5962306a36Sopenharmony_ci	void (*dcache_clean_area)(void *addr, int size);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/*
6262306a36Sopenharmony_ci	 * Set the page table
6362306a36Sopenharmony_ci	 */
6462306a36Sopenharmony_ci	void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm);
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * Set a possibly extended PTE.  Non-extended PTEs should
6762306a36Sopenharmony_ci	 * ignore 'ext'.
6862306a36Sopenharmony_ci	 */
6962306a36Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
7062306a36Sopenharmony_ci	void (*set_pte_ext)(pte_t *ptep, pte_t pte);
7162306a36Sopenharmony_ci#else
7262306a36Sopenharmony_ci	void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext);
7362306a36Sopenharmony_ci#endif
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* Suspend/resume */
7662306a36Sopenharmony_ci	unsigned int suspend_size;
7762306a36Sopenharmony_ci	void (*do_suspend)(void *);
7862306a36Sopenharmony_ci	void (*do_resume)(void *);
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#ifndef MULTI_CPU
8262306a36Sopenharmony_cistatic inline void init_proc_vtable(const struct processor *p)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciextern void cpu_proc_init(void);
8762306a36Sopenharmony_ciextern void cpu_proc_fin(void);
8862306a36Sopenharmony_ciextern int cpu_do_idle(void);
8962306a36Sopenharmony_ciextern void cpu_dcache_clean_area(void *, int);
9062306a36Sopenharmony_ciextern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
9162306a36Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
9262306a36Sopenharmony_ciextern void cpu_set_pte_ext(pte_t *ptep, pte_t pte);
9362306a36Sopenharmony_ci#else
9462306a36Sopenharmony_ciextern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
9562306a36Sopenharmony_ci#endif
9662306a36Sopenharmony_ciextern void cpu_reset(unsigned long addr, bool hvc) __attribute__((noreturn));
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* These three are private to arch/arm/kernel/suspend.c */
9962306a36Sopenharmony_ciextern void cpu_do_suspend(void *);
10062306a36Sopenharmony_ciextern void cpu_do_resume(void *);
10162306a36Sopenharmony_ci#else
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciextern struct processor processor;
10462306a36Sopenharmony_ci#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
10562306a36Sopenharmony_ci#include <linux/smp.h>
10662306a36Sopenharmony_ci/*
10762306a36Sopenharmony_ci * This can't be a per-cpu variable because we need to access it before
10862306a36Sopenharmony_ci * per-cpu has been initialised.  We have a couple of functions that are
10962306a36Sopenharmony_ci * called in a pre-emptible context, and so can't use smp_processor_id()
11062306a36Sopenharmony_ci * there, hence PROC_TABLE().  We insist in init_proc_vtable() that the
11162306a36Sopenharmony_ci * function pointers for these are identical across all CPUs.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_ciextern struct processor *cpu_vtable[];
11462306a36Sopenharmony_ci#define PROC_VTABLE(f)			cpu_vtable[smp_processor_id()]->f
11562306a36Sopenharmony_ci#define PROC_TABLE(f)			cpu_vtable[0]->f
11662306a36Sopenharmony_cistatic inline void init_proc_vtable(const struct processor *p)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	unsigned int cpu = smp_processor_id();
11962306a36Sopenharmony_ci	*cpu_vtable[cpu] = *p;
12062306a36Sopenharmony_ci	WARN_ON_ONCE(cpu_vtable[cpu]->dcache_clean_area !=
12162306a36Sopenharmony_ci		     cpu_vtable[0]->dcache_clean_area);
12262306a36Sopenharmony_ci	WARN_ON_ONCE(cpu_vtable[cpu]->set_pte_ext !=
12362306a36Sopenharmony_ci		     cpu_vtable[0]->set_pte_ext);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci#else
12662306a36Sopenharmony_ci#define PROC_VTABLE(f)			processor.f
12762306a36Sopenharmony_ci#define PROC_TABLE(f)			processor.f
12862306a36Sopenharmony_cistatic inline void init_proc_vtable(const struct processor *p)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	processor = *p;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci#endif
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#define cpu_proc_init			PROC_VTABLE(_proc_init)
13562306a36Sopenharmony_ci#define cpu_check_bugs			PROC_VTABLE(check_bugs)
13662306a36Sopenharmony_ci#define cpu_proc_fin			PROC_VTABLE(_proc_fin)
13762306a36Sopenharmony_ci#define cpu_reset			PROC_VTABLE(reset)
13862306a36Sopenharmony_ci#define cpu_do_idle			PROC_VTABLE(_do_idle)
13962306a36Sopenharmony_ci#define cpu_dcache_clean_area		PROC_TABLE(dcache_clean_area)
14062306a36Sopenharmony_ci#define cpu_set_pte_ext			PROC_TABLE(set_pte_ext)
14162306a36Sopenharmony_ci#define cpu_do_switch_mm		PROC_VTABLE(switch_mm)
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/* These two are private to arch/arm/kernel/suspend.c */
14462306a36Sopenharmony_ci#define cpu_do_suspend			PROC_VTABLE(do_suspend)
14562306a36Sopenharmony_ci#define cpu_do_resume			PROC_VTABLE(do_resume)
14662306a36Sopenharmony_ci#endif
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ciextern void cpu_resume(void);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#ifdef CONFIG_MMU
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define cpu_get_ttbr(nr)					\
15762306a36Sopenharmony_ci	({							\
15862306a36Sopenharmony_ci		u64 ttbr;					\
15962306a36Sopenharmony_ci		__asm__("mrrc	p15, " #nr ", %Q0, %R0, c2"	\
16062306a36Sopenharmony_ci			: "=r" (ttbr));				\
16162306a36Sopenharmony_ci		ttbr;						\
16262306a36Sopenharmony_ci	})
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define cpu_get_pgd()	\
16562306a36Sopenharmony_ci	({						\
16662306a36Sopenharmony_ci		u64 pg = cpu_get_ttbr(0);		\
16762306a36Sopenharmony_ci		pg &= ~(PTRS_PER_PGD*sizeof(pgd_t)-1);	\
16862306a36Sopenharmony_ci		(pgd_t *)phys_to_virt(pg);		\
16962306a36Sopenharmony_ci	})
17062306a36Sopenharmony_ci#else
17162306a36Sopenharmony_ci#define cpu_get_pgd()	\
17262306a36Sopenharmony_ci	({						\
17362306a36Sopenharmony_ci		unsigned long pg;			\
17462306a36Sopenharmony_ci		__asm__("mrc	p15, 0, %0, c2, c0, 0"	\
17562306a36Sopenharmony_ci			 : "=r" (pg) : : "cc");		\
17662306a36Sopenharmony_ci		pg &= ~0x3fff;				\
17762306a36Sopenharmony_ci		(pgd_t *)phys_to_virt(pg);		\
17862306a36Sopenharmony_ci	})
17962306a36Sopenharmony_ci#endif
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#else	/*!CONFIG_MMU */
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define cpu_switch_mm(pgd,mm)	{ }
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#endif
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
18862306a36Sopenharmony_ci#endif /* __KERNEL__ */
18962306a36Sopenharmony_ci#endif /* __ASM_PROCFNS_H */
190