1fb2f18f8Sesaxe /* 2fb2f18f8Sesaxe * CDDL HEADER START 3fb2f18f8Sesaxe * 4fb2f18f8Sesaxe * The contents of this file are subject to the terms of the 5fb2f18f8Sesaxe * Common Development and Distribution License (the "License"). 6fb2f18f8Sesaxe * You may not use this file except in compliance with the License. 7fb2f18f8Sesaxe * 8fb2f18f8Sesaxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fb2f18f8Sesaxe * or http://www.opensolaris.org/os/licensing. 10fb2f18f8Sesaxe * See the License for the specific language governing permissions 11fb2f18f8Sesaxe * and limitations under the License. 12fb2f18f8Sesaxe * 13fb2f18f8Sesaxe * When distributing Covered Code, include this CDDL HEADER in each 14fb2f18f8Sesaxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fb2f18f8Sesaxe * If applicable, add the following below this CDDL HEADER, with the 16fb2f18f8Sesaxe * fields enclosed by brackets "[]" replaced with your own identifying 17fb2f18f8Sesaxe * information: Portions Copyright [yyyy] [name of copyright owner] 18fb2f18f8Sesaxe * 19fb2f18f8Sesaxe * CDDL HEADER END 20fb2f18f8Sesaxe */ 21fb2f18f8Sesaxe /* 220e751525SEric Saxe * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fb2f18f8Sesaxe * Use is subject to license terms. 24fb2f18f8Sesaxe */ 25fb2f18f8Sesaxe 26fb2f18f8Sesaxe #include <sys/systm.h> 27fb2f18f8Sesaxe #include <sys/types.h> 28fb2f18f8Sesaxe #include <sys/param.h> 29fb2f18f8Sesaxe #include <sys/thread.h> 30fb2f18f8Sesaxe #include <sys/cpuvar.h> 31fb2f18f8Sesaxe #include <sys/cpupart.h> 32fb2f18f8Sesaxe #include <sys/kmem.h> 33fb2f18f8Sesaxe #include <sys/cmn_err.h> 34fb2f18f8Sesaxe #include <sys/kstat.h> 35fb2f18f8Sesaxe #include <sys/processor.h> 36fb2f18f8Sesaxe #include <sys/disp.h> 37fb2f18f8Sesaxe #include <sys/group.h> 38fb2f18f8Sesaxe #include <sys/pg.h> 39fb2f18f8Sesaxe 40fb2f18f8Sesaxe /* 41fb2f18f8Sesaxe * Processor groups 42fb2f18f8Sesaxe * 43fb2f18f8Sesaxe * With the introduction of Chip Multi-Threaded (CMT) processor architectures, 44fb2f18f8Sesaxe * it is no longer necessarily true that a given physical processor module 45fb2f18f8Sesaxe * will present itself as a single schedulable entity (cpu_t). Rather, each 46fb2f18f8Sesaxe * chip and/or processor core may present itself as one or more "logical" CPUs. 47fb2f18f8Sesaxe * 48fb2f18f8Sesaxe * The logical CPUs presented may share physical components such as caches, 49fb2f18f8Sesaxe * data pipes, execution pipelines, FPUs, etc. It is advantageous to have the 50fb2f18f8Sesaxe * kernel be aware of the relationships existing between logical CPUs so that 51fb2f18f8Sesaxe * the appropriate optmizations may be employed. 52fb2f18f8Sesaxe * 53fb2f18f8Sesaxe * The processor group abstraction represents a set of logical CPUs that 54fb2f18f8Sesaxe * generally share some sort of physical or characteristic relationship. 55fb2f18f8Sesaxe * 56fb2f18f8Sesaxe * In the case of a physical sharing relationship, the CPUs in the group may 57fb2f18f8Sesaxe * share a pipeline, cache or floating point unit. In the case of a logical 58fb2f18f8Sesaxe * relationship, a PG may represent the set of CPUs in a processor set, or the 59fb2f18f8Sesaxe * set of CPUs running at a particular clock speed. 60fb2f18f8Sesaxe * 61fb2f18f8Sesaxe * The generic processor group structure, pg_t, contains the elements generic 62fb2f18f8Sesaxe * to a group of CPUs. Depending on the nature of the CPU relationship 63fb2f18f8Sesaxe * (LOGICAL or PHYSICAL), a pointer to a pg may be recast to a "view" of that 64fb2f18f8Sesaxe * PG where more specific data is represented. 65fb2f18f8Sesaxe * 66fb2f18f8Sesaxe * As an example, a PG representing a PHYSICAL relationship, may be recast to 67fb2f18f8Sesaxe * a pghw_t, where data further describing the hardware sharing relationship 68fb2f18f8Sesaxe * is maintained. See pghw.c and pghw.h for details on physical PGs. 69fb2f18f8Sesaxe * 70fb2f18f8Sesaxe * At this time a more specialized casting of a PG representing a LOGICAL 71fb2f18f8Sesaxe * relationship has not been implemented, but the architecture allows for this 72fb2f18f8Sesaxe * in the future. 73fb2f18f8Sesaxe * 74fb2f18f8Sesaxe * Processor Group Classes 75fb2f18f8Sesaxe * 76fb2f18f8Sesaxe * Processor group consumers may wish to maintain and associate specific 77fb2f18f8Sesaxe * data with the PGs they create. For this reason, a mechanism for creating 78fb2f18f8Sesaxe * class specific PGs exists. Classes may overload the default functions for 79fb2f18f8Sesaxe * creating, destroying, and associating CPUs with PGs, and may also register 80fb2f18f8Sesaxe * class specific callbacks to be invoked when the CPU related system 81fb2f18f8Sesaxe * configuration changes. Class specific data is stored/associated with 82fb2f18f8Sesaxe * PGs by incorporating the pg_t (or pghw_t, as appropriate), as the first 83fb2f18f8Sesaxe * element of a class specific PG object. In memory, such a structure may look 84fb2f18f8Sesaxe * like: 85fb2f18f8Sesaxe * 86fb2f18f8Sesaxe * ----------------------- - - - 87fb2f18f8Sesaxe * | common | | | | <--(pg_t *) 88fb2f18f8Sesaxe * ----------------------- | | - 89fb2f18f8Sesaxe * | HW specific | | | <-----(pghw_t *) 90fb2f18f8Sesaxe * ----------------------- | - 91fb2f18f8Sesaxe * | class specific | | <-------(pg_cmt_t *) 92fb2f18f8Sesaxe * ----------------------- - 93fb2f18f8Sesaxe * 94fb2f18f8Sesaxe * Access to the PG class specific data can be had by casting a pointer to 95fb2f18f8Sesaxe * it's class specific view. 96fb2f18f8Sesaxe */ 97fb2f18f8Sesaxe 98fb2f18f8Sesaxe static pg_t *pg_alloc_default(pg_class_t); 99fb2f18f8Sesaxe static void pg_free_default(pg_t *); 1000e751525SEric Saxe static void pg_null_op(); 101fb2f18f8Sesaxe 102fb2f18f8Sesaxe /* 103fb2f18f8Sesaxe * Bootstrap CPU specific PG data 104fb2f18f8Sesaxe * See pg_cpu_bootstrap() 105fb2f18f8Sesaxe */ 106fb2f18f8Sesaxe static cpu_pg_t bootstrap_pg_data; 107fb2f18f8Sesaxe 108fb2f18f8Sesaxe /* 109fb2f18f8Sesaxe * Bitset of allocated PG ids (they are sequential) 110fb2f18f8Sesaxe * and the next free id in the set. 111fb2f18f8Sesaxe */ 112fb2f18f8Sesaxe static bitset_t pg_id_set; 113*b885580bSAlexander Kolbasov 114*b885580bSAlexander Kolbasov /* 115*b885580bSAlexander Kolbasov * ID space starts from 1 to assume that root has ID 0; 116*b885580bSAlexander Kolbasov */ 117*b885580bSAlexander Kolbasov static pgid_t pg_id_next = 1; 118fb2f18f8Sesaxe 119fb2f18f8Sesaxe /* 120fb2f18f8Sesaxe * Default and externed PG ops vectors 121fb2f18f8Sesaxe */ 122fb2f18f8Sesaxe static struct pg_ops pg_ops_default = { 123fb2f18f8Sesaxe pg_alloc_default, /* alloc */ 124fb2f18f8Sesaxe pg_free_default, /* free */ 125fb2f18f8Sesaxe NULL, /* cpu_init */ 126fb2f18f8Sesaxe NULL, /* cpu_fini */ 127fb2f18f8Sesaxe NULL, /* cpu_active */ 128fb2f18f8Sesaxe NULL, /* cpu_inactive */ 129fb2f18f8Sesaxe NULL, /* cpupart_in */ 130fb2f18f8Sesaxe NULL, /* cpupart_out */ 131fb2f18f8Sesaxe NULL, /* cpupart_move */ 132fb2f18f8Sesaxe NULL, /* cpu_belongs */ 1330e751525SEric Saxe NULL, /* policy_name */ 1340e751525SEric Saxe }; 1350e751525SEric Saxe 1360e751525SEric Saxe static struct pg_cb_ops pg_cb_ops_default = { 1370e751525SEric Saxe pg_null_op, /* thread_swtch */ 1380e751525SEric Saxe pg_null_op, /* thread_remain */ 139fb2f18f8Sesaxe }; 140fb2f18f8Sesaxe 141fb2f18f8Sesaxe /* 142fb2f18f8Sesaxe * Class specific PG allocation callbacks 143fb2f18f8Sesaxe */ 144fb2f18f8Sesaxe #define PG_ALLOC(class) \ 145fb2f18f8Sesaxe (pg_classes[class].pgc_ops->alloc ? \ 146fb2f18f8Sesaxe pg_classes[class].pgc_ops->alloc() : \ 147fb2f18f8Sesaxe pg_classes[pg_default_cid].pgc_ops->alloc()) 148fb2f18f8Sesaxe 149fb2f18f8Sesaxe #define PG_FREE(pg) \ 150fb2f18f8Sesaxe ((pg)->pg_class->pgc_ops->free ? \ 151fb2f18f8Sesaxe (pg)->pg_class->pgc_ops->free(pg) : \ 152fb2f18f8Sesaxe pg_classes[pg_default_cid].pgc_ops->free(pg)) \ 153fb2f18f8Sesaxe 154fb2f18f8Sesaxe 155fb2f18f8Sesaxe /* 1560e751525SEric Saxe * Class specific PG policy name 1570e751525SEric Saxe */ 1580e751525SEric Saxe #define PG_POLICY_NAME(pg) \ 1590e751525SEric Saxe ((pg)->pg_class->pgc_ops->policy_name ? \ 1600e751525SEric Saxe (pg)->pg_class->pgc_ops->policy_name(pg) : NULL) \ 1610e751525SEric Saxe 1620e751525SEric Saxe /* 163fb2f18f8Sesaxe * Class specific membership test callback 164fb2f18f8Sesaxe */ 165fb2f18f8Sesaxe #define PG_CPU_BELONGS(pg, cp) \ 166fb2f18f8Sesaxe ((pg)->pg_class->pgc_ops->cpu_belongs ? \ 167fb2f18f8Sesaxe (pg)->pg_class->pgc_ops->cpu_belongs(pg, cp) : 0) \ 168fb2f18f8Sesaxe 169fb2f18f8Sesaxe /* 170fb2f18f8Sesaxe * CPU configuration callbacks 171fb2f18f8Sesaxe */ 17247ab0c7cSEric Saxe #define PG_CPU_INIT(class, cp, cpu_pg) \ 173fb2f18f8Sesaxe { \ 174fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_init) \ 17547ab0c7cSEric Saxe pg_classes[class].pgc_ops->cpu_init(cp, cpu_pg); \ 176fb2f18f8Sesaxe } 177fb2f18f8Sesaxe 17847ab0c7cSEric Saxe #define PG_CPU_FINI(class, cp, cpu_pg) \ 179fb2f18f8Sesaxe { \ 180fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_fini) \ 18147ab0c7cSEric Saxe pg_classes[class].pgc_ops->cpu_fini(cp, cpu_pg); \ 182fb2f18f8Sesaxe } 183fb2f18f8Sesaxe 184fb2f18f8Sesaxe #define PG_CPU_ACTIVE(class, cp) \ 185fb2f18f8Sesaxe { \ 186fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_active) \ 187fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpu_active(cp); \ 188fb2f18f8Sesaxe } 189fb2f18f8Sesaxe 190fb2f18f8Sesaxe #define PG_CPU_INACTIVE(class, cp) \ 191fb2f18f8Sesaxe { \ 192fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpu_inactive) \ 193fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpu_inactive(cp); \ 194fb2f18f8Sesaxe } 195fb2f18f8Sesaxe 196fb2f18f8Sesaxe /* 197fb2f18f8Sesaxe * CPU / cpupart configuration callbacks 198fb2f18f8Sesaxe */ 199fb2f18f8Sesaxe #define PG_CPUPART_IN(class, cp, pp) \ 200fb2f18f8Sesaxe { \ 201fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpupart_in) \ 202fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpupart_in(cp, pp); \ 203fb2f18f8Sesaxe } 204fb2f18f8Sesaxe 205fb2f18f8Sesaxe #define PG_CPUPART_OUT(class, cp, pp) \ 206fb2f18f8Sesaxe { \ 207fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpupart_out) \ 208fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpupart_out(cp, pp); \ 209fb2f18f8Sesaxe } 210fb2f18f8Sesaxe 211fb2f18f8Sesaxe #define PG_CPUPART_MOVE(class, cp, old, new) \ 212fb2f18f8Sesaxe { \ 213fb2f18f8Sesaxe if (pg_classes[class].pgc_ops->cpupart_move) \ 214fb2f18f8Sesaxe pg_classes[class].pgc_ops->cpupart_move(cp, old, new); \ 215fb2f18f8Sesaxe } 216fb2f18f8Sesaxe 217fb2f18f8Sesaxe 218fb2f18f8Sesaxe 219fb2f18f8Sesaxe static pg_class_t *pg_classes; 220fb2f18f8Sesaxe static int pg_nclasses; 221fb2f18f8Sesaxe 222fb2f18f8Sesaxe static pg_cid_t pg_default_cid; 223fb2f18f8Sesaxe 224fb2f18f8Sesaxe /* 2250e751525SEric Saxe * Initialze common PG subsystem. 226fb2f18f8Sesaxe */ 227fb2f18f8Sesaxe void 228fb2f18f8Sesaxe pg_init(void) 229fb2f18f8Sesaxe { 2300e751525SEric Saxe extern void pg_cmt_class_init(); 231ad7a79fdSEric Saxe extern void pg_cmt_cpu_startup(); 2320e751525SEric Saxe 233fb2f18f8Sesaxe pg_default_cid = 234fb2f18f8Sesaxe pg_class_register("default", &pg_ops_default, PGR_LOGICAL); 2350e751525SEric Saxe 2360e751525SEric Saxe /* 2370e751525SEric Saxe * Initialize classes to allow them to register with the framework 2380e751525SEric Saxe */ 2390e751525SEric Saxe pg_cmt_class_init(); 2400e751525SEric Saxe 2410e751525SEric Saxe pg_cpu0_init(); 242ad7a79fdSEric Saxe pg_cmt_cpu_startup(CPU); 243fb2f18f8Sesaxe } 244fb2f18f8Sesaxe 245fb2f18f8Sesaxe /* 246fb2f18f8Sesaxe * Perform CPU 0 initialization 247fb2f18f8Sesaxe */ 248fb2f18f8Sesaxe void 249fb2f18f8Sesaxe pg_cpu0_init(void) 250fb2f18f8Sesaxe { 251fb2f18f8Sesaxe extern void pghw_physid_create(); 252fb2f18f8Sesaxe 253fb2f18f8Sesaxe /* 254fb2f18f8Sesaxe * Create the physical ID cache for the boot CPU 255fb2f18f8Sesaxe */ 256fb2f18f8Sesaxe pghw_physid_create(CPU); 257fb2f18f8Sesaxe 258fb2f18f8Sesaxe /* 259fb2f18f8Sesaxe * pg_cpu_* require that cpu_lock be held 260fb2f18f8Sesaxe */ 261fb2f18f8Sesaxe mutex_enter(&cpu_lock); 262fb2f18f8Sesaxe 263023e71deSHaik Aftandilian (void) pg_cpu_init(CPU, B_FALSE); 264fb2f18f8Sesaxe pg_cpupart_in(CPU, &cp_default); 265fb2f18f8Sesaxe pg_cpu_active(CPU); 266fb2f18f8Sesaxe 267fb2f18f8Sesaxe mutex_exit(&cpu_lock); 268fb2f18f8Sesaxe } 269fb2f18f8Sesaxe 270fb2f18f8Sesaxe /* 271a6604450Sesaxe * Invoked when topology for CPU0 changes 272a6604450Sesaxe * post pg_cpu0_init(). 273a6604450Sesaxe * 274a6604450Sesaxe * Currently happens as a result of null_proc_lpa 275a6604450Sesaxe * on Starcat. 276a6604450Sesaxe */ 277a6604450Sesaxe void 278a6604450Sesaxe pg_cpu0_reinit(void) 279a6604450Sesaxe { 280a6604450Sesaxe mutex_enter(&cpu_lock); 281a6604450Sesaxe pg_cpu_inactive(CPU); 282a6604450Sesaxe pg_cpupart_out(CPU, &cp_default); 283023e71deSHaik Aftandilian pg_cpu_fini(CPU, NULL); 284a6604450Sesaxe 285023e71deSHaik Aftandilian (void) pg_cpu_init(CPU, B_FALSE); 286a6604450Sesaxe pg_cpupart_in(CPU, &cp_default); 287a6604450Sesaxe pg_cpu_active(CPU); 288a6604450Sesaxe mutex_exit(&cpu_lock); 289a6604450Sesaxe } 290a6604450Sesaxe 291a6604450Sesaxe /* 292fb2f18f8Sesaxe * Register a new PG class 293fb2f18f8Sesaxe */ 294fb2f18f8Sesaxe pg_cid_t 295fb2f18f8Sesaxe pg_class_register(char *name, struct pg_ops *ops, pg_relation_t relation) 296fb2f18f8Sesaxe { 297fb2f18f8Sesaxe pg_class_t *newclass; 298fb2f18f8Sesaxe pg_class_t *classes_old; 299fb2f18f8Sesaxe id_t cid; 300fb2f18f8Sesaxe 301fb2f18f8Sesaxe mutex_enter(&cpu_lock); 302fb2f18f8Sesaxe 303fb2f18f8Sesaxe /* 304fb2f18f8Sesaxe * Allocate a new pg_class_t in the pg_classes array 305fb2f18f8Sesaxe */ 306fb2f18f8Sesaxe if (pg_nclasses == 0) { 307fb2f18f8Sesaxe pg_classes = kmem_zalloc(sizeof (pg_class_t), KM_SLEEP); 308fb2f18f8Sesaxe } else { 309fb2f18f8Sesaxe classes_old = pg_classes; 310fb2f18f8Sesaxe pg_classes = 311fb2f18f8Sesaxe kmem_zalloc(sizeof (pg_class_t) * (pg_nclasses + 1), 312fb2f18f8Sesaxe KM_SLEEP); 313fb2f18f8Sesaxe (void) kcopy(classes_old, pg_classes, 314fb2f18f8Sesaxe sizeof (pg_class_t) * pg_nclasses); 315fb2f18f8Sesaxe kmem_free(classes_old, sizeof (pg_class_t) * pg_nclasses); 316fb2f18f8Sesaxe } 317fb2f18f8Sesaxe 318fb2f18f8Sesaxe cid = pg_nclasses++; 319fb2f18f8Sesaxe newclass = &pg_classes[cid]; 320fb2f18f8Sesaxe 321fb2f18f8Sesaxe (void) strncpy(newclass->pgc_name, name, PG_CLASS_NAME_MAX); 322fb2f18f8Sesaxe newclass->pgc_id = cid; 323fb2f18f8Sesaxe newclass->pgc_ops = ops; 324fb2f18f8Sesaxe newclass->pgc_relation = relation; 325fb2f18f8Sesaxe 326fb2f18f8Sesaxe mutex_exit(&cpu_lock); 327fb2f18f8Sesaxe 328fb2f18f8Sesaxe return (cid); 329fb2f18f8Sesaxe } 330fb2f18f8Sesaxe 331fb2f18f8Sesaxe /* 332fb2f18f8Sesaxe * Try to find an existing pg in set in which to place cp. 333fb2f18f8Sesaxe * Returns the pg if found, and NULL otherwise. 334fb2f18f8Sesaxe * In the event that the CPU could belong to multiple 335fb2f18f8Sesaxe * PGs in the set, the first matching PG will be returned. 336fb2f18f8Sesaxe */ 337fb2f18f8Sesaxe pg_t * 338fb2f18f8Sesaxe pg_cpu_find_pg(cpu_t *cp, group_t *set) 339fb2f18f8Sesaxe { 340fb2f18f8Sesaxe pg_t *pg; 341fb2f18f8Sesaxe group_iter_t i; 342fb2f18f8Sesaxe 343fb2f18f8Sesaxe group_iter_init(&i); 344fb2f18f8Sesaxe while ((pg = group_iterate(set, &i)) != NULL) { 345fb2f18f8Sesaxe /* 346fb2f18f8Sesaxe * Ask the class if the CPU belongs here 347fb2f18f8Sesaxe */ 348fb2f18f8Sesaxe if (PG_CPU_BELONGS(pg, cp)) 349fb2f18f8Sesaxe return (pg); 350fb2f18f8Sesaxe } 351fb2f18f8Sesaxe return (NULL); 352fb2f18f8Sesaxe } 353fb2f18f8Sesaxe 354fb2f18f8Sesaxe /* 355fb2f18f8Sesaxe * Iterate over the CPUs in a PG after initializing 356fb2f18f8Sesaxe * the iterator with PG_CPU_ITR_INIT() 357fb2f18f8Sesaxe */ 358fb2f18f8Sesaxe cpu_t * 359fb2f18f8Sesaxe pg_cpu_next(pg_cpu_itr_t *itr) 360fb2f18f8Sesaxe { 361fb2f18f8Sesaxe cpu_t *cpu; 362fb2f18f8Sesaxe pg_t *pg = itr->pg; 363fb2f18f8Sesaxe 364fb2f18f8Sesaxe cpu = group_iterate(&pg->pg_cpus, &itr->position); 365fb2f18f8Sesaxe return (cpu); 366fb2f18f8Sesaxe } 367fb2f18f8Sesaxe 368fb2f18f8Sesaxe /* 3690e751525SEric Saxe * Test if a given PG contains a given CPU 3700e751525SEric Saxe */ 3710e751525SEric Saxe boolean_t 3720e751525SEric Saxe pg_cpu_find(pg_t *pg, cpu_t *cp) 3730e751525SEric Saxe { 3740e751525SEric Saxe if (group_find(&pg->pg_cpus, cp) == (uint_t)-1) 3750e751525SEric Saxe return (B_FALSE); 3760e751525SEric Saxe 3770e751525SEric Saxe return (B_TRUE); 3780e751525SEric Saxe } 3790e751525SEric Saxe 3800e751525SEric Saxe /* 3810e751525SEric Saxe * Set the PGs callbacks to the default 3820e751525SEric Saxe */ 3830e751525SEric Saxe void 3840e751525SEric Saxe pg_callback_set_defaults(pg_t *pg) 3850e751525SEric Saxe { 3860e751525SEric Saxe bcopy(&pg_cb_ops_default, &pg->pg_cb, sizeof (struct pg_cb_ops)); 3870e751525SEric Saxe } 3880e751525SEric Saxe 3890e751525SEric Saxe /* 390fb2f18f8Sesaxe * Create a PG of a given class. 391fb2f18f8Sesaxe * This routine may block. 392fb2f18f8Sesaxe */ 393fb2f18f8Sesaxe pg_t * 394fb2f18f8Sesaxe pg_create(pg_cid_t cid) 395fb2f18f8Sesaxe { 396fb2f18f8Sesaxe pg_t *pg; 397fb2f18f8Sesaxe pgid_t id; 398fb2f18f8Sesaxe 399fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 400fb2f18f8Sesaxe 401fb2f18f8Sesaxe /* 402fb2f18f8Sesaxe * Call the class specific PG allocation routine 403fb2f18f8Sesaxe */ 404fb2f18f8Sesaxe pg = PG_ALLOC(cid); 405fb2f18f8Sesaxe pg->pg_class = &pg_classes[cid]; 406fb2f18f8Sesaxe pg->pg_relation = pg->pg_class->pgc_relation; 407fb2f18f8Sesaxe 408fb2f18f8Sesaxe /* 409fb2f18f8Sesaxe * Find the next free sequential pg id 410fb2f18f8Sesaxe */ 411fb2f18f8Sesaxe do { 412fb2f18f8Sesaxe if (pg_id_next >= bitset_capacity(&pg_id_set)) 413fb2f18f8Sesaxe bitset_resize(&pg_id_set, pg_id_next + 1); 414fb2f18f8Sesaxe id = pg_id_next++; 415fb2f18f8Sesaxe } while (bitset_in_set(&pg_id_set, id)); 416fb2f18f8Sesaxe 417fb2f18f8Sesaxe pg->pg_id = id; 418fb2f18f8Sesaxe bitset_add(&pg_id_set, pg->pg_id); 419fb2f18f8Sesaxe 420fb2f18f8Sesaxe /* 421fb2f18f8Sesaxe * Create the PG's CPU group 422fb2f18f8Sesaxe */ 423fb2f18f8Sesaxe group_create(&pg->pg_cpus); 424fb2f18f8Sesaxe 4250e751525SEric Saxe /* 4260e751525SEric Saxe * Initialize the events ops vector 4270e751525SEric Saxe */ 4280e751525SEric Saxe pg_callback_set_defaults(pg); 4290e751525SEric Saxe 430fb2f18f8Sesaxe return (pg); 431fb2f18f8Sesaxe } 432fb2f18f8Sesaxe 433fb2f18f8Sesaxe /* 434fb2f18f8Sesaxe * Destroy a PG. 435fb2f18f8Sesaxe * This routine may block. 436fb2f18f8Sesaxe */ 437fb2f18f8Sesaxe void 438fb2f18f8Sesaxe pg_destroy(pg_t *pg) 439fb2f18f8Sesaxe { 440fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 441fb2f18f8Sesaxe 442fb2f18f8Sesaxe group_destroy(&pg->pg_cpus); 443fb2f18f8Sesaxe 444fb2f18f8Sesaxe /* 445fb2f18f8Sesaxe * Unassign the pg_id 446fb2f18f8Sesaxe */ 447fb2f18f8Sesaxe if (pg_id_next > pg->pg_id) 448fb2f18f8Sesaxe pg_id_next = pg->pg_id; 449fb2f18f8Sesaxe bitset_del(&pg_id_set, pg->pg_id); 450fb2f18f8Sesaxe 451fb2f18f8Sesaxe /* 452fb2f18f8Sesaxe * Invoke the class specific de-allocation routine 453fb2f18f8Sesaxe */ 454fb2f18f8Sesaxe PG_FREE(pg); 455fb2f18f8Sesaxe } 456fb2f18f8Sesaxe 457fb2f18f8Sesaxe /* 458fb2f18f8Sesaxe * Add the CPU "cp" to processor group "pg" 459fb2f18f8Sesaxe * This routine may block. 460fb2f18f8Sesaxe */ 461fb2f18f8Sesaxe void 46247ab0c7cSEric Saxe pg_cpu_add(pg_t *pg, cpu_t *cp, cpu_pg_t *cpu_pg) 463fb2f18f8Sesaxe { 464fb2f18f8Sesaxe int err; 465fb2f18f8Sesaxe 466fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 467fb2f18f8Sesaxe 468fb2f18f8Sesaxe /* This adds the CPU to the PG's CPU group */ 469fb2f18f8Sesaxe err = group_add(&pg->pg_cpus, cp, GRP_RESIZE); 470fb2f18f8Sesaxe ASSERT(err == 0); 471fb2f18f8Sesaxe 47247ab0c7cSEric Saxe /* 47347ab0c7cSEric Saxe * The CPU should be referencing the bootstrap PG data still 47447ab0c7cSEric Saxe * at this point, since this routine may block causing us to 47547ab0c7cSEric Saxe * enter the dispatcher. 47647ab0c7cSEric Saxe */ 4771a77c24bSEric Saxe ASSERT(pg_cpu_is_bootstrapped(cp)); 47847ab0c7cSEric Saxe 479fb2f18f8Sesaxe /* This adds the PG to the CPUs PG group */ 48047ab0c7cSEric Saxe err = group_add(&cpu_pg->pgs, pg, GRP_RESIZE); 481fb2f18f8Sesaxe ASSERT(err == 0); 482fb2f18f8Sesaxe } 483fb2f18f8Sesaxe 484fb2f18f8Sesaxe /* 485fb2f18f8Sesaxe * Remove "cp" from "pg". 486fb2f18f8Sesaxe * This routine may block. 487fb2f18f8Sesaxe */ 488fb2f18f8Sesaxe void 48947ab0c7cSEric Saxe pg_cpu_delete(pg_t *pg, cpu_t *cp, cpu_pg_t *cpu_pg) 490fb2f18f8Sesaxe { 491fb2f18f8Sesaxe int err; 492fb2f18f8Sesaxe 493fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 494fb2f18f8Sesaxe 495fb2f18f8Sesaxe /* Remove the CPU from the PG */ 496fb2f18f8Sesaxe err = group_remove(&pg->pg_cpus, cp, GRP_RESIZE); 497fb2f18f8Sesaxe ASSERT(err == 0); 498fb2f18f8Sesaxe 49947ab0c7cSEric Saxe /* 50047ab0c7cSEric Saxe * The CPU should be referencing the bootstrap PG data still 50147ab0c7cSEric Saxe * at this point, since this routine may block causing us to 50247ab0c7cSEric Saxe * enter the dispatcher. 50347ab0c7cSEric Saxe */ 5041a77c24bSEric Saxe ASSERT(pg_cpu_is_bootstrapped(cp)); 50547ab0c7cSEric Saxe 506fb2f18f8Sesaxe /* Remove the PG from the CPU's PG group */ 50747ab0c7cSEric Saxe err = group_remove(&cpu_pg->pgs, pg, GRP_RESIZE); 508fb2f18f8Sesaxe ASSERT(err == 0); 509fb2f18f8Sesaxe } 510fb2f18f8Sesaxe 511fb2f18f8Sesaxe /* 512fb2f18f8Sesaxe * Allocate a CPU's PG data. This hangs off struct cpu at cpu_pg 513fb2f18f8Sesaxe */ 514fb2f18f8Sesaxe static cpu_pg_t * 515fb2f18f8Sesaxe pg_cpu_data_alloc(void) 516fb2f18f8Sesaxe { 517fb2f18f8Sesaxe cpu_pg_t *pgd; 518fb2f18f8Sesaxe 519fb2f18f8Sesaxe pgd = kmem_zalloc(sizeof (cpu_pg_t), KM_SLEEP); 520fb2f18f8Sesaxe group_create(&pgd->pgs); 521fb2f18f8Sesaxe group_create(&pgd->cmt_pgs); 522fb2f18f8Sesaxe 523fb2f18f8Sesaxe return (pgd); 524fb2f18f8Sesaxe } 525fb2f18f8Sesaxe 526fb2f18f8Sesaxe /* 527fb2f18f8Sesaxe * Free the CPU's PG data. 528fb2f18f8Sesaxe */ 529fb2f18f8Sesaxe static void 530fb2f18f8Sesaxe pg_cpu_data_free(cpu_pg_t *pgd) 531fb2f18f8Sesaxe { 532fb2f18f8Sesaxe group_destroy(&pgd->pgs); 533fb2f18f8Sesaxe group_destroy(&pgd->cmt_pgs); 534fb2f18f8Sesaxe kmem_free(pgd, sizeof (cpu_pg_t)); 535fb2f18f8Sesaxe } 536fb2f18f8Sesaxe 537fb2f18f8Sesaxe /* 538023e71deSHaik Aftandilian * Called when either a new CPU is coming into the system (either 539023e71deSHaik Aftandilian * via booting or DR) or when the CPU's PG data is being recalculated. 540023e71deSHaik Aftandilian * Allocate its PG data, and notify all registered classes about 541fb2f18f8Sesaxe * the new CPU. 542fb2f18f8Sesaxe * 543023e71deSHaik Aftandilian * If "deferred_init" is B_TRUE, the CPU's PG data will be allocated 544023e71deSHaik Aftandilian * and returned, but the "bootstrap" structure will be left in place. 545023e71deSHaik Aftandilian * The deferred_init option is used when all CPUs in the system are 546023e71deSHaik Aftandilian * using the bootstrap structure as part of the process of recalculating 547023e71deSHaik Aftandilian * all PG data. The caller must replace the bootstrap structure with the 548023e71deSHaik Aftandilian * allocated PG data before pg_cpu_active is called. 549023e71deSHaik Aftandilian * 550fb2f18f8Sesaxe * This routine may block. 551fb2f18f8Sesaxe */ 552023e71deSHaik Aftandilian cpu_pg_t * 553023e71deSHaik Aftandilian pg_cpu_init(cpu_t *cp, boolean_t deferred_init) 554fb2f18f8Sesaxe { 555fb2f18f8Sesaxe pg_cid_t i; 55647ab0c7cSEric Saxe cpu_pg_t *cpu_pg; 557fb2f18f8Sesaxe 558fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 559fb2f18f8Sesaxe 560fb2f18f8Sesaxe /* 561fb2f18f8Sesaxe * Allocate and size the per CPU pg data 56247ab0c7cSEric Saxe * 56347ab0c7cSEric Saxe * The CPU's PG data will be populated by the various 56447ab0c7cSEric Saxe * PG classes during the invocation of the PG_CPU_INIT() 56547ab0c7cSEric Saxe * callback below. 56647ab0c7cSEric Saxe * 56747ab0c7cSEric Saxe * Since the we could block and enter the dispatcher during 56847ab0c7cSEric Saxe * this process, the CPU will continue to reference the bootstrap 56947ab0c7cSEric Saxe * PG data until all the initialization completes. 570fb2f18f8Sesaxe */ 5711a77c24bSEric Saxe ASSERT(pg_cpu_is_bootstrapped(cp)); 57247ab0c7cSEric Saxe 57347ab0c7cSEric Saxe cpu_pg = pg_cpu_data_alloc(); 574fb2f18f8Sesaxe 575fb2f18f8Sesaxe /* 576fb2f18f8Sesaxe * Notify all registered classes about the new CPU 577fb2f18f8Sesaxe */ 578fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 57947ab0c7cSEric Saxe PG_CPU_INIT(i, cp, cpu_pg); 58047ab0c7cSEric Saxe 58147ab0c7cSEric Saxe /* 58247ab0c7cSEric Saxe * The CPU's PG data is now ready to use. 58347ab0c7cSEric Saxe */ 584023e71deSHaik Aftandilian if (deferred_init == B_FALSE) 58547ab0c7cSEric Saxe cp->cpu_pg = cpu_pg; 586023e71deSHaik Aftandilian 587023e71deSHaik Aftandilian return (cpu_pg); 588fb2f18f8Sesaxe } 589fb2f18f8Sesaxe 590fb2f18f8Sesaxe /* 591023e71deSHaik Aftandilian * Either this CPU is being deleted from the system or its PG data is 592023e71deSHaik Aftandilian * being recalculated. Notify the classes and free up the CPU's PG data. 593023e71deSHaik Aftandilian * 594023e71deSHaik Aftandilian * If "cpu_pg_deferred" is non-NULL, it points to the CPU's PG data and 595023e71deSHaik Aftandilian * serves to indicate that this CPU is already using the bootstrap 596023e71deSHaik Aftandilian * stucture. Used as part of the process to recalculate the PG data for 597023e71deSHaik Aftandilian * all CPUs in the system. 598fb2f18f8Sesaxe */ 599fb2f18f8Sesaxe void 600023e71deSHaik Aftandilian pg_cpu_fini(cpu_t *cp, cpu_pg_t *cpu_pg_deferred) 601fb2f18f8Sesaxe { 602fb2f18f8Sesaxe pg_cid_t i; 60347ab0c7cSEric Saxe cpu_pg_t *cpu_pg; 604fb2f18f8Sesaxe 605fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 606fb2f18f8Sesaxe 607023e71deSHaik Aftandilian if (cpu_pg_deferred == NULL) { 60847ab0c7cSEric Saxe cpu_pg = cp->cpu_pg; 60947ab0c7cSEric Saxe 610fb2f18f8Sesaxe /* 611fb2f18f8Sesaxe * This can happen if the CPU coming into the system 612fb2f18f8Sesaxe * failed to power on. 613fb2f18f8Sesaxe */ 6141a77c24bSEric Saxe if (cpu_pg == NULL || pg_cpu_is_bootstrapped(cp)) 615fb2f18f8Sesaxe return; 616fb2f18f8Sesaxe 61747ab0c7cSEric Saxe /* 61847ab0c7cSEric Saxe * Have the CPU reference the bootstrap PG data to survive 61947ab0c7cSEric Saxe * the dispatcher should it block from here on out. 62047ab0c7cSEric Saxe */ 6211a77c24bSEric Saxe pg_cpu_bootstrap(cp); 622023e71deSHaik Aftandilian } else { 623023e71deSHaik Aftandilian ASSERT(pg_cpu_is_bootstrapped(cp)); 624023e71deSHaik Aftandilian cpu_pg = cpu_pg_deferred; 625023e71deSHaik Aftandilian } 626fb2f18f8Sesaxe 62747ab0c7cSEric Saxe for (i = 0; i < pg_nclasses; i++) 62847ab0c7cSEric Saxe PG_CPU_FINI(i, cp, cpu_pg); 62947ab0c7cSEric Saxe 63047ab0c7cSEric Saxe pg_cpu_data_free(cpu_pg); 631fb2f18f8Sesaxe } 632fb2f18f8Sesaxe 633fb2f18f8Sesaxe /* 634fb2f18f8Sesaxe * This CPU is becoming active (online) 635fb2f18f8Sesaxe * This routine may not block as it is called from paused CPUs 636fb2f18f8Sesaxe * context. 637fb2f18f8Sesaxe */ 638fb2f18f8Sesaxe void 639fb2f18f8Sesaxe pg_cpu_active(cpu_t *cp) 640fb2f18f8Sesaxe { 641fb2f18f8Sesaxe pg_cid_t i; 642fb2f18f8Sesaxe 643fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 644fb2f18f8Sesaxe 645fb2f18f8Sesaxe /* 646fb2f18f8Sesaxe * Notify all registered classes about the new CPU 647fb2f18f8Sesaxe */ 648fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 649fb2f18f8Sesaxe PG_CPU_ACTIVE(i, cp); 650fb2f18f8Sesaxe } 651fb2f18f8Sesaxe 652fb2f18f8Sesaxe /* 653fb2f18f8Sesaxe * This CPU is going inactive (offline) 654fb2f18f8Sesaxe * This routine may not block, as it is called from paused 655fb2f18f8Sesaxe * CPUs context. 656fb2f18f8Sesaxe */ 657fb2f18f8Sesaxe void 658fb2f18f8Sesaxe pg_cpu_inactive(cpu_t *cp) 659fb2f18f8Sesaxe { 660fb2f18f8Sesaxe pg_cid_t i; 661fb2f18f8Sesaxe 662fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 663fb2f18f8Sesaxe 664fb2f18f8Sesaxe /* 665fb2f18f8Sesaxe * Notify all registered classes about the new CPU 666fb2f18f8Sesaxe */ 667fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 668fb2f18f8Sesaxe PG_CPU_INACTIVE(i, cp); 669fb2f18f8Sesaxe } 670fb2f18f8Sesaxe 671fb2f18f8Sesaxe /* 672fb2f18f8Sesaxe * Invoked when the CPU is about to move into the partition 673fb2f18f8Sesaxe * This routine may block. 674fb2f18f8Sesaxe */ 675fb2f18f8Sesaxe void 676fb2f18f8Sesaxe pg_cpupart_in(cpu_t *cp, cpupart_t *pp) 677fb2f18f8Sesaxe { 678fb2f18f8Sesaxe int i; 679fb2f18f8Sesaxe 680fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 681fb2f18f8Sesaxe 682fb2f18f8Sesaxe /* 683fb2f18f8Sesaxe * Notify all registered classes that the 684fb2f18f8Sesaxe * CPU is about to enter the CPU partition 685fb2f18f8Sesaxe */ 686fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 687fb2f18f8Sesaxe PG_CPUPART_IN(i, cp, pp); 688fb2f18f8Sesaxe } 689fb2f18f8Sesaxe 690fb2f18f8Sesaxe /* 691fb2f18f8Sesaxe * Invoked when the CPU is about to move out of the partition 692fb2f18f8Sesaxe * This routine may block. 693fb2f18f8Sesaxe */ 694fb2f18f8Sesaxe /*ARGSUSED*/ 695fb2f18f8Sesaxe void 696fb2f18f8Sesaxe pg_cpupart_out(cpu_t *cp, cpupart_t *pp) 697fb2f18f8Sesaxe { 698fb2f18f8Sesaxe int i; 699fb2f18f8Sesaxe 700fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 701fb2f18f8Sesaxe 702fb2f18f8Sesaxe /* 703fb2f18f8Sesaxe * Notify all registered classes that the 704fb2f18f8Sesaxe * CPU is about to leave the CPU partition 705fb2f18f8Sesaxe */ 706fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 707fb2f18f8Sesaxe PG_CPUPART_OUT(i, cp, pp); 708fb2f18f8Sesaxe } 709fb2f18f8Sesaxe 710fb2f18f8Sesaxe /* 711fb2f18f8Sesaxe * Invoked when the CPU is *moving* partitions. 712fb2f18f8Sesaxe * 713fb2f18f8Sesaxe * This routine may not block, as it is called from paused CPUs 714fb2f18f8Sesaxe * context. 715fb2f18f8Sesaxe */ 716fb2f18f8Sesaxe void 717fb2f18f8Sesaxe pg_cpupart_move(cpu_t *cp, cpupart_t *oldpp, cpupart_t *newpp) 718fb2f18f8Sesaxe { 719fb2f18f8Sesaxe int i; 720fb2f18f8Sesaxe 721fb2f18f8Sesaxe ASSERT(MUTEX_HELD(&cpu_lock)); 722fb2f18f8Sesaxe 723fb2f18f8Sesaxe /* 724fb2f18f8Sesaxe * Notify all registered classes that the 725fb2f18f8Sesaxe * CPU is about to leave the CPU partition 726fb2f18f8Sesaxe */ 727fb2f18f8Sesaxe for (i = 0; i < pg_nclasses; i++) 728fb2f18f8Sesaxe PG_CPUPART_MOVE(i, cp, oldpp, newpp); 729fb2f18f8Sesaxe } 730fb2f18f8Sesaxe 731fb2f18f8Sesaxe /* 7320e751525SEric Saxe * Return a class specific string describing a policy implemented 7330e751525SEric Saxe * across this PG 7340e751525SEric Saxe */ 7350e751525SEric Saxe char * 7360e751525SEric Saxe pg_policy_name(pg_t *pg) 7370e751525SEric Saxe { 7380e751525SEric Saxe char *str; 7390e751525SEric Saxe if ((str = PG_POLICY_NAME(pg)) != NULL) 7400e751525SEric Saxe return (str); 7410e751525SEric Saxe 7420e751525SEric Saxe return ("N/A"); 7430e751525SEric Saxe } 7440e751525SEric Saxe 7450e751525SEric Saxe /* 746fb2f18f8Sesaxe * Provide the specified CPU a bootstrap pg 747fb2f18f8Sesaxe * This is needed to allow sane behaviour if any PG consuming 748fb2f18f8Sesaxe * code needs to deal with a partially initialized CPU 749fb2f18f8Sesaxe */ 750fb2f18f8Sesaxe void 751fb2f18f8Sesaxe pg_cpu_bootstrap(cpu_t *cp) 752fb2f18f8Sesaxe { 753fb2f18f8Sesaxe cp->cpu_pg = &bootstrap_pg_data; 754fb2f18f8Sesaxe } 755fb2f18f8Sesaxe 7561a77c24bSEric Saxe /* 7571a77c24bSEric Saxe * Return non-zero if the specified CPU is bootstrapped, 7581a77c24bSEric Saxe * which means it's CPU specific PG data has not yet been 7591a77c24bSEric Saxe * fully constructed. 7601a77c24bSEric Saxe */ 7611a77c24bSEric Saxe int 7621a77c24bSEric Saxe pg_cpu_is_bootstrapped(cpu_t *cp) 7631a77c24bSEric Saxe { 7641a77c24bSEric Saxe return (cp->cpu_pg == &bootstrap_pg_data); 7651a77c24bSEric Saxe } 7661a77c24bSEric Saxe 767fb2f18f8Sesaxe /*ARGSUSED*/ 768fb2f18f8Sesaxe static pg_t * 769fb2f18f8Sesaxe pg_alloc_default(pg_class_t class) 770fb2f18f8Sesaxe { 771fb2f18f8Sesaxe return (kmem_zalloc(sizeof (pg_t), KM_SLEEP)); 772fb2f18f8Sesaxe } 773fb2f18f8Sesaxe 774fb2f18f8Sesaxe /*ARGSUSED*/ 775fb2f18f8Sesaxe static void 776fb2f18f8Sesaxe pg_free_default(struct pg *pg) 777fb2f18f8Sesaxe { 778fb2f18f8Sesaxe kmem_free(pg, sizeof (pg_t)); 779fb2f18f8Sesaxe } 7800e751525SEric Saxe 7810e751525SEric Saxe static void 7820e751525SEric Saxe pg_null_op() 7830e751525SEric Saxe { 7840e751525SEric Saxe } 7850e751525SEric Saxe 7860e751525SEric Saxe /* 7870e751525SEric Saxe * Invoke the "thread switch" callback for each of the CPU's PGs 7880e751525SEric Saxe * This is invoked from the dispatcher swtch() routine, which is called 7890e751525SEric Saxe * when a thread running an a CPU should switch to another thread. 7900e751525SEric Saxe * "cp" is the CPU on which the thread switch is happening 7910e751525SEric Saxe * "now" is an unscaled hrtime_t timestamp taken in swtch() 7920e751525SEric Saxe * "old" and "new" are the outgoing and incoming threads, respectively. 7930e751525SEric Saxe */ 7940e751525SEric Saxe void 7950e751525SEric Saxe pg_ev_thread_swtch(struct cpu *cp, hrtime_t now, kthread_t *old, kthread_t *new) 7960e751525SEric Saxe { 7970e751525SEric Saxe int i, sz; 7980e751525SEric Saxe group_t *grp; 7990e751525SEric Saxe pg_t *pg; 8000e751525SEric Saxe 8010e751525SEric Saxe grp = &cp->cpu_pg->pgs; 8020e751525SEric Saxe sz = GROUP_SIZE(grp); 8030e751525SEric Saxe for (i = 0; i < sz; i++) { 8040e751525SEric Saxe pg = GROUP_ACCESS(grp, i); 8050e751525SEric Saxe pg->pg_cb.thread_swtch(pg, cp, now, old, new); 8060e751525SEric Saxe } 8070e751525SEric Saxe } 8080e751525SEric Saxe 8090e751525SEric Saxe /* 8100e751525SEric Saxe * Invoke the "thread remain" callback for each of the CPU's PGs. 8110e751525SEric Saxe * This is called from the dispatcher's swtch() routine when a thread 8120e751525SEric Saxe * running on the CPU "cp" is switching to itself, which can happen as an 8130e751525SEric Saxe * artifact of the thread's timeslice expiring. 8140e751525SEric Saxe */ 8150e751525SEric Saxe void 8160e751525SEric Saxe pg_ev_thread_remain(struct cpu *cp, kthread_t *t) 8170e751525SEric Saxe { 8180e751525SEric Saxe int i, sz; 8190e751525SEric Saxe group_t *grp; 8200e751525SEric Saxe pg_t *pg; 8210e751525SEric Saxe 8220e751525SEric Saxe grp = &cp->cpu_pg->pgs; 8230e751525SEric Saxe sz = GROUP_SIZE(grp); 8240e751525SEric Saxe for (i = 0; i < sz; i++) { 8250e751525SEric Saxe pg = GROUP_ACCESS(grp, i); 8260e751525SEric Saxe pg->pg_cb.thread_remain(pg, cp, t); 8270e751525SEric Saxe } 8280e751525SEric Saxe } 829