Subject: Re: more on cache ops... What are they actually supposed to do?
To: Michael L. Hitch <mhitch@lightning.msu.montana.edu>
From: Chris G. Demetriou <cgd@sibyte.com>
List: port-mips
Date: 06/19/2000 23:37:32
"Michael L. Hitch" <mhitch@lightning.msu.montana.edu> writes:
> > * the scary bit of code in pmap.c (around line 2136):
> 
>   It is rather scary, isn't it?

that's the nice way of saing it.  8-)


>   This "works" because the virtual address passed to FlushDCache() is
> converted to KSEG0 address using the index bits.  This produces a valid
> address which will flush the primary cache lines.  If secondary cache is
> present, the cache flush using the VA won't flush the correct secondary
> cache lines, since the KSEG0 address won't map to the read physical
> address.  The second cache flush is done using the physical address,
> which is also converted to a KSEG0 address using the physical address as
> the index.  This is a "brue-force" method, which has the nasty side effect
> of flushing much more cache than is really needed.

"Yes."  This was the impression that i got when reading the code,
after my eyes stopped bleeding.  8-)

however, one of the things that it means is, basically, anyplace which
does a mips3_FlushDCache() on a non-kseg0 address is potentially
suspect, right?

At the very least, in the MI code, this includes:

	pmap.c:983

does it not?  The rest of the uses (excluding the Ugh!) are only hit if
there's no l2 cache, on kseg0 addresses, or in one case (pmap.c:1751)
a physical address.

btw, the code on ll 1738-2178 in pmap.c looks ... iffy to me.  Why is
that in a defined(MIPS3_L2CACHE_ABSENT) #ifdef, if it doesn't bother
checking for !mips_L2CachePresent like the similar bits of #ifdef'd
flushing code do?  (If the test is irrelevant, why is it
conditionalized?!)


>     The correct way is to use the "hit" cache ops so that only the desired
> cache lines get flushed proprly.  The problem with this is that this
> requires a valid mapping to be present.  I attempmted to do this once upon
> a time, but did not have much success at the time.  If the VA is a user
> address, it requires the proper ASID to match the VA, and that the TLB
> miss handler uses the proper TLB table.

yeah.  basically, you've gotta do your flushes before you take things
out of your MMU tables for a process.


> [One think I'm unclear on is if
> the cache op can take a TLB miss, or if the TLB has to be valid to start
> with.]

My understanding having read a bunch of docs is that it's the former:
you can take a TLB miss (or other TLB-related exception) on the cache
op.



> > * code sequences (like pmap.c:983) which look like:
> > 
> >                 MachFlushDCache(va, len);
> >                 MachFlushICache(MIPS_PHYS_TO_KSEG0(va &
> >                     (mips_L1ICacheSize - 1)), len);
> > 
> >   (when there's no substantive difference in the descriptions of those
> >   two functions' arguments).  This goes back to comments in the first point
> >   above.
> 
>   I think I'm responsible for that, and I can't remember my reasoning for
> it at the time.  [I really should have documented what I was trying to
> accomplish at the time.]  I'll need to cogitate on this a bit, but I think
> it's to make sure the desired primary and secondary cache lines get
> flushed.

so, there are a few things here:

(1) the point above is about doing the kseg conversion in C there for
    FlushICache, but in assembly for FlushDCache.  Of the mips3
    FlushICache calls i could find in the MI pmap, 2 were done with a
    kseg0 address, but one was done with a potentially-user va, AFAIK.
    (again the requirement of virtual indexing, correct?) In the one
    done with a 'random' va (pmap.c:1340), the pa is at hand, why not
    use it, and then you could make the calling interface consistent?

(2) one of the things that _really_ confused me about it is that
    mips3_FlushICache() uses the VA provided, but
    mips3_FlushICache_2way() takes the address, chops bits off, and
    offsets it into kseg0.  For that case, you do twice the work,
    and the C code wouldn't get the mask right anyhow, as-is.

(3) there're issues around secondary I-caches (for split secondary
    caches), but it's not clear that _anybody_ really cares about
    them.  I don't think i've ever even heard of them in the wild.


>   Hmm, as I recall (but it's been quite a while since I've had to think
> about this), the MIPS1 cache was physically-indexed and physically
> tagged.

That's what See Mips Run indicates, unless i'm misreading it.


[ ... hit ops ... ]
>   I'd say that's the right way to do it, but I'm not sure how you would
> ensure the TLB translation is valid.  I have though about maybe having a
> cache flush routine that would take a virtual address and physical address
> and use a wired TLB entry to ensure a valid TLB entry.

yeah, the issue there is, if you've already got an active TLB entry
for that page, and you try to write the new tlb entry, doesn't that
make the machine (possibly) fall down go boom?  I suppose you could
probe first...  seems annoying.

if you passed virtual and physical, and did no more than a page at a
time, you could have a processor's/board's cache ops do whatever was
appropriate for that processor (i.e., pick virtual or physical
address, based on indexing type for each cache).  it looks like just
about every place which uses the cache ops either has both a pa and a
va (of some type) at hand...  hmm.  this maybe seems like a good idea.


>   I've also alway thought there should be some cache invalidate operations
> for those cases where you don't need the cache flushed to memory.

yeah, the pre-DMA ops could use this type of thing, certainly.



cgd