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
lgrp_plat_init(lgrp_init_stages_t stage)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
lgrp_plat_config(lgrp_config_flag_t flag,uintptr_t arg)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
lgrp_plat_cpu_to_hand(processorid_t id)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
lgrp_plat_pfn_to_hand(pfn_t pfn)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
lgrp_plat_max_lgrps(void)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
lgrp_plat_mem_size(lgrp_handle_t plathand,lgrp_mem_query_t query)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
lgrp_plat_latency(lgrp_handle_t from,lgrp_handle_t to)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
lgrp_plat_root_hand(void)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
lgrp_plat_mem_size_default(lgrp_handle_t lgrphand,lgrp_mem_query_t query)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
plat_lgrphand_to_mem_node(lgrp_handle_t plathand)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
plat_mem_node_to_lgrphand(int mnode)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
plat_assign_lgrphand_to_mem_node(lgrp_handle_t plathand,int mnode)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 *
lgrp_plat_alloc(lgrp_id_t lgrpid)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