]> git.saurik.com Git - apple/xnu.git/blob - iokit/IOKit/IOReportMacros.h
xnu-3247.1.106.tar.gz
[apple/xnu.git] / iokit / IOKit / IOReportMacros.h
1 /*
2 * Copyright (c) 2012-2014 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 #ifndef _IOREPORT_MACROS_H_
30 #define _IOREPORT_MACROS_H_
31
32 #include "IOReportTypes.h"
33
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37
38 #ifndef IOREPORT_ABORT
39 #define IOREPORT_ABORT panic
40 #endif
41
42 /*
43 Background
44
45 These macros allow non-I/O Kit software to generate IOReporting
46 reports. Clients must prevent concurrent access to any given
47 report buffer from multiple threads.
48
49 While these macros allow non-I/O Kit software to participate
50 in IOReporting, an IOService instance must lend its driver ID,
51 respond to the appropriate IOService overrides, and shuttle
52 data back and forth. In some cases, it may be useful to have
53 the I/O Kit driver initialize the report buffer with the
54 appropriate macro.
55 */
56
57
58 /* ----- Reporting Single Integers (SimpleReport) ----- */
59
60 /*
61 * The buffer size required for a SimpleReport.
62 */
63
64 #define SIMPLEREPORT_BUFSIZE (sizeof(IOReportElement))
65
66
67 /*
68 * Initialize a buffer to hold a SimpleReport.
69 *
70 * void* buffer - ptr to SIMPLEREPORT_BUFSIZE bytes
71 * size_t bufSize - sanity check of buffer's size
72 * uint64_t providerID - registry Entry ID of the reporting service
73 * uint64_t channelID - the report's channel ID
74 * IOReportCategories categories - categories of this channel
75 *
76 * If the buffer is not of sufficient size, the macro calls IOREPORT_ABORT().
77 * If that returns, the buffer is filled with 0xbadcafe.
78 */
79
80 #define SIMPLEREPORT_INIT(buffer, bufSize, providerID, channelID, cats) \
81 do { \
82 IOReportElement *__elem = (IOReportElement *)(buffer); \
83 IOSimpleReportValues *__vals; \
84 if ((bufSize) >= SIMPLEREPORT_BUFSIZE) { \
85 __elem->channel_id = (channelID); \
86 __elem->provider_id = (providerID); \
87 __elem->channel_type.report_format = kIOReportFormatSimple; \
88 __elem->channel_type.reserved = 0; \
89 __elem->channel_type.categories = (cats); \
90 __elem->channel_type.nelements = 1; \
91 __elem->channel_type.element_idx = 0; \
92 __elem->timestamp = 0; \
93 __vals = (IOSimpleReportValues*)&__elem->values; \
94 __vals->simple_value = kIOReportInvalidIntValue; \
95 } \
96 else { \
97 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
98 __POLLUTE_BUF((buffer), (bufSize)); \
99 } \
100 } while(0)
101
102
103 /*
104 * Set a SimpleReport to a new value.
105 *
106 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
107 * int64_t new_value - new value for the report
108 */
109
110 #define SIMPLEREPORT_SETVALUE(simp_buf, new_value) \
111 do { \
112 IOReportElement *__elem = (IOReportElement *)(simp_buf); \
113 IOSimpleReportValues *__vals; \
114 __vals = (IOSimpleReportValues*)&__elem->values; \
115 __vals->simple_value = (new_value); \
116 } while(0)
117
118
119 /*
120 * Increment the value of a SimpleReport.
121 *
122 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
123 * int64_t increment - amount by which to increment the value
124 */
125 #define SIMPLEREPORT_INCREMENTVALUE(simp_buf, new_value) \
126 do { \
127 IOReportElement *__elem = (IOReportElement *)(simp_buf); \
128 IOSimpleReportValues *__vals; \
129 __vals = (IOSimpleReportValues*)&__elem->values; \
130 __vals->simple_value += (new_value); \
131 } while(0)
132
133
134 /*
135 * Prepare a SimpleReport for
136 * IOService::updateReport(kIOReportCopyChannelData...)
137 *
138 * void* simp_buf - Ptr to memory updated by SIMPLEREPORT_SETVALUE()
139 * void* ptr2cpy - On return, 'ptr2cpy' points to the memory that needs to be
140 * copied for kIOReportCopyChannelData.
141 * size_t size2cpy - On return, 'size2cpy' is set to the size of the report
142 * data that needs to be copied for kIOReportCopyChannelData.
143 */
144
145 #define SIMPLEREPORT_UPDATEPREP(simp_buf, ptr2cpy, size2cpy) \
146 do { \
147 (ptr2cpy) = (simp_buf); \
148 (size2cpy) = sizeof(IOReportElement); \
149 } while(0)
150
151
152 /*
153 * Update the result field received as a parameter for
154 * kIOReportGetDimensions & kIOReportCopyChannelData actions.
155 *
156 * IOReportConfigureAction action - configure/updateReport() 'action' param
157 * void* result - configure/updateReport() 'result' param
158 */
159
160 #define SIMPLEREPORT_UPDATERES(action, result) \
161 do { \
162 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
163 int *__nElements = (int *)(result); \
164 *__nElements += 1; \
165 } \
166 } while (0)
167
168
169 /*
170 * Get the 64-bit channel ID of a SimpleReport.
171 *
172 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
173 */
174
175 #define SIMPLEREPORT_GETCHID(simp_buf) \
176 (((IOReportElement *)(simp_buf))->channel_id)
177
178 /*
179 * Get the IOReportChannelType of a SimpleReport.
180 *
181 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
182 */
183
184 #define SIMPLEREPORT_GETCHTYPE(simp_buf) \
185 (*(uint64_t*)&(((IOReportElement *)(simp_buf))->channel_type))
186
187
188 /*
189 * Get the integer value of a SimpleReport.
190 *
191 * void* simp_buf - memory initialized by SIMPLEREPORT_INIT()
192 */
193
194 #define SIMPLEREPORT_GETVALUE(simp_buf) \
195 (((IOSimpleReportValues*)&(((IOReportElement*)(simp_buf))->values)) \
196 ->simple_value)
197
198
199 /* ----- State Machine Reporting (StateReport) ----- */
200
201 // Internal struct for StateReport
202 typedef struct {
203 uint16_t curr_state;
204 uint64_t update_ts;
205 IOReportElement elem[]; // Array of elements
206 } IOStateReportInfo;
207
208 /*
209 * Determine the size required for a StateReport buffer.
210 *
211 * int nstates - number of states to be reported
212 */
213 #define STATEREPORT_BUFSIZE(nstates) \
214 (sizeof(IOStateReportInfo) + (nstates) * sizeof(IOReportElement))
215
216
217 /*
218 * Initialize a StateReport buffer.
219 *
220 * int nstates - number of states to be reported
221 * void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes
222 * size_t bufSize - sanity check of buffer's size
223 * uint64_t providerID - registry Entry ID of the reporting service
224 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
225 * IOReportCategories categories - categories of this channel
226 *
227 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
228 * If that returns, the buffer is filled with 0xbadcafe.
229 */
230 #define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \
231 do { \
232 IOStateReportInfo *__info = (IOStateReportInfo *)(buf); \
233 IOStateReportValues *__rep; \
234 IOReportElement *__elem; \
235 if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) { \
236 for (unsigned __no = 0; __no < (nstates); __no++) { \
237 __elem = &(__info->elem[__no]); \
238 __rep = (IOStateReportValues *) &(__elem->values); \
239 __elem->channel_id = (channelID); \
240 __elem->provider_id = (providerID); \
241 __elem->channel_type.report_format = kIOReportFormatState; \
242 __elem->channel_type.reserved = 0; \
243 __elem->channel_type.categories = (cats); \
244 __elem->channel_type.nelements = (nstates); \
245 __elem->channel_type.element_idx = __no; \
246 __elem->timestamp = 0; \
247 __rep->state_id = __no; \
248 __rep->intransitions = 0; \
249 __rep->upticks = 0; \
250 } \
251 __info->curr_state = 0; \
252 __info->update_ts = 0; \
253 } \
254 else { \
255 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
256 __POLLUTE_BUF((buf), (bufSize)); \
257 } \
258 } while(0)
259
260 /*
261 * Initialize the state id field of a state with the specified value. By
262 * default, STATEREPORT_INIT() initializes the state IDs with the index of
263 * that state. This macro can be used to provide a more descriptive state id.
264 *
265 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
266 * unsigned stateIdx - index of the state, out of bounds -> no-op
267 * uint64_t stateID - new state id, see IOREPORT_MAKEID()
268 */
269 #define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID) \
270 do { \
271 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
272 IOStateReportValues *__rep; \
273 if ((stateIdx) < __info->elem[0].channel_type.nelements) { \
274 __rep = (IOStateReportValues*) &(__info->elem[(stateIdx)].values); \
275 __rep->state_id = (stateID); \
276 } \
277 } while (0)
278
279
280 /*
281 * Set the state of a StateReport.
282 *
283 * void* state_buf - pointer to memory initialized by STATEREPORT_INIT()
284 * unsigned newStateIdx - index of new state, out of bounds -> no-op
285 * uint64_t changeTime - time at which the transition occurred
286 */
287 #define STATEREPORT_SETSTATE(state_buf, newStateIdx, changeTime) \
288 do { \
289 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
290 IOStateReportValues *__rep; \
291 if ((newStateIdx) < __info->elem[0].channel_type.nelements ) { \
292 __rep = (IOStateReportValues*) &(__info->elem[__info->curr_state].values); \
293 if (__info->update_ts) \
294 __rep->upticks += (changeTime) - __info->update_ts; \
295 __info->elem[(newStateIdx)].timestamp = (changeTime); \
296 __rep = (IOStateReportValues*) &(__info->elem[(newStateIdx)].values); \
297 __rep->intransitions++; \
298 __info->curr_state = (newStateIdx); \
299 __info->update_ts = (changeTime); \
300 } \
301 } while(0)
302
303 /*
304 * Prepare a StateReport for
305 * IOService::updateReport(kIOReportCopyChannelData...)
306 *
307 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
308 * uint64_t currentTime - current timestamp
309 * void* ptr2cpy - filled in with pointer to buffer to be copied out
310 * size_t size2cpy - filled in with the size of the buffer to copy out
311 */
312 #define STATEREPORT_UPDATEPREP(state_buf, currentTime, ptr2cpy, size2cpy) \
313 do { \
314 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
315 IOReportElement *__elem; \
316 IOStateReportValues *__state; \
317 (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
318 (ptr2cpy) = (void *) &__info->elem[0]; \
319 if (__info->update_ts) { \
320 __elem = &__info->elem[__info->curr_state]; \
321 __state = (IOStateReportValues *)&__elem->values; \
322 __elem->timestamp = (currentTime); \
323 __state->upticks += (currentTime) - __info->update_ts; \
324 __info->update_ts = (currentTime); \
325 } \
326 } while(0)
327
328 /*
329 * Update the result field received as a parameter for kIOReportGetDimensions &
330 * kIOReportCopyChannelData actions.
331 *
332 * void* state_buf - memory initialized by STATEREPORT_INIT()
333 * IOReportConfigureAction action - configure/updateReport() 'action'
334 * void* result - configure/updateReport() 'result'
335 */
336
337 #define STATEREPORT_UPDATERES(state_buf, action, result) \
338 do { \
339 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
340 IOReportElement *__elem; \
341 int *__nElements = (int *)(result); \
342 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
343 __elem = &(__info->elem[0]); \
344 *__nElements += __elem->channel_type.nelements; \
345 } \
346 } while (0)
347
348
349 /*
350 * Get the 64-bit channel ID of a StateReport.
351 *
352 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
353 */
354 #define STATEREPORT_GETCHID(state_buf) \
355 (((IOStateReportInfo *)(state_buf))->elem[0].channel_id)
356
357 /*
358 * Get the IOReportChannelType of a StateReport.
359 *
360 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
361 */
362 #define STATEREPORT_GETCHTYPE(state_buf) \
363 (*(uint64_t*)&(((IOStateReportInfo *)(state_buf))->elem[0].channel_type))
364
365 /*
366 * Get the number of transitions into a given state.
367 *
368 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
369 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
370 *
371 */
372 #define STATEREPORT_GETTRANSITIONS(state_buf, stateIdx) \
373 (((stateIdx) < ((IOStateReportInfo *)(state_buf))->elem[0].channel_type.nelements) \
374 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->intransitions \
375 : kIOReportInvalidValue)
376
377 /*
378 * Get the total number of ticks spent in a given state.
379 *
380 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
381 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
382 */
383 #define STATEREPORT_GETTICKS(state_buf, stateIdx) \
384 (((stateIdx) < ((IOStateReportInfo*)(state_buf))->elem[0].channel_type.nelements) \
385 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->upticks \
386 : kIOReportInvalidValue)
387
388
389 /* ----- Reporting an Array of Integers (SimpleArrayReport) ----- */
390
391 /*
392 * Determine the buffer size for a SimpleArrayReport.
393 *
394 * int nValues - number of values to be reported
395 */
396
397 #define SIMPLEARRAY_BUFSIZE(nValues) \
398 ((((nValues)/IOR_VALUES_PER_ELEMENT) + (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1:0)) \
399 * sizeof(IOReportElement))
400
401 /*
402 * Initialize a buffer for use as a SimpleArrayReport.
403 *
404 * int nValues - number of elements to be reported
405 * void* buf - ptr to SIMPLEARRAY_BUFSIZE(nValues) bytes
406 * size_t bufSize - sanity check of buffer's size
407 * uint64_t providerID - registry Entry ID of the reporting service
408 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
409 * IOReportCategories categories - categories of this channel
410 *
411 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT()
412 * and, if that returns, fills the buffer with 0xbadcafe.
413 */
414
415 #define SIMPLEARRAY_INIT(nValues, buf, bufSize, providerID, channelID, cats) \
416 do { \
417 IOSimpleArrayReportValues *__rep; \
418 IOReportElement *__elem; \
419 uint32_t __nElems = (((nValues) / IOR_VALUES_PER_ELEMENT) + \
420 (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1 : 0)); \
421 if ((bufSize) >= SIMPLEARRAY_BUFSIZE(nValues)) { \
422 for (unsigned __no = 0; __no < __nElems; __no++) { \
423 __elem = &(((IOReportElement *)(buf))[__no]); \
424 __rep = (IOSimpleArrayReportValues *) &(__elem->values); \
425 __elem->channel_id = (channelID); \
426 __elem->provider_id = (providerID); \
427 __elem->channel_type.report_format = kIOReportFormatSimpleArray; \
428 __elem->channel_type.reserved = 0; \
429 __elem->channel_type.categories = (cats); \
430 __elem->channel_type.nelements = (__nElems); \
431 __elem->channel_type.element_idx = __no; \
432 __elem->timestamp = 0; \
433 __rep->simple_values[0] = kIOReportInvalidIntValue; \
434 __rep->simple_values[1] = kIOReportInvalidIntValue; \
435 __rep->simple_values[2] = kIOReportInvalidIntValue; \
436 __rep->simple_values[3] = kIOReportInvalidIntValue; \
437 } \
438 } \
439 else { \
440 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
441 __POLLUTE_BUF((buf), (bufSize)); \
442 } \
443 } while(0)
444
445
446 /* SimpleArrayReport helpers */
447
448 #define __SA_FINDREP(array_buf, idx) \
449 IOSimpleArrayReportValues *__rep; \
450 IOReportElement *__elem; \
451 unsigned __elemIdx = (idx) / IOR_VALUES_PER_ELEMENT; \
452 unsigned __valueIdx = (idx) % IOR_VALUES_PER_ELEMENT; \
453 __elem = &(((IOReportElement *)(array_buf))[0]); \
454 if (__elemIdx < __elem->channel_type.nelements) { \
455 __elem = &(((IOReportElement *)(array_buf))[__elemIdx]); \
456 __rep = (IOSimpleArrayReportValues *) &(__elem->values); \
457
458 #define __SA_MAXINDEX(array_buf) \
459 ((((IOReportElement*)(array_buf))->channel_type.nelements) \
460 * IOR_VALUES_PER_ELEMENT) - 1
461
462 /*
463 * Set a value at a specified index in a SimpleArrayReport.
464 *
465 * void* array_bufbuf - ptr to memory initialized by SIMPLEARRAY_INIT()
466 * unsigned idx - array index, out of bounds -> no-op
467 * uint64_t newValue - new value to be stored at array[idx]
468 */
469 #define SIMPLEARRAY_SETVALUE(array_buf, idx, newValue) \
470 do { \
471 __SA_FINDREP((array_buf), (idx)) \
472 __rep->simple_values[__valueIdx] = (newValue); \
473 } \
474 } while(0)
475
476 /*
477 * Increment an array value within a SimpleArrayReport.
478 *
479 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
480 * unsigned idx - array index to increment, out of bounds -> no-op
481 * int64_t value - amount by which to increment array[idx]
482 */
483 #define SIMPLEARRAY_INCREMENTVALUE(array_buf, idx, value) \
484 do { \
485 __SA_FINDREP((array_buf), (idx)) \
486 __rep->simple_values[__valueIdx] += (value); \
487 } \
488 } while(0)
489
490
491 /*
492 * Prepare a SimpleArrayReport for
493 * IOService::updateReport(kIOReportCopyChannelData...)
494 *
495 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
496 * void* ptr2cpy - filled in with pointer to buffer to be copied out
497 * size_t size2cpy - filled in with the size of the buffer to copy out
498 */
499
500 #define SIMPLEARRAY_UPDATEPREP(array_buf, ptr2cpy, size2cpy) \
501 do { \
502 IOReportElement *__elem; \
503 __elem = &(((IOReportElement *)(array_buf))[0]); \
504 (ptr2cpy) = (void *) (array_buf); \
505 (size2cpy) = __elem->channel_type.nelements * sizeof(IOReportElement); \
506 } while(0)
507
508
509 /*
510 * Update the result field received as a parameter for kIOReportGetDimensions &
511 * kIOReportCopyChannelData actions.
512 *
513 * void* array_buf - memory initialized by SIMPLEARRAY_INIT()
514 * IOReportConfigureAction action - configure/updateReport() 'action'
515 * void* result - configure/updateReport() 'result'
516 */
517
518 #define SIMPLEARRAY_UPDATERES(array_buf, action, result) \
519 do { \
520 IOReportElement *__elem; \
521 int *__nElements = (int *)(result); \
522 __elem = &(((IOReportElement *)(array_buf))[0]); \
523 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
524 *__nElements += __elem->channel_type.nelements; \
525 } \
526 } while (0)
527
528
529 /*
530 * Get the 64-bit channel ID of a SimpleArrayReport.
531 *
532 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
533 */
534 #define SIMPLEARRAY_GETCHID(array_buf) \
535 (((IOReportElement *)(array_buf))->channel_id)
536
537
538 /*
539 * Get the IOReportChannelType of a SimpleArrayReport.
540 *
541 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
542 */
543 #define SIMPLEARRAY_GETCHTYPE(array_buf) \
544 (*(uint64_t*)&(((IOReportElement *)(array_buf))->channel_type))
545
546 /*
547 * Get a value from a SimpleArrayReport.
548 *
549 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
550 * unsigned idx - index of the value, out of bounds -> kIOReportInvalidValue
551 */
552 #define SIMPLEARRAY_GETVALUE(array_buf, idx) \
553 (((idx) > __SA_MAXINDEX(array_buf) || (idx) < 0) ? kIOReportInvalidIntValue : \
554 ((IOSimpleArrayReportValues*)&( \
555 ((IOReportElement*)(array_buf))[(idx) / IOR_VALUES_PER_ELEMENT].values)) \
556 ->simple_values[(idx) % IOR_VALUES_PER_ELEMENT])
557
558
559 /* ----- Histogram Reporting (HistogramReport) ----- */
560
561 // Internal struct for HistogramReport
562 typedef struct {
563 int bucketWidth;
564 IOReportElement elem[]; // Array of elements
565 } IOHistReportInfo;
566
567 /*
568 * Determine the size required for a HistogramReport buffer.
569 *
570 * int nbuckets - number of buckets in the histogram
571 */
572 #define HISTREPORT_BUFSIZE(nbuckets) \
573 (sizeof(IOHistReportInfo) + ((nbuckets) * sizeof(IOReportElement)))
574
575 /*
576 * Initialize a HistogramReport buffer. Supports only linear scale histogram.
577 *
578 * int nbuckets - number of buckets data is combined into
579 * uint32_t bucketWidth - size of each bucket
580 * void* buffer - ptr to HISTREPORT_BUFSIZE(nbuckets) bytes
581 * size_t bufSize - sanity check of buffer's size
582 * uint64_t providerID - registry Entry ID of the reporting service
583 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
584 * IOReportCategories categories - categories of this channel
585 *
586 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
587 * If that returns, the buffer is filled with 0xbadcafe.
588 */
589 #define HISTREPORT_INIT(nbuckets, bktSize, buf, bufSize, providerID, channelID, cats) \
590 do { \
591 IOHistReportInfo *__info = (IOHistReportInfo *)(buf); \
592 IOReportElement *__elem; \
593 IOHistogramReportValues *__rep; \
594 if ((bufSize) >= HISTREPORT_BUFSIZE(nbuckets)) { \
595 __info->bucketWidth = (bktSize); \
596 for (unsigned __no = 0; __no < (nbuckets); __no++) { \
597 __elem = &(__info->elem[__no]); \
598 __rep = (IOHistogramReportValues *) &(__elem->values); \
599 __elem->channel_id = (channelID); \
600 __elem->provider_id = (providerID); \
601 __elem->channel_type.report_format = kIOReportFormatHistogram; \
602 __elem->channel_type.reserved = 0; \
603 __elem->channel_type.categories = (cats); \
604 __elem->channel_type.nelements = (nbuckets); \
605 __elem->channel_type.element_idx = __no; \
606 __elem->timestamp = 0; \
607 bzero(__rep, sizeof(IOHistogramReportValues)); \
608 } \
609 } \
610 else { \
611 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
612 __POLLUTE_BUF((buf), (bufSize)); \
613 } \
614 } while (0)
615
616 /*
617 * Update histogram with a new value.
618 *
619 *
620 * void* hist_buf - pointer to memory initialized by HISTREPORT_INIT()
621 * int64_t value - new value to add to the histogram
622 */
623 #define HISTREPORT_TALLYVALUE(hist_buf, value) \
624 do { \
625 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
626 IOReportElement *__elem; \
627 IOHistogramReportValues *__rep; \
628 for (unsigned __no = 0; __no < __info->elem[0].channel_type.nelements; __no++) { \
629 if ((value) <= __info->bucketWidth * (__no+1)) { \
630 __elem = &(__info->elem[__no]); \
631 __rep = (IOHistogramReportValues *) &(__elem->values); \
632 if (__rep->bucket_hits == 0) { \
633 __rep->bucket_min = __rep->bucket_max = (value); \
634 } \
635 else if ((value) < __rep->bucket_min) { \
636 __rep->bucket_min = (value); \
637 } \
638 else if ((value) > __rep->bucket_max) { \
639 __rep->bucket_max = (value); \
640 } \
641 __rep->bucket_sum += (value); \
642 __rep->bucket_hits++; \
643 break; \
644 } \
645 } \
646 } while (0)
647
648 /*
649 * Prepare a HistogramReport for
650 * IOService::updateReport(kIOReportCopyChannelData...)
651 *
652 * void* array_buf - ptr to memory initialized by HISTREPORT_INIT()
653 * void* ptr2cpy - filled in with pointer to buffer to be copied out
654 * size_t size2cpy - filled in with the size of the buffer to copy out
655 */
656
657 #define HISTREPORT_UPDATEPREP(hist_buf, ptr2cpy, size2cpy) \
658 do { \
659 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
660 (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
661 (ptr2cpy) = (void *) &__info->elem[0]; \
662 } while(0)
663
664
665 /*
666 * Update the result field received as a parameter for kIOReportGetDimensions &
667 * kIOReportCopyChannelData actions.
668 *
669 * void* array_buf - memory initialized by HISTREPORT_INIT()
670 * IOReportConfigureAction action - configure/updateReport() 'action'
671 * void* result - configure/updateReport() 'result'
672 */
673
674 #define HISTREPORT_UPDATERES(hist_buf, action, result) \
675 do { \
676 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
677 int *__nElements = (int *)(result); \
678 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
679 *__nElements += __info->elem[0].channel_type.nelements; \
680 } \
681 } while (0)
682
683 /*
684 * Get the 64-bit channel ID of a HistogramReport.
685 *
686 * void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
687 */
688 #define HISTREPORT_GETCHID(hist_buf) \
689 (((IOHistReportInfo *)(hist_buf))->elem[0].channel_id)
690
691 /*
692 * Get the IOReportChannelType of a HistogramReport.
693 *
694 * void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
695 */
696 #define HISTREPORT_GETCHTYPE(hist_buf) \
697 (*(uint64_t*)&(((IOHistReportInfo *)(hist_buf))->elem[0].channel_type))
698
699
700
701 /* generic utilities */
702
703 #define __POLLUTE_BUF(buf, bufSize) \
704 do { \
705 int __cnt = (bufSize)/sizeof(uint32_t); \
706 while (--__cnt >= 0) \
707 ((uint32_t*)(buf))[__cnt] = 0xbadcafe; \
708 } while (0)
709
710 #ifdef __cplusplus
711 }
712 #endif
713
714 #endif // _IOREPORT_MACROS_H_
715
716