1 /* 2 * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 #define IOKIT_ENABLE_SHARED_PTR 30 31 #include <libkern/c++/OSSharedPtr.h> 32 #include <IOKit/IOKernelReportStructs.h> 33 #include <IOKit/IOKernelReporters.h> 34 #include "IOReporterDefs.h" 35 36 37 #define super IOReporter 38 OSDefineMetaClassAndStructors(IOStateReporter, IOReporter); 39 40 41 /* static */ 42 OSSharedPtr<IOStateReporter> 43 IOStateReporter::with(IOService *reportingService, 44 IOReportCategories categories, 45 int nstates, 46 IOReportUnit unit /* = kIOReportUnitHWTicks*/) 47 { 48 OSSharedPtr<IOStateReporter> reporter; 49 50 if (nstates > INT16_MAX) { 51 return nullptr; 52 } 53 54 reporter = OSMakeShared<IOStateReporter>(); 55 if (!reporter) { 56 return nullptr; 57 } 58 59 if (!reporter->initWith(reportingService, categories, (int16_t) nstates, unit)) { 60 return nullptr; 61 } 62 63 return reporter; 64 } 65 66 bool 67 IOStateReporter::initWith(IOService *reportingService, 68 IOReportCategories categories, 69 int16_t nstates, 70 IOReportUnit unit) 71 { 72 bool success = false; 73 74 IOReportChannelType channelType = { 75 .categories = categories, 76 .report_format = kIOReportFormatState, 77 .nelements = static_cast<uint16_t>(nstates), 78 .element_idx = 0 79 }; 80 81 if (super::init(reportingService, channelType, unit) != true) { 82 IORLOG("ERROR super::initWith failed"); 83 success = false; 84 goto finish; 85 } 86 87 _currentStates = NULL; 88 _lastUpdateTimes = NULL; 89 90 success = true; 91 92 finish: 93 return success; 94 } 95 96 97 void 98 IOStateReporter::free(void) 99 { 100 if (_currentStates) { 101 PREFL_MEMOP_PANIC(_nChannels, int); 102 IOFreeData(_currentStates, (size_t)_nChannels * sizeof(int)); 103 } 104 if (_lastUpdateTimes) { 105 PREFL_MEMOP_PANIC(_nChannels, uint64_t); 106 IOFreeData(_lastUpdateTimes, (size_t)_nChannels * sizeof(uint64_t)); 107 } 108 109 super::free(); 110 } 111 112 113 IOReturn 114 IOStateReporter::handleSwapPrepare(int newNChannels) 115 { 116 IOReturn res = kIOReturnError; 117 size_t newCurStatesSize, newTSSize; 118 119 //IORLOG("handleSwapPrepare (state) _nChannels before = %u", _nChannels); 120 121 IOREPORTER_CHECK_CONFIG_LOCK(); 122 123 if (_swapCurrentStates || _swapLastUpdateTimes) { 124 panic("IOStateReporter::_swap* already in use"); 125 } 126 127 // new currentStates buffer 128 PREFL_MEMOP_FAIL(newNChannels, int); 129 newCurStatesSize = (size_t)newNChannels * sizeof(int); 130 _swapCurrentStates = (int*)IOMallocData(newCurStatesSize); 131 if (_swapCurrentStates == NULL) { 132 res = kIOReturnNoMemory; goto finish; 133 } 134 memset(_swapCurrentStates, -1, newCurStatesSize); // init w/"no state" 135 136 // new timestamps buffer 137 PREFL_MEMOP_FAIL(newNChannels, uint64_t); 138 newTSSize = (size_t)newNChannels * sizeof(uint64_t); 139 _swapLastUpdateTimes = (uint64_t *)IOMallocZeroData(newTSSize); 140 if (_swapLastUpdateTimes == NULL) { 141 res = kIOReturnNoMemory; goto finish; 142 } 143 144 res = super::handleSwapPrepare(newNChannels); 145 146 finish: 147 if (res) { 148 if (_swapCurrentStates) { 149 IOFreeData(_swapCurrentStates, newCurStatesSize); 150 _swapCurrentStates = NULL; 151 } 152 if (_swapLastUpdateTimes) { 153 IOFreeData(_swapLastUpdateTimes, newTSSize); 154 _swapLastUpdateTimes = NULL; 155 } 156 } 157 158 return res; 159 } 160 161 IOReturn 162 IOStateReporter::handleAddChannelSwap(uint64_t channelID, 163 const OSSymbol *symChannelName) 164 { 165 IOReturn res = kIOReturnError; 166 int cnt; 167 int *tmpCurStates; 168 uint64_t *tmpTimestamps; 169 bool swapComplete = false; 170 171 //IORLOG("IOStateReporter::handleSwap"); 172 173 if (!_swapCurrentStates || !_swapLastUpdateTimes) { 174 IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!"); 175 goto finish; 176 } 177 178 IOREPORTER_CHECK_CONFIG_LOCK(); 179 IOREPORTER_CHECK_LOCK(); 180 181 // Copy any existing buffers 182 if (_currentStates) { 183 PREFL_MEMOP_FAIL(_nChannels, int); 184 memcpy(_swapCurrentStates, _currentStates, 185 (size_t)_nChannels * sizeof(int)); 186 187 if (!_lastUpdateTimes) { 188 panic("IOStateReporter::handleAddChannelSwap _lastUpdateTimes unset despite non-NULL _currentStates"); 189 } 190 PREFL_MEMOP_FAIL(_nChannels, uint64_t); 191 memcpy(_swapLastUpdateTimes, _lastUpdateTimes, 192 (size_t)_nChannels * sizeof(uint64_t)); 193 } 194 195 // Update principal instance variables, keep old values in _swap* for cleanup 196 tmpCurStates = _currentStates; 197 _currentStates = _swapCurrentStates; 198 _swapCurrentStates = tmpCurStates; 199 200 tmpTimestamps = _lastUpdateTimes; 201 _lastUpdateTimes = _swapLastUpdateTimes; 202 _swapLastUpdateTimes = tmpTimestamps; 203 204 swapComplete = true; 205 206 // subclass success 207 208 // invoke superclass(es): base class updates _nChannels & _nElements 209 res = super::handleAddChannelSwap(channelID, symChannelName); 210 if (res) { 211 IORLOG("handleSwap(state) ERROR super::handleSwap failed!"); 212 goto finish; 213 } 214 215 // Channel added successfully, initialize the new channel's state_ids to 0..nStates-1 216 for (cnt = 0; cnt < _channelDimension; cnt++) { 217 handleSetStateID(channelID, cnt, (uint64_t)cnt); 218 } 219 220 finish: 221 if (res && swapComplete) { 222 // unswap so the unused buffers get cleaned up 223 tmpCurStates = _currentStates; 224 _currentStates = _swapCurrentStates; 225 _swapCurrentStates = tmpCurStates; 226 227 tmpTimestamps = _lastUpdateTimes; 228 _lastUpdateTimes = _swapLastUpdateTimes; 229 _swapLastUpdateTimes = tmpTimestamps; 230 } 231 232 return res; 233 } 234 235 236 void 237 IOStateReporter::handleSwapCleanup(int swapNChannels) 238 { 239 IOREPORTER_CHECK_CONFIG_LOCK(); 240 241 super::handleSwapCleanup(swapNChannels); 242 243 if (_swapCurrentStates) { 244 PREFL_MEMOP_PANIC(swapNChannels, int); 245 IOFreeData(_swapCurrentStates, (size_t)swapNChannels * sizeof(int)); 246 _swapCurrentStates = NULL; 247 } 248 if (_swapLastUpdateTimes) { 249 PREFL_MEMOP_PANIC(swapNChannels, uint64_t); 250 IOFreeData(_swapLastUpdateTimes, (size_t)swapNChannels * sizeof(uint64_t)); 251 _swapLastUpdateTimes = NULL; 252 } 253 } 254 255 256 IOReturn 257 IOStateReporter::_getStateIndices(uint64_t channel_id, 258 uint64_t state_id, 259 int *channel_index, 260 int *state_index) 261 { 262 IOReturn res = kIOReturnError; 263 int cnt; 264 IOStateReportValues *values; 265 int element_index = 0; 266 267 IOREPORTER_CHECK_LOCK(); 268 269 if (getChannelIndices(channel_id, 270 channel_index, 271 &element_index) != kIOReturnSuccess) { 272 res = kIOReturnBadArgument; 273 274 goto finish; 275 } 276 277 for (cnt = 0; cnt < _channelDimension; cnt++) { 278 values = (IOStateReportValues *)getElementValues(element_index + cnt); 279 280 if (values == NULL) { 281 res = kIOReturnError; 282 goto finish; 283 } 284 285 if (values->state_id == state_id) { 286 *state_index = cnt; 287 res = kIOReturnSuccess; 288 goto finish; 289 } 290 } 291 292 res = kIOReturnBadArgument; 293 294 finish: 295 return res; 296 } 297 298 299 IOReturn 300 IOStateReporter::setChannelState(uint64_t channel_id, 301 uint64_t new_state_id) 302 { 303 IOReturn res = kIOReturnError; 304 int channel_index, new_state_index; 305 uint64_t last_intransition = 0; 306 uint64_t prev_state_residency = 0; 307 308 lockReporter(); 309 310 if (_getStateIndices(channel_id, new_state_id, &channel_index, &new_state_index) == kIOReturnSuccess) { 311 res = handleSetStateByIndices(channel_index, new_state_index, 312 last_intransition, 313 prev_state_residency); 314 goto finish; 315 } 316 317 res = kIOReturnBadArgument; 318 319 finish: 320 unlockReporter(); 321 return res; 322 } 323 324 IOReturn 325 IOStateReporter::setChannelState(uint64_t channel_id, 326 uint64_t new_state_id, 327 uint64_t last_intransition, 328 uint64_t prev_state_residency) 329 { 330 return setChannelState(channel_id, new_state_id); 331 } 332 333 IOReturn 334 IOStateReporter::overrideChannelState(uint64_t channel_id, 335 uint64_t state_id, 336 uint64_t time_in_state, 337 uint64_t intransitions, 338 uint64_t last_intransition /*=0*/) 339 { 340 IOReturn res = kIOReturnError; 341 int channel_index, state_index; 342 343 lockReporter(); 344 345 if (_getStateIndices(channel_id, state_id, &channel_index, &state_index) == kIOReturnSuccess) { 346 if (_lastUpdateTimes[channel_index]) { 347 panic("overrideChannelState() cannot be used after setChannelState()!"); 348 } 349 350 res = handleOverrideChannelStateByIndices(channel_index, state_index, 351 time_in_state, intransitions, 352 last_intransition); 353 goto finish; 354 } 355 356 res = kIOReturnBadArgument; 357 358 finish: 359 unlockReporter(); 360 return res; 361 } 362 363 364 IOReturn 365 IOStateReporter::handleOverrideChannelStateByIndices(int channel_index, 366 int state_index, 367 uint64_t time_in_state, 368 uint64_t intransitions, 369 uint64_t last_intransition /*=0*/) 370 { 371 IOReturn kerr, result = kIOReturnError; 372 IOStateReportValues state_values; 373 int element_index; 374 375 if (channel_index < 0 || channel_index >= _nChannels) { 376 result = kIOReturnBadArgument; goto finish; 377 } 378 379 if (channel_index < 0 || channel_index > (_nElements - state_index) 380 / _channelDimension) { 381 result = kIOReturnOverrun; goto finish; 382 } 383 element_index = channel_index * _channelDimension + state_index; 384 385 kerr = copyElementValues(element_index, (IOReportElementValues*)&state_values); 386 if (kerr) { 387 result = kerr; goto finish; 388 } 389 390 // last_intransition = 0 -> no current state ("residency summary only") 391 state_values.last_intransition = last_intransition; 392 state_values.intransitions = intransitions; 393 state_values.upticks = time_in_state; 394 395 // determines current time for metadata 396 kerr = setElementValues(element_index, (IOReportElementValues *)&state_values); 397 if (kerr) { 398 result = kerr; goto finish; 399 } 400 401 // success 402 result = kIOReturnSuccess; 403 404 finish: 405 return result; 406 } 407 408 409 IOReturn 410 IOStateReporter::incrementChannelState(uint64_t channel_id, 411 uint64_t state_id, 412 uint64_t time_in_state, 413 uint64_t intransitions, 414 uint64_t last_intransition /*=0*/) 415 { 416 IOReturn res = kIOReturnError; 417 int channel_index, state_index; 418 419 lockReporter(); 420 421 if (_getStateIndices(channel_id, state_id, &channel_index, &state_index) == kIOReturnSuccess) { 422 if (_lastUpdateTimes[channel_index]) { 423 panic("incrementChannelState() cannot be used after setChannelState()!"); 424 } 425 426 res = handleIncrementChannelStateByIndices(channel_index, state_index, 427 time_in_state, intransitions, 428 last_intransition); 429 goto finish; 430 } 431 432 res = kIOReturnBadArgument; 433 434 finish: 435 unlockReporter(); 436 return res; 437 } 438 439 440 IOReturn 441 IOStateReporter::handleIncrementChannelStateByIndices(int channel_index, 442 int state_index, 443 uint64_t time_in_state, 444 uint64_t intransitions, 445 uint64_t last_intransition /*=0*/) 446 { 447 IOReturn kerr, result = kIOReturnError; 448 IOStateReportValues state_values; 449 int element_index; 450 451 if (channel_index < 0 || channel_index >= _nChannels) { 452 result = kIOReturnBadArgument; goto finish; 453 } 454 455 if (channel_index < 0 || channel_index > (_nElements - state_index) 456 / _channelDimension) { 457 result = kIOReturnOverrun; goto finish; 458 } 459 element_index = channel_index * _channelDimension + state_index; 460 461 kerr = copyElementValues(element_index, (IOReportElementValues*)&state_values); 462 if (kerr) { 463 result = kerr; 464 goto finish; 465 } 466 467 state_values.last_intransition = last_intransition; 468 state_values.intransitions += intransitions; 469 state_values.upticks += time_in_state; 470 471 // determines current time for metadata 472 kerr = setElementValues(element_index, (IOReportElementValues *)&state_values); 473 if (kerr) { 474 result = kerr; 475 goto finish; 476 } 477 478 // success 479 result = kIOReturnSuccess; 480 481 finish: 482 return result; 483 } 484 485 486 IOReturn 487 IOStateReporter::setState(uint64_t new_state_id) 488 { 489 uint64_t last_intransition = 0; 490 uint64_t prev_state_residency = 0; 491 IOReturn res = kIOReturnError; 492 IOStateReportValues *values; 493 int channel_index = 0, element_index = 0, new_state_index = 0; 494 int cnt; 495 496 lockReporter(); 497 498 if (_nChannels == 1) { 499 for (cnt = 0; cnt < _channelDimension; cnt++) { 500 new_state_index = element_index + cnt; 501 502 values = (IOStateReportValues *)getElementValues(new_state_index); 503 504 if (values == NULL) { 505 res = kIOReturnError; 506 goto finish; 507 } 508 509 if (values->state_id == new_state_id) { 510 res = handleSetStateByIndices(channel_index, new_state_index, 511 last_intransition, 512 prev_state_residency); 513 goto finish; 514 } 515 } 516 } 517 518 res = kIOReturnBadArgument; 519 520 finish: 521 unlockReporter(); 522 return res; 523 } 524 525 IOReturn 526 IOStateReporter::setState(uint64_t new_state_id, 527 uint64_t last_intransition, 528 uint64_t prev_state_residency) 529 { 530 return setState(new_state_id); 531 } 532 533 IOReturn 534 IOStateReporter::setStateID(uint64_t channel_id, 535 int state_index, 536 uint64_t state_id) 537 { 538 IOReturn res = kIOReturnError; 539 540 lockReporter(); 541 542 res = handleSetStateID(channel_id, state_index, state_id); 543 544 unlockReporter(); 545 546 return res; 547 } 548 549 550 IOReturn 551 IOStateReporter::handleSetStateID(uint64_t channel_id, 552 int state_index, 553 uint64_t state_id) 554 { 555 IOReturn res = kIOReturnError; 556 IOStateReportValues state_values; 557 int element_index = 0; 558 559 IOREPORTER_CHECK_LOCK(); 560 561 if (getFirstElementIndex(channel_id, &element_index) == kIOReturnSuccess) { 562 if (state_index >= _channelDimension) { 563 res = kIOReturnBadArgument; goto finish; 564 } 565 if (_nElements - state_index <= element_index) { 566 res = kIOReturnOverrun; goto finish; 567 } 568 element_index += state_index; 569 570 if (copyElementValues(element_index, (IOReportElementValues *)&state_values) != kIOReturnSuccess) { 571 res = kIOReturnBadArgument; 572 goto finish; 573 } 574 575 state_values.state_id = state_id; 576 577 res = setElementValues(element_index, (IOReportElementValues *)&state_values); 578 } 579 580 // FIXME: set a bit somewhere (reporter-wide?) that state_ids can no longer be 581 // assumed to be contiguous 582 finish: 583 return res; 584 } 585 586 IOReturn 587 IOStateReporter::setStateByIndices(int channel_index, 588 int new_state_index) 589 { 590 IOReturn res = kIOReturnError; 591 uint64_t last_intransition = 0; 592 uint64_t prev_state_residency = 0; 593 594 lockReporter(); 595 596 res = handleSetStateByIndices(channel_index, new_state_index, 597 last_intransition, prev_state_residency); 598 599 unlockReporter(); 600 601 return res; 602 } 603 604 IOReturn 605 IOStateReporter::setStateByIndices(int channel_index, 606 int new_state_index, 607 uint64_t last_intransition, 608 uint64_t prev_state_residency) 609 { 610 return setStateByIndices(channel_index, new_state_index); 611 } 612 613 IOReturn 614 IOStateReporter::handleSetStateByIndices(int channel_index, 615 int new_state_index, 616 uint64_t last_intransition, 617 uint64_t prev_state_residency) 618 { 619 IOReturn res = kIOReturnError; 620 621 IOStateReportValues curr_state_values, new_state_values; 622 int curr_state_index = 0; 623 int curr_element_index, new_element_index; 624 uint64_t last_ch_update_time = 0; 625 uint64_t recordTime = mach_absolute_time(); 626 627 IOREPORTER_CHECK_LOCK(); 628 629 if (channel_index < 0 || channel_index >= _nChannels) { 630 res = kIOReturnBadArgument; goto finish; 631 } 632 633 // if no timestamp provided, last_intransition = time of recording (now) 634 if (last_intransition == 0) { 635 last_intransition = recordTime; 636 } 637 638 // First update target state if different than the current state 639 // _currentStates[] initialized to -1 to detect first state transition 640 curr_state_index = _currentStates[channel_index]; 641 if (new_state_index != curr_state_index) { 642 // fetch element data 643 if (channel_index < 0 || channel_index > (_nElements - new_state_index) 644 / _channelDimension) { 645 res = kIOReturnOverrun; goto finish; 646 } 647 new_element_index = channel_index * _channelDimension + new_state_index; 648 if (copyElementValues(new_element_index, 649 (IOReportElementValues *)&new_state_values)) { 650 res = kIOReturnBadArgument; 651 goto finish; 652 } 653 654 // Update new state's transition info 655 new_state_values.intransitions += 1; 656 new_state_values.last_intransition = last_intransition; 657 658 // and store the values 659 res = setElementValues(new_element_index, 660 (IOReportElementValues *)&new_state_values, 661 recordTime); 662 663 if (res != kIOReturnSuccess) { 664 goto finish; 665 } 666 667 _currentStates[channel_index] = new_state_index; 668 } 669 670 /* Now update time spent in any previous state 671 * If new_state_index = curr_state_index, this updates time in the 672 * current state. If this is the channel's first state transition, 673 * the last update time will be zero. 674 * 675 * Note: While setState() should never be called on a channel being 676 * updated with increment/overrideChannelState(), that's another way 677 * that the last update time might not exist. Regardless, if there 678 * is no basis for determining time spent in previous state, there's 679 * nothing to update! 680 */ 681 last_ch_update_time = _lastUpdateTimes[channel_index]; 682 if (last_ch_update_time != 0) { 683 if (channel_index < 0 || channel_index > (_nElements - curr_state_index) 684 / _channelDimension) { 685 res = kIOReturnOverrun; goto finish; 686 } 687 curr_element_index = channel_index * _channelDimension + curr_state_index; 688 if (copyElementValues(curr_element_index, 689 (IOReportElementValues *)&curr_state_values)) { 690 res = kIOReturnBadArgument; 691 goto finish; 692 } 693 // compute the time spent in previous state, unless provided 694 if (prev_state_residency == 0) { 695 prev_state_residency = last_intransition - last_ch_update_time; 696 } 697 698 curr_state_values.upticks += prev_state_residency; 699 700 res = setElementValues(curr_element_index, 701 (IOReportElementValues*)&curr_state_values, 702 recordTime); 703 704 if (res != kIOReturnSuccess) { 705 goto finish; 706 } 707 } 708 709 // record basis for next "time in prior state" calculation 710 // (also arms a panic in override/incrementChannelState()) 711 _lastUpdateTimes[channel_index] = last_intransition; 712 713 finish: 714 return res; 715 } 716 717 718 // blocks might make this slightly easier? 719 uint64_t 720 IOStateReporter::getStateInTransitions(uint64_t channel_id, 721 uint64_t state_id) 722 { 723 return _getStateValue(channel_id, state_id, kInTransitions); 724 } 725 726 uint64_t 727 IOStateReporter::getStateResidencyTime(uint64_t channel_id, 728 uint64_t state_id) 729 { 730 return _getStateValue(channel_id, state_id, kResidencyTime); 731 } 732 733 uint64_t 734 IOStateReporter::getStateLastTransitionTime(uint64_t channel_id, 735 uint64_t state_id) 736 { 737 return _getStateValue(channel_id, state_id, kLastTransitionTime); 738 } 739 740 uint64_t 741 IOStateReporter::_getStateValue(uint64_t channel_id, 742 uint64_t state_id, 743 enum valueSelector value) 744 { 745 int channel_index = 0, element_index = 0, cnt; 746 IOStateReportValues *values = NULL; 747 uint64_t result = kIOReportInvalidValue; 748 749 lockReporter(); 750 751 if (getChannelIndices(channel_id, &channel_index, &element_index) == kIOReturnSuccess) { 752 if (updateChannelValues(channel_index) == kIOReturnSuccess) { 753 for (cnt = 0; cnt < _channelDimension; cnt++) { 754 values = (IOStateReportValues *)getElementValues(element_index); 755 756 if (state_id == values->state_id) { 757 switch (value) { 758 case kInTransitions: 759 result = values->intransitions; 760 break; 761 case kResidencyTime: 762 result = values->upticks; 763 break; 764 case kLastTransitionTime: 765 result = values->last_intransition; 766 break; 767 default: 768 break; 769 } 770 771 break; 772 } 773 774 element_index++; 775 } 776 } 777 } 778 779 unlockReporter(); 780 return result; 781 } 782 783 784 uint64_t 785 IOStateReporter::getStateLastChannelUpdateTime(uint64_t channel_id) 786 { 787 int channel_index; 788 uint64_t result = kIOReportInvalidValue; 789 790 lockReporter(); 791 792 if (getChannelIndex(channel_id, &channel_index) == kIOReturnSuccess) { 793 result = _lastUpdateTimes[channel_index]; 794 } 795 796 unlockReporter(); 797 798 return result; 799 } 800 801 802 /* updateChannelValues() is called to refresh state before being 803 * reported outside the reporter. In the case of IOStateReporter, 804 * this is primarily an update to the "time in state" data. 805 */ 806 IOReturn 807 IOStateReporter::updateChannelValues(int channel_index) 808 { 809 IOReturn kerr, result = kIOReturnError; 810 811 int state_index, element_idx; 812 uint64_t currentTime; 813 uint64_t last_ch_update_time; 814 uint64_t time_in_state; 815 IOStateReportValues state_values; 816 817 IOREPORTER_CHECK_LOCK(); 818 819 if (channel_index < 0 || channel_index >= _nChannels) { 820 result = kIOReturnBadArgument; goto finish; 821 } 822 823 /* First check to see whether this channel has begun self- 824 * calculation of time in state. It's possible this channel 825 * has yet to be initialized or that the driver is updating 826 * the channel with override/incrementChannelState() which 827 * never enable automatic time-in-state updates. In that case, 828 * there is nothing to update and we return success. 829 */ 830 last_ch_update_time = _lastUpdateTimes[channel_index]; 831 if (last_ch_update_time == 0) { 832 result = kIOReturnSuccess; goto finish; 833 } 834 835 // figure out the current state (if any) 836 state_index = _currentStates[channel_index]; 837 838 // e.g. given 4 4-state channels, the boundary is ch[3].st[3] <- _elems[15] 839 if (channel_index < 0 || channel_index > (_nElements - state_index) 840 / _channelDimension) { 841 result = kIOReturnOverrun; goto finish; 842 } 843 element_idx = channel_index * _channelDimension + state_index; 844 845 // get the current values 846 kerr = copyElementValues(element_idx, (IOReportElementValues*)&state_values); 847 if (kerr) { 848 result = kerr; goto finish; 849 } 850 851 // calculate time in state 852 currentTime = mach_absolute_time(); 853 time_in_state = currentTime - last_ch_update_time; 854 state_values.upticks += time_in_state; 855 856 // and store the values 857 kerr = setElementValues(element_idx, 858 (IOReportElementValues *)&state_values, 859 currentTime); 860 if (kerr) { 861 result = kerr; goto finish; 862 } 863 864 // Record basis for next "prior time" calculation 865 _lastUpdateTimes[channel_index] = currentTime; 866 867 868 // success 869 result = kIOReturnSuccess; 870 871 finish: 872 return result; 873 } 874 875 /* static */ OSPtr<IOReportLegendEntry> 876 IOStateReporter::createLegend(const uint64_t *channelIDs, 877 const char **channelNames, 878 int channelCount, 879 int nstates, 880 IOReportCategories categories, 881 IOReportUnit unit) 882 { 883 IOReportChannelType channelType = { 884 .categories = categories, 885 .report_format = kIOReportFormatState, 886 .nelements = static_cast<uint16_t>(nstates), 887 .element_idx = 0 888 }; 889 890 return IOReporter::legendWith(channelIDs, channelNames, channelCount, channelType, unit); 891 } 892