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):