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
|