summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/mvme88k/mvme88k/m88110.c53
1 files changed, 52 insertions, 1 deletions
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