Skip to content

Commit

Permalink
MIPS: cache: optimise changing of k0 CCA mode
Browse files Browse the repository at this point in the history
Changing the Cache Coherency Algorithm (CCA) for kernel mode
requires executing from KSEG1. Thus do a jump from KSEG0 to KSEG1
before changing the CCA mode. Jump back to KSEG0 afterwards.

Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
  • Loading branch information
danielschwierzeck committed Sep 22, 2018
1 parent 2f85c2b commit b838586
Showing 1 changed file with 32 additions and 22 deletions.
54 changes: 32 additions & 22 deletions arch/mips/lib/cache_init.S
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
10:
.set pop
.endm

/*
* mips_cache_reset - low level initialisation of the primary caches
*
Expand Down Expand Up @@ -319,19 +320,21 @@ l1_init:
PTR_LI t0, INDEX_BASE
cache_loop t0, t1, R_IC_LINE, INDEX_STORE_TAG_I
#endif

/* Enable use of the I-cache by setting Config.K0 */
sync
mfc0 t0, CP0_CONFIG
li t1, CONFIG_SYS_MIPS_CACHE_MODE
#if __mips_isa_rev >= 2
ins t0, t1, 0, 3
#else
ori t0, t0, CONF_CM_CMASK
xori t0, t0, CONF_CM_CMASK

/*
* Enable use of the I-cache by setting Config.K0. The code for this
* must be executed from KSEG1. Jump from KSEG0 to KSEG1 to do this.
* Jump back to KSEG0 after caches are enabled and insert an
* instruction hazard barrier.
*/
PTR_LA t0, change_k0_cca
li t1, CPHYSADDR(~0)
and t0, t0, t1
PTR_LI t1, CKSEG1
or t0, t0, t1
#endif
mtc0 t0, CP0_CONFIG
li a0, CONFIG_SYS_MIPS_CACHE_MODE
jalr.hb t0

/*
* then initialize D-cache.
Expand Down Expand Up @@ -391,16 +394,9 @@ l2_unbypass:
beqz t0, 2f

/* Change Config.K0 to a coherent CCA */
mfc0 t0, CP0_CONFIG
li t1, CONF_CM_CACHABLE_COW
#if __mips_isa_rev >= 2
ins t0, t1, 0, 3
#else
ori t0, t0, CONF_CM_CMASK
xori t0, t0, CONF_CM_CMASK
or t0, t0, t1
#endif
mtc0 t0, CP0_CONFIG
PTR_LA t0, change_k0_cca
li a0, CONF_CM_CACHABLE_COW
jalr t0

/*
* Join the coherent domain such that the caches of this core are kept
Expand All @@ -421,5 +417,19 @@ l2_unbypass:
return:
/* Ensure all cache operations complete before returning */
sync
jr ra
jr R_RETURN
END(mips_cache_reset)

This comment has been minimized.

Copy link
@ddqxy138

ddqxy138 Oct 27, 2023

when __mips_isa_rev >= 2
mfc0 t0, CP0_CONFIG
ins t0, a0, 0, 3 <<----------- what this instruction do??
mtc0 a0, CP0_CONFIG

This comment has been minimized.

Copy link
@trini

trini Oct 27, 2023

Contributor

Can you please elaborate on your question? Someone could give the literal answer of what that opcode does, but presumably that's not what you're after. Is there some use case you're having showing a problem in this case? Something else? Thanks.

This comment has been minimized.

Copy link
@ddqxy138

ddqxy138 Oct 28, 2023

I haven't encountered any problems. I am only a bit confused when reading the source code.

mfc0 t0, CP0_CONFIG # get cp0_config
ins t0, a0, 0, 3 # insert value of $a0 to $t0 lower 3 bits. Here $t0 be changed, not $a0, right?
mtc0 a0, CP0_CONFIG # why write $a0 value back to cp0_config, not $t0 ?

Is there a mistake in my understanding?

This comment has been minimized.

Copy link
@trini

trini Oct 28, 2023

Contributor

Thanks for elaborating. @danielschwierzeck any comments?

This comment has been minimized.

Copy link
@danielschwierzeck

danielschwierzeck Oct 30, 2023

Author Contributor

@ddqxy138 the INS instruction is encoded as INS rt, rs, pos, size. In change_k0_cca the a0 shall actually be the target register whereas t0 shall be the source register. Thus the patch was incorrect, correct line must be ins a0, t0, 0, 3. Thanks for spotting. Can you send a patch or shall I prepare one?

This comment has been minimized.

Copy link
@danielschwierzeck

danielschwierzeck Nov 6, 2023

Author Contributor

@ddqxy138 I checked again with Qemu and GDB. The INS instruction is correct but the mtc0 a0, CP0_CONFIG is wrong because the modified value of t0 (which holds the CP0_CONFIG register value) is also stored in t0. Thus we have to write back t0 to CP0_CONFIG. But if I fix the mtc0 line, I also need to fix the xor instruction one line above to also store the value in t0 in the legacy code path.

Thus the correct code should be:

LEAF(change_k0_cca)
	mfc0		t0, CP0_CONFIG
#if __mips_isa_rev >= 2
	ins		t0, a0, 0, 3
#else
	xor		a0, a0, t0
	andi		a0, a0, CONF_CM_CMASK
	xor		t0, a0, t0
#endif
	mtc0		t0, CP0_CONFIG

	jr.hb		ra
	END(change_k0_cca)

PS: the intention of the code is this:

u32 t0 = read_c0_config();
t0 &= !CONF_CM_MASK;
t0 |= a0;
write_c0_config(t0);
LEAF(change_k0_cca)
mfc0 t0, CP0_CONFIG
#if __mips_isa_rev >= 2
ins t0, a0, 0, 3
#else
xor a0, a0, t0
andi a0, a0, CONF_CM_CMASK
xor a0, a0, t0
#endif
mtc0 a0, CP0_CONFIG

jr.hb ra
END(change_k0_cca)

0 comments on commit b838586

Please sign in to comment.