1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org> 5 * Copyright (c) 2025 The FreeBSD Foundation 6 * 7 * Portions of this software were developed by Tom Jones <thj@FreeBSD.org> 8 * under sponsorship from the FreeBSD Foundation. 9 */ 10 11 #include <sys/param.h> 12 #include <sys/systm.h> 13 #include <net/ethernet.h> 14 15 #include <net80211/ieee80211.h> 16 17 #define le32_to_cpup(_a_) (le32toh(*(const uint32_t *)(_a_))) 18 19 #include <dev/iwx/if_iwxreg.h> 20 #include <dev/iwx/if_iwx_debug.h> 21 22 static uint16_t bbl_idx = 0; 23 static uint32_t bbl_seq = 0; 24 static uint8_t bbl_compress = 1; 25 26 static const char * 27 iwx_bbl_to_str(int type) 28 { 29 switch(type) { 30 case IWX_BBL_PKT_TX: 31 return ("IWX_BBL_PKT_TX"); 32 case IWX_BBL_PKT_RX: 33 return ("IWX_BBL_PKT_RX"); 34 case IWX_BBL_PKT_DUP: 35 return ("IWX_BBL_PKT_DUP"); 36 case IWX_BBL_CMD_TX: 37 return ("IWX_BBL_CMD_TX"); 38 case IWX_BBL_CMD_RX: 39 return ("IWX_BBL_CMD_RX"); 40 case IWX_BBL_ANY: 41 return ("IWX_BBL_ANY"); 42 default: 43 return ("ERROR"); 44 } 45 } 46 47 static const char * 48 get_label(struct opcode_label *table, uint8_t opcode) 49 { 50 struct opcode_label *op = table; 51 while(op->label != NULL) { 52 if (op->opcode == opcode) 53 return op->label; 54 op++; 55 } 56 return "NOT FOUND IN TABLE"; 57 } 58 59 static struct opcode_label * 60 get_table(uint8_t group) 61 { 62 switch (group) 63 { 64 case IWX_LEGACY_GROUP: 65 case IWX_LONG_GROUP: 66 return legacy_opcodes; 67 break; 68 case IWX_SYSTEM_GROUP: 69 return system_opcodes; 70 break; 71 case IWX_MAC_CONF_GROUP: 72 return macconf_opcodes; 73 break; 74 case IWX_DATA_PATH_GROUP: 75 return data_opcodes; 76 break; 77 case IWX_REGULATORY_AND_NVM_GROUP: 78 return reg_opcodes; 79 break; 80 case IWX_PHY_OPS_GROUP: 81 return phyops_opcodes; 82 break; 83 case IWX_PROT_OFFLOAD_GROUP: 84 break; 85 } 86 return NULL; 87 } 88 89 void 90 print_opcode(const char *func, int line, int type, uint32_t code) 91 { 92 int print = print_mask & type; 93 uint8_t opcode = iwx_cmd_opcode(code); 94 uint8_t group = iwx_cmd_groupid(code); 95 96 struct opcode_label *table = get_table(group); 97 if (table == NULL) { 98 printf("Couldn't find opcode table for 0x%08x", code); 99 return; 100 } 101 102 for (int i = 0; i < nitems(print_codes); i++) 103 if (print_codes[i][0] == group && print_codes[i][1] == opcode) 104 print = 1; 105 106 if (print) { 107 printf("%s:%d %s\t%s\t%s\t(0x%08x)\n", func, line, 108 iwx_bbl_to_str(type), get_label(command_group, group), 109 get_label(table, opcode), code); 110 } 111 } 112 113 void 114 iwx_dump_cmd(uint32_t id, void *data, uint16_t len, const char *str, int type) 115 { 116 int dump = dump_mask & type; 117 uint8_t opcode = iwx_cmd_opcode(id); 118 uint8_t group = iwx_cmd_groupid(id); 119 120 for (int i = 0; i < nitems(dump_codes); i++) 121 if (dump_codes[i][0] == group && dump_codes[i][1] == opcode) 122 dump = 1; 123 124 if (dump) 125 hexdump(data, len, str, 0); 126 } 127 128 void 129 iwx_bbl_add_entry(uint32_t code, int type, int ticks) 130 { 131 /* 132 * Compress together repeated notifications, but increment the sequence 133 * number so we can track things processing. 134 */ 135 if (bbl_compress && (iwx_bb_log[bbl_idx].code == code && 136 iwx_bb_log[bbl_idx].type == type)) { 137 iwx_bb_log[bbl_idx].count++; 138 iwx_bb_log[bbl_idx].seq = bbl_seq++; 139 iwx_bb_log[bbl_idx].ticks = ticks; 140 return; 141 } 142 143 if (bbl_idx++ > IWX_BBL_ENTRIES) { 144 #if 0 145 printf("iwx bbl roll over: type %d (%lu)\n", type, code); 146 #endif 147 bbl_idx = 0; 148 } 149 iwx_bb_log[bbl_idx].code = code; 150 iwx_bb_log[bbl_idx].type = type; 151 iwx_bb_log[bbl_idx].seq = bbl_seq++; 152 iwx_bb_log[bbl_idx].ticks = ticks; 153 iwx_bb_log[bbl_idx].count = 1; 154 } 155 156 static void 157 iwx_bbl_print_entry(struct iwx_bbl_entry *e) 158 { 159 uint8_t opcode = iwx_cmd_opcode(e->code); 160 uint8_t group = iwx_cmd_groupid(e->code); 161 162 switch(e->type) { 163 case IWX_BBL_PKT_TX: 164 printf("pkt "); 165 printf("seq %08d\t pkt len %u", 166 e->seq, e->code); 167 break; 168 printf("pkt dup "); 169 printf("seq %08d\t dup count %u", 170 e->seq, e->code); 171 break; 172 case IWX_BBL_CMD_TX: 173 printf("tx -> "); 174 printf("seq %08d\tcode 0x%08x (%s:%s)", 175 e->seq, e->code, get_label(command_group, group), 176 get_label(get_table(group), opcode)); 177 break; 178 case IWX_BBL_CMD_RX: 179 printf("rx "); 180 printf("seq %08d\tcode 0x%08x (%s:%s)", 181 e->seq, e->code, get_label(command_group, group), 182 get_label(get_table(group), opcode)); 183 break; 184 } 185 if (e->count > 1) 186 printf(" (count %d)", e->count); 187 printf("\n"); 188 } 189 190 void 191 iwx_bbl_print_log(void) 192 { 193 int start = -1; 194 195 start = bbl_idx+1; 196 if (start > IWX_BBL_ENTRIES-1) 197 start = 0; 198 199 for (int i = start; i < IWX_BBL_ENTRIES; i++) { 200 struct iwx_bbl_entry *e = &iwx_bb_log[i]; 201 printf("bbl entry %05d %05d: ", i, e->ticks); 202 iwx_bbl_print_entry(e); 203 } 204 for (int i = 0; i < start; i++) { 205 struct iwx_bbl_entry *e = &iwx_bb_log[i]; 206 printf("bbl entry %05d %05d: ", i, e->ticks); 207 iwx_bbl_print_entry(e); 208 } 209 printf("iwx bblog index %d seq %d\n", bbl_idx, bbl_seq); 210 } 211 212 void 213 print_ratenflags(const char *func, int line, uint32_t flags, int ver) 214 { 215 printf("%s:%d\n\t flags 0x%08x ", func, line, flags); 216 217 if (ver >= 2) { 218 printf(" rate_n_flags version 2\n"); 219 220 uint32_t type = (flags & IWX_RATE_MCS_MOD_TYPE_MSK) >> IWX_RATE_MCS_MOD_TYPE_POS; 221 222 switch(type) 223 { 224 case 0: 225 printf("\t(0) Legacy CCK: "); 226 switch (flags & IWX_RATE_LEGACY_RATE_MSK) 227 { 228 case 0: 229 printf("(0) 0xa - 1 Mbps\n"); 230 break; 231 case 1: 232 printf("(1) 0x14 - 2 Mbps\n"); 233 break; 234 case 2: 235 printf("(2) 0x37 - 5.5 Mbps\n"); 236 break; 237 case 3: 238 printf("(3) 0x6e - 11 nbps\n"); 239 break; 240 } 241 break; 242 case 1: 243 printf("\t(1) Legacy OFDM \n"); 244 switch (flags & IWX_RATE_LEGACY_RATE_MSK) 245 { 246 case 0: 247 printf("(0) 6 Mbps\n"); 248 break; 249 case 1: 250 printf("(1) 9 Mbps\n"); 251 break; 252 case 2: 253 printf("(2) 12 Mbps\n"); 254 break; 255 case 3: 256 printf("(3) 18 Mbps\n"); 257 break; 258 case 4: 259 printf("(4) 24 Mbps\n"); 260 break; 261 case 5: 262 printf("(5) 36 Mbps\n"); 263 break; 264 case 6: 265 printf("(6) 48 Mbps\n"); 266 break; 267 case 7: 268 printf("(7) 54 Mbps\n"); 269 break; 270 } 271 break; 272 case 2: 273 printf("\t(2) High-throughput (HT)\n"); 274 break; 275 case 3: 276 printf("\t(3) Very High-throughput (VHT) \n"); 277 break; 278 case 4: 279 printf("\t(4) High-efficiency (HE)\n"); 280 break; 281 case 5: 282 printf("\t(5) Extremely High-throughput (EHT)\n"); 283 break; 284 default: 285 printf("invalid\n"); 286 } 287 288 /* Not a legacy rate. */ 289 if (type > 1) { 290 printf("\tMCS %d ", IWX_RATE_HT_MCS_INDEX(flags)); 291 switch((flags & IWX_RATE_MCS_CHAN_WIDTH_MSK) >> IWX_RATE_MCS_CHAN_WIDTH_POS) 292 { 293 case 0: 294 printf("20MHz "); 295 break; 296 case 1: 297 printf("40MHz "); 298 break; 299 case 2: 300 printf("80MHz "); 301 break; 302 case 3: 303 printf("160MHz "); 304 break; 305 case 4: 306 printf("320MHz "); 307 break; 308 309 } 310 printf("antennas: (%s|%s) ", 311 flags & (1 << 14) ? "A" : " ", 312 flags & (1 << 15) ? "B" : " "); 313 if (flags & (1 << 16)) 314 printf("ldpc "); 315 printf("\n"); 316 } 317 } else { 318 printf("%s:%d rate_n_flags versions other than < 2 not implemented", 319 __func__, __LINE__); 320 } 321 } 322