mirror of
https://github.com/revyos/th1520-vendor-uboot.git
synced 2026-06-21 09:02:25 +02:00
fix(c9xx): don't flush dcache when invalidating
The data cache invalidation function for c9xx CPUs uses `dcache.cipa`
instruction. According to T-Head extension specification[1] section
3.1.5, this instruction also performs a cache clean along with the
invalidation.
On top of being incorrect, this leads to a serious issue on the
designware ethernet driver, where stalled cache may get flushed each
time we handle a new received packet[2]. As a result, received packet
are randomly corrupted with old cached data. This can easily be
reproduced by sending an ARP request to the device during a TFTP
transfer. The last TFTP block is treated as the ARP reply we just sent,
which makes U-Boot hang on the block.
Always use `dcache.ipa` instruction to invalidate dcache. Replace
existing usages of `dcache.ipa` with our implementation.
Note that this fix is slightly intrusive as it changes the cache
invalidation behavior in all drivers. However, I have not noticed any
side-effect during my tests.
[1] https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.3.0/xthead-2023-11-10-2.3.0.pdf
[2] 918a8c89e0/drivers/net/designware.c (L475)
This commit is contained in:
committed by
Han Gao/Revy/Rabenda
parent
7632089652
commit
adec30ace4
@@ -104,16 +104,6 @@ void invalidate_dcache_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
register unsigned long i asm("a0") = start & ~(CONFIG_SYS_CACHELINE_SIZE - 1);
|
||||
|
||||
for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
|
||||
asm volatile(".long 0x02b5000b"); /* dcache.cipa a0 */
|
||||
|
||||
sync_is();
|
||||
}
|
||||
|
||||
void invalid_dcache_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
register unsigned long i asm("a0") = start & ~(CONFIG_SYS_CACHELINE_SIZE - 1);
|
||||
|
||||
for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
|
||||
asm volatile(".long 0x02a5000b"); /* dcache.ipa a0 */
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ extern ulong mem_test_quick(vu_long *buf, ulong start_addr, ulong end_addr,
|
||||
#endif
|
||||
extern void flush_dcache_range(unsigned long start, unsigned long end);
|
||||
extern void invalidate_dcache_range(unsigned long start, unsigned long end);
|
||||
extern void invalid_dcache_range(unsigned long start, unsigned long end);
|
||||
|
||||
#ifdef CONFIG_CMD_MEMTEST
|
||||
int test_stuck_address(ulv *bufa, ulong count);
|
||||
|
||||
@@ -50,7 +50,6 @@ u64 t_end;
|
||||
|
||||
extern void flush_dcache_range(unsigned long start, unsigned long end);
|
||||
extern void invalidate_dcache_range(unsigned long start, unsigned long end);
|
||||
extern void invalid_dcache_range(unsigned long start, unsigned long end);
|
||||
|
||||
extern unsigned long get_ddr_density(void);
|
||||
extern int riscv_get_time(u64 *time);
|
||||
@@ -305,7 +304,7 @@ int prbs_test(struct PRBS_ELE *prbs, unsigned int *buf, int pos, bool random_dq,
|
||||
// compare result
|
||||
// invalid cache before read
|
||||
mdelay(100);
|
||||
invalid_dcache_range((ulong)buf, (ulong)buf+(bit_len*4*2*2));
|
||||
invalidate_dcache_range((ulong)buf, (ulong)buf+(bit_len*4*2*2));
|
||||
p1 = buf;
|
||||
bit_cnt = 0;
|
||||
for (i = 0; i < bit_len; i++) {
|
||||
|
||||
@@ -247,10 +247,9 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
|
||||
}
|
||||
} while (!(stat & SDHCI_INT_DATA_END));
|
||||
#ifdef CONFIG_TARGET_LIGHT_C910
|
||||
extern void invalid_dcache_range(unsigned long start, unsigned long end);
|
||||
/*After read ,invalid dcache range again to avoid cache filled during read tranfer*/
|
||||
if(data->flags == MMC_DATA_READ){
|
||||
invalid_dcache_range(host->start_addr,host->start_addr+ROUND(data->blocks*data->blocksize, ARCH_DMA_MINALIGN));
|
||||
invalidate_dcache_range(host->start_addr,host->start_addr+ROUND(data->blocks*data->blocksize, ARCH_DMA_MINALIGN));
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@@ -906,8 +906,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
|
||||
dep->resource_index = 0;
|
||||
dwc->setup_packet_pending = false;
|
||||
#ifdef CONFIG_TARGET_LIGHT_C910
|
||||
extern void invalid_dcache_range(unsigned long start, unsigned long end);
|
||||
invalid_dcache_range((unsigned long)dwc->ctrl_req, (dmaaddr_t)dwc->ctrl_req + ROUND(sizeof(*dwc->ctrl_req), CACHELINE_SIZE));
|
||||
invalidate_dcache_range((unsigned long)dwc->ctrl_req, (dmaaddr_t)dwc->ctrl_req + ROUND(sizeof(*dwc->ctrl_req), CACHELINE_SIZE));
|
||||
#endif
|
||||
|
||||
switch (dwc->ep0state) {
|
||||
|
||||
Reference in New Issue
Block a user