summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4v/cpu/niagara2.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/sun4v/cpu/niagara2.c')
-rw-r--r--usr/src/uts/sun4v/cpu/niagara2.c284
1 files changed, 232 insertions, 52 deletions
diff --git a/usr/src/uts/sun4v/cpu/niagara2.c b/usr/src/uts/sun4v/cpu/niagara2.c
index e791361578..e77b2ef3b4 100644
--- a/usr/src/uts/sun4v/cpu/niagara2.c
+++ b/usr/src/uts/sun4v/cpu/niagara2.c
@@ -198,9 +198,9 @@ cpu_map_exec_units(struct cpu *cp)
* share the same L2 cache. If no such info is available, we
* set the cpu to belong to the defacto chip 0.
*/
- cp->cpu_m.cpu_chip = cpunodes[cp->cpu_id].l2_cache_mapping;
- if (cp->cpu_m.cpu_chip == NO_CHIP_MAPPING_FOUND)
- cp->cpu_m.cpu_chip = 0;
+ cp->cpu_m.cpu_mpipe = cpunodes[cp->cpu_id].l2_cache_mapping;
+ if (cp->cpu_m.cpu_mpipe == NO_L2_CACHE_MAPPING_FOUND)
+ cp->cpu_m.cpu_mpipe = CPU_L2_CACHEID_INVALID;
}
static int cpucnt;
@@ -283,22 +283,112 @@ cpu_trapstat_data(void *buf, uint_t tstat_pgszs)
}
}
+/*
+ * Page coloring support for hashed cache index mode
+ */
+
+/*
+ * Node id bits from machine description (MD). Node id distinguishes
+ * local versus remote memory. Because of MPO, page allocation does
+ * not cross node boundaries. Therefore, remove the node id bits from
+ * the color, since they are fixed. Either bit 30, or 31:30 in
+ * Victoria Falls processors.
+ * The number of node id bits is always 0 in Niagara2.
+ */
+typedef struct n2color {
+ uchar_t nnbits; /* number of node id bits */
+ uchar_t nnmask; /* mask for node id bits */
+ uchar_t lomask; /* mask for bits below node id */
+ uchar_t lobits; /* number of bits below node id */
+} n2color_t;
+
+n2color_t n2color[MMU_PAGE_SIZES];
+static uchar_t nhbits[] = {7, 7, 6, 5, 5, 5};
+
+/*
+ * Remove node id bits from color bits 32:28.
+ * This will reduce the number of colors.
+ * No change if number of node bits is zero.
+ */
+static inline uint_t
+n2_hash2color(uint_t color, uchar_t szc)
+{
+ n2color_t m = n2color[szc];
+
+ if (m.nnbits > 0) {
+ color = ((color >> m.nnbits) & ~m.lomask) | (color & m.lomask);
+ ASSERT((color & ~(hw_page_array[szc].hp_colors - 1)) == 0);
+ }
+
+ return (color);
+}
+
+/*
+ * Restore node id bits into page color.
+ * This will increase the number of colors to match N2.
+ * No change if number of node bits is zero.
+ */
+static inline uint_t
+n2_color2hash(uint_t color, uchar_t szc, uint_t node)
+{
+ n2color_t m = n2color[szc];
+
+ if (m.nnbits > 0) {
+ color = ((color & ~m.lomask) << m.nnbits) | (color & m.lomask);
+ color |= (node & m.nnmask) << m.lobits;
+ }
+
+ return (color);
+}
+
/* NI2 L2$ index is pa[32:28]^pa[17:13].pa[19:18]^pa[12:11].pa[10:6] */
+
+/*
+ * iterator NULL means pfn is VA, do not adjust ra_to_pa
+ * iterator (-1) means pfn is RA, need to convert to PA
+ * iterator non-null means pfn is RA, use ra_to_pa
+ */
uint_t
-page_pfn_2_color_cpu(pfn_t pfn, uchar_t szc)
+page_pfn_2_color_cpu(pfn_t pfn, uchar_t szc, void *cookie)
{
+ mem_node_iterator_t *it = cookie;
uint_t color;
ASSERT(szc <= TTE256M);
+ if (it == ((mem_node_iterator_t *)(-1))) {
+ pfn = plat_rapfn_to_papfn(pfn);
+ } else if (it != NULL) {
+ ASSERT(pfn >= it->mi_mblock_base && pfn <= it->mi_mblock_end);
+ pfn = pfn + it->mi_ra_to_pa;
+ }
pfn = PFN_BASE(pfn, szc);
color = ((pfn >> 15) ^ pfn) & 0x1f;
- if (szc >= TTE4M)
- return (color);
+ if (szc < TTE4M) {
+ /* 19:18 */
+ color = (color << 2) | ((pfn >> 5) & 0x3);
+ if (szc > TTE64K)
+ color >>= 1; /* 19 */
+ }
+ return (n2_hash2color(color, szc));
+}
- color = (color << 2) | ((pfn >> 5) & 0x3);
+static uint_t
+page_papfn_2_color_cpu(pfn_t papfn, uchar_t szc)
+{
+ uint_t color;
+
+ ASSERT(szc <= TTE256M);
- return (szc <= TTE64K ? color : (color >> 1));
+ papfn = PFN_BASE(papfn, szc);
+ color = ((papfn >> 15) ^ papfn) & 0x1f;
+ if (szc < TTE4M) {
+ /* 19:18 */
+ color = (color << 2) | ((papfn >> 5) & 0x3);
+ if (szc > TTE64K)
+ color >>= 1; /* 19 */
+ }
+ return (color);
}
#if TTE256M != 5
@@ -310,46 +400,91 @@ page_get_nsz_color_mask_cpu(uchar_t szc, uint_t mask)
{
static uint_t ni2_color_masks[5] = {0x63, 0x1e, 0x3e, 0x1f, 0x1f};
ASSERT(szc < TTE256M);
-
+ mask = n2_color2hash(mask, szc, 0);
mask &= ni2_color_masks[szc];
- return ((szc == TTE64K || szc == TTE512K) ? (mask >> 1) : mask);
+ if (szc == TTE64K || szc == TTE512K)
+ mask >>= 1;
+ return (n2_hash2color(mask, szc + 1));
}
uint_t
page_get_nsz_color_cpu(uchar_t szc, uint_t color)
{
ASSERT(szc < TTE256M);
- return ((szc == TTE64K || szc == TTE512K) ? (color >> 1) : color);
+ color = n2_color2hash(color, szc, 0);
+ if (szc == TTE64K || szc == TTE512K)
+ color >>= 1;
+ return (n2_hash2color(color, szc + 1));
}
uint_t
page_get_color_shift_cpu(uchar_t szc, uchar_t nszc)
{
+ uint_t s;
ASSERT(nszc >= szc);
ASSERT(nszc <= TTE256M);
- if (szc == nszc)
- return (0);
- if (szc <= TTE64K)
- return ((nszc >= TTE4M) ? 2 : ((nszc >= TTE512K) ? 1 : 0));
- if (szc == TTE512K)
- return (1);
+ s = nhbits[szc] - n2color[szc].nnbits;
+ s -= nhbits[nszc] - n2color[nszc].nnbits;
- return (0);
+ return (s);
+}
+
+uint_t
+page_convert_color_cpu(uint_t ncolor, uchar_t szc, uchar_t nszc)
+{
+ uint_t color;
+
+ ASSERT(nszc > szc);
+ ASSERT(nszc <= TTE256M);
+ ncolor = n2_color2hash(ncolor, nszc, 0);
+ color = ncolor << (nhbits[szc] - nhbits[nszc]);
+ color = n2_hash2color(color, szc);
+ return (color);
}
+#define PAPFN_2_MNODE(pfn) \
+ (((pfn) & it->mi_mnode_pfn_mask) >> it->mi_mnode_pfn_shift)
+
/*ARGSUSED*/
pfn_t
page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color,
- uint_t ceq_mask, uint_t color_mask)
+ uint_t ceq_mask, uint_t color_mask, void *cookie)
{
+ mem_node_iterator_t *it = cookie;
pfn_t pstep = PNUM_SIZE(szc);
pfn_t npfn, pfn_ceq_mask, pfn_color;
pfn_t tmpmask, mask = (pfn_t)-1;
+ uint_t pfnmn;
ASSERT((color & ~ceq_mask) == 0);
-
- if (((page_pfn_2_color_cpu(pfn, szc) ^ color) & ceq_mask) == 0) {
+ ASSERT(pfn >= it->mi_mblock_base && pfn <= it->mi_mblock_end);
+
+ /* convert RA to PA for accurate color calculation */
+ if (it->mi_init) {
+ /* first call after it, so cache these values */
+ it->mi_hash_ceq_mask =
+ n2_color2hash(ceq_mask, szc, it->mi_mnode_mask);
+ it->mi_hash_color =
+ n2_color2hash(color, szc, it->mi_mnode);
+ it->mi_init = 0;
+ } else {
+ ASSERT(it->mi_hash_ceq_mask ==
+ n2_color2hash(ceq_mask, szc, it->mi_mnode_mask));
+ ASSERT(it->mi_hash_color ==
+ n2_color2hash(color, szc, it->mi_mnode));
+ }
+ ceq_mask = it->mi_hash_ceq_mask;
+ color = it->mi_hash_color;
+ pfn += it->mi_ra_to_pa;
+
+ /* restart here when we switch memblocks */
+next_mem_block:
+ if (szc <= TTE64K) {
+ pfnmn = PAPFN_2_MNODE(pfn);
+ }
+ if (((page_papfn_2_color_cpu(pfn, szc) ^ color) & ceq_mask) == 0 &&
+ (szc > TTE64K || pfnmn == it->mi_mnode)) {
/* we start from the page with correct color */
if (szc >= TTE512K) {
@@ -361,18 +496,19 @@ page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color,
pfn_ceq_mask = ((ceq_mask & 1) << 6) |
((ceq_mask >> 1) << 15);
}
- pfn = ADD_MASKED(pfn, pstep, pfn_ceq_mask, mask);
- return (pfn);
+ npfn = ADD_MASKED(pfn, pstep, pfn_ceq_mask, mask);
+ goto done;
} else {
/*
* We deal 64K or 8K page. Check if we could the
* satisfy the request without changing PA[32:28]
*/
pfn_ceq_mask = ((ceq_mask & 3) << 5) | (ceq_mask >> 2);
+ pfn_ceq_mask |= it->mi_mnode_pfn_mask;
npfn = ADD_MASKED(pfn, pstep, pfn_ceq_mask, mask);
if ((((npfn ^ pfn) >> 15) & 0x1f) == 0)
- return (npfn);
+ goto done;
/*
* for next pfn we have to change bits PA[32:28]
@@ -382,15 +518,14 @@ page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color,
npfn |= (ceq_mask & color & 3) << 5;
pfn_ceq_mask = (szc == TTE8K) ? 0 :
(ceq_mask & 0x1c) << 13;
+ pfn_ceq_mask |= it->mi_mnode_pfn_mask;
npfn = ADD_MASKED(npfn, (1 << 15), pfn_ceq_mask, mask);
/*
* set bits PA[17:13] to match the color
*/
- ceq_mask >>= 2;
- color = (color >> 2) & ceq_mask;
- npfn |= ((npfn >> 15) ^ color) & ceq_mask;
- return (npfn);
+ npfn |= ((npfn >> 15) ^ (color >> 2)) & (ceq_mask >> 2);
+ goto done;
}
}
@@ -405,9 +540,9 @@ page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color,
} else {
/* try get the right color by changing bit PA[19:19] */
npfn = pfn + pstep;
- if (((page_pfn_2_color_cpu(npfn, szc) ^ color) &
+ if (((page_papfn_2_color_cpu(npfn, szc) ^ color) &
ceq_mask) == 0)
- return (npfn);
+ goto done;
/* page color is PA[32:28].PA[19:19] */
pfn_ceq_mask = ((ceq_mask & 1) << 6) |
@@ -419,34 +554,45 @@ page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color,
while (npfn <= pfn) {
npfn = ADD_MASKED(npfn, pstep, pfn_ceq_mask, mask);
}
- return (npfn);
+ goto done;
}
/*
- * We deal 64K or 8K page of incorrect color.
+ * We deal 64K or 8K page of incorrect color.
* Try correcting color without changing PA[32:28]
*/
-
pfn_ceq_mask = ((ceq_mask & 3) << 5) | (ceq_mask >> 2);
pfn_color = ((color & 3) << 5) | (color >> 2);
- npfn = (pfn & ~(pfn_t)0x7f);
- npfn |= (((pfn >> 15) & 0x1f) ^ pfn_color) & pfn_ceq_mask;
- npfn = (szc == TTE64K) ? (npfn & ~(pfn_t)0x7) : npfn;
-
- if (((page_pfn_2_color_cpu(npfn, szc) ^ color) & ceq_mask) == 0) {
-
- /* the color is fixed - find the next page */
- while (npfn <= pfn) {
- npfn = ADD_MASKED(npfn, pstep, pfn_ceq_mask, mask);
+ if (pfnmn == it->mi_mnode) {
+ npfn = (pfn & ~(pfn_t)0x7f);
+ npfn |= (((pfn >> 15) & 0x1f) ^ pfn_color) & pfn_ceq_mask;
+ npfn = (szc == TTE64K) ? (npfn & ~(pfn_t)0x7) : npfn;
+
+ if (((page_papfn_2_color_cpu(npfn, szc) ^ color) &
+ ceq_mask) == 0) {
+ /* the color is fixed - find the next page */
+ pfn_ceq_mask |= it->mi_mnode_pfn_mask;
+ while (npfn <= pfn) {
+ npfn = ADD_MASKED(npfn, pstep, pfn_ceq_mask,
+ mask);
+ }
+ if ((((npfn ^ pfn) >> 15) & 0x1f) == 0)
+ goto done;
}
- if ((((npfn ^ pfn) >> 15) & 0x1f) == 0)
- return (npfn);
}
/* to fix the color need to touch PA[32:28] */
npfn = (szc == TTE8K) ? ((pfn >> 15) << 15) :
(((pfn >> 18) << 18) | ((color & 0x1c) << 13));
+
+ /* fix mnode if input pfn is in the wrong mnode. */
+ if ((pfnmn = PAPFN_2_MNODE(npfn)) != it->mi_mnode) {
+ npfn += ((it->mi_mnode - pfnmn) & it->mi_mnode_mask) <<
+ it->mi_mnode_pfn_shift;
+ }
+
tmpmask = (szc == TTE8K) ? 0 : (ceq_mask & 0x1c) << 13;
+ tmpmask |= it->mi_mnode_pfn_mask;
while (npfn <= pfn) {
npfn = ADD_MASKED(npfn, (1 << 15), tmpmask, mask);
@@ -456,25 +602,58 @@ page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color,
npfn |= (((npfn >> 15) & 0x1f) ^ pfn_color) & pfn_ceq_mask;
npfn = (szc == TTE64K) ? (npfn & ~(pfn_t)0x7) : npfn;
- ASSERT(((page_pfn_2_color_cpu(npfn, szc) ^ color) & ceq_mask) == 0);
+done:
+ ASSERT(((page_papfn_2_color_cpu(npfn, szc) ^ color) & ceq_mask) == 0);
+ ASSERT(PAPFN_2_MNODE(npfn) == it->mi_mnode);
+
+ /* PA to RA */
+ npfn -= it->mi_ra_to_pa;
+
+ /* check for possible memblock switch */
+ if (npfn > it->mi_mblock_end) {
+ pfn = plat_mem_node_iterator_init(npfn, it->mi_mnode, it, 0);
+ if (pfn == (pfn_t)-1)
+ return (pfn);
+ ASSERT(pfn >= it->mi_mblock_base && pfn <= it->mi_mblock_end);
+ pfn += it->mi_ra_to_pa;
+ goto next_mem_block;
+ }
return (npfn);
}
/*
* init page coloring
+ * VF encodes node_id for an L-group in either bit 30 or 31:30,
+ * which effectively reduces the number of colors available per mnode.
*/
void
page_coloring_init_cpu()
{
int i;
-
- hw_page_array[0].hp_colors = 1 << 7;
- hw_page_array[1].hp_colors = 1 << 7;
- hw_page_array[2].hp_colors = 1 << 6;
-
- for (i = 3; i < mmu_page_sizes; i++) {
- hw_page_array[i].hp_colors = 1 << 5;
+ uchar_t id;
+ uchar_t lo;
+ uchar_t hi;
+ n2color_t m;
+ mem_node_iterator_t it;
+ static uchar_t idmask[] = {0, 0x7, 0x1f, 0x1f, 0x1f, 0x1f};
+
+ (void) plat_mem_node_iterator_init(0, 0, &it, 1);
+ for (i = 0; i < mmu_page_sizes; i++) {
+ memset(&m, 0, sizeof (m));
+ id = it.mi_mnode_pfn_mask >> 15; /* node id mask */
+ id &= idmask[i];
+ lo = lowbit(id);
+ if (lo > 0) {
+ hi = highbit(id);
+ m.nnbits = hi - lo + 1;
+ m.nnmask = (1 << m.nnbits) - 1;
+ lo += nhbits[i] - 5;
+ m.lomask = (1 << (lo - 1)) - 1;
+ m.lobits = lo - 1;
+ }
+ hw_page_array[i].hp_colors = 1 << (nhbits[i] - m.nnbits);
+ n2color[i] = m;
}
}
@@ -486,6 +665,7 @@ page_set_colorequiv_arr_cpu(void)
{
static uint_t nequiv_shades_log2[MMU_PAGE_SIZES] = {2, 5, 0, 0, 0, 0};
+ nequiv_shades_log2[1] -= n2color[1].nnbits;
if (colorequiv > 1) {
int i;
uint_t sv_a = lowbit(colorequiv) - 1;