]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOStateReporter.cpp
xnu-7195.81.3.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
f427ee49
A
29#define IOKIT_ENABLE_SHARED_PTR
30
31#include <libkern/c++/OSSharedPtr.h>
fe8ab488
A
32#include <IOKit/IOKernelReportStructs.h>
33#include <IOKit/IOKernelReporters.h>
34#include "IOReporterDefs.h"
35
36
37#define super IOReporter
38OSDefineMetaClassAndStructors(IOStateReporter, IOReporter);
39
40
41/* static */
f427ee49 42OSSharedPtr<IOStateReporter>
fe8ab488 43IOStateReporter::with(IOService *reportingService,
0a7de745
A
44 IOReportCategories categories,
45 int nstates,
46 IOReportUnit unit /* = kIOReportUnitHWTicks*/)
fe8ab488 47{
f427ee49 48 OSSharedPtr<IOStateReporter> reporter;
0a7de745 49
f427ee49
A
50 if (nstates > INT16_MAX) {
51 return nullptr;
0a7de745
A
52 }
53
f427ee49
A
54 reporter = OSMakeShared<IOStateReporter>();
55 if (!reporter) {
56 return nullptr;
0a7de745
A
57 }
58
f427ee49
A
59 if (!reporter->initWith(reportingService, categories, (int16_t) nstates, unit)) {
60 return nullptr;
0a7de745
A
61 }
62
f427ee49 63 return reporter;
fe8ab488
A
64}
65
66bool
67IOStateReporter::initWith(IOService *reportingService,
0a7de745
A
68 IOReportCategories categories,
69 int16_t nstates,
70 IOReportUnit unit)
fe8ab488 71{
0a7de745
A
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
92finish:
93 return success;
fe8ab488
A
94}
95
96
97void
98IOStateReporter::free(void)
99{
0a7de745
A
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();
fe8ab488
A
110}
111
112
113IOReturn
114IOStateReporter::handleSwapPrepare(int newNChannels)
115{
0a7de745
A
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
fe8ab488 147finish:
0a7de745
A
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;
fe8ab488
A
160}
161
162IOReturn
163IOStateReporter::handleAddChannelSwap(uint64_t channelID,
0a7de745 164 const OSSymbol *symChannelName)
fe8ab488 165{
0a7de745
A
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
fe8ab488 221finish:
0a7de745
A
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;
fe8ab488
A
234}
235
236
237void
238IOStateReporter::handleSwapCleanup(int swapNChannels)
239{
0a7de745
A
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 }
fe8ab488
A
254}
255
256
257IOReturn
258IOStateReporter::_getStateIndices(uint64_t channel_id,
0a7de745
A
259 uint64_t state_id,
260 int *channel_index,
261 int *state_index)
fe8ab488 262{
0a7de745
A
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
fe8ab488 295finish:
0a7de745 296 return res;
fe8ab488
A
297}
298
299
300IOReturn
301IOStateReporter::setChannelState(uint64_t channel_id,
0a7de745 302 uint64_t new_state_id)
fe8ab488 303{
0a7de745
A
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
fe8ab488 320finish:
0a7de745
A
321 unlockReporter();
322 return res;
fe8ab488
A
323}
324
325IOReturn
326IOStateReporter::setChannelState(uint64_t channel_id,
0a7de745
A
327 uint64_t new_state_id,
328 uint64_t last_intransition,
329 uint64_t prev_state_residency)
fe8ab488 330{
0a7de745 331 return setChannelState(channel_id, new_state_id);
fe8ab488
A
332}
333
334IOReturn
335IOStateReporter::overrideChannelState(uint64_t channel_id,
0a7de745
A
336 uint64_t state_id,
337 uint64_t time_in_state,
338 uint64_t intransitions,
339 uint64_t last_intransition /*=0*/)
fe8ab488 340{
0a7de745
A
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
fe8ab488 359finish:
0a7de745
A
360 unlockReporter();
361 return res;
fe8ab488
A
362}
363
364
365IOReturn
366IOStateReporter::handleOverrideChannelStateByIndices(int channel_index,
0a7de745
A
367 int state_index,
368 uint64_t time_in_state,
369 uint64_t intransitions,
370 uint64_t last_intransition /*=0*/)
fe8ab488 371{
0a7de745
A
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
fe8ab488 405finish:
0a7de745 406 return result;
fe8ab488
A
407}
408
409
410IOReturn
411IOStateReporter::incrementChannelState(uint64_t channel_id,
0a7de745
A
412 uint64_t state_id,
413 uint64_t time_in_state,
414 uint64_t intransitions,
415 uint64_t last_intransition /*=0*/)
fe8ab488 416{
0a7de745
A
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 }
fe8ab488 426
0a7de745
A
427 res = handleIncrementChannelStateByIndices(channel_index, state_index,
428 time_in_state, intransitions,
429 last_intransition);
430 goto finish;
431 }
432
433 res = kIOReturnBadArgument;
434
435finish:
436 unlockReporter();
437 return res;
fe8ab488
A
438}
439
440
441IOReturn
442IOStateReporter::handleIncrementChannelStateByIndices(int channel_index,
0a7de745
A
443 int state_index,
444 uint64_t time_in_state,
445 uint64_t intransitions,
446 uint64_t last_intransition /*=0*/)
fe8ab488 447{
0a7de745
A
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
fe8ab488 482finish:
0a7de745 483 return result;
fe8ab488
A
484}
485
486
487IOReturn
488IOStateReporter::setState(uint64_t new_state_id)
489{
0a7de745
A
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;
fe8ab488
A
520
521finish:
0a7de745
A
522 unlockReporter();
523 return res;
fe8ab488
A
524}
525
526IOReturn
527IOStateReporter::setState(uint64_t new_state_id,
0a7de745
A
528 uint64_t last_intransition,
529 uint64_t prev_state_residency)
fe8ab488 530{
0a7de745 531 return setState(new_state_id);
fe8ab488
A
532}
533
534IOReturn
535IOStateReporter::setStateID(uint64_t channel_id,
0a7de745
A
536 int state_index,
537 uint64_t state_id)
fe8ab488 538{
0a7de745
A
539 IOReturn res = kIOReturnError;
540
541 lockReporter();
542
543 res = handleSetStateID(channel_id, state_index, state_id);
544
545 unlockReporter();
546
547 return res;
fe8ab488
A
548}
549
550
551IOReturn
552IOStateReporter::handleSetStateID(uint64_t channel_id,
0a7de745
A
553 int state_index,
554 uint64_t state_id)
fe8ab488 555{
0a7de745
A
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
fe8ab488 583finish:
0a7de745 584 return res;
fe8ab488
A
585}
586
587IOReturn
588IOStateReporter::setStateByIndices(int channel_index,
0a7de745 589 int new_state_index)
fe8ab488 590{
0a7de745
A
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;
fe8ab488
A
603}
604
605IOReturn
606IOStateReporter::setStateByIndices(int channel_index,
0a7de745
A
607 int new_state_index,
608 uint64_t last_intransition,
609 uint64_t prev_state_residency)
fe8ab488 610{
0a7de745 611 return setStateByIndices(channel_index, new_state_index);
fe8ab488
A
612}
613
614IOReturn
615IOStateReporter::handleSetStateByIndices(int channel_index,
0a7de745
A
616 int new_state_index,
617 uint64_t last_intransition,
618 uint64_t prev_state_residency)
fe8ab488 619{
0a7de745
A
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
fe8ab488 714finish:
0a7de745 715 return res;
fe8ab488
A
716}
717
718
719// blocks might make this slightly easier?
720uint64_t
721IOStateReporter::getStateInTransitions(uint64_t channel_id,
0a7de745 722 uint64_t state_id)
fe8ab488 723{
0a7de745 724 return _getStateValue(channel_id, state_id, kInTransitions);
fe8ab488
A
725}
726
727uint64_t
728IOStateReporter::getStateResidencyTime(uint64_t channel_id,
0a7de745 729 uint64_t state_id)
fe8ab488 730{
0a7de745 731 return _getStateValue(channel_id, state_id, kResidencyTime);
fe8ab488
A
732}
733
734uint64_t
735IOStateReporter::getStateLastTransitionTime(uint64_t channel_id,
0a7de745 736 uint64_t state_id)
fe8ab488 737{
0a7de745 738 return _getStateValue(channel_id, state_id, kLastTransitionTime);
fe8ab488
A
739}
740
741uint64_t
742IOStateReporter::_getStateValue(uint64_t channel_id,
0a7de745
A
743 uint64_t state_id,
744 enum valueSelector value)
fe8ab488 745{
0a7de745
A
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;
fe8ab488
A
782}
783
784
785uint64_t
786IOStateReporter::getStateLastChannelUpdateTime(uint64_t channel_id)
787{
0a7de745
A
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;
fe8ab488
A
800}
801
802
803/* updateChannelValues() is called to refresh state before being
0a7de745
A
804 * reported outside the reporter. In the case of IOStateReporter,
805 * this is primarily an update to the "time in state" data.
806 */
fe8ab488
A
807IOReturn
808IOStateReporter::updateChannelValues(int channel_index)
809{
0a7de745
A
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
fe8ab488 872finish:
0a7de745 873 return result;
fe8ab488 874}