]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOStateReporter.cpp
xnu-6153.141.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOStateReporter.cpp
CommitLineData
fe8ab488
A
1/*
2 * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved.
0a7de745 3 *
fe8ab488 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
fe8ab488
A
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.
0a7de745 14 *
fe8ab488
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
fe8ab488
A
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.
0a7de745 25 *
fe8ab488
A
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,
0a7de745
A
41 IOReportCategories categories,
42 int nstates,
43 IOReportUnit unit /* = kIOReportUnitHWTicks*/)
fe8ab488 44{
0a7de745
A
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
fe8ab488 61finish:
0a7de745
A
62 if (!rval) {
63 OSSafeReleaseNULL(reporter);
64 }
65
66 return rval;
fe8ab488
A
67}
68
69bool
70IOStateReporter::initWith(IOService *reportingService,
0a7de745
A
71 IOReportCategories categories,
72 int16_t nstates,
73 IOReportUnit unit)
fe8ab488 74{
0a7de745
A
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
95finish:
96 return success;
fe8ab488
A
97}
98
99
100void
101IOStateReporter::free(void)
102{
0a7de745
A
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();
fe8ab488
A
113}
114
115
116IOReturn
117IOStateReporter::handleSwapPrepare(int newNChannels)
118{
0a7de745
A
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
fe8ab488 150finish:
0a7de745
A
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;
fe8ab488
A
163}
164
165IOReturn
166IOStateReporter::handleAddChannelSwap(uint64_t channelID,
0a7de745 167 const OSSymbol *symChannelName)
fe8ab488 168{
0a7de745
A
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
fe8ab488 224finish:
0a7de745
A
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;
fe8ab488
A
237}
238
239
240void
241IOStateReporter::handleSwapCleanup(int swapNChannels)
242{
0a7de745
A
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 }
fe8ab488
A
257}
258
259
260IOReturn
261IOStateReporter::_getStateIndices(uint64_t channel_id,
0a7de745
A
262 uint64_t state_id,
263 int *channel_index,
264 int *state_index)
fe8ab488 265{
0a7de745
A
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
fe8ab488 298finish:
0a7de745 299 return res;
fe8ab488
A
300}
301
302
303IOReturn
304IOStateReporter::setChannelState(uint64_t channel_id,
0a7de745 305 uint64_t new_state_id)
fe8ab488 306{
0a7de745
A
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
fe8ab488 323finish:
0a7de745
A
324 unlockReporter();
325 return res;
fe8ab488
A
326}
327
328IOReturn
329IOStateReporter::setChannelState(uint64_t channel_id,
0a7de745
A
330 uint64_t new_state_id,
331 uint64_t last_intransition,
332 uint64_t prev_state_residency)
fe8ab488 333{
0a7de745 334 return setChannelState(channel_id, new_state_id);
fe8ab488
A
335}
336
337IOReturn
338IOStateReporter::overrideChannelState(uint64_t channel_id,
0a7de745
A
339 uint64_t state_id,
340 uint64_t time_in_state,
341 uint64_t intransitions,
342 uint64_t last_intransition /*=0*/)
fe8ab488 343{
0a7de745
A
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
fe8ab488 362finish:
0a7de745
A
363 unlockReporter();
364 return res;
fe8ab488
A
365}
366
367
368IOReturn
369IOStateReporter::handleOverrideChannelStateByIndices(int channel_index,
0a7de745
A
370 int state_index,
371 uint64_t time_in_state,
372 uint64_t intransitions,
373 uint64_t last_intransition /*=0*/)
fe8ab488 374{
0a7de745
A
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
fe8ab488 408finish:
0a7de745 409 return result;
fe8ab488
A
410}
411
412
413IOReturn
414IOStateReporter::incrementChannelState(uint64_t channel_id,
0a7de745
A
415 uint64_t state_id,
416 uint64_t time_in_state,
417 uint64_t intransitions,
418 uint64_t last_intransition /*=0*/)
fe8ab488 419{
0a7de745
A
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 }
fe8ab488 429
0a7de745
A
430 res = handleIncrementChannelStateByIndices(channel_index, state_index,
431 time_in_state, intransitions,
432 last_intransition);
433 goto finish;
434 }
435
436 res = kIOReturnBadArgument;
437
438finish:
439 unlockReporter();
440 return res;
fe8ab488
A
441}
442
443
444IOReturn
445IOStateReporter::handleIncrementChannelStateByIndices(int channel_index,
0a7de745
A
446 int state_index,
447 uint64_t time_in_state,
448 uint64_t intransitions,
449 uint64_t last_intransition /*=0*/)
fe8ab488 450{
0a7de745
A
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
fe8ab488 485finish:
0a7de745 486 return result;
fe8ab488
A
487}
488
489
490IOReturn
491IOStateReporter::setState(uint64_t new_state_id)
492{
0a7de745
A
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;
fe8ab488
A
523
524finish:
0a7de745
A
525 unlockReporter();
526 return res;
fe8ab488
A
527}
528
529IOReturn
530IOStateReporter::setState(uint64_t new_state_id,
0a7de745
A
531 uint64_t last_intransition,
532 uint64_t prev_state_residency)
fe8ab488 533{
0a7de745 534 return setState(new_state_id);
fe8ab488
A
535}
536
537IOReturn
538IOStateReporter::setStateID(uint64_t channel_id,
0a7de745
A
539 int state_index,
540 uint64_t state_id)
fe8ab488 541{
0a7de745
A
542 IOReturn res = kIOReturnError;
543
544 lockReporter();
545
546 res = handleSetStateID(channel_id, state_index, state_id);
547
548 unlockReporter();
549
550 return res;
fe8ab488
A
551}
552
553
554IOReturn
555IOStateReporter::handleSetStateID(uint64_t channel_id,
0a7de745
A
556 int state_index,
557 uint64_t state_id)
fe8ab488 558{
0a7de745
A
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
fe8ab488 586finish:
0a7de745 587 return res;
fe8ab488
A
588}
589
590IOReturn
591IOStateReporter::setStateByIndices(int channel_index,
0a7de745 592 int new_state_index)
fe8ab488 593{
0a7de745
A
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;
fe8ab488
A
606}
607
608IOReturn
609IOStateReporter::setStateByIndices(int channel_index,
0a7de745
A
610 int new_state_index,
611 uint64_t last_intransition,
612 uint64_t prev_state_residency)
fe8ab488 613{
0a7de745 614 return setStateByIndices(channel_index, new_state_index);
fe8ab488
A
615}
616
617IOReturn
618IOStateReporter::handleSetStateByIndices(int channel_index,
0a7de745
A
619 int new_state_index,
620 uint64_t last_intransition,
621 uint64_t prev_state_residency)
fe8ab488 622{
0a7de745
A
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
fe8ab488 717finish:
0a7de745 718 return res;
fe8ab488
A
719}
720
721
722// blocks might make this slightly easier?
723uint64_t
724IOStateReporter::getStateInTransitions(uint64_t channel_id,
0a7de745 725 uint64_t state_id)
fe8ab488 726{
0a7de745 727 return _getStateValue(channel_id, state_id, kInTransitions);
fe8ab488
A
728}
729
730uint64_t
731IOStateReporter::getStateResidencyTime(uint64_t channel_id,
0a7de745 732 uint64_t state_id)
fe8ab488 733{
0a7de745 734 return _getStateValue(channel_id, state_id, kResidencyTime);
fe8ab488
A
735}
736
737uint64_t
738IOStateReporter::getStateLastTransitionTime(uint64_t channel_id,
0a7de745 739 uint64_t state_id)
fe8ab488 740{
0a7de745 741 return _getStateValue(channel_id, state_id, kLastTransitionTime);
fe8ab488
A
742}
743
744uint64_t
745IOStateReporter::_getStateValue(uint64_t channel_id,
0a7de745
A
746 uint64_t state_id,
747 enum valueSelector value)
fe8ab488 748{
0a7de745
A
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;
fe8ab488
A
785}
786
787
788uint64_t
789IOStateReporter::getStateLastChannelUpdateTime(uint64_t channel_id)
790{
0a7de745
A
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;
fe8ab488
A
803}
804
805
806/* updateChannelValues() is called to refresh state before being
0a7de745
A
807 * reported outside the reporter. In the case of IOStateReporter,
808 * this is primarily an update to the "time in state" data.
809 */
fe8ab488
A
810IOReturn
811IOStateReporter::updateChannelValues(int channel_index)
812{
0a7de745
A
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
fe8ab488 875finish:
0a7de745 876 return result;
fe8ab488 877}