From cb48bd111b349dafceab40372ffe880babd1e427 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Sat, 17 Apr 2010 22:10:14 +0000 Subject: Work around yet another MC88110 errata, causing cache writebacks upon snooping to sometimes fail, by only using cache operation sequences known not to trigger the errata, at the expense of a small (barely noticeable) performance hit. This workaround is only enabled when compiling a MULTIPROCESSOR kernel, since the problem will not arise when using only one processor. This change, refined over a few months, finally makes GENERIC.MP run stably on 197DP systems. Of course, just writing this is enough to invoke Murphy's law and make it fail again in an even more obscure and rare way... --- sys/arch/mvme88k/mvme88k/m88110.c | 53 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'sys/arch/mvme88k') diff --git a/sys/arch/mvme88k/mvme88k/m88110.c b/sys/arch/mvme88k/mvme88k/m88110.c index deb4525c1e8..acc86352093 100644 --- a/sys/arch/mvme88k/mvme88k/m88110.c +++ b/sys/arch/mvme88k/mvme88k/m88110.c @@ -1,4 +1,4 @@ -/* $OpenBSD: m88110.c,v 1.63 2009/04/19 17:56:13 miod Exp $ */ +/* $OpenBSD: m88110.c,v 1.64 2010/04/17 22:10:13 miod Exp $ */ /* * Copyright (c) 1998 Steve Murphree, Jr. * All rights reserved. @@ -488,6 +488,30 @@ m88110_flush_tlb(cpuid_t cpu, u_int kernel, vaddr_t vaddr, u_int count) * will occur before we do, it is not necessary to pay attention to this. */ +#ifdef MULTIPROCESSOR +/* + * 88110 rev 4.2 errata #17: + * ``A copyback initiated by a flush page/line with invalidate command, + * which is retried on the external bus, and is preceded by a snoop + * copyback before the retry cycle occurs, can be incorrectly marked + * as invalid, and not copied back to memory. + * Suggested fix: Use flush page/line followed by flush page/line with + * invalidate to avoid this condition.'' + * + * This really only matters to us when running a MULTIPROCESSOR kernel + * (otherwise there is no snooping happening), and given the intrusive + * changes it requires (see the comment about invalidates being turned + * into flushes with invalidate in m88110_cmmu_inval_cache below), as + * well as the small performance impact it has), we define a specific + * symbol to enable the suggested workaround. + * + * Also, note that m88110_dma_cachectl() is never invoked when running on + * a multiprocessor system, therefore does not need to implement this + * workaround. + */ +#define ENABLE_88110_ERRATA_17 +#endif + #define trunc_cache_line(a) ((a) & ~(MC88110_CACHE_LINE - 1)) #define round_cache_line(a) trunc_cache_line((a) + MC88110_CACHE_LINE - 1) @@ -577,19 +601,28 @@ m88410_flush_inst_cache(cpuid_t cpu, paddr_t pa, psize_t size) void m88110_cmmu_sync_cache(paddr_t pa, psize_t size) { +#ifdef ENABLE_88110_ERRATA_17 + mc88110_flush_data_page(pa); +#else if (size <= MC88110_CACHE_LINE) mc88110_flush_data_line(pa); else mc88110_flush_data_page(pa); +#endif } void m88110_cmmu_sync_inval_cache(paddr_t pa, psize_t size) { +#ifdef ENABLE_88110_ERRATA_17 + mc88110_flush_data_page(pa); + mc88110_sync_data_page(pa); +#else if (size <= MC88110_CACHE_LINE) mc88110_sync_data_line(pa); else mc88110_sync_data_page(pa); +#endif } void @@ -678,7 +711,11 @@ m88410_dma_cachectl_local(paddr_t pa, psize_t size, int op) ext_flusher = mc88410_sync; break; default: +#ifdef ENABLE_88110_ERRATA_17 + flusher = m88110_cmmu_sync_inval_cache; +#else flusher = m88110_cmmu_inval_cache; +#endif #ifdef notyet ext_flusher = mc88410_inval; #else @@ -702,8 +739,12 @@ m88410_dma_cachectl_local(paddr_t pa, psize_t size, int op) } else { mc88110_inval_inst(); while (size != 0) { +#ifdef ENABLE_88110_ERRATA_17 + count = PAGE_SIZE; +#else count = (pa & PAGE_MASK) == 0 && size >= PAGE_SIZE ? PAGE_SIZE : MC88110_CACHE_LINE; +#endif (*flusher)(pa, count); @@ -724,6 +765,15 @@ m88410_dma_cachectl(paddr_t _pa, psize_t _size, int op) paddr_t pa; psize_t size; +#ifdef ENABLE_88110_ERRATA_17 + pa = trunc_page(_pa); + size = round_page(_pa + _size) - pa; + +#if 0 /* not required since m88410_dma_cachectl_local() behaves identically */ + if (op == DMA_CACHE_INV) + op = DMA_CACHE_SYNC_INVAL; +#endif +#else if (op == DMA_CACHE_SYNC) { pa = trunc_page(_pa); size = round_page(_pa + _size) - pa; @@ -736,6 +786,7 @@ m88410_dma_cachectl(paddr_t _pa, psize_t _size, int op) op = DMA_CACHE_SYNC_INVAL; } } +#endif m88410_dma_cachectl_local(pa, size, op); #ifdef MULTIPROCESSOR -- cgit v1.2.3