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 55608Srv207048 * Common Development and Distribution License (the "License"). 65608Srv207048 * 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 */ 210Sstevel@tonic-gate /* 22*7632SNick.Todd@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * lgroup topology 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/cpupart.h> 310Sstevel@tonic-gate #include <sys/lgrp.h> 320Sstevel@tonic-gate #include <sys/promif.h> 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate 360Sstevel@tonic-gate #define LGRP_TOPO_LEVELS 4 /* default height limit */ 370Sstevel@tonic-gate #define LGRP_TOPO_LEVELS_MAX 4 /* max height limit */ 380Sstevel@tonic-gate 390Sstevel@tonic-gate 400Sstevel@tonic-gate /* 410Sstevel@tonic-gate * Only collapse lgroups which have same latency (and resources) 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate int lgrp_collapse_equidist = 1; 440Sstevel@tonic-gate 450Sstevel@tonic-gate int lgrp_collapse_off = 1; /* disable collapsing of duplicates */ 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * Height to limit lgroup topology 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate unsigned int lgrp_topo_levels = LGRP_TOPO_LEVELS; 510Sstevel@tonic-gate 520Sstevel@tonic-gate int lgrp_split_off = 1; /* disable splitting lgroups */ 530Sstevel@tonic-gate 540Sstevel@tonic-gate #ifdef DEBUG 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * Debugging output 570Sstevel@tonic-gate * - 0: off 580Sstevel@tonic-gate * - >0: on and bigger means more 590Sstevel@tonic-gate */ 600Sstevel@tonic-gate int lgrp_topo_debug = 0; 610Sstevel@tonic-gate 620Sstevel@tonic-gate 630Sstevel@tonic-gate void 640Sstevel@tonic-gate klgrpset_print(klgrpset_t lgrpset) 650Sstevel@tonic-gate { 660Sstevel@tonic-gate int i; 670Sstevel@tonic-gate 680Sstevel@tonic-gate 690Sstevel@tonic-gate prom_printf("0x%llx(", (u_longlong_t)lgrpset); 700Sstevel@tonic-gate for (i = 0; i <= lgrp_alloc_max; i++) 710Sstevel@tonic-gate if (klgrpset_ismember(lgrpset, i)) 720Sstevel@tonic-gate prom_printf("%d ", i); 730Sstevel@tonic-gate prom_printf(")\n"); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate 760Sstevel@tonic-gate 770Sstevel@tonic-gate void 780Sstevel@tonic-gate lgrp_rsets_print(char *string, klgrpset_t *rsets) 790Sstevel@tonic-gate { 800Sstevel@tonic-gate int i; 810Sstevel@tonic-gate 820Sstevel@tonic-gate prom_printf("%s\n", string); 830Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 840Sstevel@tonic-gate klgrpset_print(rsets[i]); 850Sstevel@tonic-gate } 860Sstevel@tonic-gate #endif /* DEBUG */ 870Sstevel@tonic-gate 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * Add "from" lgroup resources to "to" lgroup resources 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate void 930Sstevel@tonic-gate lgrp_rsets_add(klgrpset_t *from, klgrpset_t *to) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate int i; 960Sstevel@tonic-gate 970Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 980Sstevel@tonic-gate klgrpset_or(to[i], from[i]); 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate /* 1030Sstevel@tonic-gate * Copy "from" lgroup resources to "to" lgroup resources 1040Sstevel@tonic-gate */ 1050Sstevel@tonic-gate void 1060Sstevel@tonic-gate lgrp_rsets_copy(klgrpset_t *from, klgrpset_t *to) 1070Sstevel@tonic-gate { 1080Sstevel@tonic-gate int i; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 1110Sstevel@tonic-gate to[i] = from[i]; 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* 1160Sstevel@tonic-gate * Delete given lgroup ID from lgroup resource set of specified lgroup 1170Sstevel@tonic-gate * and its ancestors if "follow_parent" is set 1180Sstevel@tonic-gate */ 1190Sstevel@tonic-gate void 1200Sstevel@tonic-gate lgrp_rsets_delete(lgrp_t *lgrp, lgrp_id_t lgrpid, int follow_parent) 1210Sstevel@tonic-gate { 1220Sstevel@tonic-gate int i; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate while (lgrp != NULL) { 1250Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 1260Sstevel@tonic-gate klgrpset_del(lgrp->lgrp_set[i], lgrpid); 1270Sstevel@tonic-gate if (!follow_parent) 1280Sstevel@tonic-gate break; 1290Sstevel@tonic-gate lgrp = lgrp->lgrp_parent; 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate /* 1350Sstevel@tonic-gate * Return whether given lgroup resource set empty 1360Sstevel@tonic-gate */ 1370Sstevel@tonic-gate int 1380Sstevel@tonic-gate lgrp_rsets_empty(klgrpset_t *rset) 1390Sstevel@tonic-gate { 1400Sstevel@tonic-gate int i; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 1430Sstevel@tonic-gate if (!klgrpset_isempty(rset[i])) 1440Sstevel@tonic-gate return (0); 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate return (1); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * Return whether given lgroup resource sets are same 1520Sstevel@tonic-gate */ 1530Sstevel@tonic-gate int 1540Sstevel@tonic-gate lgrp_rsets_equal(klgrpset_t *rset1, klgrpset_t *rset2) 1550Sstevel@tonic-gate { 1560Sstevel@tonic-gate int i; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 1590Sstevel@tonic-gate if (rset1[i] != rset2[i]) 1600Sstevel@tonic-gate return (0); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate return (1); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate /* 1670Sstevel@tonic-gate * Return whether specified lgroup ID is in given lgroup resource set 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate int 1700Sstevel@tonic-gate lgrp_rsets_member(klgrpset_t *rset, lgrp_id_t lgrpid) 1710Sstevel@tonic-gate { 1720Sstevel@tonic-gate int i; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 1750Sstevel@tonic-gate if (klgrpset_ismember(rset[i], lgrpid)) 1760Sstevel@tonic-gate return (1); 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate return (0); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 1830Sstevel@tonic-gate * Return whether specified lgroup ID is in all lgroup resources 1840Sstevel@tonic-gate */ 1850Sstevel@tonic-gate int 1860Sstevel@tonic-gate lgrp_rsets_member_all(klgrpset_t *rset, lgrp_id_t lgrpid) 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate int i; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 1910Sstevel@tonic-gate if (!klgrpset_ismember(rset[i], lgrpid)) 1920Sstevel@tonic-gate return (0); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate return (1); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * Replace resources for given lgroup with specified resources at given 2000Sstevel@tonic-gate * latency and shift its old resources to its parent and its parent's resources 2010Sstevel@tonic-gate * to its parent, etc. until root lgroup reached 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate void 2040Sstevel@tonic-gate lgrp_rsets_replace(klgrpset_t *rset, int latency, lgrp_t *lgrp, int shift) 2050Sstevel@tonic-gate { 2060Sstevel@tonic-gate lgrp_t *cur; 2070Sstevel@tonic-gate int lat_new; 2080Sstevel@tonic-gate int lat_saved; 2090Sstevel@tonic-gate klgrpset_t rset_new[LGRP_RSRC_COUNT]; 2100Sstevel@tonic-gate klgrpset_t rset_saved[LGRP_RSRC_COUNT]; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate cur = lgrp; 2130Sstevel@tonic-gate lat_saved = latency; 2140Sstevel@tonic-gate lgrp_rsets_copy(rset, rset_saved); 2150Sstevel@tonic-gate while (cur && cur != lgrp_root) { 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * Save current resources and latency to insert in parent and 2180Sstevel@tonic-gate * then replace with new resources and latency 2190Sstevel@tonic-gate */ 2200Sstevel@tonic-gate lgrp_rsets_copy(rset_saved, rset_new); 2210Sstevel@tonic-gate lgrp_rsets_copy(cur->lgrp_set, rset_saved); 2220Sstevel@tonic-gate lgrp_rsets_copy(rset_new, cur->lgrp_set); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate lat_new = lat_saved; 2250Sstevel@tonic-gate lat_saved = cur->lgrp_latency; 2260Sstevel@tonic-gate cur->lgrp_latency = lat_new; 2270Sstevel@tonic-gate if (!shift) 2280Sstevel@tonic-gate break; 2290Sstevel@tonic-gate cur = cur->lgrp_parent; 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* 2350Sstevel@tonic-gate * Set "to" lgroup resource set with given lgroup ID 2360Sstevel@tonic-gate */ 2370Sstevel@tonic-gate void 2380Sstevel@tonic-gate lgrp_rsets_set(klgrpset_t *to, lgrp_id_t lgrpid) 2390Sstevel@tonic-gate { 2400Sstevel@tonic-gate klgrpset_t from; 2410Sstevel@tonic-gate int i; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate klgrpset_clear(from); 2440Sstevel@tonic-gate klgrpset_add(from, lgrpid); 2450Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) { 2460Sstevel@tonic-gate klgrpset_clear(to[i]); 2470Sstevel@tonic-gate klgrpset_or(to[i], from); 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * Delete any ancestors of given child lgroup which don't have any other 2540Sstevel@tonic-gate * children 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate int 2570Sstevel@tonic-gate lgrp_ancestor_delete(lgrp_t *child, klgrpset_t *changed) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate int count; 2600Sstevel@tonic-gate lgrp_t *current; 2610Sstevel@tonic-gate lgrp_id_t lgrpid; 2620Sstevel@tonic-gate lgrp_t *parent; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate #ifdef DEBUG 2650Sstevel@tonic-gate if (lgrp_topo_debug > 1) { 2660Sstevel@tonic-gate prom_printf("lgrp_ancestor_delete(0x%p[%d],0x%p)\n", 267*7632SNick.Todd@Sun.COM (void *)child, child->lgrp_id, (void *)changed); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate #endif /* DEBUG */ 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate count = 0; 2720Sstevel@tonic-gate if (changed) 2730Sstevel@tonic-gate klgrpset_clear(*changed); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate /* 2760Sstevel@tonic-gate * Visit ancestors, decrement child count for each, and remove any 2770Sstevel@tonic-gate * that don't have any children left until we reach an ancestor that 2780Sstevel@tonic-gate * has multiple children 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate current = child; 2810Sstevel@tonic-gate parent = child->lgrp_parent; 2820Sstevel@tonic-gate lgrpid = current->lgrp_id; 2830Sstevel@tonic-gate while (parent != NULL) { 2840Sstevel@tonic-gate #ifdef DEBUG 2850Sstevel@tonic-gate if (lgrp_topo_debug > 1) 2860Sstevel@tonic-gate prom_printf("lgrp_ancestor_delete: parent %d," 2870Sstevel@tonic-gate " current %d\n", 2880Sstevel@tonic-gate parent->lgrp_id, lgrpid); 2890Sstevel@tonic-gate #endif /* DEBUG */ 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate klgrpset_del(parent->lgrp_leaves, lgrpid); 2920Sstevel@tonic-gate klgrpset_del(parent->lgrp_children, lgrpid); 2930Sstevel@tonic-gate parent->lgrp_childcnt--; 2940Sstevel@tonic-gate if (changed) 2950Sstevel@tonic-gate klgrpset_add(*changed, parent->lgrp_id); 2960Sstevel@tonic-gate count++; 2970Sstevel@tonic-gate if (parent->lgrp_childcnt != 0) 2980Sstevel@tonic-gate break; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate current = parent; 3010Sstevel@tonic-gate parent = current->lgrp_parent; 3020Sstevel@tonic-gate lgrpid = current->lgrp_id; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate #ifdef DEBUG 3050Sstevel@tonic-gate if (lgrp_topo_debug > 0) 3060Sstevel@tonic-gate prom_printf("lgrp_ancestor_delete: destroy" 3070Sstevel@tonic-gate " lgrp %d at 0x%p\n", 308*7632SNick.Todd@Sun.COM current->lgrp_id, (void *)current); 3090Sstevel@tonic-gate #endif /* DEBUG */ 3100Sstevel@tonic-gate lgrp_destroy(current); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate #ifdef DEBUG 3140Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 3150Sstevel@tonic-gate prom_printf("lgrp_ancestor_delete: changed %d lgrps: 0x%llx\n", 3160Sstevel@tonic-gate count, (u_longlong_t)*changed); 3170Sstevel@tonic-gate #endif /* DEBUG */ 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate return (count); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate /* 3240Sstevel@tonic-gate * Consolidate lgrp1 into lgrp2 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate int 3270Sstevel@tonic-gate lgrp_consolidate(lgrp_t *lgrp1, lgrp_t *lgrp2, klgrpset_t *changed) 3280Sstevel@tonic-gate { 3290Sstevel@tonic-gate klgrpset_t changes; 3300Sstevel@tonic-gate lgrp_t *child; 3310Sstevel@tonic-gate int count; 3320Sstevel@tonic-gate int i; 3330Sstevel@tonic-gate lgrp_t *parent; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * Leaf lgroups should never need to be consolidated 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate if (lgrp1 == NULL || lgrp2 == NULL || lgrp1->lgrp_childcnt < 1 || 3390Sstevel@tonic-gate lgrp2->lgrp_childcnt < 1) 3400Sstevel@tonic-gate return (0); 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate #ifdef DEBUG 3430Sstevel@tonic-gate if (lgrp_topo_debug > 0) 3440Sstevel@tonic-gate prom_printf("lgrp_consolidate(0x%p[%d],0x%p[%d],0x%p)\n", 345*7632SNick.Todd@Sun.COM (void *)lgrp1, lgrp1->lgrp_id, (void *)lgrp2, 346*7632SNick.Todd@Sun.COM lgrp2->lgrp_id, (void *)changed); 3470Sstevel@tonic-gate #endif /* DEBUG */ 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate count = 0; 3500Sstevel@tonic-gate if (changed) 3510Sstevel@tonic-gate klgrpset_clear(*changed); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /* 3540Sstevel@tonic-gate * Lgroup represents resources within certain latency, so need to keep 3550Sstevel@tonic-gate * biggest latency value of lgroups being consolidated 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate if (lgrp1->lgrp_latency > lgrp2->lgrp_latency) 3580Sstevel@tonic-gate lgrp2->lgrp_latency = lgrp1->lgrp_latency; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * Delete ancestors of lgrp1 that don't have any other children 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate #ifdef DEBUG 3640Sstevel@tonic-gate if (lgrp_topo_debug > 1) 3650Sstevel@tonic-gate prom_printf("lgrp_consolidate: delete ancestors\n"); 3660Sstevel@tonic-gate #endif /* DEBUG */ 3670Sstevel@tonic-gate count += lgrp_ancestor_delete(lgrp1, &changes); 3680Sstevel@tonic-gate if (changed) { 3690Sstevel@tonic-gate klgrpset_or(*changed, changes); 3700Sstevel@tonic-gate klgrpset_or(*changed, lgrp1->lgrp_id); 3710Sstevel@tonic-gate count++; 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* 3750Sstevel@tonic-gate * Reparent children lgroups of lgrp1 to lgrp2 3760Sstevel@tonic-gate */ 3770Sstevel@tonic-gate for (i = 0; i <= lgrp_alloc_max; i++) { 3780Sstevel@tonic-gate if (i == lgrp2->lgrp_id || 3790Sstevel@tonic-gate !klgrpset_ismember(lgrp1->lgrp_children, i)) 3800Sstevel@tonic-gate continue; 3810Sstevel@tonic-gate child = lgrp_table[i]; 3820Sstevel@tonic-gate if (!LGRP_EXISTS(child)) 3830Sstevel@tonic-gate continue; 3840Sstevel@tonic-gate #ifdef DEBUG 3850Sstevel@tonic-gate if (lgrp_topo_debug > 0) 3860Sstevel@tonic-gate prom_printf("lgrp_consolidate: reparent " 3870Sstevel@tonic-gate "lgrp %d to lgrp %d\n", 3880Sstevel@tonic-gate child->lgrp_id, lgrp2->lgrp_id); 3890Sstevel@tonic-gate #endif /* DEBUG */ 3900Sstevel@tonic-gate klgrpset_or(lgrp2->lgrp_leaves, child->lgrp_leaves); 3910Sstevel@tonic-gate klgrpset_add(lgrp2->lgrp_children, child->lgrp_id); 3920Sstevel@tonic-gate lgrp2->lgrp_childcnt++; 3930Sstevel@tonic-gate child->lgrp_parent = lgrp2; 3940Sstevel@tonic-gate if (changed) { 3950Sstevel@tonic-gate klgrpset_add(*changed, child->lgrp_id); 3960Sstevel@tonic-gate klgrpset_add(*changed, lgrp2->lgrp_id); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate count += 2; 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate /* 4020Sstevel@tonic-gate * Proprogate leaves from lgrp2 to root 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate child = lgrp2; 4050Sstevel@tonic-gate parent = child->lgrp_parent; 4060Sstevel@tonic-gate while (parent != NULL) { 4070Sstevel@tonic-gate klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves); 4080Sstevel@tonic-gate if (changed) 4090Sstevel@tonic-gate klgrpset_add(*changed, parent->lgrp_id); 4100Sstevel@tonic-gate count++; 4110Sstevel@tonic-gate child = parent; 4120Sstevel@tonic-gate parent = parent->lgrp_parent; 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate #ifdef DEBUG 4160Sstevel@tonic-gate if (lgrp_topo_debug > 0) 4170Sstevel@tonic-gate prom_printf("lgrp_consolidate: destroy lgrp %d at 0x%p\n", 418*7632SNick.Todd@Sun.COM lgrp1->lgrp_id, (void *)lgrp1); 4190Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 4200Sstevel@tonic-gate prom_printf("lgrp_consolidate: changed %d lgrps: 0x%llx\n", 4210Sstevel@tonic-gate count, (u_longlong_t)*changed); 4220Sstevel@tonic-gate #endif /* DEBUG */ 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate lgrp_destroy(lgrp1); 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate return (count); 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate /* 4300Sstevel@tonic-gate * Collapse duplicates of target lgroups given 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate int 4330Sstevel@tonic-gate lgrp_collapse_dups(klgrpset_t target_set, int equidist_only, 4340Sstevel@tonic-gate klgrpset_t *changed) 4350Sstevel@tonic-gate { 4360Sstevel@tonic-gate klgrpset_t changes; 4370Sstevel@tonic-gate int count; 4380Sstevel@tonic-gate int i; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate count = 0; 4410Sstevel@tonic-gate if (changed) 4420Sstevel@tonic-gate klgrpset_clear(*changed); 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate if (lgrp_collapse_off) 4450Sstevel@tonic-gate return (0); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate #ifdef DEBUG 4480Sstevel@tonic-gate if (lgrp_topo_debug > 0) 4490Sstevel@tonic-gate prom_printf("lgrp_collapse_dups(0x%llx)\n", 4500Sstevel@tonic-gate (u_longlong_t)target_set); 4510Sstevel@tonic-gate #endif /* DEBUG */ 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * Look for duplicates of each target lgroup 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate for (i = 0; i <= lgrp_alloc_max; i++) { 4570Sstevel@tonic-gate int j; 4580Sstevel@tonic-gate lgrp_t *keep; 4590Sstevel@tonic-gate lgrp_t *target; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate target = lgrp_table[i]; 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * Skip to next lgroup if there isn't one here, this is root 4650Sstevel@tonic-gate * or leaf lgroup, or this isn't a target lgroup 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate if (!LGRP_EXISTS(target) || 4680Sstevel@tonic-gate target == lgrp_root || target->lgrp_childcnt == 0 || 4690Sstevel@tonic-gate !klgrpset_ismember(target_set, target->lgrp_id)) 4700Sstevel@tonic-gate continue; 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate /* 4730Sstevel@tonic-gate * Find all lgroups with same resources and latency 4740Sstevel@tonic-gate */ 4750Sstevel@tonic-gate #ifdef DEBUG 4760Sstevel@tonic-gate if (lgrp_topo_debug > 1) 4770Sstevel@tonic-gate prom_printf("lgrp_collapse_dups: find " 4780Sstevel@tonic-gate "dups of lgrp %d at 0x%p\n", 479*7632SNick.Todd@Sun.COM target->lgrp_id, (void *)target); 4800Sstevel@tonic-gate #endif /* DEBUG */ 4810Sstevel@tonic-gate keep = NULL; 4820Sstevel@tonic-gate for (j = 0; j <= lgrp_alloc_max; j++) { 4830Sstevel@tonic-gate lgrp_t *lgrp; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate lgrp = lgrp_table[j]; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* 4880Sstevel@tonic-gate * Skip lgroup if there isn't one here, this is root 4890Sstevel@tonic-gate * lgroup or leaf (which shouldn't have dups), or this 4900Sstevel@tonic-gate * lgroup doesn't have same resources 4910Sstevel@tonic-gate */ 4920Sstevel@tonic-gate if (!LGRP_EXISTS(lgrp) || 4930Sstevel@tonic-gate lgrp->lgrp_childcnt == 0 || 4940Sstevel@tonic-gate !lgrp_rsets_equal(lgrp->lgrp_set, 4950Sstevel@tonic-gate target->lgrp_set) || 4960Sstevel@tonic-gate (lgrp->lgrp_latency != target->lgrp_latency && 4970Sstevel@tonic-gate equidist_only)) 4980Sstevel@tonic-gate continue; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate /* 5010Sstevel@tonic-gate * Keep first matching lgroup (but always keep root) 5020Sstevel@tonic-gate * and consolidate other duplicates into it 5030Sstevel@tonic-gate */ 5040Sstevel@tonic-gate if (keep == NULL) { 5050Sstevel@tonic-gate keep = lgrp; 5060Sstevel@tonic-gate #ifdef DEBUG 5070Sstevel@tonic-gate if (lgrp_topo_debug > 1) 5080Sstevel@tonic-gate prom_printf("lgrp_collapse_dups: " 5090Sstevel@tonic-gate "keep lgrp %d at 0x%p\n", 510*7632SNick.Todd@Sun.COM keep->lgrp_id, (void *)keep); 5110Sstevel@tonic-gate #endif /* DEBUG */ 5120Sstevel@tonic-gate } else { 5130Sstevel@tonic-gate if (lgrp == lgrp_root) { 5140Sstevel@tonic-gate lgrp = keep; 5150Sstevel@tonic-gate keep = lgrp_root; 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate #ifdef DEBUG 5180Sstevel@tonic-gate if (lgrp_topo_debug > 0) 5190Sstevel@tonic-gate prom_printf("lgrp_collapse_dups:" 5200Sstevel@tonic-gate " consolidate lgrp %d at 0x%p" 5210Sstevel@tonic-gate " into lgrp %d at 0x%p\n", 522*7632SNick.Todd@Sun.COM lgrp->lgrp_id, (void *)lgrp, 523*7632SNick.Todd@Sun.COM keep->lgrp_id, (void *)keep); 5240Sstevel@tonic-gate #endif /* DEBUG */ 5250Sstevel@tonic-gate count += lgrp_consolidate(lgrp, keep, 5260Sstevel@tonic-gate &changes); 5270Sstevel@tonic-gate if (changed) 5280Sstevel@tonic-gate klgrpset_or(*changed, changes); 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate #ifdef DEBUG 5340Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 5350Sstevel@tonic-gate prom_printf("lgrp_collapse_dups: changed %d lgrps: 0x%llx\n", 5360Sstevel@tonic-gate count, (u_longlong_t)*changed); 5370Sstevel@tonic-gate #endif /* DEBUG */ 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate return (count); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * Create new parent lgroup with given latency and resources for 5450Sstevel@tonic-gate * specified child lgroup, and insert it into hierarchy 5460Sstevel@tonic-gate */ 5470Sstevel@tonic-gate int 5480Sstevel@tonic-gate lgrp_new_parent(lgrp_t *child, int latency, klgrpset_t *rset, 5490Sstevel@tonic-gate klgrpset_t *changed) 5500Sstevel@tonic-gate { 5510Sstevel@tonic-gate int count; 5520Sstevel@tonic-gate lgrp_t *new; 5530Sstevel@tonic-gate lgrp_t *old; 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate count = 0; 5560Sstevel@tonic-gate if (changed) 5570Sstevel@tonic-gate klgrpset_clear(*changed); 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate /* 5600Sstevel@tonic-gate * Create lgroup and set its latency and resources 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate new = lgrp_create(); 5630Sstevel@tonic-gate new->lgrp_latency = latency; 5640Sstevel@tonic-gate lgrp_rsets_add(rset, new->lgrp_set); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * Insert new lgroup into hierarchy 5680Sstevel@tonic-gate */ 5690Sstevel@tonic-gate old = child->lgrp_parent; 5700Sstevel@tonic-gate new->lgrp_parent = old; 5710Sstevel@tonic-gate klgrpset_add(new->lgrp_children, child->lgrp_id); 5720Sstevel@tonic-gate new->lgrp_childcnt++; 5730Sstevel@tonic-gate klgrpset_add(new->lgrp_children, child->lgrp_id); 5740Sstevel@tonic-gate klgrpset_copy(new->lgrp_leaves, child->lgrp_leaves); 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate child->lgrp_parent = new; 5770Sstevel@tonic-gate if (old) { 5780Sstevel@tonic-gate klgrpset_del(old->lgrp_children, child->lgrp_id); 5790Sstevel@tonic-gate klgrpset_add(old->lgrp_children, new->lgrp_id); 5800Sstevel@tonic-gate if (changed) 5810Sstevel@tonic-gate klgrpset_add(*changed, old->lgrp_id); 5820Sstevel@tonic-gate count++; 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate if (changed) { 5860Sstevel@tonic-gate klgrpset_add(*changed, child->lgrp_id); 5870Sstevel@tonic-gate klgrpset_add(*changed, new->lgrp_id); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate count += 2; 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate #ifdef DEBUG 5920Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 5930Sstevel@tonic-gate prom_printf("lgrp_new_parent: changed %d lgrps: 0x%llx\n", 5940Sstevel@tonic-gate count, (u_longlong_t)*changed); 5950Sstevel@tonic-gate #endif /* DEBUG */ 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate return (count); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate /* 6020Sstevel@tonic-gate * Proprogate resources of new leaf into parent lgroup of given child 6030Sstevel@tonic-gate */ 6040Sstevel@tonic-gate int 6050Sstevel@tonic-gate lgrp_proprogate(lgrp_t *newleaf, lgrp_t *child, int latency, 6060Sstevel@tonic-gate klgrpset_t *changed) 6070Sstevel@tonic-gate { 6080Sstevel@tonic-gate int count; 6090Sstevel@tonic-gate lgrp_t *parent; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate count = 0; 6120Sstevel@tonic-gate if (changed) 6130Sstevel@tonic-gate klgrpset_clear(*changed); 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate if (child == NULL || child->lgrp_parent == NULL) 6160Sstevel@tonic-gate return (0); 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate parent = child->lgrp_parent; 6190Sstevel@tonic-gate klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves); 6200Sstevel@tonic-gate if (changed) 6210Sstevel@tonic-gate klgrpset_add(*changed, parent->lgrp_id); 6220Sstevel@tonic-gate count++; 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* 6250Sstevel@tonic-gate * Don't proprogate new leaf resources to parent if it already 6260Sstevel@tonic-gate * contains these resources 6270Sstevel@tonic-gate */ 6280Sstevel@tonic-gate if (lgrp_rsets_member_all(parent->lgrp_set, newleaf->lgrp_id)) { 6290Sstevel@tonic-gate #ifdef DEBUG 6300Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 6310Sstevel@tonic-gate prom_printf("lgrp_proprogate: changed %d lgrps:" 6320Sstevel@tonic-gate " 0x%llx\n", 6330Sstevel@tonic-gate count, (u_longlong_t)*changed); 6340Sstevel@tonic-gate #endif /* DEBUG */ 6350Sstevel@tonic-gate return (count); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* 6390Sstevel@tonic-gate * Add leaf resources to parent lgroup 6400Sstevel@tonic-gate */ 6410Sstevel@tonic-gate lgrp_rsets_add(newleaf->lgrp_set, parent->lgrp_set); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate #ifdef DEBUG 6440Sstevel@tonic-gate if (lgrp_topo_debug > 1) { 6450Sstevel@tonic-gate prom_printf("lgrp_proprogate: newleaf %d(0x%p), " 6460Sstevel@tonic-gate "latency %d, child %d(0x%p), parent %d(0x%p)\n", 647*7632SNick.Todd@Sun.COM newleaf->lgrp_id, (void *)newleaf, latency, child->lgrp_id, 648*7632SNick.Todd@Sun.COM (void *)child, parent->lgrp_id, (void *)parent); 6490Sstevel@tonic-gate prom_printf("lgrp_proprogate: parent's leaves becomes 0x%llx\n", 6500Sstevel@tonic-gate (u_longlong_t)parent->lgrp_leaves); 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate if (lgrp_topo_debug > 0) { 6530Sstevel@tonic-gate prom_printf("lgrp_proprogate: adding to parent %d (0x%p)\n", 654*7632SNick.Todd@Sun.COM parent->lgrp_id, (void *)parent); 6550Sstevel@tonic-gate lgrp_rsets_print("parent resources become:", parent->lgrp_set); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (lgrp_topo_debug > 2 && changed) 6590Sstevel@tonic-gate prom_printf("lgrp_proprogate: changed %d lgrps: 0x%llx\n", 6600Sstevel@tonic-gate count, (u_longlong_t)*changed); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate #endif /* DEBUG */ 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate return (count); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * Split parent lgroup of given child if child's leaf decendant (oldleaf) has 6700Sstevel@tonic-gate * different latency to new leaf lgroup (newleaf) than leaf lgroups of given 6710Sstevel@tonic-gate * child's siblings 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate int 6740Sstevel@tonic-gate lgrp_split(lgrp_t *oldleaf, lgrp_t *newleaf, lgrp_t *child, 6750Sstevel@tonic-gate klgrpset_t *changed) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate klgrpset_t changes; 6780Sstevel@tonic-gate int count; 6790Sstevel@tonic-gate int i; 6800Sstevel@tonic-gate int latency; 6810Sstevel@tonic-gate lgrp_t *parent; 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate count = 0; 6840Sstevel@tonic-gate if (changed) 6850Sstevel@tonic-gate klgrpset_clear(*changed); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate if (lgrp_split_off || newleaf == NULL || child == NULL) 6880Sstevel@tonic-gate return (0); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate /* 6910Sstevel@tonic-gate * Parent must have more than one child to have a child split from it 6920Sstevel@tonic-gate * and root lgroup contains all resources and never needs to be split 6930Sstevel@tonic-gate */ 6940Sstevel@tonic-gate parent = child->lgrp_parent; 6950Sstevel@tonic-gate if (parent == NULL || parent->lgrp_childcnt < 2 || parent == lgrp_root) 6960Sstevel@tonic-gate return (0); 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate #ifdef DEBUG 6990Sstevel@tonic-gate if (lgrp_topo_debug > 1) 7000Sstevel@tonic-gate prom_printf("lgrp_split(0x%p[%d],0x%p[%d],0x%p[%d],0x%p)\n", 701*7632SNick.Todd@Sun.COM (void *)oldleaf, oldleaf->lgrp_id, 702*7632SNick.Todd@Sun.COM (void *)newleaf, newleaf->lgrp_id, 703*7632SNick.Todd@Sun.COM (void *)child, child->lgrp_id, (void *)changed); 7040Sstevel@tonic-gate #endif /* DEBUG */ 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate /* 7070Sstevel@tonic-gate * Get latency between new leaf and old leaf whose lineage it is 7080Sstevel@tonic-gate * being added 7090Sstevel@tonic-gate */ 7100Sstevel@tonic-gate latency = lgrp_plat_latency(oldleaf->lgrp_plathand, 7110Sstevel@tonic-gate newleaf->lgrp_plathand); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* 7140Sstevel@tonic-gate * Check whether all sibling leaves of given child lgroup have same 7150Sstevel@tonic-gate * latency to new leaf 7160Sstevel@tonic-gate */ 7170Sstevel@tonic-gate for (i = 0; i <= lgrp_alloc_max; i++) { 7180Sstevel@tonic-gate lgrp_t *grandparent; 7190Sstevel@tonic-gate lgrp_t *lgrp; 7200Sstevel@tonic-gate int sibling_latency; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate lgrp = lgrp_table[i]; 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate /* 7250Sstevel@tonic-gate * Skip non-existent lgroups, old leaf, and any lgroups that 7260Sstevel@tonic-gate * don't have parent as common ancestor 7270Sstevel@tonic-gate */ 7280Sstevel@tonic-gate if (!LGRP_EXISTS(lgrp) || lgrp == oldleaf || 7290Sstevel@tonic-gate !klgrpset_ismember(parent->lgrp_leaves, lgrp->lgrp_id)) 7300Sstevel@tonic-gate continue; 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * Same latency, so skip 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate sibling_latency = lgrp_plat_latency(lgrp->lgrp_plathand, 7360Sstevel@tonic-gate newleaf->lgrp_plathand); 7370Sstevel@tonic-gate #ifdef DEBUG 7380Sstevel@tonic-gate if (lgrp_topo_debug > 1) 7390Sstevel@tonic-gate prom_printf("lgrp_split: latency(%d,%d) %d," 7400Sstevel@tonic-gate " latency(%d,%d) %d\n", 7410Sstevel@tonic-gate oldleaf->lgrp_id, newleaf->lgrp_id, latency, 7420Sstevel@tonic-gate lgrp->lgrp_id, newleaf->lgrp_id, sibling_latency); 7430Sstevel@tonic-gate #endif /* DEBUG */ 7440Sstevel@tonic-gate if (sibling_latency == latency) 7450Sstevel@tonic-gate continue; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate /* 7480Sstevel@tonic-gate * Different latencies, so remove child from its parent and 7490Sstevel@tonic-gate * make new parent for old leaf with same latency and same 7500Sstevel@tonic-gate * resources 7510Sstevel@tonic-gate */ 7520Sstevel@tonic-gate parent->lgrp_childcnt--; 7530Sstevel@tonic-gate klgrpset_del(parent->lgrp_children, child->lgrp_id); 7540Sstevel@tonic-gate klgrpset_del(parent->lgrp_leaves, oldleaf->lgrp_id); 7550Sstevel@tonic-gate grandparent = parent->lgrp_parent; 7560Sstevel@tonic-gate if (grandparent) { 7570Sstevel@tonic-gate grandparent->lgrp_childcnt++; 7580Sstevel@tonic-gate klgrpset_add(grandparent->lgrp_children, 7590Sstevel@tonic-gate child->lgrp_id); 7600Sstevel@tonic-gate count++; 7610Sstevel@tonic-gate if (changed) 7620Sstevel@tonic-gate klgrpset_add(*changed, grandparent->lgrp_id); 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate child->lgrp_parent = grandparent; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate count += lgrp_new_parent(child, parent->lgrp_latency, 7670Sstevel@tonic-gate parent->lgrp_set, &changes); 7680Sstevel@tonic-gate if (changed) { 7690Sstevel@tonic-gate klgrpset_or(*changed, changes); 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate klgrpset_add(*changed, parent->lgrp_id); 7720Sstevel@tonic-gate klgrpset_add(*changed, child->lgrp_id); 7730Sstevel@tonic-gate count += 2; 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate parent = child->lgrp_parent; 7770Sstevel@tonic-gate #ifdef DEBUG 7780Sstevel@tonic-gate if (lgrp_topo_debug > 0) { 7790Sstevel@tonic-gate prom_printf("lgrp_split: new parent %d (0x%p) for" 7800Sstevel@tonic-gate " lgrp %d (0x%p)\n", 781*7632SNick.Todd@Sun.COM parent->lgrp_id, (void *)parent, 782*7632SNick.Todd@Sun.COM child->lgrp_id, (void *)child); 7830Sstevel@tonic-gate lgrp_rsets_print("new parent resources:", 7840Sstevel@tonic-gate parent->lgrp_set); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 7880Sstevel@tonic-gate prom_printf("lgrp_split: changed %d lgrps: 0x%llx\n", 7890Sstevel@tonic-gate count, (u_longlong_t)*changed); 7900Sstevel@tonic-gate #endif /* DEBUG */ 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate return (count); 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate #ifdef DEBUG 7960Sstevel@tonic-gate if (lgrp_topo_debug > 1) 7970Sstevel@tonic-gate prom_printf("lgrp_split: no changes\n"); 7980Sstevel@tonic-gate #endif /* DEBUG */ 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate return (count); 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate /* 8050Sstevel@tonic-gate * Return height of lgroup topology from given lgroup to root 8060Sstevel@tonic-gate */ 8070Sstevel@tonic-gate int 8080Sstevel@tonic-gate lgrp_topo_height(lgrp_t *lgrp) 8090Sstevel@tonic-gate { 8100Sstevel@tonic-gate int nlevels; 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if (!LGRP_EXISTS(lgrp)) 8130Sstevel@tonic-gate return (0); 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate nlevels = 0; 8160Sstevel@tonic-gate while (lgrp != NULL) { 8170Sstevel@tonic-gate lgrp = lgrp->lgrp_parent; 8180Sstevel@tonic-gate nlevels++; 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate return (nlevels); 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate /* 8250Sstevel@tonic-gate * Add resources of new leaf to old leaf's lineage 8260Sstevel@tonic-gate * 8270Sstevel@tonic-gate * Assumes the following: 8280Sstevel@tonic-gate * - Lgroup hierarchy consists of at least a root lgroup and its leaves 8290Sstevel@tonic-gate * including old and new ones given below 8300Sstevel@tonic-gate * - New leaf lgroup has been created and does not need to have its resources 8310Sstevel@tonic-gate * added to it 8320Sstevel@tonic-gate * - Latencies have been set for root and leaf lgroups 8330Sstevel@tonic-gate */ 8340Sstevel@tonic-gate int 8350Sstevel@tonic-gate lgrp_lineage_add(lgrp_t *newleaf, lgrp_t *oldleaf, klgrpset_t *changed) 8360Sstevel@tonic-gate { 8370Sstevel@tonic-gate klgrpset_t changes; 8380Sstevel@tonic-gate lgrp_t *child; 8390Sstevel@tonic-gate klgrpset_t collapse; 8400Sstevel@tonic-gate int count; 8410Sstevel@tonic-gate int latency; 8420Sstevel@tonic-gate int nlevels; 8430Sstevel@tonic-gate lgrp_t *parent; 8440Sstevel@tonic-gate int proprogate; 8450Sstevel@tonic-gate int total; 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate count = total = 0; 8490Sstevel@tonic-gate if (changed) 8500Sstevel@tonic-gate klgrpset_clear(*changed); 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate if (newleaf == NULL || oldleaf == NULL || newleaf == oldleaf) 8530Sstevel@tonic-gate return (0); 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate #ifdef DEBUG 8560Sstevel@tonic-gate if (lgrp_topo_debug > 0) 8570Sstevel@tonic-gate prom_printf("\nlgrp_lineage_add(0x%p[%d],0x%p[%d],0x%p)\n", 858*7632SNick.Todd@Sun.COM (void *)newleaf, newleaf->lgrp_id, 859*7632SNick.Todd@Sun.COM (void *)oldleaf, oldleaf->lgrp_id, 860*7632SNick.Todd@Sun.COM (void *)changed); 8610Sstevel@tonic-gate #endif /* DEBUG */ 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate /* 8640Sstevel@tonic-gate * Get latency between old and new leaves, so we can determine 8650Sstevel@tonic-gate * where the new leaf fits in the old leaf's lineage 8660Sstevel@tonic-gate */ 8670Sstevel@tonic-gate latency = lgrp_plat_latency(oldleaf->lgrp_plathand, 8680Sstevel@tonic-gate newleaf->lgrp_plathand); 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate /* 8710Sstevel@tonic-gate * Determine height of lgroup topology from old leaf to root lgroup, 8720Sstevel@tonic-gate * so height of topology may be limited if necessary 8730Sstevel@tonic-gate */ 8740Sstevel@tonic-gate nlevels = lgrp_topo_height(oldleaf); 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate #ifdef DEBUG 8770Sstevel@tonic-gate if (lgrp_topo_debug > 1) 8780Sstevel@tonic-gate prom_printf("lgrp_lineage_add: latency(%d,%d) 0x%x, ht %d\n", 8790Sstevel@tonic-gate oldleaf->lgrp_id, newleaf->lgrp_id, latency, nlevels); 8800Sstevel@tonic-gate #endif /* DEBUG */ 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * Can't add new leaf to old leaf's lineage if we haven't 8840Sstevel@tonic-gate * determined latency between them yet 8850Sstevel@tonic-gate */ 8860Sstevel@tonic-gate if (latency == 0) 8870Sstevel@tonic-gate return (0); 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate child = oldleaf; 8900Sstevel@tonic-gate parent = child->lgrp_parent; 8910Sstevel@tonic-gate proprogate = 0; 8920Sstevel@tonic-gate klgrpset_clear(collapse); 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* 8950Sstevel@tonic-gate * Lineage of old leaf is basically a sorted list of the other leaves 8960Sstevel@tonic-gate * from closest to farthest, so find where to add new leaf to the 8970Sstevel@tonic-gate * lineage and proprogate its resources from that point up to the root 8980Sstevel@tonic-gate * lgroup since parent lgroups contain all the resources of their 8990Sstevel@tonic-gate * children 9000Sstevel@tonic-gate */ 9010Sstevel@tonic-gate do { 9020Sstevel@tonic-gate klgrpset_t rset[LGRP_RSRC_COUNT]; 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate #ifdef DEBUG 9050Sstevel@tonic-gate if (lgrp_topo_debug > 1) 9060Sstevel@tonic-gate prom_printf("lgrp_lineage_add: child %d (0x%p), parent" 9070Sstevel@tonic-gate " %d (0x%p)\n", 908*7632SNick.Todd@Sun.COM child->lgrp_id, (void *)child, 909*7632SNick.Todd@Sun.COM parent->lgrp_id, (void *)parent); 9100Sstevel@tonic-gate #endif /* DEBUG */ 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate /* 9130Sstevel@tonic-gate * See whether parent lgroup needs to be split 9140Sstevel@tonic-gate * 9150Sstevel@tonic-gate * May need to split parent lgroup when it is ancestor to more 9160Sstevel@tonic-gate * than one leaf, but all its leaves don't have latency to new 9170Sstevel@tonic-gate * leaf within the parent lgroup's latency 9180Sstevel@tonic-gate * NOTE: Don't want to collapse this lgroup since we just split 9190Sstevel@tonic-gate * it from parent 9200Sstevel@tonic-gate */ 9210Sstevel@tonic-gate count = lgrp_split(oldleaf, newleaf, child, &changes); 9220Sstevel@tonic-gate if (count) { 9230Sstevel@tonic-gate #ifdef DEBUG 9240Sstevel@tonic-gate if (lgrp_topo_debug > 0) 9250Sstevel@tonic-gate prom_printf("lgrp_lineage_add: setting parent" 9260Sstevel@tonic-gate " for child %d from %d to %d\n", 9270Sstevel@tonic-gate child->lgrp_id, parent->lgrp_id, 9280Sstevel@tonic-gate child->lgrp_parent->lgrp_id); 9290Sstevel@tonic-gate #endif /* DEBUG */ 9300Sstevel@tonic-gate parent = child->lgrp_parent; 9310Sstevel@tonic-gate total += count; 9320Sstevel@tonic-gate if (changed) 9330Sstevel@tonic-gate klgrpset_or(*changed, changes); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate /* 9370Sstevel@tonic-gate * Already found where resources of new leaf belong in old 9380Sstevel@tonic-gate * leaf's lineage, so proprogate resources of new leaf up 9390Sstevel@tonic-gate * through rest of ancestors 9400Sstevel@tonic-gate */ 9410Sstevel@tonic-gate if (proprogate) { 9420Sstevel@tonic-gate total += lgrp_proprogate(newleaf, child, latency, 9430Sstevel@tonic-gate &changes); 9440Sstevel@tonic-gate if (changed) 9450Sstevel@tonic-gate klgrpset_or(*changed, changes); 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate parent = child->lgrp_parent; 9480Sstevel@tonic-gate klgrpset_add(collapse, parent->lgrp_id); 9490Sstevel@tonic-gate child = parent; 9500Sstevel@tonic-gate parent = parent->lgrp_parent; 9510Sstevel@tonic-gate continue; 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate #ifdef DEBUG 9550Sstevel@tonic-gate if (lgrp_topo_debug > 1) 9560Sstevel@tonic-gate prom_printf("lgrp_lineage_add: latency 0x%x," 9570Sstevel@tonic-gate " parent latency 0x%x\n", 9580Sstevel@tonic-gate latency, parent->lgrp_latency); 9590Sstevel@tonic-gate #endif /* DEBUG */ 9600Sstevel@tonic-gate /* 9610Sstevel@tonic-gate * As we work our way from the old leaf to the root lgroup, 9620Sstevel@tonic-gate * new leaf resources should go in between two lgroups or into 9630Sstevel@tonic-gate * one of the parent lgroups somewhere along the line 9640Sstevel@tonic-gate */ 9650Sstevel@tonic-gate if (latency < parent->lgrp_latency) { 9660Sstevel@tonic-gate lgrp_t *intermed; 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate /* 9690Sstevel@tonic-gate * New leaf resources should go in between current 9700Sstevel@tonic-gate * child and parent 9710Sstevel@tonic-gate */ 9720Sstevel@tonic-gate #ifdef DEBUG 9730Sstevel@tonic-gate if (lgrp_topo_debug > 0) 9740Sstevel@tonic-gate prom_printf("lgrp_lineage_add: " 9750Sstevel@tonic-gate "latency < parent latency\n"); 9760Sstevel@tonic-gate #endif /* DEBUG */ 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate /* 9790Sstevel@tonic-gate * Create lgroup with desired resources and insert it 9800Sstevel@tonic-gate * between child and parent 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate lgrp_rsets_copy(child->lgrp_set, rset); 9830Sstevel@tonic-gate lgrp_rsets_add(newleaf->lgrp_set, rset); 9840Sstevel@tonic-gate if (nlevels >= lgrp_topo_levels) { 9850Sstevel@tonic-gate if (parent == lgrp_root) 9860Sstevel@tonic-gate break; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate #ifdef DEBUG 9890Sstevel@tonic-gate if (lgrp_topo_debug > 0) { 9900Sstevel@tonic-gate prom_printf("lgrp_lineage_add: " 9910Sstevel@tonic-gate "replaced parent lgrp %d at 0x%p" 9920Sstevel@tonic-gate " for lgrp %d\n", 993*7632SNick.Todd@Sun.COM parent->lgrp_id, (void *)parent, 9940Sstevel@tonic-gate child->lgrp_id); 9950Sstevel@tonic-gate lgrp_rsets_print("old parent" 9960Sstevel@tonic-gate " resources:", parent->lgrp_set); 9970Sstevel@tonic-gate lgrp_rsets_print("new parent " 9980Sstevel@tonic-gate "resources:", rset); 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate #endif /* DEBUG */ 10010Sstevel@tonic-gate /* 10020Sstevel@tonic-gate * Replace contents of parent with new 10030Sstevel@tonic-gate * leaf + child resources since new leaf is 10040Sstevel@tonic-gate * closer and shift its parent's resources to 10050Sstevel@tonic-gate * its parent, etc. until root lgroup reached 10060Sstevel@tonic-gate */ 10070Sstevel@tonic-gate lgrp_rsets_replace(rset, latency, parent, 1); 10080Sstevel@tonic-gate if (*changed) 10090Sstevel@tonic-gate klgrpset_or(*changed, parent->lgrp_id); 10100Sstevel@tonic-gate total++; 10110Sstevel@tonic-gate proprogate++; 10120Sstevel@tonic-gate } else { 10130Sstevel@tonic-gate total += lgrp_new_parent(child, latency, rset, 10140Sstevel@tonic-gate &changes); 10150Sstevel@tonic-gate intermed = child->lgrp_parent; 10160Sstevel@tonic-gate klgrpset_add(collapse, intermed->lgrp_id); 10170Sstevel@tonic-gate if (changed) 10180Sstevel@tonic-gate klgrpset_or(*changed, changes); 10190Sstevel@tonic-gate child = intermed; 10200Sstevel@tonic-gate proprogate++; 10210Sstevel@tonic-gate #ifdef DEBUG 10220Sstevel@tonic-gate if (lgrp_topo_debug > 0) { 10230Sstevel@tonic-gate prom_printf("lgrp_lineage_add: new " 10240Sstevel@tonic-gate "parent lgrp %d at 0x%p for " 10250Sstevel@tonic-gate "lgrp %d\n", intermed->lgrp_id, 1026*7632SNick.Todd@Sun.COM (void *)intermed, child->lgrp_id); 10270Sstevel@tonic-gate lgrp_rsets_print("new parent " 10280Sstevel@tonic-gate "resources:", rset); 10290Sstevel@tonic-gate } 10300Sstevel@tonic-gate #endif /* DEBUG */ 10310Sstevel@tonic-gate continue; 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate } else if (latency == parent->lgrp_latency) { 10350Sstevel@tonic-gate /* 10360Sstevel@tonic-gate * New leaf resources should go into parent 10370Sstevel@tonic-gate */ 10380Sstevel@tonic-gate #ifdef DEBUG 10390Sstevel@tonic-gate if (lgrp_topo_debug > 0) 10400Sstevel@tonic-gate prom_printf("lgrp_lineage_add: latency == " 10410Sstevel@tonic-gate "parent latency\n"); 10420Sstevel@tonic-gate #endif /* DEBUG */ 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate /* 10450Sstevel@tonic-gate * It's already there, so don't need to do anything. 10460Sstevel@tonic-gate */ 10470Sstevel@tonic-gate if (lgrp_rsets_member_all(parent->lgrp_set, 10480Sstevel@tonic-gate newleaf->lgrp_id)) 10490Sstevel@tonic-gate break; 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate total += lgrp_proprogate(newleaf, child, latency, 10520Sstevel@tonic-gate &changes); 10530Sstevel@tonic-gate parent = child->lgrp_parent; 10540Sstevel@tonic-gate klgrpset_add(collapse, parent->lgrp_id); 10550Sstevel@tonic-gate if (changed) 10560Sstevel@tonic-gate klgrpset_or(*changed, changes); 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate proprogate++; 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate child = parent; 10620Sstevel@tonic-gate parent = parent->lgrp_parent; 10630Sstevel@tonic-gate } while (parent != NULL); 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate /* 10660Sstevel@tonic-gate * Consolidate any duplicate lgroups of ones just changed 10670Sstevel@tonic-gate * Assume that there were no duplicates before last round of changes 10680Sstevel@tonic-gate */ 10690Sstevel@tonic-gate #ifdef DEBUG 10700Sstevel@tonic-gate if (lgrp_topo_debug > 1) 10710Sstevel@tonic-gate prom_printf("lgrp_lineage_add: collapsing dups....\n"); 10720Sstevel@tonic-gate #endif /* DEBUG */ 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate total += lgrp_collapse_dups(collapse, lgrp_collapse_equidist, 10750Sstevel@tonic-gate &changes); 10760Sstevel@tonic-gate if (changed) 10770Sstevel@tonic-gate klgrpset_or(*changed, changes); 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate #ifdef DEBUG 10800Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 10810Sstevel@tonic-gate prom_printf("lgrp_lineage_add: changed %d lgrps: 0x%llx\n", 10820Sstevel@tonic-gate total, (u_longlong_t)*changed); 10830Sstevel@tonic-gate #endif /* DEBUG */ 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate return (total); 10860Sstevel@tonic-gate } 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate /* 10900Sstevel@tonic-gate * Add leaf lgroup to lgroup topology 10910Sstevel@tonic-gate */ 10920Sstevel@tonic-gate int 10930Sstevel@tonic-gate lgrp_leaf_add(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count, 10940Sstevel@tonic-gate klgrpset_t *changed) 10950Sstevel@tonic-gate { 10960Sstevel@tonic-gate klgrpset_t changes; 10970Sstevel@tonic-gate int count; 10980Sstevel@tonic-gate int i; 10990Sstevel@tonic-gate int latency; 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 || 11020Sstevel@tonic-gate !lgrp_initialized); 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate #ifdef DEBUG 11050Sstevel@tonic-gate if (lgrp_topo_debug > 1) 11060Sstevel@tonic-gate prom_printf("\nlgrp_leaf_add(0x%p[%d],0x%p,%d,0x%p)\n", 1107*7632SNick.Todd@Sun.COM (void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count, 1108*7632SNick.Todd@Sun.COM (void *)changed); 11090Sstevel@tonic-gate #endif /* DEBUG */ 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate count = 0; 11120Sstevel@tonic-gate if (changed) 11130Sstevel@tonic-gate klgrpset_clear(*changed); 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate /* 11160Sstevel@tonic-gate * Initialize parent of leaf lgroup to root 11170Sstevel@tonic-gate */ 11180Sstevel@tonic-gate if (leaf->lgrp_parent == NULL) { 11190Sstevel@tonic-gate leaf->lgrp_parent = lgrp_root; 11200Sstevel@tonic-gate lgrp_root->lgrp_childcnt++; 11210Sstevel@tonic-gate klgrpset_add(lgrp_root->lgrp_children, leaf->lgrp_id); 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate klgrpset_or(lgrp_root->lgrp_leaves, leaf->lgrp_leaves); 11240Sstevel@tonic-gate lgrp_rsets_add(leaf->lgrp_set, lgrp_root->lgrp_set); 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate #ifdef DEBUG 11270Sstevel@tonic-gate if (lgrp_topo_debug > 1) 11280Sstevel@tonic-gate lgrp_rsets_print("lgrp_leaf_add: root lgrp resources", 11290Sstevel@tonic-gate lgrp_root->lgrp_set); 11300Sstevel@tonic-gate #endif /* DEBUG */ 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate if (changed) { 11330Sstevel@tonic-gate klgrpset_add(*changed, lgrp_root->lgrp_id); 11340Sstevel@tonic-gate klgrpset_add(*changed, leaf->lgrp_id); 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate count += 2; 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate /* 11400Sstevel@tonic-gate * Can't add leaf lgroup to rest of topology (and vice versa) unless 11410Sstevel@tonic-gate * latency for it is available 11420Sstevel@tonic-gate */ 11430Sstevel@tonic-gate latency = lgrp_plat_latency(leaf->lgrp_plathand, leaf->lgrp_plathand); 11440Sstevel@tonic-gate if (latency == 0) { 11450Sstevel@tonic-gate #ifdef DEBUG 11460Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 11470Sstevel@tonic-gate prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n", 11480Sstevel@tonic-gate count, (u_longlong_t)*changed); 11490Sstevel@tonic-gate #endif /* DEBUG */ 11500Sstevel@tonic-gate return (count); 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate /* 11540Sstevel@tonic-gate * Make sure that root and leaf lgroup latencies are set 11550Sstevel@tonic-gate */ 11560Sstevel@tonic-gate lgrp_root->lgrp_latency = lgrp_plat_latency(lgrp_root->lgrp_plathand, 11570Sstevel@tonic-gate lgrp_root->lgrp_plathand); 11580Sstevel@tonic-gate leaf->lgrp_latency = latency; 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* 11610Sstevel@tonic-gate * Add leaf to lineage of other leaves and vice versa 11620Sstevel@tonic-gate * since leaves come into existence at different times 11630Sstevel@tonic-gate */ 11640Sstevel@tonic-gate for (i = 0; i < lgrp_count; i++) { 11650Sstevel@tonic-gate lgrp_t *lgrp; 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate lgrp = lgrps[i]; 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate /* 11700Sstevel@tonic-gate * Skip non-existent lgroups, new leaf lgroup, and 11710Sstevel@tonic-gate * non-leaf lgroups 11720Sstevel@tonic-gate */ 11730Sstevel@tonic-gate if (!LGRP_EXISTS(lgrp) || lgrp == leaf || 11740Sstevel@tonic-gate lgrp->lgrp_childcnt != 0) { 11750Sstevel@tonic-gate #ifdef DEBUG 11760Sstevel@tonic-gate if (lgrp_topo_debug > 1) 11770Sstevel@tonic-gate prom_printf("lgrp_leaf_add: skip " 11780Sstevel@tonic-gate "lgrp %d at 0x%p\n", 1179*7632SNick.Todd@Sun.COM lgrp->lgrp_id, (void *)lgrp); 11800Sstevel@tonic-gate #endif /* DEBUG */ 11810Sstevel@tonic-gate continue; 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate #ifdef DEBUG 11850Sstevel@tonic-gate if (lgrp_topo_debug > 0) 11860Sstevel@tonic-gate prom_printf("lgrp_leaf_add: lgrp %d (0x%p) =>" 11870Sstevel@tonic-gate " lgrp %d (0x%p)\n", 1188*7632SNick.Todd@Sun.COM leaf->lgrp_id, (void *)leaf, lgrp->lgrp_id, 1189*7632SNick.Todd@Sun.COM (void *)lgrp); 11900Sstevel@tonic-gate #endif /* DEBUG */ 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate count += lgrp_lineage_add(leaf, lgrp, &changes); 11930Sstevel@tonic-gate if (changed) 11940Sstevel@tonic-gate klgrpset_or(*changed, changes); 11950Sstevel@tonic-gate 11960Sstevel@tonic-gate count += lgrp_lineage_add(lgrp, leaf, &changes); 11970Sstevel@tonic-gate if (changed) 11980Sstevel@tonic-gate klgrpset_or(*changed, changes); 11990Sstevel@tonic-gate } 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate #ifdef DEBUG 12020Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 12030Sstevel@tonic-gate prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n", 12040Sstevel@tonic-gate count, (u_longlong_t)*changed); 12050Sstevel@tonic-gate #endif /* DEBUG */ 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate return (count); 12080Sstevel@tonic-gate } 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate /* 12120Sstevel@tonic-gate * Remove resources of leaf from lgroup hierarchy 12130Sstevel@tonic-gate */ 12140Sstevel@tonic-gate int 12150Sstevel@tonic-gate lgrp_leaf_delete(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count, 12160Sstevel@tonic-gate klgrpset_t *changed) 12170Sstevel@tonic-gate { 12180Sstevel@tonic-gate klgrpset_t changes; 12190Sstevel@tonic-gate klgrpset_t collapse; 12200Sstevel@tonic-gate int count; 12210Sstevel@tonic-gate int i; 12220Sstevel@tonic-gate lgrp_t *lgrp; 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 || 12250Sstevel@tonic-gate !lgrp_initialized); 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate count = 0; 12280Sstevel@tonic-gate klgrpset_clear(collapse); 12290Sstevel@tonic-gate if (changed) 12300Sstevel@tonic-gate klgrpset_clear(*changed); 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate /* 12330Sstevel@tonic-gate * Nothing to do if no leaf given 12340Sstevel@tonic-gate */ 12350Sstevel@tonic-gate if (leaf == NULL) 12360Sstevel@tonic-gate return (0); 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate #ifdef DEBUG 12390Sstevel@tonic-gate if (lgrp_topo_debug > 0) 12400Sstevel@tonic-gate prom_printf("lgrp_leaf_delete(0x%p[%d],0x%p,%d,0x%p)\n", 1241*7632SNick.Todd@Sun.COM (void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count, 1242*7632SNick.Todd@Sun.COM (void *)changed); 12430Sstevel@tonic-gate #endif /* DEBUG */ 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate /* 12460Sstevel@tonic-gate * Remove leaf from any lgroups containing its resources 12470Sstevel@tonic-gate */ 12480Sstevel@tonic-gate for (i = 0; i < lgrp_count; i++) { 12490Sstevel@tonic-gate lgrp = lgrps[i]; 12500Sstevel@tonic-gate if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE || 12510Sstevel@tonic-gate !lgrp_rsets_member(lgrp->lgrp_set, leaf->lgrp_id)) 12520Sstevel@tonic-gate continue; 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate #ifdef DEBUG 12550Sstevel@tonic-gate if (lgrp_topo_debug > 0) 12560Sstevel@tonic-gate prom_printf("lgrp_leaf_delete: remove leaf from" 1257*7632SNick.Todd@Sun.COM " lgrp %d at %p\n", lgrp->lgrp_id, (void *)lgrp); 12580Sstevel@tonic-gate #endif /* DEBUG */ 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate lgrp_rsets_delete(lgrp, leaf->lgrp_id, 0); 12610Sstevel@tonic-gate klgrpset_del(lgrp->lgrp_leaves, leaf->lgrp_id); 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate klgrpset_add(collapse, lgrp->lgrp_id); 12640Sstevel@tonic-gate count++; 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate /* 12680Sstevel@tonic-gate * Remove leaf and its ancestors that don't have any other children 12690Sstevel@tonic-gate */ 12700Sstevel@tonic-gate #ifdef DEBUG 12710Sstevel@tonic-gate if (lgrp_topo_debug > 1) 12720Sstevel@tonic-gate prom_printf("lgrp_leaf_delete: remove leaf and ancestors\n"); 12730Sstevel@tonic-gate #endif /* DEBUG */ 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate count += lgrp_ancestor_delete(leaf, &changes); 12760Sstevel@tonic-gate klgrpset_or(collapse, changes); 12770Sstevel@tonic-gate klgrpset_add(collapse, leaf->lgrp_id); 12780Sstevel@tonic-gate count++; 12790Sstevel@tonic-gate lgrp_destroy(leaf); 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate /* 12820Sstevel@tonic-gate * Consolidate any duplicate lgroups of ones just changed 12830Sstevel@tonic-gate * Assume that there were no duplicates before last round of changes 12840Sstevel@tonic-gate */ 12850Sstevel@tonic-gate #ifdef DEBUG 12860Sstevel@tonic-gate if (lgrp_topo_debug > 1) 12870Sstevel@tonic-gate prom_printf("lgrp_leaf_delete: collapsing dups\n"); 12880Sstevel@tonic-gate #endif /* DEBUG */ 12890Sstevel@tonic-gate count += lgrp_collapse_dups(collapse, lgrp_collapse_equidist, 12900Sstevel@tonic-gate &changes); 12910Sstevel@tonic-gate klgrpset_or(collapse, changes); 12920Sstevel@tonic-gate if (changed) 12930Sstevel@tonic-gate klgrpset_copy(*changed, collapse); 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate #ifdef DEBUG 12960Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 12970Sstevel@tonic-gate prom_printf("lgrp_leaf_delete: changed %d lgrps: 0x%llx\n", 12980Sstevel@tonic-gate count, (u_longlong_t)*changed); 12990Sstevel@tonic-gate #endif /* DEBUG */ 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate return (count); 13020Sstevel@tonic-gate } 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate 13050Sstevel@tonic-gate /* 13060Sstevel@tonic-gate * Flatten lgroup topology down to height specified 13070Sstevel@tonic-gate */ 13080Sstevel@tonic-gate int 13090Sstevel@tonic-gate lgrp_topo_flatten(int levels, lgrp_t **lgrps, int lgrp_count, 13100Sstevel@tonic-gate klgrpset_t *changed) 13110Sstevel@tonic-gate { 13120Sstevel@tonic-gate int count; 13130Sstevel@tonic-gate int i; 13140Sstevel@tonic-gate lgrp_t *lgrp; 13155608Srv207048 lgrp_handle_t hdl; 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate /* 13180Sstevel@tonic-gate * Only flatten down to 2 level for now 13190Sstevel@tonic-gate */ 13200Sstevel@tonic-gate if (levels != 2) 13210Sstevel@tonic-gate return (0); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate /* 13240Sstevel@tonic-gate * Look for non-leaf lgroups to remove and leaf lgroups to reparent 13250Sstevel@tonic-gate */ 13260Sstevel@tonic-gate count = 0; 13270Sstevel@tonic-gate for (i = 0; i <= lgrp_count; i++) { 13280Sstevel@tonic-gate /* 13290Sstevel@tonic-gate * Skip non-existent lgroups and root 13300Sstevel@tonic-gate */ 13310Sstevel@tonic-gate lgrp = lgrps[i]; 13325602Srv207048 if (!LGRP_EXISTS(lgrp)) 13330Sstevel@tonic-gate continue; 13340Sstevel@tonic-gate 13355608Srv207048 hdl = lgrp->lgrp_plathand; 13365608Srv207048 13375608Srv207048 if (lgrp == lgrp_root) { 13385608Srv207048 lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl); 13395602Srv207048 continue; 13405602Srv207048 } 13415602Srv207048 13420Sstevel@tonic-gate if (lgrp->lgrp_childcnt > 0) { 13430Sstevel@tonic-gate lgrp_t *parent; 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate /* 13460Sstevel@tonic-gate * Remove non-leaf lgroup from lgroup topology 13470Sstevel@tonic-gate */ 13480Sstevel@tonic-gate parent = lgrp->lgrp_parent; 13490Sstevel@tonic-gate if (changed) { 13500Sstevel@tonic-gate klgrpset_add(*changed, lgrp->lgrp_id); 13510Sstevel@tonic-gate klgrpset_add(*changed, parent->lgrp_id); 13520Sstevel@tonic-gate count += 2; 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate if (parent) { 13550Sstevel@tonic-gate klgrpset_del(parent->lgrp_children, 13560Sstevel@tonic-gate lgrp->lgrp_id); 13570Sstevel@tonic-gate parent->lgrp_childcnt--; 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate lgrp_destroy(lgrp); 13600Sstevel@tonic-gate } else if (lgrp->lgrp_parent != lgrp_root) { 13610Sstevel@tonic-gate /* 13620Sstevel@tonic-gate * Reparent leaf lgroup to root 13630Sstevel@tonic-gate */ 13640Sstevel@tonic-gate if (changed) { 13650Sstevel@tonic-gate klgrpset_add(*changed, lgrp_root->lgrp_id); 13660Sstevel@tonic-gate klgrpset_add(*changed, lgrp->lgrp_id); 13670Sstevel@tonic-gate count += 2; 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate lgrp->lgrp_parent = lgrp_root; 13700Sstevel@tonic-gate klgrpset_add(lgrp_root->lgrp_children, lgrp->lgrp_id); 13710Sstevel@tonic-gate lgrp_root->lgrp_childcnt++; 13720Sstevel@tonic-gate klgrpset_add(lgrp_root->lgrp_leaves, lgrp->lgrp_id); 13735602Srv207048 13745608Srv207048 lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl); 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate } 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate return (count); 13790Sstevel@tonic-gate } 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate /* 13830Sstevel@tonic-gate * Return current height limit for lgroup topology 13840Sstevel@tonic-gate */ 13850Sstevel@tonic-gate int 13860Sstevel@tonic-gate lgrp_topo_ht_limit(void) 13870Sstevel@tonic-gate { 13880Sstevel@tonic-gate return (lgrp_topo_levels); 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate /* 13930Sstevel@tonic-gate * Return default height limit for lgroup topology 13940Sstevel@tonic-gate */ 13950Sstevel@tonic-gate int 13960Sstevel@tonic-gate lgrp_topo_ht_limit_default(void) 13970Sstevel@tonic-gate { 13980Sstevel@tonic-gate return (LGRP_TOPO_LEVELS); 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate /* 14030Sstevel@tonic-gate * Set height limit for lgroup topology 14040Sstevel@tonic-gate */ 14050Sstevel@tonic-gate int 14060Sstevel@tonic-gate lgrp_topo_ht_limit_set(int ht) 14070Sstevel@tonic-gate { 14080Sstevel@tonic-gate if (ht > LGRP_TOPO_LEVELS_MAX) 14090Sstevel@tonic-gate lgrp_topo_levels = LGRP_TOPO_LEVELS_MAX; 14100Sstevel@tonic-gate else 14110Sstevel@tonic-gate lgrp_topo_levels = ht; 14120Sstevel@tonic-gate 14130Sstevel@tonic-gate return (ht); 14140Sstevel@tonic-gate } 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate /* 14180Sstevel@tonic-gate * Update lgroup topology for any leaves that don't have their latency set 14190Sstevel@tonic-gate * 14200Sstevel@tonic-gate * This may happen on some machines when the lgroup platform support doesn't 14210Sstevel@tonic-gate * know the latencies between nodes soon enough to provide it when the 14220Sstevel@tonic-gate * resources are being added. If the lgroup platform code needs to probe 14230Sstevel@tonic-gate * memory to determine the latencies between nodes, it must wait until the 14240Sstevel@tonic-gate * CPUs become active so at least one CPU in each node can probe memory in 14250Sstevel@tonic-gate * each node. 14260Sstevel@tonic-gate */ 14270Sstevel@tonic-gate int 14280Sstevel@tonic-gate lgrp_topo_update(lgrp_t **lgrps, int lgrp_count, klgrpset_t *changed) 14290Sstevel@tonic-gate { 14300Sstevel@tonic-gate klgrpset_t changes; 14310Sstevel@tonic-gate int count; 14320Sstevel@tonic-gate int i; 14330Sstevel@tonic-gate lgrp_t *lgrp; 14340Sstevel@tonic-gate 14350Sstevel@tonic-gate count = 0; 14360Sstevel@tonic-gate if (changed) 14370Sstevel@tonic-gate klgrpset_clear(*changed); 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate /* 14400Sstevel@tonic-gate * For UMA machines, make sure that root lgroup contains all 14410Sstevel@tonic-gate * resources. The root lgrp should also name itself as its own leaf 14420Sstevel@tonic-gate */ 14430Sstevel@tonic-gate if (nlgrps == 1) { 14440Sstevel@tonic-gate for (i = 0; i < LGRP_RSRC_COUNT; i++) 14450Sstevel@tonic-gate klgrpset_add(lgrp_root->lgrp_set[i], 14460Sstevel@tonic-gate lgrp_root->lgrp_id); 14470Sstevel@tonic-gate klgrpset_add(lgrp_root->lgrp_leaves, lgrp_root->lgrp_id); 14480Sstevel@tonic-gate return (0); 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate mutex_enter(&cpu_lock); 14520Sstevel@tonic-gate pause_cpus(NULL); 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate /* 14550Sstevel@tonic-gate * Look for any leaf lgroup without its latency set, finish adding it 14560Sstevel@tonic-gate * to the lgroup topology assuming that it exists and has the root 14570Sstevel@tonic-gate * lgroup as its parent, and update the memory nodes of all lgroups 14580Sstevel@tonic-gate * that have it as a memory resource. 14590Sstevel@tonic-gate */ 14600Sstevel@tonic-gate for (i = 0; i < lgrp_count; i++) { 14610Sstevel@tonic-gate lgrp = lgrps[i]; 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate /* 14640Sstevel@tonic-gate * Skip non-existent and non-leaf lgroups and any lgroup 14650Sstevel@tonic-gate * with its latency set already 14660Sstevel@tonic-gate */ 14670Sstevel@tonic-gate if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE || 14680Sstevel@tonic-gate lgrp->lgrp_childcnt != 0 || lgrp->lgrp_latency != 0) 14690Sstevel@tonic-gate continue; 14700Sstevel@tonic-gate 14710Sstevel@tonic-gate #ifdef DEBUG 14720Sstevel@tonic-gate if (lgrp_topo_debug > 1) { 14730Sstevel@tonic-gate prom_printf("\nlgrp_topo_update: updating lineage " 1474*7632SNick.Todd@Sun.COM "of lgrp %d at 0x%p\n", lgrp->lgrp_id, 1475*7632SNick.Todd@Sun.COM (void *)lgrp); 14760Sstevel@tonic-gate } 14770Sstevel@tonic-gate #endif /* DEBUG */ 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate count += lgrp_leaf_add(lgrp, lgrps, lgrp_count, &changes); 14800Sstevel@tonic-gate if (changed) 14810Sstevel@tonic-gate klgrpset_or(*changed, changes); 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate if (!klgrpset_isempty(changes)) 14840Sstevel@tonic-gate (void) lgrp_mnode_update(changes, NULL); 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate #ifdef DEBUG 14870Sstevel@tonic-gate if (lgrp_topo_debug > 1 && changed) 14880Sstevel@tonic-gate prom_printf("lgrp_topo_update: changed %d lgrps: " 14890Sstevel@tonic-gate "0x%llx\n", 14900Sstevel@tonic-gate count, (u_longlong_t)*changed); 14910Sstevel@tonic-gate #endif /* DEBUG */ 14920Sstevel@tonic-gate } 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate if (lgrp_topo_levels < LGRP_TOPO_LEVELS && lgrp_topo_levels == 2) { 14950Sstevel@tonic-gate count += lgrp_topo_flatten(2, lgrps, lgrp_count, changed); 14960Sstevel@tonic-gate (void) lpl_topo_flatten(2); 14970Sstevel@tonic-gate } 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate start_cpus(); 15000Sstevel@tonic-gate mutex_exit(&cpu_lock); 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate return (count); 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate #ifdef DEBUG 15060Sstevel@tonic-gate void 15070Sstevel@tonic-gate lgrp_print(lgrp_t *lgrp) 15080Sstevel@tonic-gate { 15090Sstevel@tonic-gate lgrp_t *parent; 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate prom_printf("LGRP %d", lgrp->lgrp_id); 15120Sstevel@tonic-gate if (lgrp->lgrp_childcnt == 0) 15130Sstevel@tonic-gate prom_printf(" (plathand %p)\n", 15140Sstevel@tonic-gate (void *)lgrp->lgrp_plathand); 15150Sstevel@tonic-gate else 15160Sstevel@tonic-gate prom_printf("\n"); 15170Sstevel@tonic-gate 15180Sstevel@tonic-gate prom_printf("\tlatency %d\n", lgrp->lgrp_latency); 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate lgrp_rsets_print("\tresources", lgrp->lgrp_set); 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate parent = lgrp->lgrp_parent; 1523*7632SNick.Todd@Sun.COM prom_printf("\tparent 0x%p", (void *)parent); 15240Sstevel@tonic-gate if (parent) 15250Sstevel@tonic-gate prom_printf("[%d]\n", parent->lgrp_id); 15260Sstevel@tonic-gate else 15270Sstevel@tonic-gate prom_printf("\n"); 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate prom_printf("\tchild count %d, children ", lgrp->lgrp_childcnt); 15300Sstevel@tonic-gate klgrpset_print(lgrp->lgrp_children); 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate prom_printf("\tleaves "); 15330Sstevel@tonic-gate klgrpset_print(lgrp->lgrp_leaves); 15340Sstevel@tonic-gate } 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate 15370Sstevel@tonic-gate void 15380Sstevel@tonic-gate lgrp_topo_print(lgrp_t **lgrps, int lgrp_max) 15390Sstevel@tonic-gate { 15400Sstevel@tonic-gate klgrpset_t siblings; 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate lgrp_print(lgrp_root); 15430Sstevel@tonic-gate siblings = lgrp_root->lgrp_children; 15440Sstevel@tonic-gate while (!klgrpset_isempty(siblings)) { 15450Sstevel@tonic-gate klgrpset_t children; 15460Sstevel@tonic-gate int i; 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate klgrpset_clear(children); 15490Sstevel@tonic-gate for (i = 0; i <= lgrp_max; i++) { 15500Sstevel@tonic-gate lgrp_t *lgrp; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate lgrp = lgrps[i]; 15530Sstevel@tonic-gate if (lgrp == NULL || !klgrpset_ismember(siblings, i)) 15540Sstevel@tonic-gate continue; 15550Sstevel@tonic-gate lgrp_print(lgrp); 15560Sstevel@tonic-gate klgrpset_or(children, lgrp->lgrp_children); 15570Sstevel@tonic-gate } 15580Sstevel@tonic-gate klgrpset_copy(siblings, children); 15590Sstevel@tonic-gate } 15600Sstevel@tonic-gate } 15610Sstevel@tonic-gate #endif /* DEBUG */ 1562