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 35OSDefineMetaClassAndStructors(IOStateReporter, IOReporter); 36 37 38/* static */ 39IOStateReporter* 40IOStateReporter::with(IOService *reportingService, 41 IOReportCategories categories, 42 int nstates, 43 IOReportUnits 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 59finish: 60 if (!rval) { 61 if (reporter) delete reporter; 62 } 63 64 return rval; 65} 66 67bool 68IOStateReporter::initWith(IOService *reportingService, 69 IOReportCategories categories, 70 int16_t nstates, 71 IOReportUnits 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 93finish: 94 return success; 95} 96 97 98void 99IOStateReporter::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 114IOReturn 115IOStateReporter::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 148finish: 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 163IOReturn 164IOStateReporter::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 222finish: 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 238void 239IOStateReporter::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 258IOReturn 259IOStateReporter::_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 298finish: 299 return res; 300} 301 302 303IOReturn 304IOStateReporter::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 323finish: 324 unlockReporter(); 325 return res; 326} 327 328IOReturn 329IOStateReporter::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 337IOReturn 338IOStateReporter::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 363finish: 364 unlockReporter(); 365 return res; 366} 367 368 369IOReturn 370IOStateReporter::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 409finish: 410 return result; 411} 412 413 414IOReturn 415IOStateReporter::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 440finish: 441 unlockReporter(); 442 return res; 443 444} 445 446 447IOReturn 448IOStateReporter::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 488finish: 489 return result; 490} 491 492 493IOReturn 494IOStateReporter::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 530finish: 531 unlockReporter(); 532 return res; 533} 534 535IOReturn 536IOStateReporter::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 543IOReturn 544IOStateReporter::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 560IOReturn 561IOStateReporter::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 593finish: 594 return res; 595} 596 597IOReturn 598IOStateReporter::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 615IOReturn 616IOStateReporter::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 624IOReturn 625IOStateReporter::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 724finish: 725 return res; 726} 727 728 729// blocks might make this slightly easier? 730uint64_t 731IOStateReporter::getStateInTransitions(uint64_t channel_id, 732 uint64_t state_id) 733{ 734 return _getStateValue(channel_id, state_id, kInTransitions); 735} 736 737uint64_t 738IOStateReporter::getStateResidencyTime(uint64_t channel_id, 739 uint64_t state_id) 740{ 741 return _getStateValue(channel_id, state_id, kResidencyTime); 742} 743 744uint64_t 745IOStateReporter::getStateLastTransitionTime(uint64_t channel_id, 746 uint64_t state_id) 747{ 748 return _getStateValue(channel_id, state_id, kLastTransitionTime); 749} 750 751uint64_t 752IOStateReporter::_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 default: 782 break; 783 } 784 785 break; 786 } 787 788 element_index++; 789 } 790 } 791 } 792 793 unlockReporter(); 794 return result; 795} 796 797 798uint64_t 799IOStateReporter::getStateLastChannelUpdateTime(uint64_t channel_id) 800{ 801 int channel_index; 802 uint64_t result = kIOReportInvalidValue; 803 804 lockReporter(); 805 806 if (getChannelIndex(channel_id, &channel_index) == kIOReturnSuccess) { 807 808 result = _lastUpdateTimes[channel_index]; 809 } 810 811 unlockReporter(); 812 813 return result; 814} 815 816 817/* updateChannelValues() is called to refresh state before being 818 reported outside the reporter. In the case of IOStateReporter, 819 this is primarily an update to the "time in state" data. 820*/ 821IOReturn 822IOStateReporter::updateChannelValues(int channel_index) 823{ 824 IOReturn kerr, result = kIOReturnError; 825 826 int state_index, element_idx; 827 uint64_t currentTime; 828 uint64_t last_ch_update_time; 829 uint64_t time_in_state; 830 IOStateReportValues state_values; 831 832 IOREPORTER_CHECK_LOCK(); 833 834 if (channel_index < 0 || channel_index >= _nChannels) { 835 result = kIOReturnBadArgument; goto finish; 836 } 837 838 /* First check to see whether this channel has begun self- 839 calculation of time in state. It's possible this channel 840 has yet to be initialized or that the driver is updating 841 the channel with override/incrementChannelState() which 842 never enable automatic time-in-state updates. In that case, 843 there is nothing to update and we return success. 844 */ 845 last_ch_update_time = _lastUpdateTimes[channel_index]; 846 if (last_ch_update_time == 0) { 847 result = kIOReturnSuccess; goto finish; 848 } 849 850 // figure out the current state (if any) 851 state_index = _currentStates[channel_index]; 852 853 // e.g. given 4 4-state channels, the boundary is ch[3].st[3] <- _elems[15] 854 if (channel_index < 0 || channel_index > (_nElements - state_index) 855 / _channelDimension) { 856 result = kIOReturnOverrun; goto finish; 857 } 858 element_idx = channel_index * _channelDimension + state_index; 859 860 // get the current values 861 kerr = copyElementValues(element_idx,(IOReportElementValues*)&state_values); 862 if (kerr) { 863 result = kerr; goto finish; 864 } 865 866 // calculate time in state 867 currentTime = mach_absolute_time(); 868 time_in_state = currentTime - last_ch_update_time; 869 state_values.upticks += time_in_state; 870 871 // and store the values 872 kerr = setElementValues(element_idx, 873 (IOReportElementValues *)&state_values, 874 currentTime); 875 if (kerr) { 876 result = kerr; goto finish; 877 } 878 879 // Record basis for next "prior time" calculation 880 _lastUpdateTimes[channel_index] = currentTime; 881 882 883 // success 884 result = kIOReturnSuccess; 885 886finish: 887 return result; 888} 889