linux-mips-fnet
[Top] [All Lists]

Re: mmap() frame buffer causes bus error on MIPS ...

To: linux-fbdev@vuser.vu.union.edu, linux-mips@oss.sgi.com, linux-mips@fnet.fr
Subject: Re: mmap() frame buffer causes bus error on MIPS ...
From: Jun Sun <jsun@mvista.com>
Date: Wed, 06 Sep 2000 14:30:05 -0700
References: <39B5BD14.A8D2F467@mvista.com> <39B5DABB.7FB85B09@mvista.com>
Sender: jsun@hermes.mvista.com
Jun Sun wrote:
> 
> Jun Sun wrote:
> >
> > With the help from Attila, I got the latest tdfx framebuffer driver
> > working on my NEC DDB5476 board.   I have console working based on this
> > driver.
> >
> > However, when I try to mmap frame buffer into user land, the mapping is
> > succesful, but trying to read the buffer causes a bus error.
> >
> > I tried to trace the kernel using gdb.  fb_mmap() seems to do the right
> > thing :
> >
> > 1) it calls fb->fb_get_fix() to get the buffer address, size, etc.  The
> > values all look fine.  The address is physical address, pointing a
> > mapped PCI memory block.  I verified that I can access that address in
> > gdb.
> >
> > 2) for MIPS, fb_mmap() turns off CACHE bit for the page.
> >
> > I would imagine when the app tries to read the buffer, a TLB miss is
> > generated.  TLB refill routine probably sets up the right TLB entry, and
> > the app will try to read again, and get the content.  I really can't
> > think of where the Bus error might occur.
> >
> > Does anybody have a clue here?  Thanks a lot.
> >
> > Jun
> 
> Did more probing on this.  It appears the TLB entry that gets filled is
> not right, even though the original page entry is generated correctly.
> See below TLB dump.
>

This is bogus.  The TLB entry is a shifted value (right-shift for 6
bits) of the entry in the page table.  That is the reason whe I see two
different values.
 
> The original page table still has the same value (not corrupted), and
> the only explanation is that tlb_refill actually gets the entry from a
> wrong place.  I then tried to decode tlb_refill code but really got lost
> there.  (Is there an explanation about the page table setup?)
> 
> How could this be? Maybe the pte's are put in the wrong place to begin
> with?  Ralf, please help ...
> 
> Jun
> 

I found the real reason, and had a work-around to make it work for now. 
However, I am not sure about the right fix.

fb_mmap() calls get_fix() to get screen info : 

        fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);

fb_mmap() then gets buffer address from fix.smem_start, which is a
physical address.  It then calls kernel's remap_page_range() with that
address, which in turn will generate pte with mk_pte_phys().

In MIPS, mk_pte_phys() is defined as follows :

extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
{
        return __pte(((physpage & PAGE_MASK) - PAGE_OFFSET) |
pgprot_val(pgprot));
}

The problematic part is " - PAGE_OFFSET" (where PAGE_OFFSET is
0x80000000).  If "physpage" is a physical address, it should not be
substracted by PAGE_OFFSET.  This is a bug.

On the other hand, I wonder why this bug is there without being caught
before (it is so fundamental).  If this is not a bug in MIPS kernel,
then the fix is in the fb_mmap(), where under __mips__ case, we should
add PAGE_OFFSET to the start of buffer address.

What is the right fix here?

Jun

<Prev in Thread] Current Thread [Next in Thread>