#include <sys/cpupart.h>
#include <sys/lgrp.h>
#include <sys/promif.h>
#include <sys/types.h>
#define LGRP_TOPO_LEVELS 4
#define LGRP_TOPO_LEVELS_MAX 4
int lgrp_collapse_equidist = 1;
int lgrp_collapse_off = 1;
unsigned int lgrp_topo_levels = LGRP_TOPO_LEVELS;
int lgrp_split_off = 1;
#ifdef DEBUG
int lgrp_topo_debug = 0;
void
klgrpset_print(klgrpset_t lgrpset)
{
int i;
prom_printf("0x%llx(", (u_longlong_t)lgrpset);
for (i = 0; i <= lgrp_alloc_max; i++)
if (klgrpset_ismember(lgrpset, i))
prom_printf("%d ", i);
prom_printf(")\n");
}
void
lgrp_rsets_print(char *string, klgrpset_t *rsets)
{
int i;
prom_printf("%s\n", string);
for (i = 0; i < LGRP_RSRC_COUNT; i++)
klgrpset_print(rsets[i]);
}
#endif
void
lgrp_rsets_add(klgrpset_t *from, klgrpset_t *to)
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
klgrpset_or(to[i], from[i]);
}
void
lgrp_rsets_copy(klgrpset_t *from, klgrpset_t *to)
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
to[i] = from[i];
}
void
lgrp_rsets_delete(lgrp_t *lgrp, lgrp_id_t lgrpid, int follow_parent)
{
int i;
while (lgrp != NULL) {
for (i = 0; i < LGRP_RSRC_COUNT; i++)
klgrpset_del(lgrp->lgrp_set[i], lgrpid);
if (!follow_parent)
break;
lgrp = lgrp->lgrp_parent;
}
}
int
lgrp_rsets_empty(klgrpset_t *rset)
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
if (!klgrpset_isempty(rset[i]))
return (0);
return (1);
}
int
lgrp_rsets_equal(klgrpset_t *rset1, klgrpset_t *rset2)
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
if (rset1[i] != rset2[i])
return (0);
return (1);
}
int
lgrp_rsets_member(klgrpset_t *rset, lgrp_id_t lgrpid)
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
if (klgrpset_ismember(rset[i], lgrpid))
return (1);
return (0);
}
int
lgrp_rsets_member_all(klgrpset_t *rset, lgrp_id_t lgrpid)
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
if (!klgrpset_ismember(rset[i], lgrpid))
return (0);
return (1);
}
void
lgrp_rsets_replace(klgrpset_t *rset, int latency, lgrp_t *lgrp, int shift)
{
lgrp_t *cur;
int lat_new;
int lat_saved;
klgrpset_t rset_new[LGRP_RSRC_COUNT];
klgrpset_t rset_saved[LGRP_RSRC_COUNT];
cur = lgrp;
lat_saved = latency;
lgrp_rsets_copy(rset, rset_saved);
while (cur && cur != lgrp_root) {
lgrp_rsets_copy(rset_saved, rset_new);
lgrp_rsets_copy(cur->lgrp_set, rset_saved);
lgrp_rsets_copy(rset_new, cur->lgrp_set);
lat_new = lat_saved;
lat_saved = cur->lgrp_latency;
cur->lgrp_latency = lat_new;
if (!shift)
break;
cur = cur->lgrp_parent;
}
}
void
lgrp_rsets_set(klgrpset_t *to, lgrp_id_t lgrpid)
{
klgrpset_t from;
int i;
klgrpset_clear(from);
klgrpset_add(from, lgrpid);
for (i = 0; i < LGRP_RSRC_COUNT; i++) {
klgrpset_clear(to[i]);
klgrpset_or(to[i], from);
}
}
int
lgrp_ancestor_delete(lgrp_t *child, klgrpset_t *changed)
{
int count;
lgrp_t *current;
lgrp_id_t lgrpid;
lgrp_t *parent;
#ifdef DEBUG
if (lgrp_topo_debug > 1) {
prom_printf("lgrp_ancestor_delete(0x%p[%d],0x%p)\n",
(void *)child, child->lgrp_id, (void *)changed);
}
#endif
count = 0;
if (changed)
klgrpset_clear(*changed);
current = child;
parent = child->lgrp_parent;
lgrpid = current->lgrp_id;
while (parent != NULL) {
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_ancestor_delete: parent %d,"
" current %d\n",
parent->lgrp_id, lgrpid);
#endif
klgrpset_del(parent->lgrp_leaves, lgrpid);
klgrpset_del(parent->lgrp_children, lgrpid);
parent->lgrp_childcnt--;
if (changed)
klgrpset_add(*changed, parent->lgrp_id);
count++;
if (parent->lgrp_childcnt != 0)
break;
current = parent;
parent = current->lgrp_parent;
lgrpid = current->lgrp_id;
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_ancestor_delete: destroy"
" lgrp %d at 0x%p\n",
current->lgrp_id, (void *)current);
#endif
lgrp_destroy(current);
}
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_ancestor_delete: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
int
lgrp_consolidate(lgrp_t *lgrp1, lgrp_t *lgrp2, klgrpset_t *changed)
{
klgrpset_t changes;
lgrp_t *child;
int count;
int i;
lgrp_t *parent;
if (lgrp1 == NULL || lgrp2 == NULL || lgrp1->lgrp_childcnt < 1 ||
lgrp2->lgrp_childcnt < 1)
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_consolidate(0x%p[%d],0x%p[%d],0x%p)\n",
(void *)lgrp1, lgrp1->lgrp_id, (void *)lgrp2,
lgrp2->lgrp_id, (void *)changed);
#endif
count = 0;
if (changed)
klgrpset_clear(*changed);
if (lgrp1->lgrp_latency > lgrp2->lgrp_latency)
lgrp2->lgrp_latency = lgrp1->lgrp_latency;
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_consolidate: delete ancestors\n");
#endif
count += lgrp_ancestor_delete(lgrp1, &changes);
if (changed) {
klgrpset_or(*changed, changes);
klgrpset_or(*changed, lgrp1->lgrp_id);
count++;
}
for (i = 0; i <= lgrp_alloc_max; i++) {
if (i == lgrp2->lgrp_id ||
!klgrpset_ismember(lgrp1->lgrp_children, i))
continue;
child = lgrp_table[i];
if (!LGRP_EXISTS(child))
continue;
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_consolidate: reparent "
"lgrp %d to lgrp %d\n",
child->lgrp_id, lgrp2->lgrp_id);
#endif
klgrpset_or(lgrp2->lgrp_leaves, child->lgrp_leaves);
klgrpset_add(lgrp2->lgrp_children, child->lgrp_id);
lgrp2->lgrp_childcnt++;
child->lgrp_parent = lgrp2;
if (changed) {
klgrpset_add(*changed, child->lgrp_id);
klgrpset_add(*changed, lgrp2->lgrp_id);
}
count += 2;
}
child = lgrp2;
parent = child->lgrp_parent;
while (parent != NULL) {
klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
if (changed)
klgrpset_add(*changed, parent->lgrp_id);
count++;
child = parent;
parent = parent->lgrp_parent;
}
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_consolidate: destroy lgrp %d at 0x%p\n",
lgrp1->lgrp_id, (void *)lgrp1);
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_consolidate: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
lgrp_destroy(lgrp1);
return (count);
}
int
lgrp_collapse_dups(klgrpset_t target_set, int equidist_only,
klgrpset_t *changed)
{
klgrpset_t changes;
int count;
int i;
count = 0;
if (changed)
klgrpset_clear(*changed);
if (lgrp_collapse_off)
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_collapse_dups(0x%llx)\n",
(u_longlong_t)target_set);
#endif
for (i = 0; i <= lgrp_alloc_max; i++) {
int j;
lgrp_t *keep;
lgrp_t *target;
target = lgrp_table[i];
if (!LGRP_EXISTS(target) ||
target == lgrp_root || target->lgrp_childcnt == 0 ||
!klgrpset_ismember(target_set, target->lgrp_id))
continue;
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_collapse_dups: find "
"dups of lgrp %d at 0x%p\n",
target->lgrp_id, (void *)target);
#endif
keep = NULL;
for (j = 0; j <= lgrp_alloc_max; j++) {
lgrp_t *lgrp;
lgrp = lgrp_table[j];
if (!LGRP_EXISTS(lgrp) ||
lgrp->lgrp_childcnt == 0 ||
!lgrp_rsets_equal(lgrp->lgrp_set,
target->lgrp_set) ||
(lgrp->lgrp_latency != target->lgrp_latency &&
equidist_only))
continue;
if (keep == NULL) {
keep = lgrp;
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_collapse_dups: "
"keep lgrp %d at 0x%p\n",
keep->lgrp_id, (void *)keep);
#endif
} else {
if (lgrp == lgrp_root) {
lgrp = keep;
keep = lgrp_root;
}
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_collapse_dups:"
" consolidate lgrp %d at 0x%p"
" into lgrp %d at 0x%p\n",
lgrp->lgrp_id, (void *)lgrp,
keep->lgrp_id, (void *)keep);
#endif
count += lgrp_consolidate(lgrp, keep,
&changes);
if (changed)
klgrpset_or(*changed, changes);
}
}
}
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_collapse_dups: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
int
lgrp_new_parent(lgrp_t *child, int latency, klgrpset_t *rset,
klgrpset_t *changed)
{
int count;
lgrp_t *new;
lgrp_t *old;
count = 0;
if (changed)
klgrpset_clear(*changed);
new = lgrp_create();
new->lgrp_latency = latency;
lgrp_rsets_add(rset, new->lgrp_set);
old = child->lgrp_parent;
new->lgrp_parent = old;
klgrpset_add(new->lgrp_children, child->lgrp_id);
new->lgrp_childcnt++;
klgrpset_add(new->lgrp_children, child->lgrp_id);
klgrpset_copy(new->lgrp_leaves, child->lgrp_leaves);
child->lgrp_parent = new;
if (old) {
klgrpset_del(old->lgrp_children, child->lgrp_id);
klgrpset_add(old->lgrp_children, new->lgrp_id);
if (changed)
klgrpset_add(*changed, old->lgrp_id);
count++;
}
if (changed) {
klgrpset_add(*changed, child->lgrp_id);
klgrpset_add(*changed, new->lgrp_id);
}
count += 2;
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_new_parent: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
int
lgrp_proprogate(lgrp_t *newleaf, lgrp_t *child, int latency,
klgrpset_t *changed)
{
int count;
lgrp_t *parent;
count = 0;
if (changed)
klgrpset_clear(*changed);
if (child == NULL || child->lgrp_parent == NULL)
return (0);
parent = child->lgrp_parent;
klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
if (changed)
klgrpset_add(*changed, parent->lgrp_id);
count++;
if (lgrp_rsets_member_all(parent->lgrp_set, newleaf->lgrp_id)) {
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_proprogate: changed %d lgrps:"
" 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
lgrp_rsets_add(newleaf->lgrp_set, parent->lgrp_set);
#ifdef DEBUG
if (lgrp_topo_debug > 1) {
prom_printf("lgrp_proprogate: newleaf %d(0x%p), "
"latency %d, child %d(0x%p), parent %d(0x%p)\n",
newleaf->lgrp_id, (void *)newleaf, latency, child->lgrp_id,
(void *)child, parent->lgrp_id, (void *)parent);
prom_printf("lgrp_proprogate: parent's leaves becomes 0x%llx\n",
(u_longlong_t)parent->lgrp_leaves);
}
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_proprogate: adding to parent %d (0x%p)\n",
parent->lgrp_id, (void *)parent);
lgrp_rsets_print("parent resources become:", parent->lgrp_set);
}
if (lgrp_topo_debug > 2 && changed)
prom_printf("lgrp_proprogate: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
int
lgrp_split(lgrp_t *oldleaf, lgrp_t *newleaf, lgrp_t *child,
klgrpset_t *changed)
{
klgrpset_t changes;
int count;
int i;
int latency;
lgrp_t *parent;
count = 0;
if (changed)
klgrpset_clear(*changed);
if (lgrp_split_off || newleaf == NULL || child == NULL)
return (0);
parent = child->lgrp_parent;
if (parent == NULL || parent->lgrp_childcnt < 2 || parent == lgrp_root)
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_split(0x%p[%d],0x%p[%d],0x%p[%d],0x%p)\n",
(void *)oldleaf, oldleaf->lgrp_id,
(void *)newleaf, newleaf->lgrp_id,
(void *)child, child->lgrp_id, (void *)changed);
#endif
latency = lgrp_plat_latency(oldleaf->lgrp_plathand,
newleaf->lgrp_plathand);
for (i = 0; i <= lgrp_alloc_max; i++) {
lgrp_t *grandparent;
lgrp_t *lgrp;
int sibling_latency;
lgrp = lgrp_table[i];
if (!LGRP_EXISTS(lgrp) || lgrp == oldleaf ||
!klgrpset_ismember(parent->lgrp_leaves, lgrp->lgrp_id))
continue;
sibling_latency = lgrp_plat_latency(lgrp->lgrp_plathand,
newleaf->lgrp_plathand);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_split: latency(%d,%d) %d,"
" latency(%d,%d) %d\n",
oldleaf->lgrp_id, newleaf->lgrp_id, latency,
lgrp->lgrp_id, newleaf->lgrp_id, sibling_latency);
#endif
if (sibling_latency == latency)
continue;
parent->lgrp_childcnt--;
klgrpset_del(parent->lgrp_children, child->lgrp_id);
klgrpset_del(parent->lgrp_leaves, oldleaf->lgrp_id);
grandparent = parent->lgrp_parent;
if (grandparent) {
grandparent->lgrp_childcnt++;
klgrpset_add(grandparent->lgrp_children,
child->lgrp_id);
count++;
if (changed)
klgrpset_add(*changed, grandparent->lgrp_id);
}
child->lgrp_parent = grandparent;
count += lgrp_new_parent(child, parent->lgrp_latency,
parent->lgrp_set, &changes);
if (changed) {
klgrpset_or(*changed, changes);
klgrpset_add(*changed, parent->lgrp_id);
klgrpset_add(*changed, child->lgrp_id);
count += 2;
}
parent = child->lgrp_parent;
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_split: new parent %d (0x%p) for"
" lgrp %d (0x%p)\n",
parent->lgrp_id, (void *)parent,
child->lgrp_id, (void *)child);
lgrp_rsets_print("new parent resources:",
parent->lgrp_set);
}
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_split: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_split: no changes\n");
#endif
return (count);
}
int
lgrp_topo_height(lgrp_t *lgrp)
{
int nlevels;
if (!LGRP_EXISTS(lgrp))
return (0);
nlevels = 0;
while (lgrp != NULL) {
lgrp = lgrp->lgrp_parent;
nlevels++;
}
return (nlevels);
}
int
lgrp_lineage_add(lgrp_t *newleaf, lgrp_t *oldleaf, klgrpset_t *changed)
{
klgrpset_t changes;
lgrp_t *child;
klgrpset_t collapse;
int count;
int latency;
int nlevels;
lgrp_t *parent;
int proprogate;
int total;
count = total = 0;
if (changed)
klgrpset_clear(*changed);
if (newleaf == NULL || oldleaf == NULL || newleaf == oldleaf)
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("\nlgrp_lineage_add(0x%p[%d],0x%p[%d],0x%p)\n",
(void *)newleaf, newleaf->lgrp_id,
(void *)oldleaf, oldleaf->lgrp_id,
(void *)changed);
#endif
latency = lgrp_plat_latency(oldleaf->lgrp_plathand,
newleaf->lgrp_plathand);
nlevels = lgrp_topo_height(oldleaf);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: latency(%d,%d) 0x%x, ht %d\n",
oldleaf->lgrp_id, newleaf->lgrp_id, latency, nlevels);
#endif
if (latency == 0)
return (0);
child = oldleaf;
parent = child->lgrp_parent;
proprogate = 0;
klgrpset_clear(collapse);
do {
klgrpset_t rset[LGRP_RSRC_COUNT];
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: child %d (0x%p), parent"
" %d (0x%p)\n",
child->lgrp_id, (void *)child,
parent->lgrp_id, (void *)parent);
#endif
count = lgrp_split(oldleaf, newleaf, child, &changes);
if (count) {
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_lineage_add: setting parent"
" for child %d from %d to %d\n",
child->lgrp_id, parent->lgrp_id,
child->lgrp_parent->lgrp_id);
#endif
parent = child->lgrp_parent;
total += count;
if (changed)
klgrpset_or(*changed, changes);
}
if (proprogate) {
total += lgrp_proprogate(newleaf, child, latency,
&changes);
if (changed)
klgrpset_or(*changed, changes);
parent = child->lgrp_parent;
klgrpset_add(collapse, parent->lgrp_id);
child = parent;
parent = parent->lgrp_parent;
continue;
}
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: latency 0x%x,"
" parent latency 0x%x\n",
latency, parent->lgrp_latency);
#endif
if (latency < parent->lgrp_latency) {
lgrp_t *intermed;
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_lineage_add: "
"latency < parent latency\n");
#endif
lgrp_rsets_copy(child->lgrp_set, rset);
lgrp_rsets_add(newleaf->lgrp_set, rset);
if (nlevels >= lgrp_topo_levels) {
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_lineage_add: nlevels "
"%d > lgrp_topo_levels %d\n",
nlevels, lgrp_topo_levels);
lgrp_rsets_print("rset ", rset);
}
#endif
if (parent == lgrp_root) {
if (lgrp_rsets_member_all(
parent->lgrp_set, newleaf->lgrp_id))
break;
total += lgrp_proprogate(newleaf, child,
latency, &changes);
break;
}
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_lineage_add: "
"replaced parent lgrp %d at 0x%p"
" for lgrp %d\n",
parent->lgrp_id, (void *)parent,
child->lgrp_id);
lgrp_rsets_print("old parent"
" resources:", parent->lgrp_set);
lgrp_rsets_print("new parent "
"resources:", rset);
}
#endif
lgrp_rsets_replace(rset, latency, parent, 1);
if (*changed)
klgrpset_or(*changed, parent->lgrp_id);
total++;
proprogate++;
} else {
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_lineage_add: "
"lgrp_new_parent(0x%p,%d)\n",
(void *)child, latency);
lgrp_rsets_print("rset ", rset);
}
#endif
total += lgrp_new_parent(child, latency, rset,
&changes);
intermed = child->lgrp_parent;
klgrpset_add(collapse, intermed->lgrp_id);
if (changed)
klgrpset_or(*changed, changes);
child = intermed;
proprogate++;
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_lineage_add: new "
"parent lgrp %d at 0x%p for "
"lgrp %d\n", intermed->lgrp_id,
(void *)intermed, child->lgrp_id);
lgrp_rsets_print("new parent "
"resources:", rset);
}
#endif
continue;
}
} else if (latency == parent->lgrp_latency) {
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_lineage_add: latency == "
"parent latency\n");
#endif
if (lgrp_rsets_member_all(parent->lgrp_set,
newleaf->lgrp_id))
break;
total += lgrp_proprogate(newleaf, child, latency,
&changes);
parent = child->lgrp_parent;
klgrpset_add(collapse, parent->lgrp_id);
if (changed)
klgrpset_or(*changed, changes);
proprogate++;
}
child = parent;
parent = parent->lgrp_parent;
} while (parent != NULL);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: collapsing dups....\n");
#endif
total += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
&changes);
if (changed)
klgrpset_or(*changed, changes);
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_lineage_add: changed %d lgrps: 0x%llx\n",
total, (u_longlong_t)*changed);
#endif
return (total);
}
int
lgrp_leaf_add(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count,
klgrpset_t *changed)
{
klgrpset_t changes;
int count;
int i;
int latency;
ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
!lgrp_initialized);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("\nlgrp_leaf_add(0x%p[%d],0x%p,%d,0x%p)\n",
(void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count,
(void *)changed);
#endif
count = 0;
if (changed)
klgrpset_clear(*changed);
if (leaf->lgrp_parent == NULL) {
leaf->lgrp_parent = lgrp_root;
lgrp_root->lgrp_childcnt++;
klgrpset_add(lgrp_root->lgrp_children, leaf->lgrp_id);
klgrpset_or(lgrp_root->lgrp_leaves, leaf->lgrp_leaves);
lgrp_rsets_add(leaf->lgrp_set, lgrp_root->lgrp_set);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
lgrp_rsets_print("lgrp_leaf_add: root lgrp resources",
lgrp_root->lgrp_set);
#endif
if (changed) {
klgrpset_add(*changed, lgrp_root->lgrp_id);
klgrpset_add(*changed, leaf->lgrp_id);
}
count += 2;
}
latency = lgrp_plat_latency(leaf->lgrp_plathand, leaf->lgrp_plathand);
if (latency == 0) {
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
lgrp_root->lgrp_latency = lgrp_plat_latency(lgrp_root->lgrp_plathand,
lgrp_root->lgrp_plathand);
leaf->lgrp_latency = latency;
for (i = 0; i < lgrp_count; i++) {
lgrp_t *lgrp;
lgrp = lgrps[i];
if (!LGRP_EXISTS(lgrp) || lgrp == leaf ||
lgrp->lgrp_childcnt != 0) {
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_leaf_add: skip "
"lgrp %d at 0x%p\n",
lgrp->lgrp_id, (void *)lgrp);
#endif
continue;
}
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_leaf_add: lgrp %d (0x%p) =>"
" lgrp %d (0x%p)\n",
leaf->lgrp_id, (void *)leaf, lgrp->lgrp_id,
(void *)lgrp);
#endif
count += lgrp_lineage_add(leaf, lgrp, &changes);
if (changed)
klgrpset_or(*changed, changes);
count += lgrp_lineage_add(lgrp, leaf, &changes);
if (changed)
klgrpset_or(*changed, changes);
}
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
int
lgrp_leaf_delete(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count,
klgrpset_t *changed)
{
klgrpset_t changes;
klgrpset_t collapse;
int count;
int i;
lgrp_t *lgrp;
ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
!lgrp_initialized);
count = 0;
klgrpset_clear(collapse);
if (changed)
klgrpset_clear(*changed);
if (leaf == NULL)
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_leaf_delete(0x%p[%d],0x%p,%d,0x%p)\n",
(void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count,
(void *)changed);
#endif
for (i = 0; i < lgrp_count; i++) {
lgrp = lgrps[i];
if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE ||
!lgrp_rsets_member(lgrp->lgrp_set, leaf->lgrp_id))
continue;
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_leaf_delete: remove leaf from"
" lgrp %d at %p\n", lgrp->lgrp_id, (void *)lgrp);
#endif
lgrp_rsets_delete(lgrp, leaf->lgrp_id, 0);
klgrpset_del(lgrp->lgrp_leaves, leaf->lgrp_id);
klgrpset_add(collapse, lgrp->lgrp_id);
count++;
}
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_leaf_delete: remove leaf and ancestors\n");
#endif
count += lgrp_ancestor_delete(leaf, &changes);
klgrpset_or(collapse, changes);
klgrpset_add(collapse, leaf->lgrp_id);
count++;
lgrp_destroy(leaf);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_leaf_delete: collapsing dups\n");
#endif
count += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
&changes);
klgrpset_or(collapse, changes);
if (changed)
klgrpset_copy(*changed, collapse);
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_leaf_delete: changed %d lgrps: 0x%llx\n",
count, (u_longlong_t)*changed);
#endif
return (count);
}
int
lgrp_topo_flatten(int levels, lgrp_t **lgrps, int lgrp_count,
klgrpset_t *changed)
{
int count;
int i;
lgrp_t *lgrp;
lgrp_handle_t hdl;
if (levels != 2)
return (0);
count = 0;
for (i = 0; i <= lgrp_count; i++) {
lgrp = lgrps[i];
if (!LGRP_EXISTS(lgrp))
continue;
hdl = lgrp->lgrp_plathand;
if (lgrp == lgrp_root) {
lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl);
continue;
}
if (lgrp->lgrp_childcnt > 0) {
lgrp_t *parent;
parent = lgrp->lgrp_parent;
if (changed) {
klgrpset_add(*changed, lgrp->lgrp_id);
klgrpset_add(*changed, parent->lgrp_id);
count += 2;
}
if (parent) {
klgrpset_del(parent->lgrp_children,
lgrp->lgrp_id);
parent->lgrp_childcnt--;
}
lgrp_destroy(lgrp);
} else if (lgrp->lgrp_parent != lgrp_root) {
if (changed) {
klgrpset_add(*changed, lgrp_root->lgrp_id);
klgrpset_add(*changed, lgrp->lgrp_id);
count += 2;
}
lgrp->lgrp_parent = lgrp_root;
klgrpset_add(lgrp_root->lgrp_children, lgrp->lgrp_id);
lgrp_root->lgrp_childcnt++;
klgrpset_add(lgrp_root->lgrp_leaves, lgrp->lgrp_id);
lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl);
}
}
return (count);
}
int
lgrp_topo_ht_limit(void)
{
return (lgrp_topo_levels);
}
int
lgrp_topo_ht_limit_default(void)
{
return (LGRP_TOPO_LEVELS);
}
int
lgrp_topo_ht_limit_set(int ht)
{
if (ht > LGRP_TOPO_LEVELS_MAX)
lgrp_topo_levels = LGRP_TOPO_LEVELS_MAX;
else
lgrp_topo_levels = ht;
return (ht);
}
int
lgrp_topo_update(lgrp_t **lgrps, int lgrp_count, klgrpset_t *changed)
{
klgrpset_t changes;
int count;
int i;
lgrp_t *lgrp;
count = 0;
if (changed)
klgrpset_clear(*changed);
if (nlgrps == 1) {
for (i = 0; i < LGRP_RSRC_COUNT; i++)
klgrpset_add(lgrp_root->lgrp_set[i],
lgrp_root->lgrp_id);
klgrpset_add(lgrp_root->lgrp_leaves, lgrp_root->lgrp_id);
return (0);
}
mutex_enter(&cpu_lock);
pause_cpus(NULL, NULL);
for (i = 0; i < lgrp_count; i++) {
lgrp = lgrps[i];
if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE ||
lgrp->lgrp_childcnt != 0 || lgrp->lgrp_latency != 0)
continue;
#ifdef DEBUG
if (lgrp_topo_debug > 1) {
prom_printf("\nlgrp_topo_update: updating lineage "
"of lgrp %d at 0x%p\n", lgrp->lgrp_id,
(void *)lgrp);
}
#endif
count += lgrp_leaf_add(lgrp, lgrps, lgrp_count, &changes);
if (changed)
klgrpset_or(*changed, changes);
if (!klgrpset_isempty(changes))
(void) lgrp_mnode_update(changes, NULL);
#ifdef DEBUG
if (lgrp_topo_debug > 1 && changed)
prom_printf("lgrp_topo_update: changed %d lgrps: "
"0x%llx\n",
count, (u_longlong_t)*changed);
#endif
}
if (lgrp_topo_levels < LGRP_TOPO_LEVELS && lgrp_topo_levels == 2) {
count += lgrp_topo_flatten(2, lgrps, lgrp_count, changed);
(void) lpl_topo_flatten(2);
}
start_cpus();
mutex_exit(&cpu_lock);
return (count);
}
#ifdef DEBUG
void
lgrp_print(lgrp_t *lgrp)
{
lgrp_t *parent;
prom_printf("LGRP %d", lgrp->lgrp_id);
if (lgrp->lgrp_childcnt == 0)
prom_printf(" (plathand %p)\n",
(void *)lgrp->lgrp_plathand);
else
prom_printf("\n");
prom_printf("\tlatency %d\n", lgrp->lgrp_latency);
lgrp_rsets_print("\tresources", lgrp->lgrp_set);
parent = lgrp->lgrp_parent;
prom_printf("\tparent 0x%p", (void *)parent);
if (parent)
prom_printf("[%d]\n", parent->lgrp_id);
else
prom_printf("\n");
prom_printf("\tchild count %d, children ", lgrp->lgrp_childcnt);
klgrpset_print(lgrp->lgrp_children);
prom_printf("\tleaves ");
klgrpset_print(lgrp->lgrp_leaves);
}
void
lgrp_topo_print(lgrp_t **lgrps, int lgrp_max)
{
klgrpset_t siblings;
lgrp_print(lgrp_root);
siblings = lgrp_root->lgrp_children;
while (!klgrpset_isempty(siblings)) {
klgrpset_t children;
int i;
klgrpset_clear(children);
for (i = 0; i <= lgrp_max; i++) {
lgrp_t *lgrp;
lgrp = lgrps[i];
if (lgrp == NULL || !klgrpset_ismember(siblings, i))
continue;
lgrp_print(lgrp);
klgrpset_or(children, lgrp->lgrp_children);
}
klgrpset_copy(siblings, children);
}
}
#endif