2005-04-16 15:20:36 -07:00
/*
* Dump R4x00 TLB for debugging purposes .
*
* Copyright ( C ) 1994 , 1995 by Waldorf Electronics , written by Ralf Baechle .
* Copyright ( C ) 1999 by Silicon Graphics , Inc .
*/
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/sched.h>
# include <linux/string.h>
# include <asm/bootinfo.h>
# include <asm/cachectl.h>
# include <asm/cpu.h>
# include <asm/mipsregs.h>
# include <asm/page.h>
# include <asm/pgtable.h>
static inline const char * msk2str ( unsigned int mask )
{
switch ( mask ) {
case PM_4K : return " 4kb " ;
case PM_16K : return " 16kb " ;
case PM_64K : return " 64kb " ;
case PM_256K : return " 256kb " ;
# ifndef CONFIG_CPU_VR41XX
case PM_1M : return " 1Mb " ;
case PM_4M : return " 4Mb " ;
case PM_16M : return " 16Mb " ;
case PM_64M : return " 64Mb " ;
case PM_256M : return " 256Mb " ;
# endif
}
return " unknown " ;
}
# define BARRIER() \
__asm__ __volatile__ ( \
" .set \t noreorder \n \t " \
" nop;nop;nop;nop;nop;nop;nop \n \t " \
" .set \t reorder " ) ;
void dump_tlb ( int first , int last )
{
unsigned long s_entryhi , entryhi , entrylo0 , entrylo1 , asid ;
unsigned int s_index , pagemask , c0 , c1 , i ;
s_entryhi = read_c0_entryhi ( ) ;
s_index = read_c0_index ( ) ;
asid = s_entryhi & 0xff ;
for ( i = first ; i < = last ; i + + ) {
write_c0_index ( i ) ;
BARRIER ( ) ;
tlb_read ( ) ;
BARRIER ( ) ;
pagemask = read_c0_pagemask ( ) ;
entryhi = read_c0_entryhi ( ) ;
entrylo0 = read_c0_entrylo0 ( ) ;
entrylo1 = read_c0_entrylo1 ( ) ;
/* Unused entries have a virtual address of CKSEG0. */
if ( ( entryhi & ~ 0x1ffffUL ) ! = CKSEG0
& & ( entryhi & 0xff ) = = asid ) {
/*
* Only print entries in use
*/
printk ( " Index: %2d pgmask=%s " , i , msk2str ( pagemask ) ) ;
c0 = ( entrylo0 > > 3 ) & 7 ;
c1 = ( entrylo1 > > 3 ) & 7 ;
printk ( " va=%011lx asid=%02lx \n " ,
( entryhi & ~ 0x1fffUL ) ,
entryhi & 0xff ) ;
printk ( " \t [pa=%011lx c=%d d=%d v=%d g=%ld] " ,
( entrylo0 < < 6 ) & PAGE_MASK , c0 ,
( entrylo0 & 4 ) ? 1 : 0 ,
( entrylo0 & 2 ) ? 1 : 0 ,
( entrylo0 & 1 ) ) ;
printk ( " [pa=%011lx c=%d d=%d v=%d g=%ld] \n " ,
( entrylo1 < < 6 ) & PAGE_MASK , c1 ,
( entrylo1 & 4 ) ? 1 : 0 ,
( entrylo1 & 2 ) ? 1 : 0 ,
( entrylo1 & 1 ) ) ;
}
}
printk ( " \n " ) ;
write_c0_entryhi ( s_entryhi ) ;
write_c0_index ( s_index ) ;
}
void dump_tlb_all ( void )
{
dump_tlb ( 0 , current_cpu_data . tlbsize - 1 ) ;
}
void dump_tlb_wired ( void )
{
int wired ;
wired = read_c0_wired ( ) ;
printk ( " Wired: %d " , wired ) ;
dump_tlb ( 0 , read_c0_wired ( ) ) ;
}
void dump_tlb_addr ( unsigned long addr )
{
unsigned int flags , oldpid ;
int index ;
local_irq_save ( flags ) ;
oldpid = read_c0_entryhi ( ) & 0xff ;
BARRIER ( ) ;
write_c0_entryhi ( ( addr & PAGE_MASK ) | oldpid ) ;
BARRIER ( ) ;
tlb_probe ( ) ;
BARRIER ( ) ;
index = read_c0_index ( ) ;
write_c0_entryhi ( oldpid ) ;
local_irq_restore ( flags ) ;
if ( index < 0 ) {
printk ( " No entry for address 0x%08lx in TLB \n " , addr ) ;
return ;
}
printk ( " Entry %d maps address 0x%08lx \n " , index , addr ) ;
dump_tlb ( index , index ) ;
}
void dump_tlb_nonwired ( void )
{
dump_tlb ( read_c0_wired ( ) , current_cpu_data . tlbsize - 1 ) ;
}
void dump_list_process ( struct task_struct * t , void * address )
{
pgd_t * page_dir , * pgd ;
2005-02-10 12:19:59 +00:00
pud_t * pud ;
2005-04-16 15:20:36 -07:00
pmd_t * pmd ;
pte_t * pte , page ;
unsigned long addr , val ;
addr = ( unsigned long ) address ;
printk ( " Addr == %08lx \n " , addr ) ;
printk ( " tasks->mm.pgd == %08lx \n " , ( unsigned long ) t - > mm - > pgd ) ;
2006-10-24 02:29:01 +01:00
page_dir = pgd_offset ( t - > mm , 0UL ) ;
2005-04-16 15:20:36 -07:00
printk ( " page_dir == %016lx \n " , ( unsigned long ) page_dir ) ;
pgd = pgd_offset ( t - > mm , addr ) ;
printk ( " pgd == %016lx \n " , ( unsigned long ) pgd ) ;
2005-02-10 12:19:59 +00:00
pud = pud_offset ( pgd , addr ) ;
printk ( " pud == %016lx \n " , ( unsigned long ) pud ) ;
pmd = pmd_offset ( pud , addr ) ;
2005-04-16 15:20:36 -07:00
printk ( " pmd == %016lx \n " , ( unsigned long ) pmd ) ;
pte = pte_offset ( pmd , addr ) ;
printk ( " pte == %016lx \n " , ( unsigned long ) pte ) ;
page = * pte ;
printk ( " page == %08lx \n " , pte_val ( page ) ) ;
val = pte_val ( page ) ;
if ( val & _PAGE_PRESENT ) printk ( " present " ) ;
if ( val & _PAGE_READ ) printk ( " read " ) ;
if ( val & _PAGE_WRITE ) printk ( " write " ) ;
if ( val & _PAGE_ACCESSED ) printk ( " accessed " ) ;
if ( val & _PAGE_MODIFIED ) printk ( " modified " ) ;
if ( val & _PAGE_R4KBUG ) printk ( " r4kbug " ) ;
if ( val & _PAGE_GLOBAL ) printk ( " global " ) ;
if ( val & _PAGE_VALID ) printk ( " valid " ) ;
printk ( " \n " ) ;
}
void dump_list_current ( void * address )
{
dump_list_process ( current , address ) ;
}
2006-10-24 02:29:01 +01:00
unsigned long vtop ( void * address )
2005-04-16 15:20:36 -07:00
{
pgd_t * pgd ;
2005-02-10 12:19:59 +00:00
pud_t * pud ;
2005-04-16 15:20:36 -07:00
pmd_t * pmd ;
pte_t * pte ;
2006-10-24 02:29:01 +01:00
unsigned long addr , paddr ;
2005-04-16 15:20:36 -07:00
addr = ( unsigned long ) address ;
pgd = pgd_offset ( current - > mm , addr ) ;
2005-02-10 12:19:59 +00:00
pud = pud_offset ( pgd , addr ) ;
pmd = pmd_offset ( pud , addr ) ;
2005-04-16 15:20:36 -07:00
pte = pte_offset ( pmd , addr ) ;
paddr = ( CKSEG1 | ( unsigned int ) pte_val ( * pte ) ) & PAGE_MASK ;
paddr | = ( addr & ~ PAGE_MASK ) ;
return paddr ;
}
void dump16 ( unsigned long * p )
{
int i ;
for ( i = 0 ; i < 8 ; i + + ) {
printk ( " *%08lx == %08lx, " , ( unsigned long ) p , * p ) ;
p + + ;
printk ( " *%08lx == %08lx \n " , ( unsigned long ) p , * p ) ;
p + + ;
}
}