1 /* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 */ 15 16 #ifndef __WLANFW_HEALTH_MON_H__ 17 #define __WLANFW_HEALTH_MON_H__ 18 19 #include <a_types.h> /* A_UINT32 */ 20 21 /* WLAN Health monitor data structure shared by host and FW */ 22 23 /* 24 * Version 1 of the upload metric structs (i.e. wlanfw_health_mon_metric_upload_t) 25 * provides a fixed allocation of 8 bytes of scratch space after each metric, 26 * to optionally hold metric-specific data, e.g. from intermediate calculations when computing the score_pct. 27 */ 28 #define WLANFW_HEALTH_MON_EXTRA_WORDS32 2 29 30 /* word0: 31 * Extract bitfields from the A_UINT32 "word" containing them. 32 * The target produces the data in little-endian order. 33 * If the host uses big-endian order, it needs to account for the endianness 34 * difference when reading the data. 35 * Definition of bitfields within 32-bit word: 36 * bits 7:0 = module ID (M7...M0) 37 * bits 14:8 = module local ID (m6...m0) 38 * bits 31:15 = instance ID (I16...I0) 39 * bits 40 * |31 15|14 8|7 0| 41 * +-------------------------------+-----------------+-------------------+ 42 * | instance ID | metric local ID | module ID | 43 * |I16 ... I0|m6 ... m0|M7 ... M0| 44 * 45 * Layout in memory: 46 * bits 47 * |7 |6 0| 48 * +---+--------------------------+ 49 * byte 0 |M7 M6 M5 M4 M3 M2 M1 M0| 50 * +---+--------------------------+ 51 * byte 1 |I0 |m6 m5 m4 m3 m2 m1 m0| 52 * +---+--------------------------+ 53 * byte 2 |I8 I7 I6 I5 I4 I3 I2 I1| 54 * +------------------------------+ 55 * byte 3 |I16 I15 I14 I13 I12 I11 I10 I9| 56 */ 57 #ifdef LITTLE_ENDIAN 58 /* The little-endian version of the macro to extract the module id and metric id */ 59 #define WLANFW_HEALTH_MON_MODULE_ID_GET(word32) \ 60 (((word32) & 0x000000ff) >> 0) 61 #define WLANFW_HEALTH_MON_METRIC_LOCAL_ID_GET(word32) \ 62 (((word32) & 0x00007f00) >> 8) 63 #define WLANFW_HEALTH_MON_INSTANCE_ID_GET(word32) \ 64 (((word32) & 0xffff8000) >> 15) 65 #else 66 /* 67 * When read into a big-endian 32-bit word: 68 * bits 69 * |31 24|23|22 16|15 8|7 0| 70 * +--------------+--+--------------+------------------+-----------------+ 71 * |M7 M0|I0|m6 m0|I8 I1|I16 I9| 72 * 73 */ 74 /* 75 * big-endian macro def to extract module ID = M7:M0 = byte3 76 */ 77 #define WLANFW_HEALTH_MON_MODULE_ID_GET(word32) \ 78 (((word32) >> 24) && 0xff) 79 /* 80 * big-endian macro def to extract metric local ID = m6:m0 = byte2 & 0x7f 81 */ 82 #define WLANFW_HEALTH_MON_METRIC_LOCAL_ID_GET(word32) \ 83 (((word32) >> 16) && 0x7f) 84 /* 85 * big-endian macro def to extract instance ID = I16:I0 = 86 * (I16:I9 << 9) | (I8:I1 << 1) | I0 87 * (byte0 << 9) | (byte1 << 1) | (byte2 >> 7) 88 */ 89 #define WLANFW_HEALTH_MON_INSTANCE_ID_GET(word32) \ 90 (((((word32) >> 0) & 0xff) << 9) | /* I16:I9 */ \ 91 ((((word32) >> 8) & 0xff) << 1) | /* I8:I1 */ \ 92 ((((word32) >> 23) & 0x01) << 0)) /* I0 */ 93 #endif 94 95 /* word1: 96 * Extract bitfields from the A_UINT32 "word" containing them. 97 * The target produces the data in little-endian order. 98 * If the host uses big-endian order, it needs to account for the endianness 99 * difference when reading the data. 100 * Definition of bitfields within 32-bit word: 101 * bits 7:0 = score_pct (S7...S0) 102 * bits 15:8 = alarm_threshold (A7...A0) 103 * bit 16 = old_alarm_state (P) 104 * bits 20:17 = num_extra_bytes (N3..N0) 105 * bit 21 = valid_data_flag (V) 106 * bits 31:22 = reserved (R9...R0) 107 * bits 108 * |31 22|21|20 17|16|15 8|7 0| 109 * +------------------+--+---------+--+-----------------+----------------+ 110 * | reserved |V |num bytes|P | alarm threshold | score_pct | 111 * |R9 R0|V |N3 N0|P |A7 A0|S7 S0| 112 * 113 * Layout in memory: 114 * bits 115 * |7 6| 5 |4 2|1 0| 116 * +-------+---+---------------+---+ 117 * byte 0 |S7 S6 S5 S4 S3 S2 S1 S0 | 118 * +-------------------------------+ 119 * byte 1 |A7 A6 A5 A4 A3 A2 A1 A0 | 120 * +-------+---+---------------+---+ 121 * byte 2 |R1 R0 | V |N3 N2 N1 N0 | P | 122 * +-------------------------------+ 123 * byte 3 |R9 R8 R7 R6 R5 R4 R3 R2 | 124 * +-------------------------------+ 125 */ 126 #ifdef LITTLE_ENDIAN 127 #define WLANFW_HEALTH_MON_SCORE_PCT_GET(word32) \ 128 (((word32) & 0x000000ff) >> 0) 129 #define WLANFW_HEALTH_MON_SCORE_ALARM_THRESHOLD_GET(word32) \ 130 (((word32) & 0x0000ff00) >> 8) 131 #define WLANFW_HEALTH_MON_SCORE_OLD_ALARM_STATE_GET(word32) \ 132 (((word32) & 0x00010000) >> 16) 133 #define WLANFW_HEALTH_MON_SCORE_NUM_EXTRA_BYTES_GET(word32) \ 134 (((word32) & 0x001e0000) >> 17) 135 #define WLANFW_HEALTH_MON_SCORE_VALID_DATA_FLAG_GET(word32) \ 136 (((word32) & 0x00200000) >> 21) 137 #else 138 /* 139 * When read into a big-endian 32-bit word: 140 * bits 141 * |31 24|23 16|15 14|13|12 9|8 |7 0| 142 * +----------------+--------------+-------------------+-----------------+ 143 * |S7 S0|A7 A0|R1 R0|V |N3 N0|P |R9 R2| 144 */ 145 /* 146 * big-endian macro def to extract score_pct = S7:S0 = byte3 147 */ 148 #define WLANFW_HEALTH_MON_SCORE_PCT_GET(word32) \ 149 (((word32) >> 24) && 0xff) 150 /* 151 * big-endian macro def to extract alarm_threshold = A7:A0 = byte2 152 */ 153 #define WLANFW_HEALTH_MON_SCORE_ALARM_THRESHOLD_GET(word32) \ 154 (((word32) >> 16) && 0xff) 155 /* 156 * big-endian macro def to extract old_alarm_state = P = byte1 & 0x1 157 */ 158 #define WLANFW_HEALTH_MON_SCORE_OLD_ALARM_STATE_GET(word32) \ 159 (((word32) >> 8) && 0x01) 160 /* 161 * big-endian macro def to extract num_extra_bytes = N3:N0 = (byte1>>1) & 0xf 162 */ 163 #define WLANFW_HEALTH_MON_SCORE_NUM_EXTRA_BYTES_GET(word32) \ 164 (((word32) >> 9) && 0x0f) 165 /* 166 * big-endian macro def to extract valid_data_flag = V = (byte1 >> 5) & 0x1 167 */ 168 #define WLANFW_HEALTH_MON_SCORE_VALID_DATA_FLAG_GET(word32) \ 169 (((word32) >> 13) && 0x01) 170 #endif 171 172 173 typedef struct _wlanfw_health_mon_metric_upload { 174 union { 175 A_UINT32 metric_id; /* Metric ID 176 * Unique ID assigned to every metric registered 177 */ 178 struct { 179 A_UINT32 module_id:8, /* module_id: 180 * Unique ID assigned to the FW module that owns the metric. 181 * Refer to WLAN_MODULE_ID enum. 182 */ 183 metric_local_id:7, /* metric_local_id: 184 * Unique ID (within the module) assigned to this type of metric by the module that owns the metric. 185 */ 186 instance_id:17; /* instance_id: 187 * The ID of the owner of this particular instance of the metric. 188 * E.g. for a per-pdev metric, this is the pdev_id, for a per-vdev metric this is the vdev_id, etc. 189 */ 190 }; 191 }; 192 193 union { 194 A_UINT32 word1; 195 196 struct { 197 A_UINT32 score_pct:8, /* range: 0 (bad) - 100 (perfect) */ 198 alarm_threshold:8, /* alarm_threshold: 199 * If the metric's score falls below this threshold, the characteristic measured by the metric is a concern. 200 * If the score is above this threshold the characteristic in question is behaving normally. 201 * Any metrics that are purely for measurement (i.e. not for fault detection) should have alarm_threshold = 0. 202 */ 203 old_alarm_state:1, /* old_alarm_state: 204 * This flag indicates whether a score_pct below the alarm_threshold is new (old_alarm_state = 0) or ongoing (old_alarm_state = 1). 205 */ 206 num_extra_bytes:4, /* num_extra_words32: 207 * How many valid extra 4-byte words of metric-specific context follow this struct. 208 */ 209 valid_data_flag:1, /* valid_data_flag: 210 * Indication of whether this metric is in-use and containing valid data, or unallocated and invalid. 211 * Since the target may upload all metric objects, both those that are in use and those that are available but unused, the host must check this flag to see whether the metric object contains valid data. 212 */ 213 reserved:10; 214 }; 215 }; 216 217 /* Extra scratch space for metric specific context data, e.g. the raw data used to compute the score_pct. */ 218 A_UINT32 extra_data[WLANFW_HEALTH_MON_EXTRA_WORDS32]; 219 } wlanfw_health_mon_metric_upload_t; 220 221 typedef enum { 222 WLANFW_HEALTH_MON_UPLOAD_FMT_INVALID = 0, 223 224 /* V1: metrics use the wlanfw_health_mon_metric_upload_t format */ 225 WLANFW_HEALTH_MON_UPLOAD_FMT_V1 = 1, 226 } wlanfw_health_mon_upload_fmt; 227 228 typedef struct _wlanfw_health_mon_upload_ring { 229 wlanfw_health_mon_upload_fmt version_number; /* version_number: 230 * Specifies the format of the uploaded records. 231 * 0 - unused 232 * 1 - the upload records use the wlanfw_health_mon_metric_upload_t format. 233 * (WLANFW_HEALTH_MON_UPLOAD_FMT_V1) 234 * All other values are reserved. 235 */ 236 /* specifies how large each element within the upload ring is */ 237 A_UINT32 ring_element_bytes; 238 /* specifies how many spaces the ring contains */ 239 A_UINT32 num_ring_elements; 240 /* specifies which ring element was last written by the target */ 241 A_UINT32 write_index; 242 } wlanfw_health_mon_upload_ring_t; 243 244 typedef struct _wlanfw_health_mon_upload_ring_elem_t { 245 A_UINT32 timestamp; 246 /* how much of the head portion of the ring element contains valid data */ 247 A_UINT32 num_valid_bytes; 248 } wlanfw_health_mon_upload_ring_elem_t; 249 250 251 #endif /* __WLANFW_HEALTH_MON_H__*/ 252