2005-04-17 02:20:36 +04:00
/*
* linux / arch / m68k / mm / sun3kmap . c
*
* Copyright ( C ) 2002 Sam Creasey < sammy @ sammy . net >
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive
* for more details .
*/
2006-10-11 20:28:27 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/vmalloc.h>
# include <asm/page.h>
# include <asm/pgtable.h>
# include <asm/io.h>
# include <asm/sun3mmu.h>
# undef SUN3_KMAP_DEBUG
# ifdef SUN3_KMAP_DEBUG
extern void print_pte_vaddr ( unsigned long vaddr ) ;
# endif
extern void mmu_emu_map_pmeg ( int context , int vaddr ) ;
static inline void do_page_mapin ( unsigned long phys , unsigned long virt ,
unsigned long type )
{
unsigned long pte ;
pte_t ptep ;
ptep = pfn_pte ( phys > > PAGE_SHIFT , PAGE_KERNEL ) ;
pte = pte_val ( ptep ) ;
pte | = type ;
sun3_put_pte ( virt , pte ) ;
# ifdef SUN3_KMAP_DEBUG
print_pte_vaddr ( virt ) ;
# endif
}
static inline void do_pmeg_mapin ( unsigned long phys , unsigned long virt ,
unsigned long type , int pages )
{
if ( sun3_get_segmap ( virt & ~ SUN3_PMEG_MASK ) = = SUN3_INVALID_PMEG )
mmu_emu_map_pmeg ( sun3_get_context ( ) , virt ) ;
while ( pages ) {
do_page_mapin ( phys , virt , type ) ;
phys + = PAGE_SIZE ;
virt + = PAGE_SIZE ;
pages - - ;
}
}
2006-10-11 20:28:17 +04:00
void __iomem * sun3_ioremap ( unsigned long phys , unsigned long size ,
2005-04-17 02:20:36 +04:00
unsigned long type )
{
struct vm_struct * area ;
unsigned long offset , virt , ret ;
int pages ;
if ( ! size )
return NULL ;
/* page align */
offset = phys & ( PAGE_SIZE - 1 ) ;
phys & = ~ ( PAGE_SIZE - 1 ) ;
size + = offset ;
size = PAGE_ALIGN ( size ) ;
if ( ( area = get_vm_area ( size , VM_IOREMAP ) ) = = NULL )
return NULL ;
# ifdef SUN3_KMAP_DEBUG
printk ( " ioremap: got virt %p size %lx(%lx) \n " ,
area - > addr , size , area - > size ) ;
# endif
pages = size / PAGE_SIZE ;
virt = ( unsigned long ) area - > addr ;
ret = virt + offset ;
while ( pages ) {
int seg_pages ;
seg_pages = ( SUN3_PMEG_SIZE - ( virt & SUN3_PMEG_MASK ) ) / PAGE_SIZE ;
if ( seg_pages > pages )
seg_pages = pages ;
do_pmeg_mapin ( phys , virt , type , seg_pages ) ;
pages - = seg_pages ;
phys + = seg_pages * PAGE_SIZE ;
virt + = seg_pages * PAGE_SIZE ;
}
2006-10-11 20:28:17 +04:00
return ( void __iomem * ) ret ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 07:33:18 +04:00
EXPORT_SYMBOL ( sun3_ioremap ) ;
2005-04-17 02:20:36 +04:00
2006-10-11 20:28:17 +04:00
void __iomem * __ioremap ( unsigned long phys , unsigned long size , int cache )
2005-04-17 02:20:36 +04:00
{
return sun3_ioremap ( phys , size , SUN3_PAGE_TYPE_IO ) ;
}
2006-10-11 20:28:27 +04:00
EXPORT_SYMBOL ( __ioremap ) ;
2005-04-17 02:20:36 +04:00
2006-10-11 20:28:17 +04:00
void iounmap ( void __iomem * addr )
2005-04-17 02:20:36 +04:00
{
vfree ( ( void * ) ( PAGE_MASK & ( unsigned long ) addr ) ) ;
}
2006-10-11 20:28:27 +04:00
EXPORT_SYMBOL ( iounmap ) ;
2005-04-17 02:20:36 +04:00
/* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val,
* trapping the potential read fault . Returns 0 if the access faulted ,
* 1 on success .
*
* This function is primarily used to check addresses on the VME bus .
*
* Mucking with the page fault handler seems a little hackish to me , but
* SunOS , NetBSD , and Mach all implemented this check in such a manner ,
* so I figure we ' re allowed .
*/
int sun3_map_test ( unsigned long addr , char * val )
{
int ret = 0 ;
__asm__ __volatile__
( " .globl _sun3_map_test_start \n "
" _sun3_map_test_start: \n "
" 1: moveb (%2), (%0) \n "
" moveq #1, %1 \n "
" 2: \n "
" .section .fixup, \" ax \" \n "
" .even \n "
" 3: moveq #0, %1 \n "
" jmp 2b \n "
" .previous \n "
" .section __ex_table, \" a \" \n "
" .align 4 \n "
" .long 1b,3b \n "
" .previous \n "
" .globl _sun3_map_test_end \n "
" _sun3_map_test_end: \n "
: " =a " ( val ) , " =r " ( ret )
: " a " ( addr ) ) ;
return ret ;
}
2007-07-20 07:33:18 +04:00
EXPORT_SYMBOL ( sun3_map_test ) ;