1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/systm.h> 27 #include <sys/types.h> 28 #include <sys/param.h> 29 #include <sys/thread.h> 30 #include <sys/cpuvar.h> 31 #include <sys/cpupart.h> 32 #include <sys/kmem.h> 33 #include <sys/cmn_err.h> 34 #include <sys/kstat.h> 35 #include <sys/processor.h> 36 #include <sys/disp.h> 37 #include <sys/group.h> 38 #include <sys/pg.h> 39 40 /* 41 * Processor groups 42 * 43 * With the introduction of Chip Multi-Threaded (CMT) processor architectures, 44 * it is no longer necessarily true that a given physical processor module 45 * will present itself as a single schedulable entity (cpu_t). Rather, each 46 * chip and/or processor core may present itself as one or more "logical" CPUs. 47 * 48 * The logical CPUs presented may share physical components such as caches, 49 * data pipes, execution pipelines, FPUs, etc. It is advantageous to have the 50 * kernel be aware of the relationships existing between logical CPUs so that 51 * the appropriate optmizations may be employed. 52 * 53 * The processor group abstraction represents a set of logical CPUs that 54 * generally share some sort of physical or characteristic relationship. 55 * 56 * In the case of a physical sharing relationship, the CPUs in the group may 57 * share a pipeline, cache or floating point unit. In the case of a logical 58 * relationship, a PG may represent the set of CPUs in a processor set, or the 59 * set of CPUs running at a particular clock speed. 60 * 61 * The generic processor group structure, pg_t, contains the elements generic 62 * to a group of CPUs. Depending on the nature of the CPU relationship 63 * (LOGICAL or PHYSICAL), a pointer to a pg may be recast to a "view" of that 64 * PG where more specific data is represented. 65 * 66 * As an example, a PG representing a PHYSICAL relationship, may be recast to 67 * a pghw_t, where data further describing the hardware sharing relationship 68 * is maintained. See pghw.c and pghw.h for details on physical PGs. 69 * 70 * At this time a more specialized casting of a PG representing a LOGICAL 71 * relationship has not been implemented, but the architecture allows for this 72 * in the future. 73 * 74 * Processor Group Classes 75 * 76 * Processor group consumers may wish to maintain and associate specific 77 * data with the PGs they create. For this reason, a mechanism for creating 78 * class specific PGs exists. Classes may overload the default functions for 79 * creating, destroying, and associating CPUs with PGs, and may also register 80 * class specific callbacks to be invoked when the CPU related system 81 * configuration changes. Class specific data is stored/associated with 82 * PGs by incorporating the pg_t (or pghw_t, as appropriate), as the first 83 * element of a class specific PG object. In memory, such a structure may look 84 * like: 85 * 86 * ----------------------- - - - 87 * | common | | | | <--(pg_t *) 88 * ----------------------- | | - 89 * | HW specific | | | <-----(pghw_t *) 90 * ----------------------- | - 91 * | class specific | | <-------(pg_cmt_t *) 92 * ----------------------- - 93 * 94 * Access to the PG class specific data can be had by casting a pointer to 95 * it's class specific view. 96 */ 97 98 static pg_t *pg_alloc_default(pg_class_t); 99 static void pg_free_default(pg_t *); 100 static void pg_null_op(); 101 102 /* 103 * Bootstrap CPU specific PG data 104 * See pg_cpu_bootstrap() 105 */ 106 static cpu_pg_t bootstrap_pg_data; 107 108 /* 109 * Bitset of allocated PG ids (they are sequential) 110 * and the next free id in the set. 111 */ 112 static bitset_t pg_id_set; 113 static pgid_t pg_id_next = 0; 114 115 /* 116 * Default and externed PG ops vectors 117 */ 118 static struct pg_ops pg_ops_default = { 119 pg_alloc_default, /* alloc */ 120 pg_free_default, /* free */ 121 NULL, /* cpu_init */ 122 NULL, /* cpu_fini */ 123 NULL, /* cpu_active */ 124 NULL, /* cpu_inactive */ 125 NULL, /* cpupart_in */ 126 NULL, /* cpupart_out */ 127 NULL, /* cpupart_move */ 128 NULL, /* cpu_belongs */ 129 NULL, /* policy_name */ 130 }; 131 132 static struct pg_cb_ops pg_cb_ops_default = { 133 pg_null_op, /* thread_swtch */ 134 pg_null_op, /* thread_remain */ 135 }; 136 137 /* 138 * Class specific PG allocation callbacks 139 */ 140 #define PG_ALLOC(class) \ 141 (pg_classes[class].pgc_ops->alloc ? \ 142 pg_classes[class].pgc_ops->alloc() : \ 143 pg_classes[pg_default_cid].pgc_ops->alloc()) 144 145 #define PG_FREE(pg) \ 146 ((pg)->pg_class->pgc_ops->free ? \ 147 (pg)->pg_class->pgc_ops->free(pg) : \ 148 pg_classes[pg_default_cid].pgc_ops->free(pg)) \ 149 150 151 /* 152 * Class specific PG policy name 153 */ 154 #define PG_POLICY_NAME(pg) \ 155 ((pg)->pg_class->pgc_ops->policy_name ? \ 156 (pg)->pg_class->pgc_ops->policy_name(pg) : NULL) \ 157 158 /* 159 * Class specific membership test callback 160 */ 161 #define PG_CPU_BELONGS(pg, cp) \ 162 ((pg)->pg_class->pgc_ops->cpu_belongs ? \ 163 (pg)->pg_class->pgc_ops->cpu_belongs(pg, cp) : 0) \ 164 165 /* 166 * CPU configuration callbacks 167 */ 168 #define PG_CPU_INIT(class, cp, cpu_pg) \ 169 { \ 170 if (pg_classes[class].pgc_ops->cpu_init) \ 171 pg_classes[class].pgc_ops->cpu_init(cp, cpu_pg); \ 172 } 173 174 #define PG_CPU_FINI(class, cp, cpu_pg) \ 175 { \ 176 if (pg_classes[class].pgc_ops->cpu_fini) \ 177 pg_classes[class].pgc_ops->cpu_fini(cp, cpu_pg); \ 178 } 179 180 #define PG_CPU_ACTIVE(class, cp) \ 181 { \ 182 if (pg_classes[class].pgc_ops->cpu_active) \ 183 pg_classes[class].pgc_ops->cpu_active(cp); \ 184 } 185 186 #define PG_CPU_INACTIVE(class, cp) \ 187 { \ 188 if (pg_classes[class].pgc_ops->cpu_inactive) \ 189 pg_classes[class].pgc_ops->cpu_inactive(cp); \ 190 } 191 192 /* 193 * CPU / cpupart configuration callbacks 194 */ 195 #define PG_CPUPART_IN(class, cp, pp) \ 196 { \ 197 if (pg_classes[class].pgc_ops->cpupart_in) \ 198 pg_classes[class].pgc_ops->cpupart_in(cp, pp); \ 199 } 200 201 #define PG_CPUPART_OUT(class, cp, pp) \ 202 { \ 203 if (pg_classes[class].pgc_ops->cpupart_out) \ 204 pg_classes[class].pgc_ops->cpupart_out(cp, pp); \ 205 } 206 207 #define PG_CPUPART_MOVE(class, cp, old, new) \ 208 { \ 209 if (pg_classes[class].pgc_ops->cpupart_move) \ 210 pg_classes[class].pgc_ops->cpupart_move(cp, old, new); \ 211 } 212 213 214 215 static pg_class_t *pg_classes; 216 static int pg_nclasses; 217 218 static pg_cid_t pg_default_cid; 219 220 /* 221 * Initialze common PG subsystem. 222 */ 223 void 224 pg_init(void) 225 { 226 extern void pg_cmt_class_init(); 227 extern void pg_cmt_cpu_startup(); 228 229 pg_default_cid = 230 pg_class_register("default", &pg_ops_default, PGR_LOGICAL); 231 232 /* 233 * Initialize classes to allow them to register with the framework 234 */ 235 pg_cmt_class_init(); 236 237 pg_cpu0_init(); 238 pg_cmt_cpu_startup(CPU); 239 } 240 241 /* 242 * Perform CPU 0 initialization 243 */ 244 void 245 pg_cpu0_init(void) 246 { 247 extern void pghw_physid_create(); 248 249 /* 250 * Create the physical ID cache for the boot CPU 251 */ 252 pghw_physid_create(CPU); 253 254 /* 255 * pg_cpu_* require that cpu_lock be held 256 */ 257 mutex_enter(&cpu_lock); 258 259 (void) pg_cpu_init(CPU, B_FALSE); 260 pg_cpupart_in(CPU, &cp_default); 261 pg_cpu_active(CPU); 262 263 mutex_exit(&cpu_lock); 264 } 265 266 /* 267 * Invoked when topology for CPU0 changes 268 * post pg_cpu0_init(). 269 * 270 * Currently happens as a result of null_proc_lpa 271 * on Starcat. 272 */ 273 void 274 pg_cpu0_reinit(void) 275 { 276 mutex_enter(&cpu_lock); 277 pg_cpu_inactive(CPU); 278 pg_cpupart_out(CPU, &cp_default); 279 pg_cpu_fini(CPU, NULL); 280 281 (void) pg_cpu_init(CPU, B_FALSE); 282 pg_cpupart_in(CPU, &cp_default); 283 pg_cpu_active(CPU); 284 mutex_exit(&cpu_lock); 285 } 286 287 /* 288 * Register a new PG class 289 */ 290 pg_cid_t 291 pg_class_register(char *name, struct pg_ops *ops, pg_relation_t relation) 292 { 293 pg_class_t *newclass; 294 pg_class_t *classes_old; 295 id_t cid; 296 297 mutex_enter(&cpu_lock); 298 299 /* 300 * Allocate a new pg_class_t in the pg_classes array 301 */ 302 if (pg_nclasses == 0) { 303 pg_classes = kmem_zalloc(sizeof (pg_class_t), KM_SLEEP); 304 } else { 305 classes_old = pg_classes; 306 pg_classes = 307 kmem_zalloc(sizeof (pg_class_t) * (pg_nclasses + 1), 308 KM_SLEEP); 309 (void) kcopy(classes_old, pg_classes, 310 sizeof (pg_class_t) * pg_nclasses); 311 kmem_free(classes_old, sizeof (pg_class_t) * pg_nclasses); 312 } 313 314 cid = pg_nclasses++; 315 newclass = &pg_classes[cid]; 316 317 (void) strncpy(newclass->pgc_name, name, PG_CLASS_NAME_MAX); 318 newclass->pgc_id = cid; 319 newclass->pgc_ops = ops; 320 newclass->pgc_relation = relation; 321 322 mutex_exit(&cpu_lock); 323 324 return (cid); 325 } 326 327 /* 328 * Try to find an existing pg in set in which to place cp. 329 * Returns the pg if found, and NULL otherwise. 330 * In the event that the CPU could belong to multiple 331 * PGs in the set, the first matching PG will be returned. 332 */ 333 pg_t * 334 pg_cpu_find_pg(cpu_t *cp, group_t *set) 335 { 336 pg_t *pg; 337 group_iter_t i; 338 339 group_iter_init(&i); 340 while ((pg = group_iterate(set, &i)) != NULL) { 341 /* 342 * Ask the class if the CPU belongs here 343 */ 344 if (PG_CPU_BELONGS(pg, cp)) 345 return (pg); 346 } 347 return (NULL); 348 } 349 350 /* 351 * Iterate over the CPUs in a PG after initializing 352 * the iterator with PG_CPU_ITR_INIT() 353 */ 354 cpu_t * 355 pg_cpu_next(pg_cpu_itr_t *itr) 356 { 357 cpu_t *cpu; 358 pg_t *pg = itr->pg; 359 360 cpu = group_iterate(&pg->pg_cpus, &itr->position); 361 return (cpu); 362 } 363 364 /* 365 * Test if a given PG contains a given CPU 366 */ 367 boolean_t 368 pg_cpu_find(pg_t *pg, cpu_t *cp) 369 { 370 if (group_find(&pg->pg_cpus, cp) == (uint_t)-1) 371 return (B_FALSE); 372 373 return (B_TRUE); 374 } 375 376 /* 377 * Set the PGs callbacks to the default 378 */ 379 void 380 pg_callback_set_defaults(pg_t *pg) 381 { 382 bcopy(&pg_cb_ops_default, &pg->pg_cb, sizeof (struct pg_cb_ops)); 383 } 384 385 /* 386 * Create a PG of a given class. 387 * This routine may block. 388 */ 389 pg_t * 390 pg_create(pg_cid_t cid) 391 { 392 pg_t *pg; 393 pgid_t id; 394 395 ASSERT(MUTEX_HELD(&cpu_lock)); 396 397 /* 398 * Call the class specific PG allocation routine 399 */ 400 pg = PG_ALLOC(cid); 401 pg->pg_class = &pg_classes[cid]; 402 pg->pg_relation = pg->pg_class->pgc_relation; 403 404 /* 405 * Find the next free sequential pg id 406 */ 407 do { 408 if (pg_id_next >= bitset_capacity(&pg_id_set)) 409 bitset_resize(&pg_id_set, pg_id_next + 1); 410 id = pg_id_next++; 411 } while (bitset_in_set(&pg_id_set, id)); 412 413 pg->pg_id = id; 414 bitset_add(&pg_id_set, pg->pg_id); 415 416 /* 417 * Create the PG's CPU group 418 */ 419 group_create(&pg->pg_cpus); 420 421 /* 422 * Initialize the events ops vector 423 */ 424 pg_callback_set_defaults(pg); 425 426 return (pg); 427 } 428 429 /* 430 * Destroy a PG. 431 * This routine may block. 432 */ 433 void 434 pg_destroy(pg_t *pg) 435 { 436 ASSERT(MUTEX_HELD(&cpu_lock)); 437 438 group_destroy(&pg->pg_cpus); 439 440 /* 441 * Unassign the pg_id 442 */ 443 if (pg_id_next > pg->pg_id) 444 pg_id_next = pg->pg_id; 445 bitset_del(&pg_id_set, pg->pg_id); 446 447 /* 448 * Invoke the class specific de-allocation routine 449 */ 450 PG_FREE(pg); 451 } 452 453 /* 454 * Add the CPU "cp" to processor group "pg" 455 * This routine may block. 456 */ 457 void 458 pg_cpu_add(pg_t *pg, cpu_t *cp, cpu_pg_t *cpu_pg) 459 { 460 int err; 461 462 ASSERT(MUTEX_HELD(&cpu_lock)); 463 464 /* This adds the CPU to the PG's CPU group */ 465 err = group_add(&pg->pg_cpus, cp, GRP_RESIZE); 466 ASSERT(err == 0); 467 468 /* 469 * The CPU should be referencing the bootstrap PG data still 470 * at this point, since this routine may block causing us to 471 * enter the dispatcher. 472 */ 473 ASSERT(pg_cpu_is_bootstrapped(cp)); 474 475 /* This adds the PG to the CPUs PG group */ 476 err = group_add(&cpu_pg->pgs, pg, GRP_RESIZE); 477 ASSERT(err == 0); 478 } 479 480 /* 481 * Remove "cp" from "pg". 482 * This routine may block. 483 */ 484 void 485 pg_cpu_delete(pg_t *pg, cpu_t *cp, cpu_pg_t *cpu_pg) 486 { 487 int err; 488 489 ASSERT(MUTEX_HELD(&cpu_lock)); 490 491 /* Remove the CPU from the PG */ 492 err = group_remove(&pg->pg_cpus, cp, GRP_RESIZE); 493 ASSERT(err == 0); 494 495 /* 496 * The CPU should be referencing the bootstrap PG data still 497 * at this point, since this routine may block causing us to 498 * enter the dispatcher. 499 */ 500 ASSERT(pg_cpu_is_bootstrapped(cp)); 501 502 /* Remove the PG from the CPU's PG group */ 503 err = group_remove(&cpu_pg->pgs, pg, GRP_RESIZE); 504 ASSERT(err == 0); 505 } 506 507 /* 508 * Allocate a CPU's PG data. This hangs off struct cpu at cpu_pg 509 */ 510 static cpu_pg_t * 511 pg_cpu_data_alloc(void) 512 { 513 cpu_pg_t *pgd; 514 515 pgd = kmem_zalloc(sizeof (cpu_pg_t), KM_SLEEP); 516 group_create(&pgd->pgs); 517 group_create(&pgd->cmt_pgs); 518 519 return (pgd); 520 } 521 522 /* 523 * Free the CPU's PG data. 524 */ 525 static void 526 pg_cpu_data_free(cpu_pg_t *pgd) 527 { 528 group_destroy(&pgd->pgs); 529 group_destroy(&pgd->cmt_pgs); 530 kmem_free(pgd, sizeof (cpu_pg_t)); 531 } 532 533 /* 534 * Called when either a new CPU is coming into the system (either 535 * via booting or DR) or when the CPU's PG data is being recalculated. 536 * Allocate its PG data, and notify all registered classes about 537 * the new CPU. 538 * 539 * If "deferred_init" is B_TRUE, the CPU's PG data will be allocated 540 * and returned, but the "bootstrap" structure will be left in place. 541 * The deferred_init option is used when all CPUs in the system are 542 * using the bootstrap structure as part of the process of recalculating 543 * all PG data. The caller must replace the bootstrap structure with the 544 * allocated PG data before pg_cpu_active is called. 545 * 546 * This routine may block. 547 */ 548 cpu_pg_t * 549 pg_cpu_init(cpu_t *cp, boolean_t deferred_init) 550 { 551 pg_cid_t i; 552 cpu_pg_t *cpu_pg; 553 554 ASSERT(MUTEX_HELD(&cpu_lock)); 555 556 /* 557 * Allocate and size the per CPU pg data 558 * 559 * The CPU's PG data will be populated by the various 560 * PG classes during the invocation of the PG_CPU_INIT() 561 * callback below. 562 * 563 * Since the we could block and enter the dispatcher during 564 * this process, the CPU will continue to reference the bootstrap 565 * PG data until all the initialization completes. 566 */ 567 ASSERT(pg_cpu_is_bootstrapped(cp)); 568 569 cpu_pg = pg_cpu_data_alloc(); 570 571 /* 572 * Notify all registered classes about the new CPU 573 */ 574 for (i = 0; i < pg_nclasses; i++) 575 PG_CPU_INIT(i, cp, cpu_pg); 576 577 /* 578 * The CPU's PG data is now ready to use. 579 */ 580 if (deferred_init == B_FALSE) 581 cp->cpu_pg = cpu_pg; 582 583 return (cpu_pg); 584 } 585 586 /* 587 * Either this CPU is being deleted from the system or its PG data is 588 * being recalculated. Notify the classes and free up the CPU's PG data. 589 * 590 * If "cpu_pg_deferred" is non-NULL, it points to the CPU's PG data and 591 * serves to indicate that this CPU is already using the bootstrap 592 * stucture. Used as part of the process to recalculate the PG data for 593 * all CPUs in the system. 594 */ 595 void 596 pg_cpu_fini(cpu_t *cp, cpu_pg_t *cpu_pg_deferred) 597 { 598 pg_cid_t i; 599 cpu_pg_t *cpu_pg; 600 601 ASSERT(MUTEX_HELD(&cpu_lock)); 602 603 if (cpu_pg_deferred == NULL) { 604 cpu_pg = cp->cpu_pg; 605 606 /* 607 * This can happen if the CPU coming into the system 608 * failed to power on. 609 */ 610 if (cpu_pg == NULL || pg_cpu_is_bootstrapped(cp)) 611 return; 612 613 /* 614 * Have the CPU reference the bootstrap PG data to survive 615 * the dispatcher should it block from here on out. 616 */ 617 pg_cpu_bootstrap(cp); 618 } else { 619 ASSERT(pg_cpu_is_bootstrapped(cp)); 620 cpu_pg = cpu_pg_deferred; 621 } 622 623 for (i = 0; i < pg_nclasses; i++) 624 PG_CPU_FINI(i, cp, cpu_pg); 625 626 pg_cpu_data_free(cpu_pg); 627 } 628 629 /* 630 * This CPU is becoming active (online) 631 * This routine may not block as it is called from paused CPUs 632 * context. 633 */ 634 void 635 pg_cpu_active(cpu_t *cp) 636 { 637 pg_cid_t i; 638 639 ASSERT(MUTEX_HELD(&cpu_lock)); 640 641 /* 642 * Notify all registered classes about the new CPU 643 */ 644 for (i = 0; i < pg_nclasses; i++) 645 PG_CPU_ACTIVE(i, cp); 646 } 647 648 /* 649 * This CPU is going inactive (offline) 650 * This routine may not block, as it is called from paused 651 * CPUs context. 652 */ 653 void 654 pg_cpu_inactive(cpu_t *cp) 655 { 656 pg_cid_t i; 657 658 ASSERT(MUTEX_HELD(&cpu_lock)); 659 660 /* 661 * Notify all registered classes about the new CPU 662 */ 663 for (i = 0; i < pg_nclasses; i++) 664 PG_CPU_INACTIVE(i, cp); 665 } 666 667 /* 668 * Invoked when the CPU is about to move into the partition 669 * This routine may block. 670 */ 671 void 672 pg_cpupart_in(cpu_t *cp, cpupart_t *pp) 673 { 674 int i; 675 676 ASSERT(MUTEX_HELD(&cpu_lock)); 677 678 /* 679 * Notify all registered classes that the 680 * CPU is about to enter the CPU partition 681 */ 682 for (i = 0; i < pg_nclasses; i++) 683 PG_CPUPART_IN(i, cp, pp); 684 } 685 686 /* 687 * Invoked when the CPU is about to move out of the partition 688 * This routine may block. 689 */ 690 /*ARGSUSED*/ 691 void 692 pg_cpupart_out(cpu_t *cp, cpupart_t *pp) 693 { 694 int i; 695 696 ASSERT(MUTEX_HELD(&cpu_lock)); 697 698 /* 699 * Notify all registered classes that the 700 * CPU is about to leave the CPU partition 701 */ 702 for (i = 0; i < pg_nclasses; i++) 703 PG_CPUPART_OUT(i, cp, pp); 704 } 705 706 /* 707 * Invoked when the CPU is *moving* partitions. 708 * 709 * This routine may not block, as it is called from paused CPUs 710 * context. 711 */ 712 void 713 pg_cpupart_move(cpu_t *cp, cpupart_t *oldpp, cpupart_t *newpp) 714 { 715 int i; 716 717 ASSERT(MUTEX_HELD(&cpu_lock)); 718 719 /* 720 * Notify all registered classes that the 721 * CPU is about to leave the CPU partition 722 */ 723 for (i = 0; i < pg_nclasses; i++) 724 PG_CPUPART_MOVE(i, cp, oldpp, newpp); 725 } 726 727 /* 728 * Return a class specific string describing a policy implemented 729 * across this PG 730 */ 731 char * 732 pg_policy_name(pg_t *pg) 733 { 734 char *str; 735 if ((str = PG_POLICY_NAME(pg)) != NULL) 736 return (str); 737 738 return ("N/A"); 739 } 740 741 /* 742 * Provide the specified CPU a bootstrap pg 743 * This is needed to allow sane behaviour if any PG consuming 744 * code needs to deal with a partially initialized CPU 745 */ 746 void 747 pg_cpu_bootstrap(cpu_t *cp) 748 { 749 cp->cpu_pg = &bootstrap_pg_data; 750 } 751 752 /* 753 * Return non-zero if the specified CPU is bootstrapped, 754 * which means it's CPU specific PG data has not yet been 755 * fully constructed. 756 */ 757 int 758 pg_cpu_is_bootstrapped(cpu_t *cp) 759 { 760 return (cp->cpu_pg == &bootstrap_pg_data); 761 } 762 763 /*ARGSUSED*/ 764 static pg_t * 765 pg_alloc_default(pg_class_t class) 766 { 767 return (kmem_zalloc(sizeof (pg_t), KM_SLEEP)); 768 } 769 770 /*ARGSUSED*/ 771 static void 772 pg_free_default(struct pg *pg) 773 { 774 kmem_free(pg, sizeof (pg_t)); 775 } 776 777 static void 778 pg_null_op() 779 { 780 } 781 782 /* 783 * Invoke the "thread switch" callback for each of the CPU's PGs 784 * This is invoked from the dispatcher swtch() routine, which is called 785 * when a thread running an a CPU should switch to another thread. 786 * "cp" is the CPU on which the thread switch is happening 787 * "now" is an unscaled hrtime_t timestamp taken in swtch() 788 * "old" and "new" are the outgoing and incoming threads, respectively. 789 */ 790 void 791 pg_ev_thread_swtch(struct cpu *cp, hrtime_t now, kthread_t *old, kthread_t *new) 792 { 793 int i, sz; 794 group_t *grp; 795 pg_t *pg; 796 797 grp = &cp->cpu_pg->pgs; 798 sz = GROUP_SIZE(grp); 799 for (i = 0; i < sz; i++) { 800 pg = GROUP_ACCESS(grp, i); 801 pg->pg_cb.thread_swtch(pg, cp, now, old, new); 802 } 803 } 804 805 /* 806 * Invoke the "thread remain" callback for each of the CPU's PGs. 807 * This is called from the dispatcher's swtch() routine when a thread 808 * running on the CPU "cp" is switching to itself, which can happen as an 809 * artifact of the thread's timeslice expiring. 810 */ 811 void 812 pg_ev_thread_remain(struct cpu *cp, kthread_t *t) 813 { 814 int i, sz; 815 group_t *grp; 816 pg_t *pg; 817 818 grp = &cp->cpu_pg->pgs; 819 sz = GROUP_SIZE(grp); 820 for (i = 0; i < sz; i++) { 821 pg = GROUP_ACCESS(grp, i); 822 pg->pg_cb.thread_remain(pg, cp, t); 823 } 824 } 825