xref: /onnv-gate/usr/src/uts/sun4/os/lgrpplat.c (revision 11474:857f9db4ef05)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
510710Sjonathan.chew@sun.com  * Common Development and Distribution License (the "License").
610710Sjonathan.chew@sun.com  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
2110710Sjonathan.chew@sun.com 
220Sstevel@tonic-gate /*
23*11474SJonathan.Adams@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/cpuvar.h>
280Sstevel@tonic-gate #include <sys/lgrp.h>
290Sstevel@tonic-gate #include <sys/memnode.h>
300Sstevel@tonic-gate #include <sys/mman.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <vm/seg_spt.h>
350Sstevel@tonic-gate #include <vm/seg_vn.h>
36414Skchow #include <vm/vm_dep.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/errno.h>
390Sstevel@tonic-gate #include <sys/kstat.h>
400Sstevel@tonic-gate #include <sys/cmn_err.h>
410Sstevel@tonic-gate #include <sys/memlist.h>
420Sstevel@tonic-gate #include <sys/sysmacros.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * Platform-specific support for lgroups common to sun4 based platforms.
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  * Those sun4 platforms wanting default lgroup behavior build with
480Sstevel@tonic-gate  * MAX_MEM_NODES = 1.  Those sun4 platforms wanting other than default
490Sstevel@tonic-gate  * lgroup behavior build with MAX_MEM_NODES > 1 and provide unique
500Sstevel@tonic-gate  * definitions to replace the #pragma weak interfaces.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * For now, there are 0 or 1 memnodes per lgroup on sun4 based platforms,
550Sstevel@tonic-gate  * plus the root lgroup.
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate #define	NLGRP	(MAX_MEM_NODES + 1)
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * Allocate lgrp and lgrp stat arrays statically.
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate struct lgrp_stats lgrp_stats[NLGRP];
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static int nlgrps_alloc;
650Sstevel@tonic-gate static lgrp_t lgrp_space[NLGRP];
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Arrays mapping lgroup handles to memnodes and vice versa.  This helps
690Sstevel@tonic-gate  * manage a copy-rename operation during DR, which moves memory from one
700Sstevel@tonic-gate  * board to another without changing addresses/pfns or memnodes.
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate int lgrphand_to_memnode[MAX_MEM_NODES];
730Sstevel@tonic-gate int memnode_to_lgrphand[MAX_MEM_NODES];
740Sstevel@tonic-gate 
750Sstevel@tonic-gate static pgcnt_t lgrp_plat_mem_size_default(lgrp_handle_t, lgrp_mem_query_t);
760Sstevel@tonic-gate int plat_lgrphand_to_mem_node(lgrp_handle_t);
770Sstevel@tonic-gate lgrp_handle_t plat_mem_node_to_lgrphand(int);
780Sstevel@tonic-gate void plat_assign_lgrphand_to_mem_node(lgrp_handle_t, int);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * Default sun4 lgroup interfaces which should be overriden
820Sstevel@tonic-gate  * by platform module.
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate extern void plat_lgrp_init(void);
850Sstevel@tonic-gate extern void plat_lgrp_config(lgrp_config_flag_t, uintptr_t);
860Sstevel@tonic-gate extern lgrp_handle_t plat_lgrp_cpu_to_hand(processorid_t);
870Sstevel@tonic-gate extern int plat_lgrp_latency(lgrp_handle_t, lgrp_handle_t);
880Sstevel@tonic-gate extern lgrp_handle_t plat_lgrp_root_hand(void);
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #pragma weak plat_lgrp_init
910Sstevel@tonic-gate #pragma weak plat_lgrp_config
920Sstevel@tonic-gate #pragma weak plat_lgrp_cpu_to_hand
930Sstevel@tonic-gate #pragma weak plat_lgrp_latency
940Sstevel@tonic-gate #pragma weak plat_lgrp_root_hand
950Sstevel@tonic-gate 
960Sstevel@tonic-gate int mpo_disabled = 0;
970Sstevel@tonic-gate lgrp_handle_t lgrp_default_handle = LGRP_DEFAULT_HANDLE;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate void
lgrp_plat_init(lgrp_init_stages_t stage)10010710Sjonathan.chew@sun.com lgrp_plat_init(lgrp_init_stages_t stage)
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	int i;
1030Sstevel@tonic-gate 
10410710Sjonathan.chew@sun.com 	switch (stage) {
10510710Sjonathan.chew@sun.com 	case LGRP_INIT_STAGE1:
10610710Sjonathan.chew@sun.com 		/*
10710710Sjonathan.chew@sun.com 		 * Initialize lookup tables to invalid values so we catch
10810710Sjonathan.chew@sun.com 		 * any illegal use of them.
10910710Sjonathan.chew@sun.com 		 */
11010710Sjonathan.chew@sun.com 		for (i = 0; i < MAX_MEM_NODES; i++) {
11110710Sjonathan.chew@sun.com 			memnode_to_lgrphand[i] = -1;
11210710Sjonathan.chew@sun.com 			lgrphand_to_memnode[i] = -1;
11310710Sjonathan.chew@sun.com 		}
1140Sstevel@tonic-gate 
11510710Sjonathan.chew@sun.com 		if (lgrp_topo_ht_limit() == 1) {
11610710Sjonathan.chew@sun.com 			max_mem_nodes = 1;
11710710Sjonathan.chew@sun.com 			return;
11810710Sjonathan.chew@sun.com 		}
1190Sstevel@tonic-gate 
12010710Sjonathan.chew@sun.com 		if (&plat_lgrp_cpu_to_hand)
12110710Sjonathan.chew@sun.com 			max_mem_nodes = MAX_MEM_NODES;
1220Sstevel@tonic-gate 
12310710Sjonathan.chew@sun.com 		if (&plat_lgrp_init)
12410710Sjonathan.chew@sun.com 			plat_lgrp_init();
12510710Sjonathan.chew@sun.com 		break;
12610710Sjonathan.chew@sun.com 	default:
12710710Sjonathan.chew@sun.com 		break;
12810710Sjonathan.chew@sun.com 	}
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /* ARGSUSED */
1320Sstevel@tonic-gate void
lgrp_plat_config(lgrp_config_flag_t flag,uintptr_t arg)1330Sstevel@tonic-gate lgrp_plat_config(lgrp_config_flag_t flag, uintptr_t arg)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate 	if (max_mem_nodes == 1)
1360Sstevel@tonic-gate 		return;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (&plat_lgrp_config) {
1390Sstevel@tonic-gate 		plat_lgrp_config(flag, arg);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate lgrp_handle_t
lgrp_plat_cpu_to_hand(processorid_t id)1440Sstevel@tonic-gate lgrp_plat_cpu_to_hand(processorid_t id)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	if (lgrp_topo_ht_limit() > 1 && &plat_lgrp_cpu_to_hand)
1470Sstevel@tonic-gate 		return (plat_lgrp_cpu_to_hand(id));
1480Sstevel@tonic-gate 	else
1490Sstevel@tonic-gate 		return (LGRP_DEFAULT_HANDLE);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate  * Lgroup interfaces common to all sun4 platforms.
1540Sstevel@tonic-gate  */
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * Return the platform handle of the lgroup that contains the physical memory
1580Sstevel@tonic-gate  * corresponding to the given page frame number
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate lgrp_handle_t
lgrp_plat_pfn_to_hand(pfn_t pfn)1610Sstevel@tonic-gate lgrp_plat_pfn_to_hand(pfn_t pfn)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	int	mnode;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if (lgrp_topo_ht_limit() == 1 || max_mem_nodes == 1)
1660Sstevel@tonic-gate 		return (LGRP_DEFAULT_HANDLE);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	if (pfn > physmax)
1690Sstevel@tonic-gate 		return (LGRP_NULL_HANDLE);
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	mnode = PFN_2_MEM_NODE(pfn);
172605Slm66018 	if (mnode < 0)
173605Slm66018 		return (LGRP_NULL_HANDLE);
174605Slm66018 
1750Sstevel@tonic-gate 	return (MEM_NODE_2_LGRPHAND(mnode));
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate /*
1790Sstevel@tonic-gate  * Return the maximum number of supported lgroups
1800Sstevel@tonic-gate  */
1810Sstevel@tonic-gate int
lgrp_plat_max_lgrps(void)1820Sstevel@tonic-gate lgrp_plat_max_lgrps(void)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	return (NLGRP);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * Return the number of free pages in an lgroup.
1890Sstevel@tonic-gate  *
1900Sstevel@tonic-gate  * For query of LGRP_MEM_SIZE_FREE, return the number of base pagesize
1910Sstevel@tonic-gate  * pages on freelists.  For query of LGRP_MEM_SIZE_AVAIL, return the
1920Sstevel@tonic-gate  * number of allocatable base pagesize pages corresponding to the
1930Sstevel@tonic-gate  * lgroup (e.g. do not include page_t's, BOP_ALLOC()'ed memory, ..)
1940Sstevel@tonic-gate  * For query of LGRP_MEM_SIZE_INSTALL, return the amount of physical
1950Sstevel@tonic-gate  * memory installed, regardless of whether or not it's usable.
1960Sstevel@tonic-gate  */
1970Sstevel@tonic-gate pgcnt_t
lgrp_plat_mem_size(lgrp_handle_t plathand,lgrp_mem_query_t query)1980Sstevel@tonic-gate lgrp_plat_mem_size(lgrp_handle_t plathand, lgrp_mem_query_t query)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 	int	mnode;
2010Sstevel@tonic-gate 	pgcnt_t	npgs = (pgcnt_t)0;
2020Sstevel@tonic-gate 	extern struct memlist *phys_avail;
2030Sstevel@tonic-gate 	extern struct memlist *phys_install;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	if (lgrp_topo_ht_limit() == 1 || max_mem_nodes == 1 || mpo_disabled ||
2070Sstevel@tonic-gate 	    plathand == LGRP_DEFAULT_HANDLE)
2080Sstevel@tonic-gate 		return (lgrp_plat_mem_size_default(plathand, query));
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	if (plathand != LGRP_NULL_HANDLE) {
2110Sstevel@tonic-gate 		mnode = plat_lgrphand_to_mem_node(plathand);
2120Sstevel@tonic-gate 		if (mnode >= 0 && mem_node_config[mnode].exists) {
2130Sstevel@tonic-gate 			switch (query) {
2140Sstevel@tonic-gate 			case LGRP_MEM_SIZE_FREE:
215414Skchow 				npgs = MNODE_PGCNT(mnode);
2160Sstevel@tonic-gate 				break;
2170Sstevel@tonic-gate 			case LGRP_MEM_SIZE_AVAIL:
2180Sstevel@tonic-gate 				npgs = mem_node_memlist_pages(mnode,
2190Sstevel@tonic-gate 				    phys_avail);
2200Sstevel@tonic-gate 				break;
2210Sstevel@tonic-gate 			case LGRP_MEM_SIZE_INSTALL:
2220Sstevel@tonic-gate 				npgs = mem_node_memlist_pages(mnode,
2230Sstevel@tonic-gate 				    phys_install);
2240Sstevel@tonic-gate 				break;
2250Sstevel@tonic-gate 			default:
2260Sstevel@tonic-gate 				break;
2270Sstevel@tonic-gate 			}
2280Sstevel@tonic-gate 		}
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 	return (npgs);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate  * Return latency between "from" and "to" lgroups
2350Sstevel@tonic-gate  * If "from" or "to" is LGRP_NONE, then just return latency within other
2360Sstevel@tonic-gate  * lgroup.  This latency number can only be used for relative comparison
2370Sstevel@tonic-gate  * between lgroups on the running system, cannot be used across platforms,
2380Sstevel@tonic-gate  * and may not reflect the actual latency.  It is platform and implementation
2390Sstevel@tonic-gate  * specific, so platform gets to decide its value.
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate int
lgrp_plat_latency(lgrp_handle_t from,lgrp_handle_t to)2420Sstevel@tonic-gate lgrp_plat_latency(lgrp_handle_t from, lgrp_handle_t to)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	if (lgrp_topo_ht_limit() > 1 && &plat_lgrp_latency)
2450Sstevel@tonic-gate 		return (plat_lgrp_latency(from, to));
2460Sstevel@tonic-gate 	else
2470Sstevel@tonic-gate 		return (0);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate  * Return platform handle for root lgroup
2520Sstevel@tonic-gate  */
2530Sstevel@tonic-gate lgrp_handle_t
lgrp_plat_root_hand(void)2540Sstevel@tonic-gate lgrp_plat_root_hand(void)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	if (&plat_lgrp_root_hand)
2570Sstevel@tonic-gate 		return (plat_lgrp_root_hand());
2580Sstevel@tonic-gate 	else
2590Sstevel@tonic-gate 		return (LGRP_DEFAULT_HANDLE);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate /* Internal interfaces */
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate  * Return the number of free, allocatable, or installed
2650Sstevel@tonic-gate  * pages in an lgroup
2660Sstevel@tonic-gate  * This is a copy of the MAX_MEM_NODES == 1 version of the routine
2670Sstevel@tonic-gate  * used when MPO is disabled (i.e. single lgroup)
2680Sstevel@tonic-gate  */
2690Sstevel@tonic-gate /* ARGSUSED */
2700Sstevel@tonic-gate static pgcnt_t
lgrp_plat_mem_size_default(lgrp_handle_t lgrphand,lgrp_mem_query_t query)2710Sstevel@tonic-gate lgrp_plat_mem_size_default(lgrp_handle_t lgrphand, lgrp_mem_query_t query)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	extern struct memlist *phys_install;
2740Sstevel@tonic-gate 	extern struct memlist *phys_avail;
2750Sstevel@tonic-gate 	struct memlist *mlist;
2760Sstevel@tonic-gate 	pgcnt_t npgs = 0;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	switch (query) {
2790Sstevel@tonic-gate 	case LGRP_MEM_SIZE_FREE:
2800Sstevel@tonic-gate 		return ((pgcnt_t)freemem);
2810Sstevel@tonic-gate 	case LGRP_MEM_SIZE_AVAIL:
2820Sstevel@tonic-gate 		memlist_read_lock();
283*11474SJonathan.Adams@Sun.COM 		for (mlist = phys_avail; mlist; mlist = mlist->ml_next)
284*11474SJonathan.Adams@Sun.COM 			npgs += btop(mlist->ml_size);
2850Sstevel@tonic-gate 		memlist_read_unlock();
2860Sstevel@tonic-gate 		return (npgs);
2870Sstevel@tonic-gate 	case LGRP_MEM_SIZE_INSTALL:
2880Sstevel@tonic-gate 		memlist_read_lock();
289*11474SJonathan.Adams@Sun.COM 		for (mlist = phys_install; mlist; mlist = mlist->ml_next)
290*11474SJonathan.Adams@Sun.COM 			npgs += btop(mlist->ml_size);
2910Sstevel@tonic-gate 		memlist_read_unlock();
2920Sstevel@tonic-gate 		return (npgs);
2930Sstevel@tonic-gate 	default:
2940Sstevel@tonic-gate 		return ((pgcnt_t)0);
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate /*
2990Sstevel@tonic-gate  * Return the memnode associated with the specified lgroup handle
3000Sstevel@tonic-gate  */
3010Sstevel@tonic-gate int
plat_lgrphand_to_mem_node(lgrp_handle_t plathand)3020Sstevel@tonic-gate plat_lgrphand_to_mem_node(lgrp_handle_t plathand)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate 	int mnode;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if (lgrp_topo_ht_limit() == 1 || mpo_disabled || max_mem_nodes == 1)
3070Sstevel@tonic-gate 		return (-1);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	/*
3100Sstevel@tonic-gate 	 * We should always receive a valid pointer to a platform
3110Sstevel@tonic-gate 	 * handle, as we can not choose the allocation policy in
3120Sstevel@tonic-gate 	 * this layer.
3130Sstevel@tonic-gate 	 */
3140Sstevel@tonic-gate 	ASSERT((int)plathand >= 0 && (int)plathand < max_mem_nodes);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	mnode = lgrphand_to_memnode[(int)plathand];
3170Sstevel@tonic-gate 	return (mnode);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate lgrp_handle_t
plat_mem_node_to_lgrphand(int mnode)3210Sstevel@tonic-gate plat_mem_node_to_lgrphand(int mnode)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	if (lgrp_topo_ht_limit() == 1 || mpo_disabled || max_mem_nodes == 1)
3240Sstevel@tonic-gate 		return (lgrp_default_handle);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	ASSERT(mnode >= 0 && mnode < max_mem_nodes);
3270Sstevel@tonic-gate 	return (memnode_to_lgrphand[mnode]);
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate void
plat_assign_lgrphand_to_mem_node(lgrp_handle_t plathand,int mnode)3310Sstevel@tonic-gate plat_assign_lgrphand_to_mem_node(lgrp_handle_t plathand, int mnode)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 	if (lgrp_topo_ht_limit() == 1 || mpo_disabled || max_mem_nodes == 1)
3340Sstevel@tonic-gate 		return;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	ASSERT(plathand < max_mem_nodes);
3370Sstevel@tonic-gate 	ASSERT(mnode >= 0 && mnode < max_mem_nodes);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	lgrphand_to_memnode[plathand] = mnode;
3400Sstevel@tonic-gate 	memnode_to_lgrphand[mnode] = plathand;
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate lgrp_t *
lgrp_plat_alloc(lgrp_id_t lgrpid)3440Sstevel@tonic-gate lgrp_plat_alloc(lgrp_id_t lgrpid)
3450Sstevel@tonic-gate {
3460Sstevel@tonic-gate 	lgrp_t *lgrp;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	lgrp = &lgrp_space[nlgrps_alloc++];
3490Sstevel@tonic-gate 	if (lgrpid >= NLGRP || nlgrps_alloc > NLGRP)
3500Sstevel@tonic-gate 		return (NULL);
3510Sstevel@tonic-gate 	return (lgrp);
3520Sstevel@tonic-gate }
353