On Tue, 3 Feb 2015, Kevin Cernekee wrote:
> >>> With the introduction of revision 2 of the MIPS architecture the CP0
> >>> EBase register was added and consequently there is no longer a guarantee
> >>> that exception vectors reside at the base of KSEG1. Using the value read
> >>> from CP0.EBase to determine a usable address might therefore be a better
> >>> idea, although the current revision of the MIPS architecture specification
> >>> that includes segmentation control makes it a bit complicated. Using a
> >>> dummy page mapped uncached instead might work the best.
> >> Would something like this work, assuming __fast_iob() doesn't get
> >> called before mem_init()?
> >> CKSEG1ADDR((void *)empty_zero_page)
> >> It is currently a GPL export, so maybe that would need to change to
> >> allow non-GPL drivers to use iob(). But that's still easier than
> >> allocating another dummy page.
You only need a mapping, not a separate page. Maybe you can use `vmap'
to alias a page from the kernel text -- no memory wasted then.
And the point of segmentation is KSEG1 may not be uncached anymore, it
may not be unmapped even. So a virtual mapping is really the proper and
only solution. And this situation is another reason to avoid using
CKSEG1ADDR and friends where possible.
But this is more of a heads-up from me rather than a request for
implementation as we don't support segmentation at this point.
> So there are two paths forward:
> 1) Make SMP86xx behave like other currently-supported CPUs, i.e. use
> the remap registers to configure the chip so that uncached reads from
> PA 0 do something sensible. This sounds like the easiest fix.
> 2) Agree to support memory configurations where PA 0 doesn't map to
> RAM, changing __fast_iob (and maybe other code) accordingly.
I suspect the latter is bound to happen sooner or later anyway. However
we handle setting CP0.EBase ourselves and we can use it to our advantage.
So knowing that our CP0.EBase points to somewhere within KSEG0 we can make
an example r2 `__fast_iob' implementation look like:
#define CKSEG1EBASE ((read_c0_ebase() | CKSEG1 | 0xfff) - 0xfff)
#define __fast_iob() \
__asm__ __volatile__( \
".set push\n\t" \
".set noreorder\n\t" \
"lw $0,%a0\n\t" \
".set pop" \
: /* no output */ \
: "p" (CKSEG1EBASE) \
which at 6 instructions produced is I think the best you can get without
using an auxiliary variable rather than CP0.EBase and then handcoding the
whole address calculation in assembly or using indirection.