18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  arch/arm/include/asm/proc-fns.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1997-1999 Russell King
68c2ecf20Sopenharmony_ci *  Copyright (C) 2000 Deep Blue Solutions Ltd
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#ifndef __ASM_PROCFNS_H
98c2ecf20Sopenharmony_ci#define __ASM_PROCFNS_H
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifdef __KERNEL__
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <asm/glue-proc.h>
148c2ecf20Sopenharmony_ci#include <asm/page.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct mm_struct;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * Don't change this structure - ASM code relies on it.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_cistruct processor {
248c2ecf20Sopenharmony_ci	/* MISC
258c2ecf20Sopenharmony_ci	 * get data abort address/flags
268c2ecf20Sopenharmony_ci	 */
278c2ecf20Sopenharmony_ci	void (*_data_abort)(unsigned long pc);
288c2ecf20Sopenharmony_ci	/*
298c2ecf20Sopenharmony_ci	 * Retrieve prefetch fault address
308c2ecf20Sopenharmony_ci	 */
318c2ecf20Sopenharmony_ci	unsigned long (*_prefetch_abort)(unsigned long lr);
328c2ecf20Sopenharmony_ci	/*
338c2ecf20Sopenharmony_ci	 * Set up any processor specifics
348c2ecf20Sopenharmony_ci	 */
358c2ecf20Sopenharmony_ci	void (*_proc_init)(void);
368c2ecf20Sopenharmony_ci	/*
378c2ecf20Sopenharmony_ci	 * Check for processor bugs
388c2ecf20Sopenharmony_ci	 */
398c2ecf20Sopenharmony_ci	void (*check_bugs)(void);
408c2ecf20Sopenharmony_ci	/*
418c2ecf20Sopenharmony_ci	 * Disable any processor specifics
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	void (*_proc_fin)(void);
448c2ecf20Sopenharmony_ci	/*
458c2ecf20Sopenharmony_ci	 * Special stuff for a reset
468c2ecf20Sopenharmony_ci	 */
478c2ecf20Sopenharmony_ci	void (*reset)(unsigned long addr, bool hvc) __attribute__((noreturn));
488c2ecf20Sopenharmony_ci	/*
498c2ecf20Sopenharmony_ci	 * Idle the processor
508c2ecf20Sopenharmony_ci	 */
518c2ecf20Sopenharmony_ci	int (*_do_idle)(void);
528c2ecf20Sopenharmony_ci	/*
538c2ecf20Sopenharmony_ci	 * Processor architecture specific
548c2ecf20Sopenharmony_ci	 */
558c2ecf20Sopenharmony_ci	/*
568c2ecf20Sopenharmony_ci	 * clean a virtual address range from the
578c2ecf20Sopenharmony_ci	 * D-cache without flushing the cache.
588c2ecf20Sopenharmony_ci	 */
598c2ecf20Sopenharmony_ci	void (*dcache_clean_area)(void *addr, int size);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/*
628c2ecf20Sopenharmony_ci	 * Set the page table
638c2ecf20Sopenharmony_ci	 */
648c2ecf20Sopenharmony_ci	void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm);
658c2ecf20Sopenharmony_ci	/*
668c2ecf20Sopenharmony_ci	 * Set a possibly extended PTE.  Non-extended PTEs should
678c2ecf20Sopenharmony_ci	 * ignore 'ext'.
688c2ecf20Sopenharmony_ci	 */
698c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
708c2ecf20Sopenharmony_ci	void (*set_pte_ext)(pte_t *ptep, pte_t pte);
718c2ecf20Sopenharmony_ci#else
728c2ecf20Sopenharmony_ci	void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext);
738c2ecf20Sopenharmony_ci#endif
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* Suspend/resume */
768c2ecf20Sopenharmony_ci	unsigned int suspend_size;
778c2ecf20Sopenharmony_ci	void (*do_suspend)(void *);
788c2ecf20Sopenharmony_ci	void (*do_resume)(void *);
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#ifndef MULTI_CPU
828c2ecf20Sopenharmony_cistatic inline void init_proc_vtable(const struct processor *p)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciextern void cpu_proc_init(void);
878c2ecf20Sopenharmony_ciextern void cpu_proc_fin(void);
888c2ecf20Sopenharmony_ciextern int cpu_do_idle(void);
898c2ecf20Sopenharmony_ciextern void cpu_dcache_clean_area(void *, int);
908c2ecf20Sopenharmony_ciextern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
918c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
928c2ecf20Sopenharmony_ciextern void cpu_set_pte_ext(pte_t *ptep, pte_t pte);
938c2ecf20Sopenharmony_ci#else
948c2ecf20Sopenharmony_ciextern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
958c2ecf20Sopenharmony_ci#endif
968c2ecf20Sopenharmony_ciextern void cpu_reset(unsigned long addr, bool hvc) __attribute__((noreturn));
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/* These three are private to arch/arm/kernel/suspend.c */
998c2ecf20Sopenharmony_ciextern void cpu_do_suspend(void *);
1008c2ecf20Sopenharmony_ciextern void cpu_do_resume(void *);
1018c2ecf20Sopenharmony_ci#else
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciextern struct processor processor;
1048c2ecf20Sopenharmony_ci#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
1058c2ecf20Sopenharmony_ci#include <linux/smp.h>
1068c2ecf20Sopenharmony_ci/*
1078c2ecf20Sopenharmony_ci * This can't be a per-cpu variable because we need to access it before
1088c2ecf20Sopenharmony_ci * per-cpu has been initialised.  We have a couple of functions that are
1098c2ecf20Sopenharmony_ci * called in a pre-emptible context, and so can't use smp_processor_id()
1108c2ecf20Sopenharmony_ci * there, hence PROC_TABLE().  We insist in init_proc_vtable() that the
1118c2ecf20Sopenharmony_ci * function pointers for these are identical across all CPUs.
1128c2ecf20Sopenharmony_ci */
1138c2ecf20Sopenharmony_ciextern struct processor *cpu_vtable[];
1148c2ecf20Sopenharmony_ci#define PROC_VTABLE(f)			cpu_vtable[smp_processor_id()]->f
1158c2ecf20Sopenharmony_ci#define PROC_TABLE(f)			cpu_vtable[0]->f
1168c2ecf20Sopenharmony_cistatic inline void init_proc_vtable(const struct processor *p)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	unsigned int cpu = smp_processor_id();
1198c2ecf20Sopenharmony_ci	*cpu_vtable[cpu] = *p;
1208c2ecf20Sopenharmony_ci	WARN_ON_ONCE(cpu_vtable[cpu]->dcache_clean_area !=
1218c2ecf20Sopenharmony_ci		     cpu_vtable[0]->dcache_clean_area);
1228c2ecf20Sopenharmony_ci	WARN_ON_ONCE(cpu_vtable[cpu]->set_pte_ext !=
1238c2ecf20Sopenharmony_ci		     cpu_vtable[0]->set_pte_ext);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci#else
1268c2ecf20Sopenharmony_ci#define PROC_VTABLE(f)			processor.f
1278c2ecf20Sopenharmony_ci#define PROC_TABLE(f)			processor.f
1288c2ecf20Sopenharmony_cistatic inline void init_proc_vtable(const struct processor *p)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	processor = *p;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci#endif
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#define cpu_proc_init			PROC_VTABLE(_proc_init)
1358c2ecf20Sopenharmony_ci#define cpu_check_bugs			PROC_VTABLE(check_bugs)
1368c2ecf20Sopenharmony_ci#define cpu_proc_fin			PROC_VTABLE(_proc_fin)
1378c2ecf20Sopenharmony_ci#define cpu_reset			PROC_VTABLE(reset)
1388c2ecf20Sopenharmony_ci#define cpu_do_idle			PROC_VTABLE(_do_idle)
1398c2ecf20Sopenharmony_ci#define cpu_dcache_clean_area		PROC_TABLE(dcache_clean_area)
1408c2ecf20Sopenharmony_ci#define cpu_set_pte_ext			PROC_TABLE(set_pte_ext)
1418c2ecf20Sopenharmony_ci#define cpu_do_switch_mm		PROC_VTABLE(switch_mm)
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/* These two are private to arch/arm/kernel/suspend.c */
1448c2ecf20Sopenharmony_ci#define cpu_do_suspend			PROC_VTABLE(do_suspend)
1458c2ecf20Sopenharmony_ci#define cpu_do_resume			PROC_VTABLE(do_resume)
1468c2ecf20Sopenharmony_ci#endif
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ciextern void cpu_resume(void);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci#include <asm/memory.h>
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci#define cpu_get_ttbr(nr)					\
1598c2ecf20Sopenharmony_ci	({							\
1608c2ecf20Sopenharmony_ci		u64 ttbr;					\
1618c2ecf20Sopenharmony_ci		__asm__("mrrc	p15, " #nr ", %Q0, %R0, c2"	\
1628c2ecf20Sopenharmony_ci			: "=r" (ttbr));				\
1638c2ecf20Sopenharmony_ci		ttbr;						\
1648c2ecf20Sopenharmony_ci	})
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci#define cpu_get_pgd()	\
1678c2ecf20Sopenharmony_ci	({						\
1688c2ecf20Sopenharmony_ci		u64 pg = cpu_get_ttbr(0);		\
1698c2ecf20Sopenharmony_ci		pg &= ~(PTRS_PER_PGD*sizeof(pgd_t)-1);	\
1708c2ecf20Sopenharmony_ci		(pgd_t *)phys_to_virt(pg);		\
1718c2ecf20Sopenharmony_ci	})
1728c2ecf20Sopenharmony_ci#else
1738c2ecf20Sopenharmony_ci#define cpu_get_pgd()	\
1748c2ecf20Sopenharmony_ci	({						\
1758c2ecf20Sopenharmony_ci		unsigned long pg;			\
1768c2ecf20Sopenharmony_ci		__asm__("mrc	p15, 0, %0, c2, c0, 0"	\
1778c2ecf20Sopenharmony_ci			 : "=r" (pg) : : "cc");		\
1788c2ecf20Sopenharmony_ci		pg &= ~0x3fff;				\
1798c2ecf20Sopenharmony_ci		(pgd_t *)phys_to_virt(pg);		\
1808c2ecf20Sopenharmony_ci	})
1818c2ecf20Sopenharmony_ci#endif
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci#else	/*!CONFIG_MMU */
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci#define cpu_switch_mm(pgd,mm)	{ }
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci#endif
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */
1908c2ecf20Sopenharmony_ci#endif /* __KERNEL__ */
1918c2ecf20Sopenharmony_ci#endif /* __ASM_PROCFNS_H */
192