xref: /kernel/linux/linux-5.10/arch/m68k/mm/sun3kmap.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * linux/arch/m68k/mm/sun3kmap.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2002 Sam Creasey <sammy@sammy.net>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
78c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
88c2ecf20Sopenharmony_ci * for more details.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/mm.h>
158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/page.h>
188c2ecf20Sopenharmony_ci#include <asm/io.h>
198c2ecf20Sopenharmony_ci#include <asm/sun3mmu.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#undef SUN3_KMAP_DEBUG
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#ifdef SUN3_KMAP_DEBUG
248c2ecf20Sopenharmony_ciextern void print_pte_vaddr(unsigned long vaddr);
258c2ecf20Sopenharmony_ci#endif
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciextern void mmu_emu_map_pmeg (int context, int vaddr);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic inline void do_page_mapin(unsigned long phys, unsigned long virt,
308c2ecf20Sopenharmony_ci				 unsigned long type)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	unsigned long pte;
338c2ecf20Sopenharmony_ci	pte_t ptep;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	ptep = pfn_pte(phys >> PAGE_SHIFT, PAGE_KERNEL);
368c2ecf20Sopenharmony_ci	pte = pte_val(ptep);
378c2ecf20Sopenharmony_ci	pte |= type;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	sun3_put_pte(virt, pte);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#ifdef SUN3_KMAP_DEBUG
428c2ecf20Sopenharmony_ci	pr_info("mapin:");
438c2ecf20Sopenharmony_ci	print_pte_vaddr(virt);
448c2ecf20Sopenharmony_ci#endif
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic inline void do_pmeg_mapin(unsigned long phys, unsigned long virt,
498c2ecf20Sopenharmony_ci				 unsigned long type, int pages)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if(sun3_get_segmap(virt & ~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG)
538c2ecf20Sopenharmony_ci		mmu_emu_map_pmeg(sun3_get_context(), virt);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	while(pages) {
568c2ecf20Sopenharmony_ci		do_page_mapin(phys, virt, type);
578c2ecf20Sopenharmony_ci		phys += PAGE_SIZE;
588c2ecf20Sopenharmony_ci		virt += PAGE_SIZE;
598c2ecf20Sopenharmony_ci		pages--;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_civoid __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
648c2ecf20Sopenharmony_ci		   unsigned long type)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct vm_struct *area;
678c2ecf20Sopenharmony_ci	unsigned long offset, virt, ret;
688c2ecf20Sopenharmony_ci	int pages;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if(!size)
718c2ecf20Sopenharmony_ci		return NULL;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* page align */
748c2ecf20Sopenharmony_ci	offset = phys & (PAGE_SIZE-1);
758c2ecf20Sopenharmony_ci	phys &= ~(PAGE_SIZE-1);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	size += offset;
788c2ecf20Sopenharmony_ci	size = PAGE_ALIGN(size);
798c2ecf20Sopenharmony_ci	if((area = get_vm_area(size, VM_IOREMAP)) == NULL)
808c2ecf20Sopenharmony_ci		return NULL;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#ifdef SUN3_KMAP_DEBUG
838c2ecf20Sopenharmony_ci	pr_info("ioremap: got virt %p size %lx(%lx)\n", area->addr, size,
848c2ecf20Sopenharmony_ci		area->size);
858c2ecf20Sopenharmony_ci#endif
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	pages = size / PAGE_SIZE;
888c2ecf20Sopenharmony_ci	virt = (unsigned long)area->addr;
898c2ecf20Sopenharmony_ci	ret = virt + offset;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	while(pages) {
928c2ecf20Sopenharmony_ci		int seg_pages;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		seg_pages = (SUN3_PMEG_SIZE - (virt & SUN3_PMEG_MASK)) / PAGE_SIZE;
958c2ecf20Sopenharmony_ci		if(seg_pages > pages)
968c2ecf20Sopenharmony_ci			seg_pages = pages;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		do_pmeg_mapin(phys, virt, type, seg_pages);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		pages -= seg_pages;
1018c2ecf20Sopenharmony_ci		phys += seg_pages * PAGE_SIZE;
1028c2ecf20Sopenharmony_ci		virt += seg_pages * PAGE_SIZE;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return (void __iomem *)ret;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sun3_ioremap);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_civoid __iomem *__ioremap(unsigned long phys, unsigned long size, int cache)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ioremap);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_civoid iounmap(void __iomem *addr)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	vfree((void *)(PAGE_MASK & (unsigned long)addr));
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iounmap);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val,
1268c2ecf20Sopenharmony_ci * trapping the potential read fault.  Returns 0 if the access faulted,
1278c2ecf20Sopenharmony_ci * 1 on success.
1288c2ecf20Sopenharmony_ci *
1298c2ecf20Sopenharmony_ci * This function is primarily used to check addresses on the VME bus.
1308c2ecf20Sopenharmony_ci *
1318c2ecf20Sopenharmony_ci * Mucking with the page fault handler seems a little hackish to me, but
1328c2ecf20Sopenharmony_ci * SunOS, NetBSD, and Mach all implemented this check in such a manner,
1338c2ecf20Sopenharmony_ci * so I figure we're allowed.
1348c2ecf20Sopenharmony_ci */
1358c2ecf20Sopenharmony_ciint sun3_map_test(unsigned long addr, char *val)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	int ret = 0;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	__asm__ __volatile__
1408c2ecf20Sopenharmony_ci		(".globl _sun3_map_test_start\n"
1418c2ecf20Sopenharmony_ci		 "_sun3_map_test_start:\n"
1428c2ecf20Sopenharmony_ci		 "1: moveb (%2), (%0)\n"
1438c2ecf20Sopenharmony_ci		 "   moveq #1, %1\n"
1448c2ecf20Sopenharmony_ci		 "2:\n"
1458c2ecf20Sopenharmony_ci		 ".section .fixup,\"ax\"\n"
1468c2ecf20Sopenharmony_ci		 ".even\n"
1478c2ecf20Sopenharmony_ci		 "3: moveq #0, %1\n"
1488c2ecf20Sopenharmony_ci		 "   jmp 2b\n"
1498c2ecf20Sopenharmony_ci		 ".previous\n"
1508c2ecf20Sopenharmony_ci		 ".section __ex_table,\"a\"\n"
1518c2ecf20Sopenharmony_ci		 ".align 4\n"
1528c2ecf20Sopenharmony_ci		 ".long 1b,3b\n"
1538c2ecf20Sopenharmony_ci		 ".previous\n"
1548c2ecf20Sopenharmony_ci		 ".globl _sun3_map_test_end\n"
1558c2ecf20Sopenharmony_ci		 "_sun3_map_test_end:\n"
1568c2ecf20Sopenharmony_ci		 : "=a"(val), "=r"(ret)
1578c2ecf20Sopenharmony_ci		 : "a"(addr));
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	return ret;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sun3_map_test);
162