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