summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/sparc64/sparc64/pmap.c118
1 files changed, 95 insertions, 23 deletions
diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c
index eea5931..2a31f6b 100644
--- a/sys/sparc64/sparc64/pmap.c
+++ b/sys/sparc64/sparc64/pmap.c
@@ -179,7 +179,13 @@ static long pmap_enter_nupdate;
static long pmap_enter_nreplace;
static long pmap_enter_nnew;
static long pmap_ncache_enter;
+static long pmap_ncache_enter_c;
+static long pmap_ncache_enter_cc;
static long pmap_ncache_enter_nc;
+static long pmap_ncache_remove;
+static long pmap_ncache_remove_c;
+static long pmap_ncache_remove_cc;
+static long pmap_ncache_remove_nc;
static long pmap_niflush;
SYSCTL_NODE(_debug, OID_AUTO, pmap_stats, CTLFLAG_RD, 0, "Statistics");
@@ -191,8 +197,20 @@ SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_enter_nnew, CTLFLAG_RD,
&pmap_enter_nnew, 0, "Number of pmap_enter() additions");
SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_enter, CTLFLAG_RD,
&pmap_ncache_enter, 0, "Number of pmap_cache_enter() calls");
+SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_enter_c, CTLFLAG_RD,
+ &pmap_ncache_enter_c, 0, "Number of pmap_cache_enter() cacheable");
+SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_enter_cc, CTLFLAG_RD,
+ &pmap_ncache_enter_cc, 0, "Number of pmap_cache_enter() change color");
SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_enter_nc, CTLFLAG_RD,
- &pmap_ncache_enter_nc, 0, "Number of pmap_cache_enter() nc");
+ &pmap_ncache_enter_nc, 0, "Number of pmap_cache_enter() noncacheable");
+SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_remove, CTLFLAG_RD,
+ &pmap_ncache_remove, 0, "Number of pmap_cache_remove() calls");
+SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_remove_c, CTLFLAG_RD,
+ &pmap_ncache_remove_c, 0, "Number of pmap_cache_remove() cacheable");
+SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_remove_cc, CTLFLAG_RD,
+ &pmap_ncache_remove_cc, 0, "Number of pmap_cache_remove() change color");
+SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_ncache_remove_nc, CTLFLAG_RD,
+ &pmap_ncache_remove_nc, 0, "Number of pmap_cache_remove() noncacheable");
SYSCTL_LONG(_debug_pmap_stats, OID_AUTO, pmap_niflush, CTLFLAG_RD,
&pmap_niflush, 0, "Number of pmap I$ flushes");
@@ -585,32 +603,53 @@ pmap_cache_enter(vm_page_t m, vm_offset_t va)
{
struct tte *tp;
int color;
- int c, i;
- CTR2(KTR_PMAP, "pmap_cache_enter: m=%p va=%#lx", m, va);
PMAP_STATS_INC(pmap_ncache_enter);
+
+ /*
+ * Find the color for this virtual address and note the added mapping.
+ */
color = DCACHE_COLOR(va);
m->md.colors[color]++;
+
+ /*
+ * If all existing mappings have the same color, the mapping is
+ * cacheable.
+ */
if (m->md.color == color) {
- CTR0(KTR_PMAP, "pmap_cache_enter: cacheable");
+ KASSERT(m->md.colors[DCACHE_OTHER_COLOR(color)] == 0,
+ ("pmap_cache_enter: cacheable, mappings of other color"));
+ PMAP_STATS_INC(pmap_ncache_enter_c);
return (1);
}
- for (c = 0, i = 0; i < DCACHE_COLORS; i++) {
- if (m->md.colors[i] != 0)
- c++;
- }
- if (c == 1) {
+
+ /*
+ * If there are no mappings of the other color, and the page still has
+ * the wrong color, this must be a new mapping. Change the color to
+ * match the new mapping, which is cacheable. We must flush the page
+ * from the cache now.
+ */
+ if (m->md.colors[DCACHE_OTHER_COLOR(color)] == 0) {
+ KASSERT(m->md.colors[color] == 1,
+ ("pmap_cache_enter: changing color, not new mapping"));
dcache_page_inval(VM_PAGE_TO_PHYS(m));
m->md.color = color;
- CTR0(KTR_PMAP, "pmap_cache_enter: cacheable");
+ PMAP_STATS_INC(pmap_ncache_enter_cc);
return (1);
}
+
PMAP_STATS_INC(pmap_ncache_enter_nc);
- if (m->md.color == -1) {
- CTR0(KTR_PMAP, "pmap_cache_enter: already uncacheable");
+
+ /*
+ * If the mapping is already non-cacheable, just return.
+ */
+ if (m->md.color == -1)
return (0);
- }
- CTR0(KTR_PMAP, "pmap_cache_enter: marking uncacheable");
+
+ /*
+ * Mark all mappings as uncacheable, flush any lines with the other
+ * color out of the dcache, and set the color to none (-1).
+ */
STAILQ_FOREACH(tp, &m->md.tte_list, tte_link) {
tp->tte_data &= ~TD_CV;
tlb_page_demap(TTE_GET_PMAP(tp), TTE_GET_VA(tp));
@@ -625,28 +664,56 @@ pmap_cache_remove(vm_page_t m, vm_offset_t va)
{
struct tte *tp;
int color;
- int c, i;
CTR3(KTR_PMAP, "pmap_cache_remove: m=%p va=%#lx c=%d", m, va,
m->md.colors[DCACHE_COLOR(va)]);
KASSERT(m->md.colors[DCACHE_COLOR(va)] > 0,
("pmap_cache_remove: no mappings %d <= 0",
m->md.colors[DCACHE_COLOR(va)]));
+ PMAP_STATS_INC(pmap_ncache_remove);
+
+ /*
+ * Find the color for this virtual address and note the removal of
+ * the mapping.
+ */
color = DCACHE_COLOR(va);
m->md.colors[color]--;
- if (m->md.color != -1 || m->md.colors[color] != 0)
+
+ /*
+ * If the page is cacheable, just return and keep the same color, even
+ * if there are no longer any mappings.
+ */
+ if (m->md.color != -1) {
+ PMAP_STATS_INC(pmap_ncache_remove_c);
return;
- for (c = 0, i = 0; i < DCACHE_COLORS; i++) {
- if (m->md.colors[i] != 0)
- c++;
}
- if (c == 0)
+
+ KASSERT(m->md.colors[DCACHE_OTHER_COLOR(color)] != 0,
+ ("pmap_cache_remove: uncacheable, no mappings of other color"));
+
+ /*
+ * If the page is not cacheable (color is -1), and the number of
+ * mappings for this color is not zero, just return. There are
+ * mappings of the other color still, so remain non-cacheable.
+ */
+ if (m->md.colors[color] != 0) {
+ PMAP_STATS_INC(pmap_ncache_remove_nc);
return;
+ }
+
+ PMAP_STATS_INC(pmap_ncache_remove_cc);
+
+ /*
+ * The number of mappings for this color is now zero. Recache the
+ * other colored mappings, and change the page color to the other
+ * color. There should be no lines in the data cache for this page,
+ * so flushing should not be needed.
+ */
STAILQ_FOREACH(tp, &m->md.tte_list, tte_link) {
tp->tte_data |= TD_CV;
tlb_page_demap(TTE_GET_PMAP(tp), TTE_GET_VA(tp));
}
- m->md.color = color;
+ m->md.color = DCACHE_OTHER_COLOR(color);
}
/*
@@ -782,11 +849,16 @@ pmap_map_direct(vm_page_t m)
vm_offset_t va;
pa = VM_PAGE_TO_PHYS(m);
- if (m->md.color == -1)
+ if (m->md.color == -1) {
+ KASSERT(m->md.colors[0] != 0 && m->md.colors[1] != 0,
+ ("pmap_map_direct: non-cacheable, only 1 color"));
va = TLB_DIRECT_MASK | pa | TLB_DIRECT_UNCACHEABLE;
- else
+ } else {
+ KASSERT(m->md.colors[DCACHE_OTHER_COLOR(m->md.color)] == 0,
+ ("pmap_map_direct: cacheable, mappings of other color"));
va = TLB_DIRECT_MASK | pa |
(m->md.color << TLB_DIRECT_COLOR_SHIFT);
+ }
return (va << TLB_DIRECT_SHIFT);
}
OpenPOWER on IntegriCloud