1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/cpuvar.h> 28 #include <sys/lgrp.h> 29 #include <sys/memnode.h> 30 #include <sys/mman.h> 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/types.h> 34 #include <vm/seg_spt.h> 35 #include <vm/seg_vn.h> 36 #include <vm/vm_dep.h> 37 38 #include <sys/errno.h> 39 #include <sys/kstat.h> 40 #include <sys/cmn_err.h> 41 #include <sys/memlist.h> 42 #include <sys/sysmacros.h> 43 44 /* 45 * Platform-specific support for lgroups common to sun4 based platforms. 46 * 47 * Those sun4 platforms wanting default lgroup behavior build with 48 * MAX_MEM_NODES = 1. Those sun4 platforms wanting other than default 49 * lgroup behavior build with MAX_MEM_NODES > 1 and provide unique 50 * definitions to replace the #pragma weak interfaces. 51 */ 52 53 /* 54 * For now, there are 0 or 1 memnodes per lgroup on sun4 based platforms, 55 * plus the root lgroup. 56 */ 57 #define NLGRP (MAX_MEM_NODES + 1) 58 59 /* 60 * Allocate lgrp and lgrp stat arrays statically. 61 */ 62 struct lgrp_stats lgrp_stats[NLGRP]; 63 64 static int nlgrps_alloc; 65 static lgrp_t lgrp_space[NLGRP]; 66 67 /* 68 * Arrays mapping lgroup handles to memnodes and vice versa. This helps 69 * manage a copy-rename operation during DR, which moves memory from one 70 * board to another without changing addresses/pfns or memnodes. 71 */ 72 int lgrphand_to_memnode[MAX_MEM_NODES]; 73 int memnode_to_lgrphand[MAX_MEM_NODES]; 74 75 static pgcnt_t lgrp_plat_mem_size_default(lgrp_handle_t, lgrp_mem_query_t); 76 int plat_lgrphand_to_mem_node(lgrp_handle_t); 77 lgrp_handle_t plat_mem_node_to_lgrphand(int); 78 void plat_assign_lgrphand_to_mem_node(lgrp_handle_t, int); 79 80 /* 81 * Default sun4 lgroup interfaces which should be overriden 82 * by platform module. 83 */ 84 extern void plat_lgrp_init(void); 85 extern void plat_lgrp_config(lgrp_config_flag_t, uintptr_t); 86 extern lgrp_handle_t plat_lgrp_cpu_to_hand(processorid_t); 87 extern int plat_lgrp_latency(lgrp_handle_t, lgrp_handle_t); 88 extern lgrp_handle_t plat_lgrp_root_hand(void); 89 90 #pragma weak plat_lgrp_init 91 #pragma weak plat_lgrp_config 92 #pragma weak plat_lgrp_cpu_to_hand 93 #pragma weak plat_lgrp_latency 94 #pragma weak plat_lgrp_root_hand 95 96 int mpo_disabled = 0; 97 lgrp_handle_t lgrp_default_handle = LGRP_DEFAULT_HANDLE; 98 99 void 100 lgrp_plat_init(lgrp_init_stages_t stage) 101 { 102 int i; 103 104 switch (stage) { 105 case LGRP_INIT_STAGE1: 106 /* 107 * Initialize lookup tables to invalid values so we catch 108 * any illegal use of them. 109 */ 110 for (i = 0; i < MAX_MEM_NODES; i++) { 111 memnode_to_lgrphand[i] = -1; 112 lgrphand_to_memnode[i] = -1; 113 } 114 115 if (lgrp_topo_ht_limit() == 1) { 116 max_mem_nodes = 1; 117 return; 118 } 119 120 if (&plat_lgrp_cpu_to_hand) 121 max_mem_nodes = MAX_MEM_NODES; 122 123 if (&plat_lgrp_init) 124 plat_lgrp_init(); 125 break; 126 default: 127 break; 128 } 129 } 130 131 /* ARGSUSED */ 132 void 133 lgrp_plat_config(lgrp_config_flag_t flag, uintptr_t arg) 134 { 135 if (max_mem_nodes == 1) 136 return; 137 138 if (&plat_lgrp_config) { 139 plat_lgrp_config(flag, arg); 140 } 141 } 142 143 lgrp_handle_t 144 lgrp_plat_cpu_to_hand(processorid_t id) 145 { 146 if (lgrp_topo_ht_limit() > 1 && &plat_lgrp_cpu_to_hand) 147 return (plat_lgrp_cpu_to_hand(id)); 148 else 149 return (LGRP_DEFAULT_HANDLE); 150 } 151 152 /* 153 * Lgroup interfaces common to all sun4 platforms. 154 */ 155 156 /* 157 * Return the platform handle of the lgroup that contains the physical memory 158 * corresponding to the given page frame number 159 */ 160 lgrp_handle_t 161 lgrp_plat_pfn_to_hand(pfn_t pfn) 162 { 163 int mnode; 164 165 if (lgrp_topo_ht_limit() == 1 || max_mem_nodes == 1) 166 return (LGRP_DEFAULT_HANDLE); 167 168 if (pfn > physmax) 169 return (LGRP_NULL_HANDLE); 170 171 mnode = PFN_2_MEM_NODE(pfn); 172 if (mnode < 0) 173 return (LGRP_NULL_HANDLE); 174 175 return (MEM_NODE_2_LGRPHAND(mnode)); 176 } 177 178 /* 179 * Return the maximum number of supported lgroups 180 */ 181 int 182 lgrp_plat_max_lgrps(void) 183 { 184 return (NLGRP); 185 } 186 187 /* 188 * Return the number of free pages in an lgroup. 189 * 190 * For query of LGRP_MEM_SIZE_FREE, return the number of base pagesize 191 * pages on freelists. For query of LGRP_MEM_SIZE_AVAIL, return the 192 * number of allocatable base pagesize pages corresponding to the 193 * lgroup (e.g. do not include page_t's, BOP_ALLOC()'ed memory, ..) 194 * For query of LGRP_MEM_SIZE_INSTALL, return the amount of physical 195 * memory installed, regardless of whether or not it's usable. 196 */ 197 pgcnt_t 198 lgrp_plat_mem_size(lgrp_handle_t plathand, lgrp_mem_query_t query) 199 { 200 int mnode; 201 pgcnt_t npgs = (pgcnt_t)0; 202 extern struct memlist *phys_avail; 203 extern struct memlist *phys_install; 204 205 206 if (lgrp_topo_ht_limit() == 1 || max_mem_nodes == 1 || mpo_disabled || 207 plathand == LGRP_DEFAULT_HANDLE) 208 return (lgrp_plat_mem_size_default(plathand, query)); 209 210 if (plathand != LGRP_NULL_HANDLE) { 211 mnode = plat_lgrphand_to_mem_node(plathand); 212 if (mnode >= 0 && mem_node_config[mnode].exists) { 213 switch (query) { 214 case LGRP_MEM_SIZE_FREE: 215 npgs = MNODE_PGCNT(mnode); 216 break; 217 case LGRP_MEM_SIZE_AVAIL: 218 npgs = mem_node_memlist_pages(mnode, 219 phys_avail); 220 break; 221 case LGRP_MEM_SIZE_INSTALL: 222 npgs = mem_node_memlist_pages(mnode, 223 phys_install); 224 break; 225 default: 226 break; 227 } 228 } 229 } 230 return (npgs); 231 } 232 233 /* 234 * Return latency between "from" and "to" lgroups 235 * If "from" or "to" is LGRP_NONE, then just return latency within other 236 * lgroup. This latency number can only be used for relative comparison 237 * between lgroups on the running system, cannot be used across platforms, 238 * and may not reflect the actual latency. It is platform and implementation 239 * specific, so platform gets to decide its value. 240 */ 241 int 242 lgrp_plat_latency(lgrp_handle_t from, lgrp_handle_t to) 243 { 244 if (lgrp_topo_ht_limit() > 1 && &plat_lgrp_latency) 245 return (plat_lgrp_latency(from, to)); 246 else 247 return (0); 248 } 249 250 /* 251 * Return platform handle for root lgroup 252 */ 253 lgrp_handle_t 254 lgrp_plat_root_hand(void) 255 { 256 if (&plat_lgrp_root_hand) 257 return (plat_lgrp_root_hand()); 258 else 259 return (LGRP_DEFAULT_HANDLE); 260 } 261 262 /* Internal interfaces */ 263 /* 264 * Return the number of free, allocatable, or installed 265 * pages in an lgroup 266 * This is a copy of the MAX_MEM_NODES == 1 version of the routine 267 * used when MPO is disabled (i.e. single lgroup) 268 */ 269 /* ARGSUSED */ 270 static pgcnt_t 271 lgrp_plat_mem_size_default(lgrp_handle_t lgrphand, lgrp_mem_query_t query) 272 { 273 extern struct memlist *phys_install; 274 extern struct memlist *phys_avail; 275 struct memlist *mlist; 276 pgcnt_t npgs = 0; 277 278 switch (query) { 279 case LGRP_MEM_SIZE_FREE: 280 return ((pgcnt_t)freemem); 281 case LGRP_MEM_SIZE_AVAIL: 282 memlist_read_lock(); 283 for (mlist = phys_avail; mlist; mlist = mlist->ml_next) 284 npgs += btop(mlist->ml_size); 285 memlist_read_unlock(); 286 return (npgs); 287 case LGRP_MEM_SIZE_INSTALL: 288 memlist_read_lock(); 289 for (mlist = phys_install; mlist; mlist = mlist->ml_next) 290 npgs += btop(mlist->ml_size); 291 memlist_read_unlock(); 292 return (npgs); 293 default: 294 return ((pgcnt_t)0); 295 } 296 } 297 298 /* 299 * Return the memnode associated with the specified lgroup handle 300 */ 301 int 302 plat_lgrphand_to_mem_node(lgrp_handle_t plathand) 303 { 304 int mnode; 305 306 if (lgrp_topo_ht_limit() == 1 || mpo_disabled || max_mem_nodes == 1) 307 return (-1); 308 309 /* 310 * We should always receive a valid pointer to a platform 311 * handle, as we can not choose the allocation policy in 312 * this layer. 313 */ 314 ASSERT((int)plathand >= 0 && (int)plathand < max_mem_nodes); 315 316 mnode = lgrphand_to_memnode[(int)plathand]; 317 return (mnode); 318 } 319 320 lgrp_handle_t 321 plat_mem_node_to_lgrphand(int mnode) 322 { 323 if (lgrp_topo_ht_limit() == 1 || mpo_disabled || max_mem_nodes == 1) 324 return (lgrp_default_handle); 325 326 ASSERT(mnode >= 0 && mnode < max_mem_nodes); 327 return (memnode_to_lgrphand[mnode]); 328 } 329 330 void 331 plat_assign_lgrphand_to_mem_node(lgrp_handle_t plathand, int mnode) 332 { 333 if (lgrp_topo_ht_limit() == 1 || mpo_disabled || max_mem_nodes == 1) 334 return; 335 336 ASSERT(plathand < max_mem_nodes); 337 ASSERT(mnode >= 0 && mnode < max_mem_nodes); 338 339 lgrphand_to_memnode[plathand] = mnode; 340 memnode_to_lgrphand[mnode] = plathand; 341 } 342 343 lgrp_t * 344 lgrp_plat_alloc(lgrp_id_t lgrpid) 345 { 346 lgrp_t *lgrp; 347 348 lgrp = &lgrp_space[nlgrps_alloc++]; 349 if (lgrpid >= NLGRP || nlgrps_alloc > NLGRP) 350 return (NULL); 351 return (lgrp); 352 } 353