Subject: Re: sh4 pmap bug? (Re: port-dreamcast/34243)
To: None <port-sh3@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-sh3
Date: 09/23/2006 02:59:02
I wrote:

> Well, Chuck Silvers pointed out we should also have PMAP_PREFER()
> for SH4 to avoid some possible aliases.
> (I thought we already had it)

Here is a new one (just taken from mips).
---
Izumi Tsutsui


Index: sys/arch/sh3/include/cache.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/include/cache.h,v
retrieving revision 1.7
diff -u -r1.7 cache.h
--- sys/arch/sh3/include/cache.h	21 Jan 2006 00:46:36 -0000	1.7
+++ sys/arch/sh3/include/cache.h	22 Sep 2006 17:57:12 -0000
@@ -156,6 +156,10 @@
 extern int sh_cache_index_mode_icache;
 extern int sh_cache_index_mode_dcache;
 
+extern int sh_cache_alias_mask;
+#define	sh_cache_indexof(x)	(sh_cache_alias_mask & (x))
+extern int sh_cache_prefer_mask;
+
 extern struct sh_cache_ops sh_cache_ops;
 
 #define	sh_icache_sync_all()						\
Index: sys/arch/sh3/include/pmap.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/include/pmap.h,v
retrieving revision 1.28
diff -u -r1.28 pmap.h
--- sys/arch/sh3/include/pmap.h	10 Apr 2006 23:12:11 -0000	1.28
+++ sys/arch/sh3/include/pmap.h	22 Sep 2006 17:57:12 -0000
@@ -77,6 +77,15 @@
 	/* Nothing. */
 }
 
+/*
+ * pmap_prefer() helps to avoid virtual cache aliases on SH4 CPUs
+ * which have the virtually-indexed cache.
+ */
+#ifdef SH4
+#define PMAP_PREFER(pa, va, sz, td)     pmap_prefer((pa), (va))
+void pmap_prefer(vaddr_t, vaddr_t *);
+#endif /* SH4 */
+
 #define	PMAP_MAP_POOLPAGE(pa)		SH3_PHYS_TO_P1SEG((pa))
 #define	PMAP_UNMAP_POOLPAGE(va)		SH3_P1SEG_TO_PHYS((va))
 
Index: sys/arch/sh3/sh3/cache.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/sh3/cache.c,v
retrieving revision 1.11
diff -u -r1.11 cache.c
--- sys/arch/sh3/sh3/cache.c	2 Jan 2006 23:37:34 -0000	1.11
+++ sys/arch/sh3/sh3/cache.c	22 Sep 2006 17:57:12 -0000
@@ -77,6 +77,8 @@
 int sh_cache_ram_mode;
 int sh_cache_index_mode_icache;
 int sh_cache_index_mode_dcache;
+int sh_cache_alias_mask;
+int sh_cache_prefer_mask;
 
 void
 sh_cache_init()
Index: sys/arch/sh3/sh3/cache_sh4.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/sh3/cache_sh4.c,v
retrieving revision 1.15
diff -u -r1.15 cache_sh4.c
--- sys/arch/sh3/sh3/cache_sh4.c	24 Dec 2005 23:24:02 -0000	1.15
+++ sys/arch/sh3/sh3/cache_sh4.c	22 Sep 2006 17:57:13 -0000
@@ -44,6 +44,7 @@
 
 #include <sh3/cache.h>
 #include <sh3/cache_sh4.h>
+#include <sh3/vmparam.h>
 
 #define	round_line(x)		(((x) + 31) & ~31)
 #define	trunc_line(x)		((x) & ~31)
@@ -134,6 +135,8 @@
 	sh_cache_enable_dcache = (r & SH4_CCR_OCE);
 	sh_cache_ways = ways;
 	sh_cache_line_size = SH4_CACHE_LINESZ;
+	sh_cache_alias_mask = (dcache_size / ways - 1) & ~PAGE_MASK;
+	sh_cache_prefer_mask = (dcache_size / ways - 1);
 	sh_cache_write_through_p0_u0_p3 = (r & SH4_CCR_WT);
 	sh_cache_write_through_p1 = !(r & SH4_CCR_CB);
 	sh_cache_write_through = sh_cache_write_through_p0_u0_p3 &&
Index: sys/arch/sh3/sh3/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/sh3/pmap.c,v
retrieving revision 1.55
diff -u -r1.55 pmap.c
--- sys/arch/sh3/sh3/pmap.c	7 Aug 2006 23:19:36 -0000	1.55
+++ sys/arch/sh3/sh3/pmap.c	22 Sep 2006 17:57:13 -0000
@@ -456,11 +456,24 @@
 
 	s = splvm();
 	if (SH_HAS_VIRTUAL_ALIAS) {
-		/* Remove all other mapping on this physical page */
+		/*
+		 * Remove all other mappings on this physical page
+		 * which have different virtual cache indexes to
+		 * avoid virtual cache aliases.
+		 *
+		 * XXX We should also handle shared mappings which
+		 * XXX have different virtual cache indexes by
+		 * XXX mapping them uncached (like arm and mips do).
+		 */
+ again:
 		pvh = &pg->mdpage;
-		while ((pv = SLIST_FIRST(&pvh->pvh_head)) != NULL) {
-			pmap_remove(pv->pv_pmap, pv->pv_va,
-			    pv->pv_va + PAGE_SIZE);
+		SLIST_FOREACH(pv, &pvh->pvh_head, pv_link) {
+			if (sh_cache_indexof(va) !=
+			    sh_cache_indexof(pv->pv_va)) {
+				pmap_remove(pv->pv_pmap, pv->pv_va,
+				    pv->pv_va + PAGE_SIZE);
+				goto again;
+			}
 		}
 	}
 
@@ -859,6 +872,26 @@
 	return (sh3_ptob(cookie));
 }
 
+#ifdef SH4
+/*
+ * pmap_prefer(vaddr_t foff, vaddr_t *vap)
+ *
+ * Find first virtual address >= *vap that doesn't cause
+ * a virtual cache alias against vaddr_t foff.
+ */
+void
+pmap_prefer(vaddr_t foff, vaddr_t *vap)
+{
+	vaddr_t va;
+
+	if (CPU_IS_SH4) {
+		va = *vap;
+
+		*vap = va + ((foff - va) & sh_cache_prefer_mask);
+	}
+}
+#endif /* SH4 */
+
 /*
  * pv_entry pool allocator:
  *	void *__pmap_pv_page_alloc(struct pool *pool, int flags):