ac.c revision 1341:6d7c4f090a72
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/* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#include <sys/types.h> 30#include <sys/conf.h> 31#include <sys/ddi.h> 32#include <sys/sunddi.h> 33#include <sys/ddi_impldefs.h> 34#include <sys/obpdefs.h> 35#include <sys/cmn_err.h> 36#include <sys/errno.h> 37#include <sys/kmem.h> 38#include <sys/debug.h> 39#include <sys/sysmacros.h> 40#include <sys/machsystm.h> 41#include <vm/hat_sfmmu.h> 42#include <sys/autoconf.h> 43#include <sys/open.h> 44#include <sys/stat.h> 45#include <sys/modctl.h> 46#include <sys/fhc.h> 47#include <sys/ac.h> 48#include <sys/cpu_module.h> 49#include <sys/x_call.h> 50#include <sys/fpu/fpusystm.h> 51#include <sys/lgrp.h> 52 53/* Useful debugging Stuff */ 54#include <sys/nexusdebug.h> 55 56/* 57 * Function prototypes 58 */ 59 60static int ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 61 void **result); 62static int ac_attach(dev_info_t *, ddi_attach_cmd_t); 63static int ac_detach(dev_info_t *, ddi_detach_cmd_t); 64static int ac_open(dev_t *, int, int, cred_t *); 65static int ac_close(dev_t, int, int, cred_t *); 66static int ac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 67 68static void ac_add_kstats(struct ac_soft_state *); 69static void ac_del_kstats(struct ac_soft_state *); 70static int ac_misc_kstat_update(kstat_t *, int); 71static void ac_add_picN_kstats(dev_info_t *dip); 72static int ac_counters_kstat_update(kstat_t *, int); 73static void ac_get_memory_status(struct ac_soft_state *, enum ac_bank_id); 74static void ac_eval_memory_status(struct ac_soft_state *, enum ac_bank_id); 75static void ac_ecache_flush(uint64_t, uint64_t); 76static int ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag); 77static int ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag); 78static int ac_reset_timeout(int rw); 79static void ac_timeout(void *); 80static int ac_enter_transition(void); 81static void ac_exit_transition(void); 82 83 84int ac_add_memory(ac_cfga_pkt_t *); 85int ac_del_memory(ac_cfga_pkt_t *); 86int ac_mem_stat(ac_cfga_pkt_t *, int); 87int ac_mem_test_start(ac_cfga_pkt_t *, int); 88int ac_mem_test_stop(ac_cfga_pkt_t *, int); 89int ac_mem_test_read(ac_cfga_pkt_t *, int); 90int ac_mem_test_write(ac_cfga_pkt_t *, int); 91void ac_mem_test_stop_on_close(uint_t, uint_t); 92/* 93 * ac audit message events 94 */ 95typedef enum { 96 AC_AUDIT_OSTATE_CONFIGURE, 97 AC_AUDIT_OSTATE_UNCONFIGURE, 98 AC_AUDIT_OSTATE_SUCCEEDED, 99 AC_AUDIT_OSTATE_CONFIGURE_FAILED, 100 AC_AUDIT_OSTATE_UNCONFIGURE_FAILED 101} ac_audit_evt_t; 102static void ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt); 103static char *ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event); 104 105/* The memory ioctl interface version of this driver. */ 106static ac_mem_version_t ac_mem_version = AC_MEM_ADMIN_VERSION; 107 108static int ac_mem_exercise(ac_cfga_pkt_t *, int); 109 110/* 111 * Configuration data structures 112 */ 113static struct cb_ops ac_cb_ops = { 114 ac_open, /* open */ 115 ac_close, /* close */ 116 nulldev, /* strategy */ 117 nulldev, /* print */ 118 nodev, /* dump */ 119 nulldev, /* read */ 120 nulldev, /* write */ 121 ac_ioctl, /* ioctl */ 122 nodev, /* devmap */ 123 nodev, /* mmap */ 124 nodev, /* segmap */ 125 nochpoll, /* poll */ 126 ddi_prop_op, /* cb_prop_op */ 127 0, /* streamtab */ 128 D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ 129 CB_REV, /* rev */ 130 nodev, /* cb_aread */ 131 nodev /* cb_awrite */ 132}; 133 134static struct dev_ops ac_ops = { 135 DEVO_REV, /* devo_rev, */ 136 0, /* refcnt */ 137 ac_info, /* getinfo */ 138 nulldev, /* identify */ 139 nulldev, /* probe */ 140 ac_attach, /* attach */ 141 ac_detach, /* detach */ 142 nulldev, /* reset */ 143 &ac_cb_ops, /* cb_ops */ 144 (struct bus_ops *)0, /* bus_ops */ 145 nulldev /* power */ 146}; 147 148/* 149 * Driver globals 150 */ 151void *acp; /* ac soft state hook */ 152static kstat_t *ac_picN_ksp[AC_NUM_PICS]; /* performance picN kstats */ 153static int ac_attachcnt = 0; /* number of instances attached */ 154static kmutex_t ac_attachcnt_mutex; /* ac_attachcnt lock - attach/detach */ 155static kmutex_t ac_hot_plug_mode_mutex; 156static timeout_id_t ac_hot_plug_timeout; 157static int ac_hot_plug_timeout_interval = 10; 158 159#define AC_GETSOFTC(I) \ 160 ((struct ac_soft_state *)ddi_get_soft_state(acp, (I))) 161 162extern struct mod_ops mod_driverops; 163 164static struct modldrv modldrv = { 165 &mod_driverops, /* Type of module. This one is a driver */ 166 "AC Leaf v%I%", /* name of module */ 167 &ac_ops, /* driver ops */ 168}; 169 170static struct modlinkage modlinkage = { 171 MODREV_1, 172 (void *)&modldrv, 173 NULL 174}; 175 176#ifndef lint 177static char _depends_on[] = "drv/fhc"; 178#endif /* lint */ 179 180/* 181 * These are the module initialization routines. 182 */ 183 184int 185_init(void) 186{ 187 int error; 188 189 if ((error = ddi_soft_state_init(&acp, sizeof (struct ac_soft_state), 190 1)) != 0) 191 return (error); 192 193 if ((error = mod_install(&modlinkage)) != 0) { 194 ddi_soft_state_fini(&acp); 195 return (error); 196 } 197 /* Initialize global mutex */ 198 mutex_init(&ac_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL); 199 mutex_init(&ac_hot_plug_mode_mutex, NULL, MUTEX_DRIVER, NULL); 200 return (0); 201} 202 203int 204_fini(void) 205{ 206 int error; 207 208 if ((error = mod_remove(&modlinkage)) == 0) { 209 ddi_soft_state_fini(&acp); 210 mutex_destroy(&ac_attachcnt_mutex); 211 mutex_destroy(&ac_hot_plug_mode_mutex); 212 } 213 return (error); 214} 215 216int 217_info(struct modinfo *modinfop) 218{ 219 return (mod_info(&modlinkage, modinfop)); 220} 221 222/* ARGSUSED */ 223static int 224ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 225{ 226 dev_t dev; 227 int instance; 228 229 if (infocmd == DDI_INFO_DEVT2INSTANCE) { 230 dev = (dev_t)arg; 231 instance = AC_GETINSTANCE(getminor(dev)); 232 *result = (void *)(uintptr_t)instance; 233 return (DDI_SUCCESS); 234 } 235 return (DDI_FAILURE); 236} 237 238static int 239ac_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 240{ 241 int instance; 242 struct ac_soft_state *softsp; 243 struct bd_list *list = NULL; 244 245 switch (cmd) { 246 case DDI_ATTACH: 247 break; 248 249 case DDI_RESUME: 250 return (DDI_SUCCESS); 251 252 default: 253 return (DDI_FAILURE); 254 } 255 256 instance = ddi_get_instance(devi); 257 258 if (ddi_soft_state_zalloc(acp, instance) != DDI_SUCCESS) { 259 cmn_err(CE_WARN, "ddi_soft_state_zalloc failed for ac%d", 260 instance); 261 return (DDI_FAILURE); 262 } 263 264 softsp = ddi_get_soft_state(acp, instance); 265 266 /* Set the dip in the soft state */ 267 softsp->dip = devi; 268 269 /* Get the board number from this nodes parent */ 270 softsp->pdip = ddi_get_parent(softsp->dip); 271 if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip, 272 DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) { 273 cmn_err(CE_WARN, "ac%d: unable to retrieve %s property", 274 instance, OBP_BOARDNUM); 275 goto bad; 276 } 277 278 DPRINTF(AC_ATTACH_DEBUG, ("ac%d: devi= 0x%p\n," 279 " softsp=0x%p\n", instance, devi, softsp)); 280 281 /* map in the registers for this device. */ 282 if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0)) { 283 cmn_err(CE_WARN, "ac%d: unable to map registers", instance); 284 goto bad; 285 } 286 287 /* Setup the pointers to the hardware registers */ 288 softsp->ac_id = (uint32_t *)softsp->ac_base; 289 softsp->ac_memctl = (uint64_t *)((char *)softsp->ac_base + 290 AC_OFF_MEMCTL); 291 softsp->ac_memdecode0 = (uint64_t *)((char *)softsp->ac_base + 292 AC_OFF_MEMDEC0); 293 softsp->ac_memdecode1 = (uint64_t *)((char *)softsp->ac_base + 294 AC_OFF_MEMDEC1); 295 softsp->ac_counter = (uint64_t *)((char *)softsp->ac_base + 296 AC_OFF_CNTR); 297 softsp->ac_mccr = (uint32_t *)((char *)softsp->ac_base + 298 AC_OFF_MCCR); 299 300 /* nothing to suspend/resume here */ 301 (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 302 "pm-hardware-state", "no-suspend-resume"); 303 304 /* setup the the AC counter registers to allow for hotplug. */ 305 list = fhc_bdlist_lock(softsp->board); 306 307 if (list == NULL) { 308 cmn_err(CE_PANIC, "ac%d: Board %d not found in database", 309 instance, softsp->board); 310 } 311 312 /* set the AC rev into the bd list structure */ 313 list->sc.ac_compid = *softsp->ac_id; 314 315 list->ac_softsp = softsp; 316 317 if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) { 318 /* Create the minor nodes */ 319 if (ddi_create_minor_node(devi, NAME_BANK0, S_IFCHR, 320 (AC_PUTINSTANCE(instance) | 0), 321 DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) { 322 cmn_err(CE_WARN, "ac%d: \"%s\" " 323 "ddi_create_minor_node failed", instance, 324 NAME_BANK0); 325 } 326 if (ddi_create_minor_node(devi, NAME_BANK1, S_IFCHR, 327 (AC_PUTINSTANCE(instance) | 1), 328 DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) { 329 cmn_err(CE_WARN, "ac%d: \"%s\" " 330 "ddi_create_minor_node failed", instance, 331 NAME_BANK0); 332 } 333 334 /* purge previous fhc pa database entries */ 335 fhc_del_memloc(softsp->board); 336 337 /* Inherit Memory Bank Status */ 338 ac_get_memory_status(softsp, Bank0); 339 ac_get_memory_status(softsp, Bank1); 340 /* Final Memory Bank Status evaluation and messaging */ 341 ac_eval_memory_status(softsp, Bank0); 342 ac_eval_memory_status(softsp, Bank1); 343 } 344 345 fhc_bdlist_unlock(); 346 347 /* create the kstats for this device. */ 348 ac_add_kstats(softsp); 349 350 ddi_report_dev(devi); 351 352 return (DDI_SUCCESS); 353 354bad: 355 ddi_soft_state_free(acp, instance); 356 return (DDI_FAILURE); 357} 358 359/* ARGSUSED */ 360static int 361ac_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 362{ 363 int instance; 364 struct ac_soft_state *softsp; 365 struct bd_list *list; 366 367 /* get the instance of this devi */ 368 instance = ddi_get_instance(devi); 369 370 /* get the soft state pointer for this device node */ 371 softsp = ddi_get_soft_state(acp, instance); 372 373 switch (cmd) { 374 case DDI_SUSPEND: 375 return (DDI_SUCCESS); 376 377 case DDI_DETACH: 378 list = fhc_bdlist_lock(softsp->board); 379 380 if (fhc_bd_detachable(softsp->board)) 381 break; 382 else 383 fhc_bdlist_unlock(); 384 /* FALLTHROUGH */ 385 386 default: 387 return (DDI_FAILURE); 388 } 389 390 ASSERT(list->ac_softsp == softsp); 391 392 if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) { 393 int cpui; 394 395 /* 396 * Test to see if memory is in use on a CPU/MEM board. 397 * In the case of a DR operation this condition 398 * will have been assured when the board was unconfigured. 399 */ 400 if (softsp->bank[Bank0].busy != 0 || 401 softsp->bank[Bank0].ostate == SYSC_CFGA_OSTATE_CONFIGURED || 402 softsp->bank[Bank1].busy != 0 || 403 softsp->bank[Bank1].ostate == SYSC_CFGA_OSTATE_CONFIGURED) { 404 fhc_bdlist_unlock(); 405 return (DDI_FAILURE); 406 } 407 /* 408 * CPU busy test is done by the DR sequencer before 409 * device detach called. 410 */ 411 412 /* 413 * Flush all E-caches to remove references to this 414 * board's memory. 415 * 416 * Do this one CPU at a time to avoid stalls and timeouts 417 * due to all CPUs flushing concurrently. 418 * xc_one returns silently for non-existant CPUs. 419 */ 420 for (cpui = 0; cpui < NCPU; cpui++) 421 xc_one(cpui, ac_ecache_flush, 0, 0); 422 } 423 424 list->ac_softsp = NULL; 425 426 /* delete the kstat for this driver. */ 427 ac_del_kstats(softsp); 428 429 /* unmap the registers */ 430 ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0); 431 432 fhc_bdlist_unlock(); 433 434 /* Remove the minor nodes. */ 435 ddi_remove_minor_node(devi, NULL); 436 437 /* free the soft state structure */ 438 ddi_soft_state_free(acp, instance); 439 ddi_prop_remove_all(devi); 440 441 return (DDI_SUCCESS); 442} 443 444/* ARGSUSED */ 445static int 446ac_open(dev_t *devp, int flag, int otyp, cred_t *credp) 447{ 448 int instance; 449 dev_t dev; 450 struct ac_soft_state *softsp; 451 struct bd_list *board; 452 int vis; 453 454 dev = *devp; 455 instance = AC_GETINSTANCE(getminor(dev)); 456 softsp = AC_GETSOFTC(instance); 457 458 /* Is the instance attached? */ 459 if (softsp == NULL) { 460#ifdef DEBUG 461 cmn_err(CE_WARN, "ac%d device not attached", instance); 462#endif /* DEBUG */ 463 return (ENXIO); 464 } 465 466 /* 467 * If the board is not configured, hide the memory APs 468 */ 469 board = fhc_bdlist_lock(softsp->board); 470 vis = (board != NULL) && MEM_BOARD_VISIBLE(board); 471 fhc_bdlist_unlock(); 472 473 if (!vis) 474 return (ENXIO); 475 476 /* verify that otyp is appropriate */ 477 if (otyp != OTYP_CHR) { 478 return (EINVAL); 479 } 480 481 return (DDI_SUCCESS); 482} 483 484/* ARGSUSED */ 485static int 486ac_close(dev_t devt, int flag, int otyp, cred_t *credp) 487{ 488 struct ac_soft_state *softsp; 489 int instance; 490 491 instance = AC_GETINSTANCE(getminor(devt)); 492 softsp = AC_GETSOFTC(instance); 493 ASSERT(softsp != NULL); 494 ac_mem_test_stop_on_close(softsp->board, AC_GETBANK(getminor(devt))); 495 return (DDI_SUCCESS); 496} 497 498static int 499ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag) 500{ 501#ifdef _MULTI_DATAMODEL 502 if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 503 ac_cfga_cmd32_t ac_cmd32; 504 505 if (ddi_copyin((void *)arg, &ac_cmd32, 506 sizeof (ac_cfga_cmd32_t), flag) != 0) { 507 return (EFAULT); 508 } 509 pkt->cmd_cfga.force = ac_cmd32.force; 510 pkt->cmd_cfga.test = ac_cmd32.test; 511 pkt->cmd_cfga.arg = ac_cmd32.arg; 512 pkt->cmd_cfga.errtype = ac_cmd32.errtype; 513 pkt->cmd_cfga.outputstr = 514 (char *)(uintptr_t)ac_cmd32.outputstr; 515 pkt->cmd_cfga.private = 516 (void *)(uintptr_t)ac_cmd32.private; 517 } else 518#endif /* _MULTI_DATAMODEL */ 519 if (ddi_copyin((void *)arg, &(pkt->cmd_cfga), 520 sizeof (ac_cfga_cmd_t), flag) != 0) { 521 return (EFAULT); 522 } 523 pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP); 524 return (0); 525} 526 527static int 528ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag) 529{ 530 int ret = TRUE; 531 532#ifdef _MULTI_DATAMODEL 533 if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 534 535 if (ddi_copyout(&(pkt->cmd_cfga.errtype), 536 (void *)&(((ac_cfga_cmd32_t *)arg)->errtype), 537 sizeof (ac_err_t), flag) != 0) { 538 ret = FALSE; 539 } 540 } else 541#endif 542 if (ddi_copyout(&(pkt->cmd_cfga.errtype), 543 (void *)&(((ac_cfga_cmd_t *)arg)->errtype), 544 sizeof (ac_err_t), flag) != 0) { 545 ret = FALSE; 546 } 547 548 if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) && 549 (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr, 550 SYSC_OUTPUT_LEN, flag) != 0))) { 551 ret = FALSE; 552 } 553 554 kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN); 555 return (ret); 556} 557 558/* ARGSUSED */ 559static int 560ac_ioctl( 561 dev_t devt, 562 int cmd, 563 intptr_t arg, 564 int flag, 565 cred_t *cred_p, 566 int *rval_p) 567{ 568 struct ac_soft_state *softsp; 569 ac_cfga_pkt_t cfga_pkt, *pkt; 570 int instance; 571 int retval; 572 573 instance = AC_GETINSTANCE(getminor(devt)); 574 softsp = AC_GETSOFTC(instance); 575 if (softsp == NULL) { 576#ifdef DEBUG 577 cmn_err(CE_NOTE, "ac%d device not attached", instance); 578#endif /* DEBUG */ 579 return (ENXIO); 580 } 581 582 /* 583 * Dispose of the easy ones first. 584 */ 585 switch (cmd) { 586 case AC_MEM_ADMIN_VER: 587 /* 588 * Specify the revision of this ioctl interface driver. 589 */ 590 if (ddi_copyout(&ac_mem_version, (void *)arg, 591 sizeof (ac_mem_version_t), flag) != 0) 592 return (EFAULT); 593 return (DDI_SUCCESS); 594 595 case AC_MEM_CONFIGURE: 596 case AC_MEM_UNCONFIGURE: 597 case AC_MEM_STAT: 598 case AC_MEM_TEST_START: 599 case AC_MEM_TEST_STOP: 600 case AC_MEM_TEST_READ: 601 case AC_MEM_TEST_WRITE: 602 case AC_MEM_EXERCISE: 603 break; 604 605 default: 606 return (ENOTTY); 607 } 608 if (cmd != AC_MEM_STAT && !fpu_exists) { 609 return (ENOTSUP); 610 } 611 612 pkt = &cfga_pkt; 613 if ((retval = ac_pkt_init(pkt, arg, flag)) != 0) 614 return (retval); 615 pkt->softsp = softsp; 616 pkt->bank = AC_GETBANK(getminor(devt)); 617 618 switch (cmd) { 619 case AC_MEM_CONFIGURE: 620 if ((flag & FWRITE) == 0) { 621 retval = EBADF; 622 break; 623 } 624 625 if (pkt->cmd_cfga.private != NULL) { 626 retval = EINVAL; 627 break; 628 } 629 ac_policy_audit_messages(AC_AUDIT_OSTATE_CONFIGURE, pkt); 630 retval = ac_add_memory(pkt); 631 if (!retval) 632 ac_policy_audit_messages( 633 AC_AUDIT_OSTATE_SUCCEEDED, pkt); 634 else 635 ac_policy_audit_messages( 636 AC_AUDIT_OSTATE_CONFIGURE_FAILED, pkt); 637 break; 638 639 case AC_MEM_UNCONFIGURE: 640 if ((flag & FWRITE) == 0) { 641 retval = EBADF; 642 break; 643 } 644 645 if (pkt->cmd_cfga.private != NULL) { 646 retval = EINVAL; 647 break; 648 } 649 ac_policy_audit_messages(AC_AUDIT_OSTATE_UNCONFIGURE, pkt); 650 retval = ac_del_memory(pkt); 651 if (!retval) { 652 ac_policy_audit_messages( 653 AC_AUDIT_OSTATE_SUCCEEDED, pkt); 654 } else 655 ac_policy_audit_messages( 656 AC_AUDIT_OSTATE_UNCONFIGURE_FAILED, pkt); 657 break; 658 659 case AC_MEM_STAT: 660 /* 661 * Query usage of a bank of memory. 662 */ 663 retval = ac_mem_stat(pkt, flag); 664 break; 665 666 case AC_MEM_TEST_START: 667 if ((flag & FWRITE) == 0) { 668 retval = EBADF; 669 break; 670 } 671 672 retval = ac_mem_test_start(pkt, flag); 673 break; 674 675 case AC_MEM_TEST_STOP: 676 if ((flag & FWRITE) == 0) { 677 retval = EBADF; 678 break; 679 } 680 681 retval = ac_mem_test_stop(pkt, flag); 682 break; 683 684 case AC_MEM_TEST_READ: 685 /* 686 * read a 'page' (or less) of memory safely. 687 */ 688 if ((flag & FWRITE) == 0) { 689 retval = EBADF; 690 break; 691 } 692 693 retval = ac_mem_test_read(pkt, flag); 694 break; 695 696 case AC_MEM_TEST_WRITE: 697 /* 698 * write a 'page' (or less) of memory safely. 699 */ 700 if ((flag & FWRITE) == 0) { 701 retval = EBADF; 702 break; 703 } 704 705 retval = ac_mem_test_write(pkt, flag); 706 break; 707 708 case AC_MEM_EXERCISE: 709 retval = ac_mem_exercise(pkt, flag); 710 break; 711 712 default: 713 ASSERT(0); 714 retval = ENOTTY; 715 break; 716 } 717 718 if (ac_pkt_fini(pkt, arg, flag) != TRUE) 719 retval = EFAULT; 720 721 return (retval); 722} 723 724static void 725ac_add_kstats(struct ac_soft_state *softsp) 726{ 727 struct kstat *ac_ksp, *ac_counters_ksp; 728 struct ac_kstat *ac_named_ksp; 729 struct kstat_named *ac_counters_named_data; 730 731 /* 732 * create the unix-misc kstat for address controller 733 * using the board number as the instance. 734 */ 735 if ((ac_ksp = kstat_create("unix", softsp->board, 736 AC_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED, 737 sizeof (struct ac_kstat) / sizeof (kstat_named_t), 738 KSTAT_FLAG_PERSISTENT)) == NULL) { 739 cmn_err(CE_WARN, "ac%d: kstat_create failed", 740 ddi_get_instance(softsp->dip)); 741 return; 742 } 743 744 ac_named_ksp = (struct ac_kstat *)(ac_ksp->ks_data); 745 746 /* initialize the named kstats */ 747 kstat_named_init(&ac_named_ksp->ac_memctl, 748 MEMCTL_KSTAT_NAMED, 749 KSTAT_DATA_UINT64); 750 751 kstat_named_init(&ac_named_ksp->ac_memdecode0, 752 MEMDECODE0_KSTAT_NAMED, 753 KSTAT_DATA_UINT64); 754 755 kstat_named_init(&ac_named_ksp->ac_memdecode1, 756 MEMDECODE1_KSTAT_NAMED, 757 KSTAT_DATA_UINT64); 758 759 kstat_named_init(&ac_named_ksp->ac_mccr, 760 MCCR_KSTAT_NAMED, 761 KSTAT_DATA_UINT32); 762 763 kstat_named_init(&ac_named_ksp->ac_counter, 764 CNTR_KSTAT_NAMED, 765 KSTAT_DATA_UINT64); 766 767 kstat_named_init(&ac_named_ksp->ac_bank0_status, 768 BANK_0_KSTAT_NAMED, 769 KSTAT_DATA_CHAR); 770 771 kstat_named_init(&ac_named_ksp->ac_bank1_status, 772 BANK_1_KSTAT_NAMED, 773 KSTAT_DATA_CHAR); 774 775 ac_ksp->ks_update = ac_misc_kstat_update; 776 ac_ksp->ks_private = (void *)softsp; 777 softsp->ac_ksp = ac_ksp; 778 kstat_install(ac_ksp); 779 780 /* 781 * Create the picN kstats if we are the first instance 782 * to attach. We use ac_attachcnt as a count of how 783 * many instances have attached. This is protected by 784 * a mutex. 785 */ 786 mutex_enter(&ac_attachcnt_mutex); 787 if (ac_attachcnt == 0) 788 ac_add_picN_kstats(softsp->dip); 789 790 ac_attachcnt ++; 791 mutex_exit(&ac_attachcnt_mutex); 792 793 /* 794 * Create the "counter" kstat for each AC instance. 795 * This provides access to the %pcr and %pic 796 * registers for that instance. 797 * 798 * The size of this kstat is AC_NUM_PICS + 1 for %pcr 799 */ 800 if ((ac_counters_ksp = kstat_create("ac", 801 ddi_get_instance(softsp->dip), "counters", 802 "bus", KSTAT_TYPE_NAMED, AC_NUM_PICS + 1, 803 KSTAT_FLAG_WRITABLE)) == NULL) { 804 805 cmn_err(CE_WARN, "ac%d counters: kstat_create failed", 806 ddi_get_instance(softsp->dip)); 807 return; 808 } 809 ac_counters_named_data = 810 (struct kstat_named *)(ac_counters_ksp->ks_data); 811 812 /* initialize the named kstats */ 813 kstat_named_init(&ac_counters_named_data[0], 814 "pcr", KSTAT_DATA_UINT64); 815 816 kstat_named_init(&ac_counters_named_data[1], 817 "pic0", KSTAT_DATA_UINT64); 818 819 kstat_named_init(&ac_counters_named_data[2], 820 "pic1", KSTAT_DATA_UINT64); 821 822 ac_counters_ksp->ks_update = ac_counters_kstat_update; 823 ac_counters_ksp->ks_private = (void *)softsp; 824 kstat_install(ac_counters_ksp); 825 826 /* update the sofstate */ 827 softsp->ac_counters_ksp = ac_counters_ksp; 828} 829 830/* 831 * called from ac_add_kstats() to create a kstat for each %pic 832 * that the AC supports. These (read-only) kstats export the 833 * event names and %pcr masks that each %pic supports. 834 * 835 * if we fail to create any of these kstats we must remove any 836 * that we have already created and return; 837 * 838 * NOTE: because all AC's use the same events we only need to 839 * create the picN kstats once. All instances can use 840 * the same picN kstats. 841 * 842 * The flexibility exists to allow each device specify it's 843 * own events by creating picN kstats with the instance number 844 * set to ddi_get_instance(softsp->dip). 845 * 846 * When searching for a picN kstat for a device you should 847 * first search for a picN kstat using the instance number 848 * of the device you are interested in. If that fails you 849 * should use the first picN kstat found for that device. 850 */ 851static void 852ac_add_picN_kstats(dev_info_t *dip) 853{ 854 typedef struct ac_event_mask { 855 char *event_name; 856 uint64_t pcr_mask; 857 } ac_event_mask_t; 858 859 /* 860 * AC Performance Events. 861 * 862 * We declare an array of event-names and event-masks. 863 */ 864 ac_event_mask_t ac_events_arr[] = { 865 {"mem_bank0_rds", 0x1}, {"mem_bank0_wrs", 0x2}, 866 {"mem_bank0_stall", 0x3}, {"mem_bank1_rds", 0x4}, 867 {"mem_bank1_wrs", 0x5}, {"mem_bank1_stall", 0x6}, 868 {"clock_cycles", 0x7}, {"addr_pkts", 0x8}, 869 {"data_pkts", 0x9}, {"flow_ctl_cyc", 0xa}, 870 {"fast_arb_pkts", 0xb}, {"bus_cont_cyc", 0xc}, 871 {"data_bus_can", 0xd}, {"ac_addr_pkts", 0xe}, 872 {"ac_data_pkts", 0xf}, {"rts_pkts", 0x10}, 873 {"rtsa_pkts", 0x11}, {"rto_pkts", 0x12}, 874 {"rs_pkts", 0x13}, {"wb_pkts", 0x14}, 875 {"ws_pkts", 0x15}, {"rio_pkts", 0x16}, 876 {"rbio_pkts", 0x17}, {"wio_pkts", 0x18}, 877 {"wbio_pkts", 0x19}, {"upa_a_rds_m", 0x1a}, 878 {"upa_a_rdo_v", 0x1b}, {"upa_b_rds_m", 0x1c}, 879 {"upa_b_rdo_v", 0x1d}, {"upa_a_preqs_fr", 0x20}, 880 {"upa_a_sreqs_to", 0x21}, {"upa_a_preqs_to", 0x22}, 881 {"upa_a_rds_fr", 0x23}, {"upa_a_rdsa_fr", 0x24}, 882 {"upa_a_rdo_fr", 0x25}, {"upa_a_rdd_fr", 0x26}, 883 {"upa_a_rio_rbio", 0x27}, {"upa_a_wio_wbio", 0x28}, 884 {"upa_a_cpb_to", 0x29}, {"upa_a_inv_to", 0x2a}, 885 {"upa_a_hits_buff", 0x2b}, {"upa_a_wb", 0x2c}, 886 {"upa_a_wi", 0x2d}, {"upa_b_preqs_fr", 0x30}, 887 {"upa_b_sreqs_to", 0x31}, {"upa_b_preqs_to", 0x32}, 888 {"upa_b_rds_fr", 0x33}, {"upa_b_rdsa_fr", 0x34}, 889 {"upa_b_rdo_fr", 0x35}, {"upa_b_rdd_fr", 0x36}, 890 {"upa_b_rio_rbio", 0x37}, {"upa_b_wio_wbio", 0x38}, 891 {"upa_b_cpb_to", 0x39}, {"upa_b_inv_to", 0x3a}, 892 {"upa_b_hits_buff", 0x3b}, {"upa_b_wb", 0x3c}, 893 {"upa_b_wi", 0x3d} 894 }; 895 896#define AC_NUM_EVENTS sizeof (ac_events_arr) / sizeof (ac_events_arr[0]) 897 898 /* 899 * array of clear masks for each pic. 900 * These masks are used to clear the %pcr bits for 901 * each pic. 902 */ 903 ac_event_mask_t ac_clear_pic[AC_NUM_PICS] = { 904 /* pic0 */ 905 {"clear_pic", (uint64_t)~(0x3f)}, 906 /* pic1 */ 907 {"clear_pic", (uint64_t)~(0x3f << 8)} 908 }; 909 910 struct kstat_named *ac_pic_named_data; 911 int event, pic; 912 char pic_name[30]; 913 int instance = ddi_get_instance(dip); 914 int pic_shift = 0; 915 916 for (pic = 0; pic < AC_NUM_PICS; pic++) { 917 /* 918 * create the picN kstat. The size of this kstat is 919 * AC_NUM_EVENTS + 1 for the clear_event_mask 920 */ 921 (void) sprintf(pic_name, "pic%d", pic); /* pic0, pic1 ... */ 922 if ((ac_picN_ksp[pic] = kstat_create("ac", 923 instance, pic_name, "bus", KSTAT_TYPE_NAMED, 924 AC_NUM_EVENTS + 1, NULL)) == NULL) { 925 926 cmn_err(CE_WARN, "ac %s: kstat_create failed", 927 pic_name); 928 929 /* remove pic0 kstat if pic1 create fails */ 930 if (pic == 1) { 931 kstat_delete(ac_picN_ksp[0]); 932 ac_picN_ksp[0] = NULL; 933 } 934 return; 935 } 936 ac_pic_named_data = 937 (struct kstat_named *)(ac_picN_ksp[pic]->ks_data); 938 939 /* 940 * when we are storing pcr_masks we need to shift bits 941 * left by 8 for pic1 events. 942 */ 943 if (pic == 1) 944 pic_shift = 8; 945 946 /* 947 * for each picN event we need to write a kstat record 948 * (name = EVENT, value.ui64 = PCR_MASK) 949 */ 950 for (event = 0; event < AC_NUM_EVENTS; event ++) { 951 952 /* pcr_mask */ 953 ac_pic_named_data[event].value.ui64 = 954 ac_events_arr[event].pcr_mask << pic_shift; 955 956 /* event-name */ 957 kstat_named_init(&ac_pic_named_data[event], 958 ac_events_arr[event].event_name, 959 KSTAT_DATA_UINT64); 960 } 961 962 /* 963 * we add the clear_pic event and mask as the last 964 * record in the kstat 965 */ 966 /* pcr mask */ 967 ac_pic_named_data[AC_NUM_EVENTS].value.ui64 = 968 ac_clear_pic[pic].pcr_mask; 969 970 /* event-name */ 971 kstat_named_init(&ac_pic_named_data[AC_NUM_EVENTS], 972 ac_clear_pic[pic].event_name, 973 KSTAT_DATA_UINT64); 974 975 kstat_install(ac_picN_ksp[pic]); 976 } 977} 978 979 980static void 981ac_del_kstats(struct ac_soft_state *softsp) 982{ 983 struct kstat *ac_ksp; 984 int pic; 985 986 /* remove "misc" kstat */ 987 ac_ksp = softsp->ac_ksp; 988 softsp->ac_ksp = NULL; 989 if (ac_ksp != NULL) { 990 ASSERT(ac_ksp->ks_private == (void *)softsp); 991 kstat_delete(ac_ksp); 992 } 993 994 /* remove "bus" kstat */ 995 ac_ksp = softsp->ac_counters_ksp; 996 softsp->ac_counters_ksp = NULL; 997 if (ac_ksp != NULL) { 998 ASSERT(ac_ksp->ks_private == (void *)softsp); 999 kstat_delete(ac_ksp); 1000 } 1001 1002 /* 1003 * if we are the last instance to detach we need to 1004 * remove the picN kstats. We use ac_attachcnt as a 1005 * count of how many instances are still attached. This 1006 * is protected by a mutex. 1007 */ 1008 mutex_enter(&ac_attachcnt_mutex); 1009 ac_attachcnt --; 1010 if (ac_attachcnt == 0) { 1011 for (pic = 0; pic < AC_NUM_PICS; pic++) { 1012 if (ac_picN_ksp[pic] != (kstat_t *)NULL) { 1013 kstat_delete(ac_picN_ksp[pic]); 1014 ac_picN_ksp[pic] = NULL; 1015 } 1016 } 1017 } 1018 mutex_exit(&ac_attachcnt_mutex); 1019} 1020 1021static enum ac_bank_status 1022ac_kstat_stat(sysc_cfga_rstate_t rst, sysc_cfga_ostate_t ost) 1023{ 1024 switch (rst) { 1025 case SYSC_CFGA_RSTATE_EMPTY: 1026 return (StNoMem); 1027 case SYSC_CFGA_RSTATE_DISCONNECTED: 1028 return (StBad); 1029 case SYSC_CFGA_RSTATE_CONNECTED: 1030 switch (ost) { 1031 case SYSC_CFGA_OSTATE_UNCONFIGURED: 1032 return (StSpare); 1033 case SYSC_CFGA_OSTATE_CONFIGURED: 1034 return (StActive); 1035 default: 1036 return (StUnknown); 1037 } 1038 default: 1039 return (StUnknown); 1040 } 1041} 1042 1043static enum ac_bank_condition 1044ac_kstat_cond(sysc_cfga_cond_t cond) 1045{ 1046 switch (cond) { 1047 case SYSC_CFGA_COND_UNKNOWN: 1048 return (ConUnknown); 1049 case SYSC_CFGA_COND_OK: 1050 return (ConOK); 1051 case SYSC_CFGA_COND_FAILING: 1052 return (ConFailing); 1053 case SYSC_CFGA_COND_FAILED: 1054 return (ConFailed); 1055 case SYSC_CFGA_COND_UNUSABLE: 1056 return (ConBad); 1057 default: 1058 return (ConUnknown); 1059 } 1060} 1061 1062static int 1063ac_misc_kstat_update(kstat_t *ksp, int rw) 1064{ 1065 struct ac_kstat *acksp; 1066 struct ac_soft_state *softsp; 1067 1068 acksp = (struct ac_kstat *)ksp->ks_data; 1069 softsp = (struct ac_soft_state *)ksp->ks_private; 1070 /* Need the NULL check in case kstat is about to be deleted. */ 1071 ASSERT(softsp->ac_ksp == NULL || ksp == softsp->ac_ksp); 1072 1073 /* this is a read-only kstat. Bail out on a write */ 1074 if (rw == KSTAT_WRITE) { 1075 return (EACCES); 1076 } else { 1077 /* 1078 * copy the current state of the hardware into the 1079 * kstat structure. 1080 */ 1081 acksp->ac_memctl.value.ui64 = *softsp->ac_memctl; 1082 acksp->ac_memdecode0.value.ui64 = *softsp->ac_memdecode0; 1083 acksp->ac_memdecode1.value.ui64 = *softsp->ac_memdecode1; 1084 acksp->ac_mccr.value.ui32 = *softsp->ac_mccr; 1085 acksp->ac_counter.value.ui64 = *softsp->ac_counter; 1086 acksp->ac_bank0_status.value.c[0] = 1087 ac_kstat_stat(softsp->bank[0].rstate, 1088 softsp->bank[0].ostate); 1089 acksp->ac_bank0_status.value.c[1] = 1090 ac_kstat_cond(softsp->bank[0].condition); 1091 acksp->ac_bank1_status.value.c[0] = 1092 ac_kstat_stat(softsp->bank[1].rstate, 1093 softsp->bank[1].ostate); 1094 acksp->ac_bank1_status.value.c[1] = 1095 ac_kstat_cond(softsp->bank[1].condition); 1096 } 1097 return (0); 1098} 1099 1100static int 1101ac_counters_kstat_update(kstat_t *ksp, int rw) 1102{ 1103 struct kstat_named *ac_counters_data; 1104 struct ac_soft_state *softsp; 1105 uint64_t pic_register; 1106 1107 ac_counters_data = (struct kstat_named *)ksp->ks_data; 1108 softsp = (struct ac_soft_state *)ksp->ks_private; 1109 1110 /* 1111 * We need to start/restart the ac_timeout that will 1112 * return the AC counters to hot-plug mode after the 1113 * ac_hot_plug_timeout_interval has expired. We tell 1114 * ac_reset_timeout() whether this is a kstat_read or a 1115 * kstat_write call. If this fails we reject the kstat 1116 * operation. 1117 */ 1118 if (ac_reset_timeout(rw) != 0) 1119 return (-1); 1120 1121 1122 if (rw == KSTAT_WRITE) { 1123 /* 1124 * Write the %pcr value to the softsp->ac_mccr. 1125 * This interface does not support writing to the 1126 * %pic. 1127 */ 1128 *softsp->ac_mccr = 1129 (uint32_t)ac_counters_data[0].value.ui64; 1130 } else { 1131 /* 1132 * Read %pcr and %pic register values and write them 1133 * into counters kstat. 1134 */ 1135 1136 /* pcr */ 1137 ac_counters_data[0].value.ui64 = *softsp->ac_mccr; 1138 1139 pic_register = *softsp->ac_counter; 1140 /* 1141 * ac pic register: 1142 * (63:32) = pic1 1143 * (31:00) = pic0 1144 */ 1145 1146 /* pic0 */ 1147 ac_counters_data[1].value.ui64 = 1148 AC_COUNTER_TO_PIC0(pic_register); 1149 /* pic1 */ 1150 ac_counters_data[2].value.ui64 = 1151 AC_COUNTER_TO_PIC1(pic_register); 1152 } 1153 return (0); 1154} 1155 1156/* 1157 * Decode the memory state given to us and plug it into the soft state 1158 */ 1159static void 1160ac_get_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id) 1161{ 1162 char *property = (id == Bank0) ? AC_BANK0_STATUS : AC_BANK1_STATUS; 1163 char *propval; 1164 int proplen; 1165 uint64_t memdec = (id == Bank0) ? 1166 *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1); 1167 uint_t grp_size; 1168 1169 softsp->bank[id].busy = 0; 1170 softsp->bank[id].status_change = ddi_get_time(); 1171 1172 if (GRP_SIZE_IS_SET(memdec)) { 1173 grp_size = GRP_SPANMB(memdec); 1174 1175 /* determine the memory bank size (in MB) */ 1176 softsp->bank[id].real_size = softsp->bank[id].use_size = 1177 (id == Bank0) ? (grp_size / INTLV0(*softsp->ac_memctl)) : 1178 (grp_size / INTLV1(*softsp->ac_memctl)); 1179 } else { 1180 softsp->bank[id].real_size = softsp->bank[id].use_size = 0; 1181 } 1182 1183 /* 1184 * decode the memory bank property. set condition based 1185 * on the values. 1186 */ 1187 if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC, 1188 DDI_PROP_DONTPASS, property, (caddr_t)&propval, &proplen) == 1189 DDI_PROP_SUCCESS) { 1190 if (strcmp(propval, AC_BANK_NOMEM) == 0) { 1191 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY; 1192 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED; 1193 softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN; 1194 } else if (strcmp(propval, AC_BANK_OK) == 0) { 1195 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED; 1196 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED; 1197 softsp->bank[id].condition = SYSC_CFGA_COND_OK; 1198 } else if (strcmp(propval, AC_BANK_SPARE) == 0) { 1199 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED; 1200 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED; 1201 softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN; 1202 } else if (strcmp(propval, AC_BANK_FAILED) == 0) { 1203 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED; 1204 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED; 1205 softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE; 1206 } else { 1207 cmn_err(CE_WARN, "ac%d: board %d, bank %d: " 1208 "unknown %smemory state [%s]", 1209 ddi_get_instance(softsp->dip), softsp->board, id, 1210 (memdec & AC_MEM_VALID) ? "connected " : "", 1211 propval); 1212 if (memdec & AC_MEM_VALID) { 1213 softsp->bank[id].rstate = 1214 SYSC_CFGA_RSTATE_CONNECTED; 1215 softsp->bank[id].ostate = 1216 SYSC_CFGA_OSTATE_CONFIGURED; 1217 softsp->bank[id].condition = 1218 SYSC_CFGA_COND_OK; 1219 } else { 1220 softsp->bank[id].rstate = 1221 SYSC_CFGA_RSTATE_DISCONNECTED; 1222 softsp->bank[id].ostate = 1223 SYSC_CFGA_OSTATE_UNCONFIGURED; 1224 softsp->bank[id].condition = 1225 SYSC_CFGA_COND_UNUSABLE; 1226 } 1227 } 1228 1229 kmem_free(propval, proplen); 1230 } else { 1231 /* we don't have the property, deduce the state of memory */ 1232 if (memdec & AC_MEM_VALID) { 1233 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED; 1234 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED; 1235 softsp->bank[id].condition = SYSC_CFGA_COND_OK; 1236 } else { 1237 /* could be an i/o board... */ 1238 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY; 1239 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED; 1240 softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN; 1241 } 1242 } 1243 1244 /* we assume that all other bank statuses are NOT valid */ 1245 if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) { 1246 if ((memdec & AC_MEM_VALID) != 0) { 1247 uint64_t base_pa; 1248 1249 ASSERT((*softsp->ac_memctl & AC_CSR_REFEN) != 0); 1250 /* register existence in the memloc database */ 1251 base_pa = GRP_REALBASE(memdec); 1252 fhc_add_memloc(softsp->board, base_pa, grp_size); 1253 } 1254 } 1255} 1256 1257static void 1258ac_eval_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id) 1259{ 1260 uint64_t memdec = (id == Bank0) ? 1261 *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1); 1262 uint64_t base_pa; 1263 1264 /* 1265 * Downgrade the status of any bank that did not get 1266 * programmed. 1267 */ 1268 if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED && 1269 softsp->bank[id].ostate == SYSC_CFGA_OSTATE_UNCONFIGURED && 1270 (memdec & AC_MEM_VALID) == 0) { 1271 cmn_err(CE_WARN, "ac%d: board %d, bank %d: " 1272 "spare memory bank not valid - it was ", 1273 ddi_get_instance(softsp->dip), softsp->board, id); 1274 cmn_err(CE_WARN, "misconfigured by the system " 1275 "firmware. Disabling..."); 1276 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED; 1277 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED; 1278 softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE; 1279 } 1280 /* 1281 * Log a message about good banks. 1282 */ 1283 if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) { 1284 ASSERT((memdec & AC_MEM_VALID) != 0); 1285 base_pa = GRP_REALBASE(memdec); 1286 1287 cmn_err(CE_CONT, "?ac%d board %d bank %d: " 1288 "base 0x%" PRIx64 " size %dmb rstate %d " 1289 "ostate %d condition %d\n", 1290 ddi_get_instance(softsp->dip), 1291 softsp->board, id, base_pa, softsp->bank[id].real_size, 1292 softsp->bank[id].rstate, softsp->bank[id].ostate, 1293 softsp->bank[id].condition); 1294 } 1295} 1296 1297/*ARGSUSED*/ 1298static void 1299ac_ecache_flush(uint64_t a, uint64_t b) 1300{ 1301 cpu_flush_ecache(); 1302} 1303 1304static char * 1305ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event) 1306{ 1307 char *type_str; 1308 1309 switch (ostate) { 1310 case SYSC_CFGA_OSTATE_UNCONFIGURED: 1311 switch (event) { 1312 case AC_AUDIT_OSTATE_UNCONFIGURE: 1313 type_str = "unconfiguring"; 1314 break; 1315 case AC_AUDIT_OSTATE_SUCCEEDED: 1316 case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED: 1317 type_str = "unconfigured"; 1318 break; 1319 default: 1320 type_str = "unconfigure?"; 1321 break; 1322 } 1323 break; 1324 case SYSC_CFGA_OSTATE_CONFIGURED: 1325 switch (event) { 1326 case AC_AUDIT_OSTATE_CONFIGURE: 1327 type_str = "configuring"; 1328 break; 1329 case AC_AUDIT_OSTATE_SUCCEEDED: 1330 case AC_AUDIT_OSTATE_CONFIGURE_FAILED: 1331 type_str = "configured"; 1332 break; 1333 default: 1334 type_str = "configure?"; 1335 break; 1336 } 1337 break; 1338 1339 default: 1340 type_str = "undefined occupant state"; 1341 break; 1342 } 1343 return (type_str); 1344} 1345 1346static void 1347ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt) 1348{ 1349 struct ac_soft_state *softsp = pkt->softsp; 1350 1351 switch (event) { 1352 case AC_AUDIT_OSTATE_CONFIGURE: 1353 cmn_err(CE_NOTE, 1354 "%s memory bank %d in slot %d", 1355 ac_ostate_typestr(SYSC_CFGA_OSTATE_CONFIGURED, 1356 event), pkt->bank, 1357 softsp->board); 1358 break; 1359 case AC_AUDIT_OSTATE_UNCONFIGURE: 1360 cmn_err(CE_NOTE, 1361 "%s memory bank %d in slot %d", 1362 ac_ostate_typestr( 1363 SYSC_CFGA_OSTATE_UNCONFIGURED, 1364 event), pkt->bank, 1365 softsp->board); 1366 break; 1367 case AC_AUDIT_OSTATE_SUCCEEDED: 1368 cmn_err(CE_NOTE, 1369 "memory bank %d in slot %d is %s", 1370 pkt->bank, softsp->board, 1371 ac_ostate_typestr( 1372 softsp->bank[pkt->bank].ostate, 1373 event)); 1374 break; 1375 case AC_AUDIT_OSTATE_CONFIGURE_FAILED: 1376 cmn_err(CE_NOTE, 1377 "memory bank %d in slot %d not %s", 1378 pkt->bank, 1379 softsp->board, 1380 ac_ostate_typestr( 1381 SYSC_CFGA_OSTATE_CONFIGURED, 1382 event)); 1383 break; 1384 case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED: 1385 cmn_err(CE_NOTE, 1386 "memory bank %d in slot %d not %s", 1387 pkt->bank, 1388 softsp->board, 1389 ac_ostate_typestr( 1390 SYSC_CFGA_OSTATE_UNCONFIGURED, 1391 event)); 1392 break; 1393 default: 1394 cmn_err(CE_NOTE, 1395 "unknown audit of memory bank %d in slot %d", 1396 pkt->bank, softsp->board); 1397 break; 1398 } 1399} 1400 1401#include <vm/page.h> 1402#include <vm/hat.h> 1403 1404static int 1405ac_mem_exercise(ac_cfga_pkt_t *pkt, int flag) 1406{ 1407 struct ac_mem_info *mem_info; 1408 pfn_t base; 1409 pgcnt_t npgs; 1410 1411 mem_info = &pkt->softsp->bank[pkt->bank]; 1412 if (mem_info->rstate == SYSC_CFGA_RSTATE_CONNECTED) { 1413 uint64_t base_pa, bank_size; 1414 uint64_t decode; 1415 1416 decode = (pkt->bank == Bank0) ? 1417 *pkt->softsp->ac_memdecode0 : *pkt->softsp->ac_memdecode1; 1418 base_pa = GRP_REALBASE(decode); 1419 bank_size = GRP_UK2SPAN(decode); 1420 1421 base = base_pa >> PAGESHIFT; 1422 npgs = bank_size >> PAGESHIFT; 1423 } else { 1424 base = 0; 1425 npgs = 0; 1426 } 1427 switch (pkt->cmd_cfga.arg) { 1428 case AC_MEMX_RELOCATE_ALL: { 1429 pfn_t pfn, pglim; 1430 struct ac_memx_relocate_stats rstat; 1431 1432 if (npgs == 0 || 1433 mem_info->ostate != SYSC_CFGA_OSTATE_CONFIGURED) { 1434 return (EINVAL); 1435 } 1436 if (mem_info->busy != FALSE) { 1437 return (EBUSY); 1438 } 1439 bzero(&rstat, sizeof (rstat)); 1440 rstat.base = (uint_t)base; 1441 rstat.npgs = (uint_t)npgs; 1442 pglim = base + npgs; 1443 for (pfn = base; pfn < pglim; pfn++) { 1444 page_t *pp, *pp_repl; 1445 1446 retry: 1447 pp = page_numtopp_nolock(pfn); 1448 if (pp != NULL) { 1449 if (!page_trylock(pp, SE_EXCL)) { 1450 pp = NULL; 1451 rstat.nolock++; 1452 } 1453 if (pp != NULL && page_pptonum(pp) != pfn) { 1454 page_unlock(pp); 1455 goto retry; 1456 } 1457 } else { 1458 rstat.nopaget++; 1459 } 1460 if (pp != NULL && PP_ISFREE(pp)) { 1461 page_unlock(pp); 1462 rstat.isfree++; 1463 pp = NULL; 1464 } 1465 if (pp != NULL) { 1466 spgcnt_t npgs; 1467 int result; 1468 1469 pp_repl = NULL; 1470 result = page_relocate(&pp, &pp_repl, 1, 1, 1471 &npgs, NULL); 1472 if (result == 0) { 1473 while (npgs-- > 0) { 1474 page_t *tpp; 1475 1476 ASSERT(pp_repl != NULL); 1477 tpp = pp_repl; 1478 page_sub(&pp_repl, tpp); 1479 page_unlock(tpp); 1480 } 1481 1482 rstat.reloc++; 1483 } else { 1484 page_unlock(pp); 1485 rstat.noreloc++; 1486 } 1487 } 1488 } 1489 if (pkt->cmd_cfga.private != NULL && ddi_copyout(&rstat, 1490 pkt->cmd_cfga.private, sizeof (rstat), flag) != 0) 1491 return (EFAULT); 1492 return (DDI_SUCCESS); 1493 } 1494 1495 default: 1496 return (EINVAL); 1497 } 1498} 1499 1500static int 1501ac_reset_timeout(int rw) 1502{ 1503 mutex_enter(&ac_hot_plug_mode_mutex); 1504 1505 if ((ac_hot_plug_timeout == (timeout_id_t)NULL) && 1506 (rw == KSTAT_READ)) { 1507 /* 1508 * We are in hot-plug mode. A kstat_read is not 1509 * going to affect this. return 0 to allow the 1510 * kstat_read to continue. 1511 */ 1512 mutex_exit(&ac_hot_plug_mode_mutex); 1513 return (0); 1514 1515 } else if ((ac_hot_plug_timeout == (timeout_id_t)NULL) && 1516 (rw == KSTAT_WRITE)) { 1517 /* 1518 * There are no pending timeouts and we have received a 1519 * kstat_write request so we must be transitioning 1520 * from "hot-plug" mode to non "hot-plug" mode. 1521 * Try to lock all boards before allowing the kstat_write. 1522 */ 1523 if (ac_enter_transition() == TRUE) 1524 fhc_bdlist_unlock(); 1525 else { 1526 /* cannot lock boards so fail */ 1527 mutex_exit(&ac_hot_plug_mode_mutex); 1528 return (-1); 1529 } 1530 1531 /* 1532 * We need to display a Warning about hot-plugging any 1533 * boards. This message is only needed when we are 1534 * transitioning out of "hot-plug" mode. 1535 */ 1536 cmn_err(CE_WARN, "This machine is being taken out of " 1537 "hot-plug mode."); 1538 cmn_err(CE_CONT, "Do not attempt to hot-plug boards " 1539 "or power supplies in this system until further notice."); 1540 1541 } else if (ac_hot_plug_timeout != (timeout_id_t)NULL) { 1542 /* 1543 * There is a pending timeout so we must already be 1544 * in non "hot-plug" mode. It doesn't matter if the 1545 * kstat request is a read or a write. 1546 * 1547 * We need to cancel the existing timeout. 1548 */ 1549 (void) untimeout(ac_hot_plug_timeout); 1550 ac_hot_plug_timeout = NULL; 1551 } 1552 1553 /* 1554 * create a new timeout. 1555 */ 1556 ac_hot_plug_timeout = timeout(ac_timeout, NULL, 1557 drv_usectohz(ac_hot_plug_timeout_interval * 1000000)); 1558 1559 mutex_exit(&ac_hot_plug_mode_mutex); 1560 return (0); 1561} 1562 1563static void 1564ac_timeout(void *arg) 1565{ 1566 struct ac_soft_state *softsp; 1567 fhc_bd_t *board; 1568 1569#ifdef lint 1570 arg = arg; 1571#endif /* lint */ 1572 1573 ac_hot_plug_timeout = (timeout_id_t)NULL; 1574 1575 (void) fhc_bdlist_lock(-1); 1576 1577 /* 1578 * Foreach ac in the board list we need to 1579 * re-program the pcr into "hot-plug" mode. 1580 * We also program the pic register with the 1581 * bus pause timing 1582 */ 1583 board = fhc_bd_first(); 1584 while (board != NULL) { 1585 softsp = board->ac_softsp; 1586 if (softsp == NULL) { 1587 /* 1588 * This board must not have an AC. 1589 * Skip it and move on. 1590 */ 1591 board = fhc_bd_next(board); 1592 continue; 1593 } 1594 /* program the pcr into hot-plug mode */ 1595 *softsp->ac_mccr = AC_CLEAR_PCR(*softsp->ac_mccr); 1596 *softsp->ac_mccr = AC_SET_HOT_PLUG(*softsp->ac_mccr); 1597 1598 /* program the pic with the bus pause time value */ 1599 *softsp->ac_counter = AC_SET_PIC_BUS_PAUSE(softsp->board); 1600 1601 /* get the next board */ 1602 board = fhc_bd_next(board); 1603 } 1604 1605 ac_exit_transition(); 1606 1607 fhc_bdlist_unlock(); 1608 1609 /* 1610 * It is now safe to start hot-plugging again. We need 1611 * to display a message. 1612 */ 1613 cmn_err(CE_NOTE, "This machine is now in hot-plug mode."); 1614 cmn_err(CE_CONT, "Board and power supply hot-plug operations " 1615 "can be resumed."); 1616} 1617 1618/* 1619 * This function will acquire the lock and set the in_transition 1620 * bit for all the slots. If the slots are being used, 1621 * we return FALSE; else set in_transition and return TRUE. 1622 */ 1623static int 1624ac_enter_transition(void) 1625{ 1626 fhc_bd_t *list; 1627 sysc_cfga_stat_t *sysc_stat_lk; 1628 1629 /* mutex lock the structure */ 1630 (void) fhc_bdlist_lock(-1); 1631 1632 list = fhc_bd_clock(); 1633 1634 /* change the in_transition bit */ 1635 sysc_stat_lk = &list->sc; 1636 if (sysc_stat_lk->in_transition == TRUE) { 1637 fhc_bdlist_unlock(); 1638 return (FALSE); 1639 } else { 1640 sysc_stat_lk->in_transition = TRUE; 1641 return (TRUE); 1642 } 1643} 1644 1645/* 1646 * clear the in_transition bit for all the slots. 1647 */ 1648static void 1649ac_exit_transition(void) 1650{ 1651 fhc_bd_t *list; 1652 sysc_cfga_stat_t *sysc_stat_lk; 1653 1654 ASSERT(fhc_bdlist_locked()); 1655 1656 list = fhc_bd_clock(); 1657 1658 sysc_stat_lk = &list->sc; 1659 ASSERT(sysc_stat_lk->in_transition == TRUE); 1660 sysc_stat_lk->in_transition = FALSE; 1661} 1662