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