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