18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _M68K_PAGE_MM_H
38c2ecf20Sopenharmony_ci#define _M68K_PAGE_MM_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/compiler.h>
88c2ecf20Sopenharmony_ci#include <asm/module.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/*
118c2ecf20Sopenharmony_ci * We don't need to check for alignment etc.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#ifdef CPU_M68040_OR_M68060_ONLY
148c2ecf20Sopenharmony_cistatic inline void copy_page(void *to, void *from)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci  unsigned long tmp;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci  __asm__ __volatile__("1:\t"
198c2ecf20Sopenharmony_ci		       ".chip 68040\n\t"
208c2ecf20Sopenharmony_ci		       "move16 %1@+,%0@+\n\t"
218c2ecf20Sopenharmony_ci		       "move16 %1@+,%0@+\n\t"
228c2ecf20Sopenharmony_ci		       ".chip 68k\n\t"
238c2ecf20Sopenharmony_ci		       "dbra  %2,1b\n\t"
248c2ecf20Sopenharmony_ci		       : "=a" (to), "=a" (from), "=d" (tmp)
258c2ecf20Sopenharmony_ci		       : "0" (to), "1" (from) , "2" (PAGE_SIZE / 32 - 1)
268c2ecf20Sopenharmony_ci		       );
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic inline void clear_page(void *page)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	unsigned long tmp;
328c2ecf20Sopenharmony_ci	unsigned long *sp = page;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	*sp++ = 0;
358c2ecf20Sopenharmony_ci	*sp++ = 0;
368c2ecf20Sopenharmony_ci	*sp++ = 0;
378c2ecf20Sopenharmony_ci	*sp++ = 0;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	__asm__ __volatile__("1:\t"
408c2ecf20Sopenharmony_ci			     ".chip 68040\n\t"
418c2ecf20Sopenharmony_ci			     "move16 %2@+,%0@+\n\t"
428c2ecf20Sopenharmony_ci			     ".chip 68k\n\t"
438c2ecf20Sopenharmony_ci			     "subqw  #8,%2\n\t"
448c2ecf20Sopenharmony_ci			     "subqw  #8,%2\n\t"
458c2ecf20Sopenharmony_ci			     "dbra   %1,1b\n\t"
468c2ecf20Sopenharmony_ci			     : "=a" (sp), "=d" (tmp)
478c2ecf20Sopenharmony_ci			     : "a" (page), "0" (sp),
488c2ecf20Sopenharmony_ci			       "1" ((PAGE_SIZE - 16) / 16 - 1));
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#else
528c2ecf20Sopenharmony_ci#define clear_page(page)	memset((page), 0, PAGE_SIZE)
538c2ecf20Sopenharmony_ci#define copy_page(to,from)	memcpy((to), (from), PAGE_SIZE)
548c2ecf20Sopenharmony_ci#endif
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define clear_user_page(addr, vaddr, page)	\
578c2ecf20Sopenharmony_ci	do {	clear_page(addr);		\
588c2ecf20Sopenharmony_ci		flush_dcache_page(page);	\
598c2ecf20Sopenharmony_ci	} while (0)
608c2ecf20Sopenharmony_ci#define copy_user_page(to, from, vaddr, page)	\
618c2ecf20Sopenharmony_ci	do {	copy_page(to, from);		\
628c2ecf20Sopenharmony_ci		flush_dcache_page(page);	\
638c2ecf20Sopenharmony_ci	} while (0)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciextern unsigned long m68k_memoffset;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#ifndef CONFIG_SUN3
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define WANT_PAGE_VIRTUAL
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic inline unsigned long ___pa(void *vaddr)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	unsigned long paddr;
748c2ecf20Sopenharmony_ci	asm (
758c2ecf20Sopenharmony_ci		"1:	addl #0,%0\n"
768c2ecf20Sopenharmony_ci		m68k_fixup(%c2, 1b+2)
778c2ecf20Sopenharmony_ci		: "=r" (paddr)
788c2ecf20Sopenharmony_ci		: "0" (vaddr), "i" (m68k_fixup_memoffset));
798c2ecf20Sopenharmony_ci	return paddr;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci#define __pa(vaddr)	___pa((void *)(long)(vaddr))
828c2ecf20Sopenharmony_cistatic inline void *__va(unsigned long paddr)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	void *vaddr;
858c2ecf20Sopenharmony_ci	asm (
868c2ecf20Sopenharmony_ci		"1:	subl #0,%0\n"
878c2ecf20Sopenharmony_ci		m68k_fixup(%c2, 1b+2)
888c2ecf20Sopenharmony_ci		: "=r" (vaddr)
898c2ecf20Sopenharmony_ci		: "0" (paddr), "i" (m68k_fixup_memoffset));
908c2ecf20Sopenharmony_ci	return vaddr;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#else	/* !CONFIG_SUN3 */
948c2ecf20Sopenharmony_ci/* This #define is a horrible hack to suppress lots of warnings. --m */
958c2ecf20Sopenharmony_ci#define __pa(x) ___pa((unsigned long)(x))
968c2ecf20Sopenharmony_cistatic inline unsigned long ___pa(unsigned long x)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci     if(x == 0)
998c2ecf20Sopenharmony_ci	  return 0;
1008c2ecf20Sopenharmony_ci     if(x >= PAGE_OFFSET)
1018c2ecf20Sopenharmony_ci        return (x-PAGE_OFFSET);
1028c2ecf20Sopenharmony_ci     else
1038c2ecf20Sopenharmony_ci        return (x+0x2000000);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic inline void *__va(unsigned long x)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci     if(x == 0)
1098c2ecf20Sopenharmony_ci	  return (void *)0;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci     if(x < 0x2000000)
1128c2ecf20Sopenharmony_ci        return (void *)(x+PAGE_OFFSET);
1138c2ecf20Sopenharmony_ci     else
1148c2ecf20Sopenharmony_ci        return (void *)(x-0x2000000);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci#endif	/* CONFIG_SUN3 */
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/*
1198c2ecf20Sopenharmony_ci * NOTE: virtual isn't really correct, actually it should be the offset into the
1208c2ecf20Sopenharmony_ci * memory node, but we have no highmem, so that works for now.
1218c2ecf20Sopenharmony_ci * TODO: implement (fast) pfn<->pgdat_idx conversion functions, this makes lots
1228c2ecf20Sopenharmony_ci * of the shifts unnecessary.
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_ci#define virt_to_pfn(kaddr)	(__pa(kaddr) >> PAGE_SHIFT)
1258c2ecf20Sopenharmony_ci#define pfn_to_virt(pfn)	__va((pfn) << PAGE_SHIFT)
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ciextern int m68k_virt_to_node_shift;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#ifdef CONFIG_SINGLE_MEMORY_CHUNK
1308c2ecf20Sopenharmony_ci#define __virt_to_node(addr)	(&pg_data_map[0])
1318c2ecf20Sopenharmony_ci#else
1328c2ecf20Sopenharmony_ciextern struct pglist_data *pg_data_table[];
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic inline __attribute_const__ int __virt_to_node_shift(void)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	int shift;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	asm (
1398c2ecf20Sopenharmony_ci		"1:	moveq	#0,%0\n"
1408c2ecf20Sopenharmony_ci		m68k_fixup(%c1, 1b)
1418c2ecf20Sopenharmony_ci		: "=d" (shift)
1428c2ecf20Sopenharmony_ci		: "i" (m68k_fixup_vnode_shift));
1438c2ecf20Sopenharmony_ci	return shift;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#define __virt_to_node(addr)	(pg_data_table[(unsigned long)(addr) >> __virt_to_node_shift()])
1478c2ecf20Sopenharmony_ci#endif
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci#define virt_to_page(addr) ({						\
1508c2ecf20Sopenharmony_ci	pfn_to_page(virt_to_pfn(addr));					\
1518c2ecf20Sopenharmony_ci})
1528c2ecf20Sopenharmony_ci#define page_to_virt(page) ({						\
1538c2ecf20Sopenharmony_ci	pfn_to_virt(page_to_pfn(page));					\
1548c2ecf20Sopenharmony_ci})
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci#define pfn_to_page(pfn) ({						\
1578c2ecf20Sopenharmony_ci	unsigned long __pfn = (pfn);					\
1588c2ecf20Sopenharmony_ci	struct pglist_data *pgdat;					\
1598c2ecf20Sopenharmony_ci	pgdat = __virt_to_node((unsigned long)pfn_to_virt(__pfn));	\
1608c2ecf20Sopenharmony_ci	pgdat->node_mem_map + (__pfn - pgdat->node_start_pfn);		\
1618c2ecf20Sopenharmony_ci})
1628c2ecf20Sopenharmony_ci#define page_to_pfn(_page) ({						\
1638c2ecf20Sopenharmony_ci	const struct page *__p = (_page);				\
1648c2ecf20Sopenharmony_ci	struct pglist_data *pgdat;					\
1658c2ecf20Sopenharmony_ci	pgdat = &pg_data_map[page_to_nid(__p)];				\
1668c2ecf20Sopenharmony_ci	((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn;		\
1678c2ecf20Sopenharmony_ci})
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci#define virt_addr_valid(kaddr)	((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
1708c2ecf20Sopenharmony_ci#define pfn_valid(pfn)		virt_addr_valid(pfn_to_virt(pfn))
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#endif /* _M68K_PAGE_MM_H */
175