1 /* 2 * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Host WMI unified implementation 21 */ 22 #include "htc_api.h" 23 #include "htc_api.h" 24 #include "wmi_unified_priv.h" 25 #include "wmi_unified_api.h" 26 #include "qdf_module.h" 27 #include "qdf_platform.h" 28 #ifdef WMI_EXT_DBG 29 #include "qdf_list.h" 30 #endif 31 32 #ifndef WMI_NON_TLV_SUPPORT 33 #include "wmi_tlv_helper.h" 34 #endif 35 36 #include <linux/debugfs.h> 37 38 #ifdef WMI_EXT_DBG 39 40 /** 41 * wmi_ext_dbg_msg_enqueue() - enqueue wmi message 42 * 43 * @wmi_handle: wmi handler 44 * 45 * Return: size of wmi message queue after enqueue 46 */ 47 static uint32_t wmi_ext_dbg_msg_enqueue(struct wmi_unified *wmi_handle, 48 struct wmi_ext_dbg_msg *msg) 49 { 50 uint32_t list_size; 51 52 qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 53 qdf_list_insert_back_size(&wmi_handle->wmi_ext_dbg_msg_queue, 54 &msg->node, &list_size); 55 qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 56 57 return list_size; 58 } 59 60 /** 61 * wmi_ext_dbg_msg_dequeue() - dequeue wmi message 62 * 63 * @wmi_handle: wmi handler 64 * 65 * Return: wmi msg on success else NULL 66 */ 67 static struct wmi_ext_dbg_msg *wmi_ext_dbg_msg_dequeue(struct wmi_unified 68 *wmi_handle) 69 { 70 qdf_list_node_t *list_node = NULL; 71 72 qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 73 qdf_list_remove_front(&wmi_handle->wmi_ext_dbg_msg_queue, &list_node); 74 qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 75 76 if (!list_node) 77 return NULL; 78 79 return qdf_container_of(list_node, struct wmi_ext_dbg_msg, node); 80 } 81 82 /** 83 * wmi_ext_dbg_msg_record() - record wmi messages 84 * 85 * @wmi_handle: wmi handler 86 * @buf: wmi message buffer 87 * @len: wmi message length 88 * @type: wmi message type 89 * 90 * Return: QDF_STATUS_SUCCESS on successful recording else failure. 91 */ 92 static QDF_STATUS wmi_ext_dbg_msg_record(struct wmi_unified *wmi_handle, 93 uint8_t *buf, uint32_t len, 94 enum WMI_MSG_TYPE type) 95 { 96 struct wmi_ext_dbg_msg *msg; 97 uint32_t list_size; 98 99 msg = wmi_ext_dbg_msg_get(len); 100 if (!msg) 101 return QDF_STATUS_E_NOMEM; 102 103 msg->len = len; 104 msg->type = type; 105 qdf_mem_copy(msg->buf, buf, len); 106 msg->ts = qdf_get_log_timestamp(); 107 list_size = wmi_ext_dbg_msg_enqueue(wmi_handle, msg); 108 109 if (list_size >= wmi_handle->wmi_ext_dbg_msg_queue_size) { 110 msg = wmi_ext_dbg_msg_dequeue(wmi_handle); 111 wmi_ext_dbg_msg_put(msg); 112 } 113 114 return QDF_STATUS_SUCCESS; 115 } 116 117 /** 118 * wmi_ext_dbg_msg_cmd_record() - record wmi command messages 119 * 120 * @wmi_handle: wmi handler 121 * @buf: wmi command buffer 122 * @len: wmi command message length 123 * 124 * Return: QDF_STATUS_SUCCESS on successful recording else failure. 125 */ 126 static QDF_STATUS wmi_ext_dbg_msg_cmd_record(struct wmi_unified *wmi_handle, 127 uint8_t *buf, uint32_t len) 128 { 129 return wmi_ext_dbg_msg_record(wmi_handle, buf, len, 130 WMI_MSG_TYPE_CMD); 131 } 132 133 /** 134 * wmi_ext_dbg_msg_event_record() - record wmi event messages 135 * 136 * @wmi_handle: wmi handler 137 * @buf: wmi event buffer 138 * @len: wmi event message length 139 * 140 * Return: QDF_STATUS_SUCCESS on successful recording else failure. 141 */ 142 static QDF_STATUS wmi_ext_dbg_msg_event_record(struct wmi_unified *wmi_handle, 143 uint8_t *buf, uint32_t len) 144 { 145 uint32_t id; 146 147 id = WMI_GET_FIELD(buf, WMI_CMD_HDR, COMMANDID); 148 if (id != wmi_handle->wmi_events[wmi_diag_event_id]) 149 return wmi_ext_dbg_msg_record(wmi_handle, buf, len, 150 WMI_MSG_TYPE_EVENT); 151 152 return QDF_STATUS_SUCCESS; 153 } 154 155 /** 156 * wmi_ext_dbg_msg_queue_init() - create debugfs queue and associated lock 157 * 158 * @wmi_handle: wmi handler 159 * 160 * Return: none 161 */ 162 static void wmi_ext_dbg_msg_queue_init(struct wmi_unified *wmi_handle) 163 { 164 qdf_list_create(&wmi_handle->wmi_ext_dbg_msg_queue, 165 wmi_handle->wmi_ext_dbg_msg_queue_size); 166 qdf_spinlock_create(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 167 } 168 169 /** 170 * wmi_ext_dbg_msg_queue_deinit() - destroy debugfs queue and associated lock 171 * 172 * @wmi_handle: wmi handler 173 * 174 * Return: none 175 */ 176 static void wmi_ext_dbg_msg_queue_deinit(struct wmi_unified *wmi_handle) 177 { 178 qdf_list_destroy(&wmi_handle->wmi_ext_dbg_msg_queue); 179 qdf_spinlock_destroy(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 180 } 181 182 /** 183 * wmi_ext_dbg_msg_show() - debugfs function to display whole content of 184 * wmi command/event messages including headers. 185 * 186 * @file: qdf debugfs file handler 187 * @arg: pointer to wmi handler 188 * 189 * Return: QDF_STATUS_SUCCESS if all the messages are shown successfully, 190 * else QDF_STATUS_E_AGAIN if more data to show. 191 */ 192 static QDF_STATUS wmi_ext_dbg_msg_show(qdf_debugfs_file_t file, void *arg) 193 { 194 struct wmi_unified *wmi_handle = (struct wmi_unified *)arg; 195 struct wmi_ext_dbg_msg *msg; 196 uint64_t secs, usecs; 197 198 msg = wmi_ext_dbg_msg_dequeue(wmi_handle); 199 if (!msg) 200 return QDF_STATUS_SUCCESS; 201 202 qdf_debugfs_printf(file, "%s: 0x%x\n", 203 msg->type == WMI_MSG_TYPE_CMD ? "COMMAND" : 204 "EVENT", WMI_GET_FIELD(msg->buf, WMI_CMD_HDR, 205 COMMANDID)); 206 qdf_log_timestamp_to_secs(msg->ts, &secs, &usecs); 207 qdf_debugfs_printf(file, "Time: %llu.%llu\n", secs, usecs); 208 qdf_debugfs_printf(file, "Length:%d\n", msg->len); 209 qdf_debugfs_hexdump(file, msg->buf, msg->len, 210 WMI_EXT_DBG_DUMP_ROW_SIZE, 211 WMI_EXT_DBG_DUMP_GROUP_SIZE); 212 qdf_debugfs_printf(file, "\n"); 213 214 if (qdf_debugfs_overflow(file)) { 215 qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 216 qdf_list_insert_front(&wmi_handle->wmi_ext_dbg_msg_queue, 217 &msg->node); 218 qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 219 220 } else { 221 wmi_ext_dbg_msg_put(msg); 222 } 223 224 return QDF_STATUS_E_AGAIN; 225 } 226 227 /** 228 * wmi_ext_dbg_msg_write() - debugfs write not supported 229 * 230 * @priv: private data 231 * @buf: received data buffer 232 * @len: length of received buffer 233 * 234 * Return: QDF_STATUS_E_NOSUPPORT. 235 */ 236 static QDF_STATUS wmi_ext_dbg_msg_write(void *priv, const char *buf, 237 qdf_size_t len) 238 { 239 return QDF_STATUS_E_NOSUPPORT; 240 } 241 242 static struct qdf_debugfs_fops wmi_ext_dbgfs_ops = { 243 .show = wmi_ext_dbg_msg_show, 244 .write = wmi_ext_dbg_msg_write, 245 .priv = NULL, 246 }; 247 248 /** 249 * wmi_ext_debugfs_init() - init debugfs items for extended wmi dump. 250 * 251 * @wmi_handle: wmi handler 252 * 253 * Return: QDF_STATUS_SUCCESS if debugfs is initialized else 254 * QDF_STATUS_E_FAILURE 255 */ 256 static QDF_STATUS wmi_ext_dbgfs_init(struct wmi_unified *wmi_handle) 257 { 258 qdf_dentry_t dentry; 259 260 dentry = qdf_debugfs_create_dir(WMI_EXT_DBG_DIR, NULL); 261 if (!dentry) { 262 WMI_LOGE("error while creating extended wmi debugfs dir"); 263 return QDF_STATUS_E_FAILURE; 264 } 265 266 wmi_ext_dbgfs_ops.priv = wmi_handle; 267 if (!qdf_debugfs_create_file(WMI_EXT_DBG_FILE, WMI_EXT_DBG_FILE_PERM, 268 dentry, &wmi_ext_dbgfs_ops)) { 269 qdf_debugfs_remove_dir(dentry); 270 WMI_LOGE("error while creating extended wmi debugfs file"); 271 return QDF_STATUS_E_FAILURE; 272 } 273 274 wmi_handle->wmi_ext_dbg_dentry = dentry; 275 wmi_handle->wmi_ext_dbg_msg_queue_size = WMI_EXT_DBG_QUEUE_SIZE; 276 wmi_ext_dbg_msg_queue_init(wmi_handle); 277 278 return QDF_STATUS_SUCCESS; 279 } 280 281 /** 282 * wmi_ext_debugfs_deinit() - cleanup/deinit debugfs items of extended wmi dump. 283 * 284 * @wmi_handle: wmi handler 285 * 286 * Return: QDF_STATUS_SUCCESS if cleanup is successful 287 */ 288 static QDF_STATUS wmi_ext_dbgfs_deinit(struct wmi_unified *wmi_handle) 289 { 290 struct wmi_ext_dbg_msg *msg; 291 292 while ((msg = wmi_ext_dbg_msg_dequeue(wmi_handle))) 293 wmi_ext_dbg_msg_put(msg); 294 295 wmi_ext_dbg_msg_queue_deinit(wmi_handle); 296 qdf_debugfs_remove_dir_recursive(wmi_handle->wmi_ext_dbg_dentry); 297 298 return QDF_STATUS_SUCCESS; 299 } 300 301 #endif /*WMI_EXT_DBG */ 302 303 /* This check for CONFIG_WIN temporary added due to redeclaration compilation 304 error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h 305 which gets included here through ol_if_athvar.h. Eventually it is expected that 306 wmi.h will be removed from wmi_unified_api.h after cleanup, which will need 307 WMI_CMD_HDR to be defined here. */ 308 #ifdef CONFIG_WIN 309 /* Copied from wmi.h */ 310 #undef MS 311 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) 312 #undef SM 313 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) 314 #undef WO 315 #define WO(_f) ((_f##_OFFSET) >> 2) 316 317 #undef GET_FIELD 318 #define GET_FIELD(_addr, _f) MS(*((uint32_t *)(_addr) + WO(_f)), _f) 319 #undef SET_FIELD 320 #define SET_FIELD(_addr, _f, _val) \ 321 (*((uint32_t *)(_addr) + WO(_f)) = \ 322 (*((uint32_t *)(_addr) + WO(_f)) & ~_f##_MASK) | SM(_val, _f)) 323 324 #define WMI_GET_FIELD(_msg_buf, _msg_type, _f) \ 325 GET_FIELD(_msg_buf, _msg_type ## _ ## _f) 326 327 #define WMI_SET_FIELD(_msg_buf, _msg_type, _f, _val) \ 328 SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val) 329 330 #define WMI_EP_APASS 0x0 331 #define WMI_EP_LPASS 0x1 332 #define WMI_EP_SENSOR 0x2 333 334 /* 335 * * Control Path 336 * */ 337 typedef PREPACK struct { 338 uint32_t commandId:24, 339 reserved:2, /* used for WMI endpoint ID */ 340 plt_priv:6; /* platform private */ 341 } POSTPACK WMI_CMD_HDR; /* used for commands and events */ 342 343 #define WMI_CMD_HDR_COMMANDID_LSB 0 344 #define WMI_CMD_HDR_COMMANDID_MASK 0x00ffffff 345 #define WMI_CMD_HDR_COMMANDID_OFFSET 0x00000000 346 #define WMI_CMD_HDR_WMI_ENDPOINTID_MASK 0x03000000 347 #define WMI_CMD_HDR_WMI_ENDPOINTID_OFFSET 24 348 #define WMI_CMD_HDR_PLT_PRIV_LSB 24 349 #define WMI_CMD_HDR_PLT_PRIV_MASK 0xff000000 350 #define WMI_CMD_HDR_PLT_PRIV_OFFSET 0x00000000 351 /* end of copy wmi.h */ 352 #endif /* CONFIG_WIN */ 353 354 #define WMI_MIN_HEAD_ROOM 64 355 356 /* WBUFF pool sizes for WMI */ 357 /* Allocation of size 256 bytes */ 358 #define WMI_WBUFF_POOL_0_SIZE 128 359 /* Allocation of size 512 bytes */ 360 #define WMI_WBUFF_POOL_1_SIZE 16 361 /* Allocation of size 1024 bytes */ 362 #define WMI_WBUFF_POOL_2_SIZE 8 363 /* Allocation of size 2048 bytes */ 364 #define WMI_WBUFF_POOL_3_SIZE 8 365 366 #ifdef WMI_INTERFACE_EVENT_LOGGING 367 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) 368 /* TODO Cleanup this backported function */ 369 static int wmi_bp_seq_printf(struct seq_file *m, const char *f, ...) 370 { 371 va_list args; 372 373 va_start(args, f); 374 seq_vprintf(m, f, args); 375 va_end(args); 376 377 return 0; 378 } 379 #else 380 #define wmi_bp_seq_printf(m, fmt, ...) seq_printf((m), fmt, ##__VA_ARGS__) 381 #endif 382 383 #ifndef MAX_WMI_INSTANCES 384 #define CUSTOM_MGMT_CMD_DATA_SIZE 4 385 #endif 386 387 #ifdef CONFIG_MCL 388 /* WMI commands */ 389 uint32_t g_wmi_command_buf_idx = 0; 390 struct wmi_command_debug wmi_command_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 391 392 /* WMI commands TX completed */ 393 uint32_t g_wmi_command_tx_cmp_buf_idx = 0; 394 struct wmi_command_debug 395 wmi_command_tx_cmp_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 396 397 /* WMI events when processed */ 398 uint32_t g_wmi_event_buf_idx = 0; 399 struct wmi_event_debug wmi_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 400 401 /* WMI events when queued */ 402 uint32_t g_wmi_rx_event_buf_idx = 0; 403 struct wmi_event_debug wmi_rx_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 404 #endif 405 406 #define WMI_COMMAND_RECORD(h, a, b) { \ 407 if (wmi_log_max_entry <= \ 408 *(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)) \ 409 *(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx) = 0;\ 410 ((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\ 411 [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)]\ 412 .command = a; \ 413 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 414 wmi_command_log_buf_info.buf) \ 415 [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].data,\ 416 b, wmi_record_max_length); \ 417 ((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\ 418 [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].\ 419 time = qdf_get_log_timestamp(); \ 420 (*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx))++; \ 421 h->log_info.wmi_command_log_buf_info.length++; \ 422 } 423 424 #define WMI_COMMAND_TX_CMP_RECORD(h, a, b) { \ 425 if (wmi_log_max_entry <= \ 426 *(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))\ 427 *(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 428 p_buf_tail_idx) = 0; \ 429 ((struct wmi_command_debug *)h->log_info. \ 430 wmi_command_tx_cmp_log_buf_info.buf) \ 431 [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 432 p_buf_tail_idx)]. \ 433 command = a; \ 434 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 435 wmi_command_tx_cmp_log_buf_info.buf) \ 436 [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 437 p_buf_tail_idx)]. \ 438 data, b, wmi_record_max_length); \ 439 ((struct wmi_command_debug *)h->log_info. \ 440 wmi_command_tx_cmp_log_buf_info.buf) \ 441 [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 442 p_buf_tail_idx)]. \ 443 time = qdf_get_log_timestamp(); \ 444 (*(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))++;\ 445 h->log_info.wmi_command_tx_cmp_log_buf_info.length++; \ 446 } 447 448 #define WMI_EVENT_RECORD(h, a, b) { \ 449 if (wmi_log_max_entry <= \ 450 *(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)) \ 451 *(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx) = 0;\ 452 ((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\ 453 [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)]. \ 454 event = a; \ 455 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 456 wmi_event_log_buf_info.buf) \ 457 [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].data, b,\ 458 wmi_record_max_length); \ 459 ((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\ 460 [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].time =\ 461 qdf_get_log_timestamp(); \ 462 (*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx))++; \ 463 h->log_info.wmi_event_log_buf_info.length++; \ 464 } 465 466 #define WMI_RX_EVENT_RECORD(h, a, b) { \ 467 if (wmi_log_max_entry <= \ 468 *(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))\ 469 *(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx) = 0;\ 470 ((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\ 471 [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ 472 event = a; \ 473 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 474 wmi_rx_event_log_buf_info.buf) \ 475 [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ 476 data, b, wmi_record_max_length); \ 477 ((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\ 478 [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ 479 time = qdf_get_log_timestamp(); \ 480 (*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))++; \ 481 h->log_info.wmi_rx_event_log_buf_info.length++; \ 482 } 483 484 #ifdef CONFIG_MCL 485 uint32_t g_wmi_mgmt_command_buf_idx = 0; 486 struct 487 wmi_command_debug wmi_mgmt_command_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; 488 489 /* wmi_mgmt commands TX completed */ 490 uint32_t g_wmi_mgmt_command_tx_cmp_buf_idx = 0; 491 struct wmi_command_debug 492 wmi_mgmt_command_tx_cmp_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; 493 494 /* wmi_mgmt events when received */ 495 uint32_t g_wmi_mgmt_rx_event_buf_idx = 0; 496 struct wmi_event_debug 497 wmi_mgmt_rx_event_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; 498 499 /* wmi_diag events when received */ 500 uint32_t g_wmi_diag_rx_event_buf_idx = 0; 501 struct wmi_event_debug 502 wmi_diag_rx_event_log_buffer[WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY]; 503 #endif 504 505 #define WMI_MGMT_COMMAND_RECORD(h, a, b) { \ 506 if (wmi_mgmt_log_max_entry <= \ 507 *(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)) \ 508 *(h->log_info.wmi_mgmt_command_log_buf_info. \ 509 p_buf_tail_idx) = 0; \ 510 ((struct wmi_command_debug *)h->log_info. \ 511 wmi_mgmt_command_log_buf_info.buf) \ 512 [*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\ 513 command = a; \ 514 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 515 wmi_mgmt_command_log_buf_info.buf) \ 516 [*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\ 517 data, b, \ 518 wmi_record_max_length); \ 519 ((struct wmi_command_debug *)h->log_info. \ 520 wmi_mgmt_command_log_buf_info.buf) \ 521 [*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\ 522 time = qdf_get_log_timestamp(); \ 523 (*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx))++;\ 524 h->log_info.wmi_mgmt_command_log_buf_info.length++; \ 525 } 526 527 #define WMI_MGMT_COMMAND_TX_CMP_RECORD(h, a, b) { \ 528 if (wmi_mgmt_log_max_entry <= \ 529 *(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 530 p_buf_tail_idx)) \ 531 *(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 532 p_buf_tail_idx) = 0; \ 533 ((struct wmi_command_debug *)h->log_info. \ 534 wmi_mgmt_command_tx_cmp_log_buf_info.buf) \ 535 [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 536 p_buf_tail_idx)].command = a; \ 537 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 538 wmi_mgmt_command_tx_cmp_log_buf_info.buf)\ 539 [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 540 p_buf_tail_idx)].data, b, \ 541 wmi_record_max_length); \ 542 ((struct wmi_command_debug *)h->log_info. \ 543 wmi_mgmt_command_tx_cmp_log_buf_info.buf) \ 544 [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 545 p_buf_tail_idx)].time = \ 546 qdf_get_log_timestamp(); \ 547 (*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 548 p_buf_tail_idx))++; \ 549 h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.length++; \ 550 } 551 552 #define WMI_MGMT_RX_EVENT_RECORD(h, a, b) do { \ 553 if (wmi_mgmt_log_max_entry <= \ 554 *(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))\ 555 *(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx) = 0;\ 556 ((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\ 557 [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)]\ 558 .event = a; \ 559 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 560 wmi_mgmt_event_log_buf_info.buf) \ 561 [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\ 562 data, b, wmi_record_max_length); \ 563 ((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\ 564 [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\ 565 time = qdf_get_log_timestamp(); \ 566 (*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))++; \ 567 h->log_info.wmi_mgmt_event_log_buf_info.length++; \ 568 } while (0); 569 570 #define WMI_DIAG_RX_EVENT_RECORD(h, a, b) do { \ 571 if (wmi_mgmt_log_max_entry <= \ 572 *(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx))\ 573 *(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx) = 0;\ 574 ((struct wmi_event_debug *)h->log_info.wmi_diag_event_log_buf_info.buf)\ 575 [*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)]\ 576 .event = a; \ 577 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 578 wmi_diag_event_log_buf_info.buf) \ 579 [*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)].\ 580 data, b, wmi_record_max_length); \ 581 ((struct wmi_event_debug *)h->log_info.wmi_diag_event_log_buf_info.buf)\ 582 [*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)].\ 583 time = qdf_get_log_timestamp(); \ 584 (*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx))++; \ 585 h->log_info.wmi_diag_event_log_buf_info.length++; \ 586 } while (0); 587 588 /* These are defined to made it as module param, which can be configured */ 589 uint32_t wmi_log_max_entry = WMI_EVENT_DEBUG_MAX_ENTRY; 590 uint32_t wmi_mgmt_log_max_entry = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; 591 uint32_t wmi_diag_log_max_entry = WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY; 592 uint32_t wmi_record_max_length = WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH; 593 uint32_t wmi_display_size = 100; 594 595 /** 596 * wmi_log_init() - Initialize WMI event logging 597 * @wmi_handle: WMI handle. 598 * 599 * Return: Initialization status 600 */ 601 #ifdef CONFIG_MCL 602 static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) 603 { 604 struct wmi_log_buf_t *cmd_log_buf = 605 &wmi_handle->log_info.wmi_command_log_buf_info; 606 struct wmi_log_buf_t *cmd_tx_cmpl_log_buf = 607 &wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info; 608 609 struct wmi_log_buf_t *event_log_buf = 610 &wmi_handle->log_info.wmi_event_log_buf_info; 611 struct wmi_log_buf_t *rx_event_log_buf = 612 &wmi_handle->log_info.wmi_rx_event_log_buf_info; 613 614 struct wmi_log_buf_t *mgmt_cmd_log_buf = 615 &wmi_handle->log_info.wmi_mgmt_command_log_buf_info; 616 struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf = 617 &wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info; 618 struct wmi_log_buf_t *mgmt_event_log_buf = 619 &wmi_handle->log_info.wmi_mgmt_event_log_buf_info; 620 struct wmi_log_buf_t *diag_event_log_buf = 621 &wmi_handle->log_info.wmi_diag_event_log_buf_info; 622 623 /* WMI commands */ 624 cmd_log_buf->length = 0; 625 cmd_log_buf->buf_tail_idx = 0; 626 cmd_log_buf->buf = wmi_command_log_buffer; 627 cmd_log_buf->p_buf_tail_idx = &g_wmi_command_buf_idx; 628 cmd_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; 629 630 /* WMI commands TX completed */ 631 cmd_tx_cmpl_log_buf->length = 0; 632 cmd_tx_cmpl_log_buf->buf_tail_idx = 0; 633 cmd_tx_cmpl_log_buf->buf = wmi_command_tx_cmp_log_buffer; 634 cmd_tx_cmpl_log_buf->p_buf_tail_idx = &g_wmi_command_tx_cmp_buf_idx; 635 cmd_tx_cmpl_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; 636 637 /* WMI events when processed */ 638 event_log_buf->length = 0; 639 event_log_buf->buf_tail_idx = 0; 640 event_log_buf->buf = wmi_event_log_buffer; 641 event_log_buf->p_buf_tail_idx = &g_wmi_event_buf_idx; 642 event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; 643 644 /* WMI events when queued */ 645 rx_event_log_buf->length = 0; 646 rx_event_log_buf->buf_tail_idx = 0; 647 rx_event_log_buf->buf = wmi_rx_event_log_buffer; 648 rx_event_log_buf->p_buf_tail_idx = &g_wmi_rx_event_buf_idx; 649 rx_event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; 650 651 /* WMI Management commands */ 652 mgmt_cmd_log_buf->length = 0; 653 mgmt_cmd_log_buf->buf_tail_idx = 0; 654 mgmt_cmd_log_buf->buf = wmi_mgmt_command_log_buffer; 655 mgmt_cmd_log_buf->p_buf_tail_idx = &g_wmi_mgmt_command_buf_idx; 656 mgmt_cmd_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; 657 658 /* WMI Management commands Tx completed*/ 659 mgmt_cmd_tx_cmp_log_buf->length = 0; 660 mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0; 661 mgmt_cmd_tx_cmp_log_buf->buf = wmi_mgmt_command_tx_cmp_log_buffer; 662 mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx = 663 &g_wmi_mgmt_command_tx_cmp_buf_idx; 664 mgmt_cmd_tx_cmp_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; 665 666 /* WMI Management events when received */ 667 mgmt_event_log_buf->length = 0; 668 mgmt_event_log_buf->buf_tail_idx = 0; 669 mgmt_event_log_buf->buf = wmi_mgmt_rx_event_log_buffer; 670 mgmt_event_log_buf->p_buf_tail_idx = &g_wmi_mgmt_rx_event_buf_idx; 671 mgmt_event_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; 672 673 /* WMI diag events when received */ 674 diag_event_log_buf->length = 0; 675 diag_event_log_buf->buf_tail_idx = 0; 676 diag_event_log_buf->buf = wmi_diag_rx_event_log_buffer; 677 diag_event_log_buf->p_buf_tail_idx = &g_wmi_diag_rx_event_buf_idx; 678 diag_event_log_buf->size = WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY; 679 680 qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); 681 wmi_handle->log_info.wmi_logging_enable = 1; 682 683 return QDF_STATUS_SUCCESS; 684 } 685 #else 686 static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) 687 { 688 struct wmi_log_buf_t *cmd_log_buf = 689 &wmi_handle->log_info.wmi_command_log_buf_info; 690 struct wmi_log_buf_t *cmd_tx_cmpl_log_buf = 691 &wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info; 692 693 struct wmi_log_buf_t *event_log_buf = 694 &wmi_handle->log_info.wmi_event_log_buf_info; 695 struct wmi_log_buf_t *rx_event_log_buf = 696 &wmi_handle->log_info.wmi_rx_event_log_buf_info; 697 698 struct wmi_log_buf_t *mgmt_cmd_log_buf = 699 &wmi_handle->log_info.wmi_mgmt_command_log_buf_info; 700 struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf = 701 &wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info; 702 struct wmi_log_buf_t *mgmt_event_log_buf = 703 &wmi_handle->log_info.wmi_mgmt_event_log_buf_info; 704 struct wmi_log_buf_t *diag_event_log_buf = 705 &wmi_handle->log_info.wmi_diag_event_log_buf_info; 706 707 wmi_handle->log_info.wmi_logging_enable = 0; 708 709 /* WMI commands */ 710 cmd_log_buf->length = 0; 711 cmd_log_buf->buf_tail_idx = 0; 712 cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( 713 wmi_log_max_entry * sizeof(struct wmi_command_debug)); 714 cmd_log_buf->size = wmi_log_max_entry; 715 716 if (!cmd_log_buf->buf) 717 return QDF_STATUS_E_NOMEM; 718 719 cmd_log_buf->p_buf_tail_idx = &cmd_log_buf->buf_tail_idx; 720 721 /* WMI commands TX completed */ 722 cmd_tx_cmpl_log_buf->length = 0; 723 cmd_tx_cmpl_log_buf->buf_tail_idx = 0; 724 cmd_tx_cmpl_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( 725 wmi_log_max_entry * sizeof(struct wmi_command_debug)); 726 cmd_tx_cmpl_log_buf->size = wmi_log_max_entry; 727 728 if (!cmd_tx_cmpl_log_buf->buf) 729 return QDF_STATUS_E_NOMEM; 730 731 cmd_tx_cmpl_log_buf->p_buf_tail_idx = 732 &cmd_tx_cmpl_log_buf->buf_tail_idx; 733 734 /* WMI events when processed */ 735 event_log_buf->length = 0; 736 event_log_buf->buf_tail_idx = 0; 737 event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( 738 wmi_log_max_entry * sizeof(struct wmi_event_debug)); 739 event_log_buf->size = wmi_log_max_entry; 740 741 if (!event_log_buf->buf) 742 return QDF_STATUS_E_NOMEM; 743 744 event_log_buf->p_buf_tail_idx = &event_log_buf->buf_tail_idx; 745 746 /* WMI events when queued */ 747 rx_event_log_buf->length = 0; 748 rx_event_log_buf->buf_tail_idx = 0; 749 rx_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( 750 wmi_log_max_entry * sizeof(struct wmi_event_debug)); 751 rx_event_log_buf->size = wmi_log_max_entry; 752 753 if (!rx_event_log_buf->buf) 754 return QDF_STATUS_E_NOMEM; 755 756 rx_event_log_buf->p_buf_tail_idx = &rx_event_log_buf->buf_tail_idx; 757 758 /* WMI Management commands */ 759 mgmt_cmd_log_buf->length = 0; 760 mgmt_cmd_log_buf->buf_tail_idx = 0; 761 mgmt_cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( 762 wmi_mgmt_log_max_entry * sizeof(struct wmi_command_debug)); 763 mgmt_cmd_log_buf->size = wmi_mgmt_log_max_entry; 764 765 if (!mgmt_cmd_log_buf->buf) 766 return QDF_STATUS_E_NOMEM; 767 768 mgmt_cmd_log_buf->p_buf_tail_idx = &mgmt_cmd_log_buf->buf_tail_idx; 769 770 /* WMI Management commands Tx completed*/ 771 mgmt_cmd_tx_cmp_log_buf->length = 0; 772 mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0; 773 mgmt_cmd_tx_cmp_log_buf->buf = (struct wmi_command_debug *) 774 qdf_mem_malloc( 775 wmi_mgmt_log_max_entry * 776 sizeof(struct wmi_command_debug)); 777 mgmt_cmd_tx_cmp_log_buf->size = wmi_mgmt_log_max_entry; 778 779 if (!mgmt_cmd_tx_cmp_log_buf->buf) 780 return QDF_STATUS_E_NOMEM; 781 782 mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx = 783 &mgmt_cmd_tx_cmp_log_buf->buf_tail_idx; 784 785 /* WMI Management events when received */ 786 mgmt_event_log_buf->length = 0; 787 mgmt_event_log_buf->buf_tail_idx = 0; 788 789 mgmt_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( 790 wmi_mgmt_log_max_entry * 791 sizeof(struct wmi_event_debug)); 792 mgmt_event_log_buf->size = wmi_mgmt_log_max_entry; 793 794 if (!mgmt_event_log_buf->buf) 795 return QDF_STATUS_E_NOMEM; 796 797 mgmt_event_log_buf->p_buf_tail_idx = &mgmt_event_log_buf->buf_tail_idx; 798 799 /* WMI diag events when received */ 800 diag_event_log_buf->length = 0; 801 diag_event_log_buf->buf_tail_idx = 0; 802 803 diag_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( 804 wmi_diag_log_max_entry * 805 sizeof(struct wmi_event_debug)); 806 diag_event_log_buf->size = wmi_diag_log_max_entry; 807 808 if (!diag_event_log_buf->buf) 809 return QDF_STATUS_E_NOMEM; 810 811 diag_event_log_buf->p_buf_tail_idx = &diag_event_log_buf->buf_tail_idx; 812 813 qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); 814 wmi_handle->log_info.wmi_logging_enable = 1; 815 816 return QDF_STATUS_SUCCESS; 817 } 818 #endif 819 820 /** 821 * wmi_log_buffer_free() - Free all dynamic allocated buffer memory for 822 * event logging 823 * @wmi_handle: WMI handle. 824 * 825 * Return: None 826 */ 827 #ifndef CONFIG_MCL 828 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) 829 { 830 if (wmi_handle->log_info.wmi_command_log_buf_info.buf) 831 qdf_mem_free(wmi_handle->log_info.wmi_command_log_buf_info.buf); 832 if (wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf) 833 qdf_mem_free( 834 wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf); 835 if (wmi_handle->log_info.wmi_event_log_buf_info.buf) 836 qdf_mem_free(wmi_handle->log_info.wmi_event_log_buf_info.buf); 837 if (wmi_handle->log_info.wmi_rx_event_log_buf_info.buf) 838 qdf_mem_free( 839 wmi_handle->log_info.wmi_rx_event_log_buf_info.buf); 840 if (wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf) 841 qdf_mem_free( 842 wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf); 843 if (wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf) 844 qdf_mem_free( 845 wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf); 846 if (wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf) 847 qdf_mem_free( 848 wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf); 849 if (wmi_handle->log_info.wmi_diag_event_log_buf_info.buf) 850 qdf_mem_free( 851 wmi_handle->log_info.wmi_diag_event_log_buf_info.buf); 852 wmi_handle->log_info.wmi_logging_enable = 0; 853 qdf_spinlock_destroy(&wmi_handle->log_info.wmi_record_lock); 854 } 855 #else 856 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) 857 { 858 /* Do Nothing */ 859 } 860 #endif 861 862 /** 863 * wmi_print_cmd_log_buffer() - an output agnostic wmi command log printer 864 * @log_buffer: the command log buffer metadata of the buffer to print 865 * @count: the maximum number of entries to print 866 * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper 867 * @print_priv: any data required by the print method, e.g. a file handle 868 * 869 * Return: None 870 */ 871 static void 872 wmi_print_cmd_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count, 873 qdf_abstract_print *print, void *print_priv) 874 { 875 static const int data_len = 876 WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t); 877 char str[128]; 878 uint32_t idx; 879 880 if (count > log_buffer->size) 881 count = log_buffer->size; 882 if (count > log_buffer->length) 883 count = log_buffer->length; 884 885 /* subtract count from index, and wrap if necessary */ 886 idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count; 887 idx %= log_buffer->size; 888 889 print(print_priv, "Time (seconds) Cmd Id Payload"); 890 while (count) { 891 struct wmi_command_debug *cmd_log = (struct wmi_command_debug *) 892 &((struct wmi_command_debug *)log_buffer->buf)[idx]; 893 uint64_t secs, usecs; 894 int len = 0; 895 int i; 896 897 qdf_log_timestamp_to_secs(cmd_log->time, &secs, &usecs); 898 len += scnprintf(str + len, sizeof(str) - len, 899 "% 8lld.%06lld %6u (0x%06x) ", 900 secs, usecs, 901 cmd_log->command, cmd_log->command); 902 for (i = 0; i < data_len; ++i) { 903 len += scnprintf(str + len, sizeof(str) - len, 904 "0x%08x ", cmd_log->data[i]); 905 } 906 907 print(print_priv, str); 908 909 --count; 910 ++idx; 911 if (idx >= log_buffer->size) 912 idx = 0; 913 } 914 } 915 916 /** 917 * wmi_print_event_log_buffer() - an output agnostic wmi event log printer 918 * @log_buffer: the event log buffer metadata of the buffer to print 919 * @count: the maximum number of entries to print 920 * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper 921 * @print_priv: any data required by the print method, e.g. a file handle 922 * 923 * Return: None 924 */ 925 static void 926 wmi_print_event_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count, 927 qdf_abstract_print *print, void *print_priv) 928 { 929 static const int data_len = 930 WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t); 931 char str[128]; 932 uint32_t idx; 933 934 if (count > log_buffer->size) 935 count = log_buffer->size; 936 if (count > log_buffer->length) 937 count = log_buffer->length; 938 939 /* subtract count from index, and wrap if necessary */ 940 idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count; 941 idx %= log_buffer->size; 942 943 print(print_priv, "Time (seconds) Event Id Payload"); 944 while (count) { 945 struct wmi_event_debug *event_log = (struct wmi_event_debug *) 946 &((struct wmi_event_debug *)log_buffer->buf)[idx]; 947 uint64_t secs, usecs; 948 int len = 0; 949 int i; 950 951 qdf_log_timestamp_to_secs(event_log->time, &secs, &usecs); 952 len += scnprintf(str + len, sizeof(str) - len, 953 "% 8lld.%06lld %6u (0x%06x) ", 954 secs, usecs, 955 event_log->event, event_log->event); 956 for (i = 0; i < data_len; ++i) { 957 len += scnprintf(str + len, sizeof(str) - len, 958 "0x%08x ", event_log->data[i]); 959 } 960 961 print(print_priv, str); 962 963 --count; 964 ++idx; 965 if (idx >= log_buffer->size) 966 idx = 0; 967 } 968 } 969 970 inline void 971 wmi_print_cmd_log(wmi_unified_t wmi, uint32_t count, 972 qdf_abstract_print *print, void *print_priv) 973 { 974 wmi_print_cmd_log_buffer( 975 &wmi->log_info.wmi_command_log_buf_info, 976 count, print, print_priv); 977 } 978 979 inline void 980 wmi_print_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count, 981 qdf_abstract_print *print, void *print_priv) 982 { 983 wmi_print_cmd_log_buffer( 984 &wmi->log_info.wmi_command_tx_cmp_log_buf_info, 985 count, print, print_priv); 986 } 987 988 inline void 989 wmi_print_mgmt_cmd_log(wmi_unified_t wmi, uint32_t count, 990 qdf_abstract_print *print, void *print_priv) 991 { 992 wmi_print_cmd_log_buffer( 993 &wmi->log_info.wmi_mgmt_command_log_buf_info, 994 count, print, print_priv); 995 } 996 997 inline void 998 wmi_print_mgmt_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count, 999 qdf_abstract_print *print, void *print_priv) 1000 { 1001 wmi_print_cmd_log_buffer( 1002 &wmi->log_info.wmi_mgmt_command_tx_cmp_log_buf_info, 1003 count, print, print_priv); 1004 } 1005 1006 inline void 1007 wmi_print_event_log(wmi_unified_t wmi, uint32_t count, 1008 qdf_abstract_print *print, void *print_priv) 1009 { 1010 wmi_print_event_log_buffer( 1011 &wmi->log_info.wmi_event_log_buf_info, 1012 count, print, print_priv); 1013 } 1014 1015 inline void 1016 wmi_print_rx_event_log(wmi_unified_t wmi, uint32_t count, 1017 qdf_abstract_print *print, void *print_priv) 1018 { 1019 wmi_print_event_log_buffer( 1020 &wmi->log_info.wmi_rx_event_log_buf_info, 1021 count, print, print_priv); 1022 } 1023 1024 inline void 1025 wmi_print_mgmt_event_log(wmi_unified_t wmi, uint32_t count, 1026 qdf_abstract_print *print, void *print_priv) 1027 { 1028 wmi_print_event_log_buffer( 1029 &wmi->log_info.wmi_mgmt_event_log_buf_info, 1030 count, print, print_priv); 1031 } 1032 1033 1034 /* debugfs routines*/ 1035 1036 /** 1037 * debug_wmi_##func_base##_show() - debugfs functions to display content of 1038 * command and event buffers. Macro uses max buffer length to display 1039 * buffer when it is wraparound. 1040 * 1041 * @m: debugfs handler to access wmi_handle 1042 * @v: Variable arguments (not used) 1043 * 1044 * Return: Length of characters printed 1045 */ 1046 #define GENERATE_COMMAND_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size) \ 1047 static int debug_wmi_##func_base##_show(struct seq_file *m, \ 1048 void *v) \ 1049 { \ 1050 wmi_unified_t wmi_handle = (wmi_unified_t) m->private; \ 1051 struct wmi_log_buf_t *wmi_log = \ 1052 &wmi_handle->log_info.wmi_##func_base##_buf_info;\ 1053 int pos, nread, outlen; \ 1054 int i; \ 1055 uint64_t secs, usecs; \ 1056 \ 1057 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1058 if (!wmi_log->length) { \ 1059 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1060 return wmi_bp_seq_printf(m, \ 1061 "no elements to read from ring buffer!\n"); \ 1062 } \ 1063 \ 1064 if (wmi_log->length <= wmi_ring_size) \ 1065 nread = wmi_log->length; \ 1066 else \ 1067 nread = wmi_ring_size; \ 1068 \ 1069 if (*(wmi_log->p_buf_tail_idx) == 0) \ 1070 /* tail can be 0 after wrap-around */ \ 1071 pos = wmi_ring_size - 1; \ 1072 else \ 1073 pos = *(wmi_log->p_buf_tail_idx) - 1; \ 1074 \ 1075 outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\ 1076 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1077 while (nread--) { \ 1078 struct wmi_command_debug *wmi_record; \ 1079 \ 1080 wmi_record = (struct wmi_command_debug *) \ 1081 &(((struct wmi_command_debug *)wmi_log->buf)[pos]);\ 1082 outlen += wmi_bp_seq_printf(m, "CMD ID = %x\n", \ 1083 (wmi_record->command)); \ 1084 qdf_log_timestamp_to_secs(wmi_record->time, &secs,\ 1085 &usecs); \ 1086 outlen += \ 1087 wmi_bp_seq_printf(m, "CMD TIME = [%llu.%06llu]\n",\ 1088 secs, usecs); \ 1089 outlen += wmi_bp_seq_printf(m, "CMD = "); \ 1090 for (i = 0; i < (wmi_record_max_length/ \ 1091 sizeof(uint32_t)); i++) \ 1092 outlen += wmi_bp_seq_printf(m, "%x ", \ 1093 wmi_record->data[i]); \ 1094 outlen += wmi_bp_seq_printf(m, "\n"); \ 1095 \ 1096 if (pos == 0) \ 1097 pos = wmi_ring_size - 1; \ 1098 else \ 1099 pos--; \ 1100 } \ 1101 return outlen; \ 1102 } \ 1103 1104 #define GENERATE_EVENT_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size) \ 1105 static int debug_wmi_##func_base##_show(struct seq_file *m, \ 1106 void *v) \ 1107 { \ 1108 wmi_unified_t wmi_handle = (wmi_unified_t) m->private; \ 1109 struct wmi_log_buf_t *wmi_log = \ 1110 &wmi_handle->log_info.wmi_##func_base##_buf_info;\ 1111 int pos, nread, outlen; \ 1112 int i; \ 1113 uint64_t secs, usecs; \ 1114 \ 1115 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1116 if (!wmi_log->length) { \ 1117 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1118 return wmi_bp_seq_printf(m, \ 1119 "no elements to read from ring buffer!\n"); \ 1120 } \ 1121 \ 1122 if (wmi_log->length <= wmi_ring_size) \ 1123 nread = wmi_log->length; \ 1124 else \ 1125 nread = wmi_ring_size; \ 1126 \ 1127 if (*(wmi_log->p_buf_tail_idx) == 0) \ 1128 /* tail can be 0 after wrap-around */ \ 1129 pos = wmi_ring_size - 1; \ 1130 else \ 1131 pos = *(wmi_log->p_buf_tail_idx) - 1; \ 1132 \ 1133 outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\ 1134 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1135 while (nread--) { \ 1136 struct wmi_event_debug *wmi_record; \ 1137 \ 1138 wmi_record = (struct wmi_event_debug *) \ 1139 &(((struct wmi_event_debug *)wmi_log->buf)[pos]);\ 1140 qdf_log_timestamp_to_secs(wmi_record->time, &secs,\ 1141 &usecs); \ 1142 outlen += wmi_bp_seq_printf(m, "Event ID = %x\n",\ 1143 (wmi_record->event)); \ 1144 outlen += \ 1145 wmi_bp_seq_printf(m, "Event TIME = [%llu.%06llu]\n",\ 1146 secs, usecs); \ 1147 outlen += wmi_bp_seq_printf(m, "CMD = "); \ 1148 for (i = 0; i < (wmi_record_max_length/ \ 1149 sizeof(uint32_t)); i++) \ 1150 outlen += wmi_bp_seq_printf(m, "%x ", \ 1151 wmi_record->data[i]); \ 1152 outlen += wmi_bp_seq_printf(m, "\n"); \ 1153 \ 1154 if (pos == 0) \ 1155 pos = wmi_ring_size - 1; \ 1156 else \ 1157 pos--; \ 1158 } \ 1159 return outlen; \ 1160 } 1161 1162 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_log, wmi_display_size); 1163 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_tx_cmp_log, wmi_display_size); 1164 GENERATE_EVENT_DEBUG_SHOW_FUNCS(event_log, wmi_display_size); 1165 GENERATE_EVENT_DEBUG_SHOW_FUNCS(rx_event_log, wmi_display_size); 1166 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_log, wmi_display_size); 1167 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_tx_cmp_log, 1168 wmi_display_size); 1169 GENERATE_EVENT_DEBUG_SHOW_FUNCS(mgmt_event_log, wmi_display_size); 1170 1171 /** 1172 * debug_wmi_enable_show() - debugfs functions to display enable state of 1173 * wmi logging feature. 1174 * 1175 * @m: debugfs handler to access wmi_handle 1176 * @v: Variable arguments (not used) 1177 * 1178 * Return: always 1 1179 */ 1180 static int debug_wmi_enable_show(struct seq_file *m, void *v) 1181 { 1182 wmi_unified_t wmi_handle = (wmi_unified_t) m->private; 1183 1184 return wmi_bp_seq_printf(m, "%d\n", 1185 wmi_handle->log_info.wmi_logging_enable); 1186 } 1187 1188 /** 1189 * debug_wmi_log_size_show() - debugfs functions to display configured size of 1190 * wmi logging command/event buffer and management command/event buffer. 1191 * 1192 * @m: debugfs handler to access wmi_handle 1193 * @v: Variable arguments (not used) 1194 * 1195 * Return: Length of characters printed 1196 */ 1197 static int debug_wmi_log_size_show(struct seq_file *m, void *v) 1198 { 1199 1200 wmi_bp_seq_printf(m, "WMI command/event log max size:%d\n", 1201 wmi_log_max_entry); 1202 return wmi_bp_seq_printf(m, 1203 "WMI management command/events log max size:%d\n", 1204 wmi_mgmt_log_max_entry); 1205 } 1206 1207 /** 1208 * debug_wmi_##func_base##_write() - debugfs functions to clear 1209 * wmi logging command/event buffer and management command/event buffer. 1210 * 1211 * @file: file handler to access wmi_handle 1212 * @buf: received data buffer 1213 * @count: length of received buffer 1214 * @ppos: Not used 1215 * 1216 * Return: count 1217 */ 1218 #define GENERATE_DEBUG_WRITE_FUNCS(func_base, wmi_ring_size, wmi_record_type)\ 1219 static ssize_t debug_wmi_##func_base##_write(struct file *file, \ 1220 const char __user *buf, \ 1221 size_t count, loff_t *ppos) \ 1222 { \ 1223 int k, ret; \ 1224 wmi_unified_t wmi_handle = \ 1225 ((struct seq_file *)file->private_data)->private;\ 1226 struct wmi_log_buf_t *wmi_log = &wmi_handle->log_info. \ 1227 wmi_##func_base##_buf_info; \ 1228 char locbuf[50]; \ 1229 \ 1230 if ((!buf) || (count > 50)) \ 1231 return -EFAULT; \ 1232 \ 1233 if (copy_from_user(locbuf, buf, count)) \ 1234 return -EFAULT; \ 1235 \ 1236 ret = sscanf(locbuf, "%d", &k); \ 1237 if ((ret != 1) || (k != 0)) { \ 1238 WMI_LOGE("Wrong input, echo 0 to clear the wmi buffer");\ 1239 return -EINVAL; \ 1240 } \ 1241 \ 1242 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1243 qdf_mem_zero(wmi_log->buf, wmi_ring_size * \ 1244 sizeof(struct wmi_record_type)); \ 1245 wmi_log->length = 0; \ 1246 *(wmi_log->p_buf_tail_idx) = 0; \ 1247 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\ 1248 \ 1249 return count; \ 1250 } 1251 1252 GENERATE_DEBUG_WRITE_FUNCS(command_log, wmi_log_max_entry, 1253 wmi_command_debug); 1254 GENERATE_DEBUG_WRITE_FUNCS(command_tx_cmp_log, wmi_log_max_entry, 1255 wmi_command_debug); 1256 GENERATE_DEBUG_WRITE_FUNCS(event_log, wmi_log_max_entry, 1257 wmi_event_debug); 1258 GENERATE_DEBUG_WRITE_FUNCS(rx_event_log, wmi_log_max_entry, 1259 wmi_event_debug); 1260 GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_log, wmi_mgmt_log_max_entry, 1261 wmi_command_debug); 1262 GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_tx_cmp_log, 1263 wmi_mgmt_log_max_entry, wmi_command_debug); 1264 GENERATE_DEBUG_WRITE_FUNCS(mgmt_event_log, wmi_mgmt_log_max_entry, 1265 wmi_event_debug); 1266 1267 /** 1268 * debug_wmi_enable_write() - debugfs functions to enable/disable 1269 * wmi logging feature. 1270 * 1271 * @file: file handler to access wmi_handle 1272 * @buf: received data buffer 1273 * @count: length of received buffer 1274 * @ppos: Not used 1275 * 1276 * Return: count 1277 */ 1278 static ssize_t debug_wmi_enable_write(struct file *file, const char __user *buf, 1279 size_t count, loff_t *ppos) 1280 { 1281 wmi_unified_t wmi_handle = 1282 ((struct seq_file *)file->private_data)->private; 1283 int k, ret; 1284 char locbuf[50]; 1285 1286 if ((!buf) || (count > 50)) 1287 return -EFAULT; 1288 1289 if (copy_from_user(locbuf, buf, count)) 1290 return -EFAULT; 1291 1292 ret = sscanf(locbuf, "%d", &k); 1293 if ((ret != 1) || ((k != 0) && (k != 1))) 1294 return -EINVAL; 1295 1296 wmi_handle->log_info.wmi_logging_enable = k; 1297 return count; 1298 } 1299 1300 /** 1301 * debug_wmi_log_size_write() - reserved. 1302 * 1303 * @file: file handler to access wmi_handle 1304 * @buf: received data buffer 1305 * @count: length of received buffer 1306 * @ppos: Not used 1307 * 1308 * Return: count 1309 */ 1310 static ssize_t debug_wmi_log_size_write(struct file *file, 1311 const char __user *buf, size_t count, loff_t *ppos) 1312 { 1313 return -EINVAL; 1314 } 1315 1316 /* Structure to maintain debug information */ 1317 struct wmi_debugfs_info { 1318 const char *name; 1319 const struct file_operations *ops; 1320 }; 1321 1322 #define DEBUG_FOO(func_base) { .name = #func_base, \ 1323 .ops = &debug_##func_base##_ops } 1324 1325 /** 1326 * debug_##func_base##_open() - Open debugfs entry for respective command 1327 * and event buffer. 1328 * 1329 * @inode: node for debug dir entry 1330 * @file: file handler 1331 * 1332 * Return: open status 1333 */ 1334 #define GENERATE_DEBUG_STRUCTS(func_base) \ 1335 static int debug_##func_base##_open(struct inode *inode, \ 1336 struct file *file) \ 1337 { \ 1338 return single_open(file, debug_##func_base##_show, \ 1339 inode->i_private); \ 1340 } \ 1341 \ 1342 \ 1343 static struct file_operations debug_##func_base##_ops = { \ 1344 .open = debug_##func_base##_open, \ 1345 .read = seq_read, \ 1346 .llseek = seq_lseek, \ 1347 .write = debug_##func_base##_write, \ 1348 .release = single_release, \ 1349 }; 1350 1351 GENERATE_DEBUG_STRUCTS(wmi_command_log); 1352 GENERATE_DEBUG_STRUCTS(wmi_command_tx_cmp_log); 1353 GENERATE_DEBUG_STRUCTS(wmi_event_log); 1354 GENERATE_DEBUG_STRUCTS(wmi_rx_event_log); 1355 GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_log); 1356 GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_tx_cmp_log); 1357 GENERATE_DEBUG_STRUCTS(wmi_mgmt_event_log); 1358 GENERATE_DEBUG_STRUCTS(wmi_enable); 1359 GENERATE_DEBUG_STRUCTS(wmi_log_size); 1360 1361 struct wmi_debugfs_info wmi_debugfs_infos[NUM_DEBUG_INFOS] = { 1362 DEBUG_FOO(wmi_command_log), 1363 DEBUG_FOO(wmi_command_tx_cmp_log), 1364 DEBUG_FOO(wmi_event_log), 1365 DEBUG_FOO(wmi_rx_event_log), 1366 DEBUG_FOO(wmi_mgmt_command_log), 1367 DEBUG_FOO(wmi_mgmt_command_tx_cmp_log), 1368 DEBUG_FOO(wmi_mgmt_event_log), 1369 DEBUG_FOO(wmi_enable), 1370 DEBUG_FOO(wmi_log_size), 1371 }; 1372 1373 1374 /** 1375 * wmi_debugfs_create() - Create debug_fs entry for wmi logging. 1376 * 1377 * @wmi_handle: wmi handle 1378 * @par_entry: debug directory entry 1379 * @id: Index to debug info data array 1380 * 1381 * Return: none 1382 */ 1383 static void wmi_debugfs_create(wmi_unified_t wmi_handle, 1384 struct dentry *par_entry) 1385 { 1386 int i; 1387 1388 if (!par_entry) 1389 goto out; 1390 1391 for (i = 0; i < NUM_DEBUG_INFOS; ++i) { 1392 wmi_handle->debugfs_de[i] = debugfs_create_file( 1393 wmi_debugfs_infos[i].name, 0644, par_entry, 1394 wmi_handle, wmi_debugfs_infos[i].ops); 1395 1396 if (!wmi_handle->debugfs_de[i]) { 1397 WMI_LOGE("debug Entry creation failed!"); 1398 goto out; 1399 } 1400 } 1401 1402 return; 1403 1404 out: 1405 WMI_LOGE("debug Entry creation failed!"); 1406 wmi_log_buffer_free(wmi_handle); 1407 return; 1408 } 1409 1410 /** 1411 * wmi_debugfs_remove() - Remove debugfs entry for wmi logging. 1412 * @wmi_handle: wmi handle 1413 * @dentry: debugfs directory entry 1414 * @id: Index to debug info data array 1415 * 1416 * Return: none 1417 */ 1418 static void wmi_debugfs_remove(wmi_unified_t wmi_handle) 1419 { 1420 int i; 1421 struct dentry *dentry = wmi_handle->log_info.wmi_log_debugfs_dir; 1422 1423 if (dentry) { 1424 for (i = 0; i < NUM_DEBUG_INFOS; ++i) { 1425 if (wmi_handle->debugfs_de[i]) 1426 wmi_handle->debugfs_de[i] = NULL; 1427 } 1428 } 1429 1430 if (dentry) 1431 debugfs_remove_recursive(dentry); 1432 } 1433 1434 /** 1435 * wmi_debugfs_init() - debugfs functions to create debugfs directory and to 1436 * create debugfs enteries. 1437 * 1438 * @h: wmi handler 1439 * 1440 * Return: init status 1441 */ 1442 static QDF_STATUS wmi_debugfs_init(wmi_unified_t wmi_handle, uint32_t pdev_idx) 1443 { 1444 char buf[32]; 1445 1446 snprintf(buf, sizeof(buf), "WMI_SOC%u_PDEV%u", 1447 wmi_handle->soc->soc_idx, pdev_idx); 1448 1449 wmi_handle->log_info.wmi_log_debugfs_dir = 1450 debugfs_create_dir(buf, NULL); 1451 1452 if (!wmi_handle->log_info.wmi_log_debugfs_dir) { 1453 WMI_LOGE("error while creating debugfs dir for %s", buf); 1454 return QDF_STATUS_E_FAILURE; 1455 } 1456 wmi_debugfs_create(wmi_handle, 1457 wmi_handle->log_info.wmi_log_debugfs_dir); 1458 1459 return QDF_STATUS_SUCCESS; 1460 } 1461 1462 /** 1463 * wmi_mgmt_cmd_record() - Wrapper function for mgmt command logging macro 1464 * 1465 * @wmi_handle: wmi handle 1466 * @cmd: mgmt command 1467 * @header: pointer to 802.11 header 1468 * @vdev_id: vdev id 1469 * @chanfreq: channel frequency 1470 * 1471 * Return: none 1472 */ 1473 void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd, 1474 void *header, uint32_t vdev_id, uint32_t chanfreq) 1475 { 1476 1477 uint32_t data[CUSTOM_MGMT_CMD_DATA_SIZE]; 1478 1479 data[0] = ((struct wmi_command_header *)header)->type; 1480 data[1] = ((struct wmi_command_header *)header)->sub_type; 1481 data[2] = vdev_id; 1482 data[3] = chanfreq; 1483 1484 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 1485 1486 WMI_MGMT_COMMAND_RECORD(wmi_handle, cmd, (uint8_t *)data); 1487 1488 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 1489 } 1490 #else 1491 /** 1492 * wmi_debugfs_remove() - Remove debugfs entry for wmi logging. 1493 * @wmi_handle: wmi handle 1494 * @dentry: debugfs directory entry 1495 * @id: Index to debug info data array 1496 * 1497 * Return: none 1498 */ 1499 static void wmi_debugfs_remove(wmi_unified_t wmi_handle) { } 1500 void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd, 1501 void *header, uint32_t vdev_id, uint32_t chanfreq) { } 1502 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) { } 1503 #endif /*WMI_INTERFACE_EVENT_LOGGING */ 1504 qdf_export_symbol(wmi_mgmt_cmd_record); 1505 1506 int wmi_get_host_credits(wmi_unified_t wmi_handle); 1507 /* WMI buffer APIs */ 1508 1509 #ifdef NBUF_MEMORY_DEBUG 1510 wmi_buf_t 1511 wmi_buf_alloc_debug(wmi_unified_t wmi_handle, uint32_t len, 1512 const char *func_name, 1513 uint32_t line_num) 1514 { 1515 wmi_buf_t wmi_buf; 1516 1517 if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) { 1518 QDF_ASSERT(0); 1519 return NULL; 1520 } 1521 1522 wmi_buf = wbuff_buff_get(wmi_handle->wbuff_handle, len, func_name, 1523 line_num); 1524 if (!wmi_buf) 1525 wmi_buf = qdf_nbuf_alloc_debug(NULL, 1526 roundup(len + WMI_MIN_HEAD_ROOM, 1527 4), 1528 WMI_MIN_HEAD_ROOM, 4, false, 1529 func_name, line_num); 1530 if (!wmi_buf) 1531 return NULL; 1532 1533 /* Clear the wmi buffer */ 1534 OS_MEMZERO(qdf_nbuf_data(wmi_buf), len); 1535 1536 /* 1537 * Set the length of the buffer to match the allocation size. 1538 */ 1539 qdf_nbuf_set_pktlen(wmi_buf, len); 1540 1541 return wmi_buf; 1542 } 1543 qdf_export_symbol(wmi_buf_alloc_debug); 1544 1545 void wmi_buf_free(wmi_buf_t net_buf) 1546 { 1547 net_buf = wbuff_buff_put(net_buf); 1548 if (net_buf) 1549 qdf_nbuf_free(net_buf); 1550 } 1551 qdf_export_symbol(wmi_buf_free); 1552 #else 1553 wmi_buf_t wmi_buf_alloc_fl(wmi_unified_t wmi_handle, uint32_t len, 1554 const char *func, uint32_t line) 1555 { 1556 wmi_buf_t wmi_buf; 1557 1558 if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) { 1559 QDF_DEBUG_PANIC("Invalid length %u (via %s:%u)", 1560 len, func, line); 1561 return NULL; 1562 } 1563 1564 wmi_buf = wbuff_buff_get(wmi_handle->wbuff_handle, len, __func__, 1565 __LINE__); 1566 if (!wmi_buf) 1567 wmi_buf = qdf_nbuf_alloc_fl(NULL, roundup(len + 1568 WMI_MIN_HEAD_ROOM, 4), WMI_MIN_HEAD_ROOM, 4, 1569 false, func, line); 1570 1571 if (!wmi_buf) { 1572 wmi_nofl_err("%s:%d, failed to alloc len:%d", func, line, len); 1573 return NULL; 1574 } 1575 1576 /* Clear the wmi buffer */ 1577 OS_MEMZERO(qdf_nbuf_data(wmi_buf), len); 1578 1579 /* 1580 * Set the length of the buffer to match the allocation size. 1581 */ 1582 qdf_nbuf_set_pktlen(wmi_buf, len); 1583 1584 return wmi_buf; 1585 } 1586 qdf_export_symbol(wmi_buf_alloc_fl); 1587 1588 void wmi_buf_free(wmi_buf_t net_buf) 1589 { 1590 net_buf = wbuff_buff_put(net_buf); 1591 if (net_buf) 1592 qdf_nbuf_free(net_buf); 1593 } 1594 qdf_export_symbol(wmi_buf_free); 1595 #endif 1596 1597 /** 1598 * wmi_get_max_msg_len() - get maximum WMI message length 1599 * @wmi_handle: WMI handle. 1600 * 1601 * This function returns the maximum WMI message length 1602 * 1603 * Return: maximum WMI message length 1604 */ 1605 uint16_t wmi_get_max_msg_len(wmi_unified_t wmi_handle) 1606 { 1607 return wmi_handle->max_msg_len - WMI_MIN_HEAD_ROOM; 1608 } 1609 qdf_export_symbol(wmi_get_max_msg_len); 1610 1611 #ifdef CONFIG_MCL 1612 #ifndef WMI_CMD_STRINGS 1613 static uint8_t *wmi_id_to_name(uint32_t wmi_command) 1614 { 1615 return "Invalid WMI cmd"; 1616 } 1617 1618 #endif 1619 1620 static inline void wmi_log_cmd_id(uint32_t cmd_id, uint32_t tag) 1621 { 1622 WMI_LOGD("Send WMI command:%s command_id:%d htc_tag:%d\n", 1623 wmi_id_to_name(cmd_id), cmd_id, tag); 1624 } 1625 1626 /** 1627 * wmi_is_pm_resume_cmd() - check if a cmd is part of the resume sequence 1628 * @cmd_id: command to check 1629 * 1630 * Return: true if the command is part of the resume sequence. 1631 */ 1632 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id) 1633 { 1634 switch (cmd_id) { 1635 case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID: 1636 case WMI_PDEV_RESUME_CMDID: 1637 return true; 1638 1639 default: 1640 return false; 1641 } 1642 } 1643 #else 1644 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id) 1645 { 1646 return false; 1647 } 1648 #endif 1649 1650 static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle) 1651 { 1652 wmi_nofl_err("Endpoint ID = %d, Tx Queue Depth = %d, soc_id = %u, target type = %s", 1653 wmi_handle->wmi_endpoint_id, 1654 htc_get_tx_queue_depth(wmi_handle->htc_handle, 1655 wmi_handle->wmi_endpoint_id), 1656 wmi_handle->soc->soc_idx, 1657 (wmi_handle->target_type == 1658 WMI_TLV_TARGET ? "WMI_TLV_TARGET" : 1659 "WMI_NON_TLV_TARGET")); 1660 } 1661 1662 QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, 1663 uint32_t len, uint32_t cmd_id, 1664 const char *func, uint32_t line) 1665 { 1666 HTC_PACKET *pkt; 1667 QDF_STATUS status; 1668 uint16_t htc_tag = 0; 1669 1670 if (wmi_get_runtime_pm_inprogress(wmi_handle)) { 1671 htc_tag = wmi_handle->ops->wmi_set_htc_tx_tag(wmi_handle, buf, 1672 cmd_id); 1673 } else if (qdf_atomic_read(&wmi_handle->is_target_suspended) && 1674 !wmi_is_pm_resume_cmd(cmd_id)) { 1675 wmi_nofl_err("Target is suspended (via %s:%u)", 1676 func, line); 1677 return QDF_STATUS_E_BUSY; 1678 } 1679 1680 if (wmi_handle->wmi_stopinprogress) { 1681 wmi_nofl_err("%s:%d, WMI stop in progress", func, line); 1682 return QDF_STATUS_E_INVAL; 1683 } 1684 1685 #ifndef WMI_NON_TLV_SUPPORT 1686 /* Do sanity check on the TLV parameter structure */ 1687 if (wmi_handle->target_type == WMI_TLV_TARGET) { 1688 void *buf_ptr = (void *)qdf_nbuf_data(buf); 1689 1690 if (wmi_handle->ops->wmi_check_command_params(NULL, buf_ptr, len, cmd_id) 1691 != 0) { 1692 wmi_nofl_err("%s:%d, Invalid WMI Param Buffer for Cmd:%d", 1693 func, line, cmd_id); 1694 return QDF_STATUS_E_INVAL; 1695 } 1696 } 1697 #endif 1698 1699 if (qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR)) == NULL) { 1700 wmi_nofl_err("%s:%d, Failed to send cmd %x, no memory", 1701 func, line, cmd_id); 1702 return QDF_STATUS_E_NOMEM; 1703 } 1704 1705 qdf_mem_zero(qdf_nbuf_data(buf), sizeof(WMI_CMD_HDR)); 1706 WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id); 1707 1708 qdf_atomic_inc(&wmi_handle->pending_cmds); 1709 if (qdf_atomic_read(&wmi_handle->pending_cmds) >= 1710 wmi_handle->wmi_max_cmds) { 1711 wmi_nofl_err("hostcredits = %d", 1712 wmi_get_host_credits(wmi_handle)); 1713 htc_dump_counter_info(wmi_handle->htc_handle); 1714 qdf_atomic_dec(&wmi_handle->pending_cmds); 1715 wmi_nofl_err("%s:%d, MAX %d WMI Pending cmds reached", 1716 func, line, wmi_handle->wmi_max_cmds); 1717 wmi_unified_debug_dump(wmi_handle); 1718 qdf_trigger_self_recovery(QDF_WMI_EXCEED_MAX_PENDING_CMDS); 1719 return QDF_STATUS_E_BUSY; 1720 } 1721 1722 pkt = qdf_mem_malloc_fl(sizeof(*pkt), func, line); 1723 if (!pkt) { 1724 qdf_atomic_dec(&wmi_handle->pending_cmds); 1725 return QDF_STATUS_E_NOMEM; 1726 } 1727 1728 SET_HTC_PACKET_INFO_TX(pkt, 1729 NULL, 1730 qdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR), 1731 wmi_handle->wmi_endpoint_id, htc_tag); 1732 1733 SET_HTC_PACKET_NET_BUF_CONTEXT(pkt, buf); 1734 #ifdef CONFIG_MCL 1735 wmi_log_cmd_id(cmd_id, htc_tag); 1736 #endif 1737 wmi_ext_dbg_msg_cmd_record(wmi_handle, 1738 qdf_nbuf_data(buf), qdf_nbuf_len(buf)); 1739 #ifdef WMI_INTERFACE_EVENT_LOGGING 1740 if (wmi_handle->log_info.wmi_logging_enable) { 1741 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 1742 /* 1743 * Record 16 bytes of WMI cmd data - 1744 * exclude TLV and WMI headers 1745 * 1746 * WMI mgmt command already recorded in wmi_mgmt_cmd_record 1747 */ 1748 if (wmi_handle->ops->is_management_record(cmd_id) == false) { 1749 WMI_COMMAND_RECORD(wmi_handle, cmd_id, 1750 qdf_nbuf_data(buf) + 1751 wmi_handle->soc->buf_offset_command); 1752 } 1753 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 1754 } 1755 #endif 1756 1757 status = htc_send_pkt(wmi_handle->htc_handle, pkt); 1758 1759 if (QDF_STATUS_SUCCESS != status) { 1760 qdf_atomic_dec(&wmi_handle->pending_cmds); 1761 wmi_nofl_err("%s:%d, htc_send_pkt failed, status:%d", 1762 func, line, status); 1763 qdf_mem_free(pkt); 1764 return status; 1765 } 1766 1767 return QDF_STATUS_SUCCESS; 1768 } 1769 qdf_export_symbol(wmi_unified_cmd_send_fl); 1770 1771 /** 1772 * wmi_unified_get_event_handler_ix() - gives event handler's index 1773 * @wmi_handle: handle to wmi 1774 * @event_id: wmi event id 1775 * 1776 * Return: event handler's index 1777 */ 1778 static int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle, 1779 uint32_t event_id) 1780 { 1781 uint32_t idx = 0; 1782 int32_t invalid_idx = -1; 1783 struct wmi_soc *soc = wmi_handle->soc; 1784 1785 for (idx = 0; (idx < soc->max_event_idx && 1786 idx < WMI_UNIFIED_MAX_EVENT); ++idx) { 1787 if (wmi_handle->event_id[idx] == event_id && 1788 wmi_handle->event_handler[idx]) { 1789 return idx; 1790 } 1791 } 1792 1793 return invalid_idx; 1794 } 1795 1796 /** 1797 * wmi_unified_register_event() - register wmi event handler 1798 * @wmi_handle: handle to wmi 1799 * @event_id: wmi event id 1800 * @handler_func: wmi event handler function 1801 * 1802 * Return: 0 on success 1803 */ 1804 int wmi_unified_register_event(wmi_unified_t wmi_handle, 1805 uint32_t event_id, 1806 wmi_unified_event_handler handler_func) 1807 { 1808 uint32_t idx = 0; 1809 uint32_t evt_id; 1810 struct wmi_soc *soc; 1811 1812 if (!wmi_handle) { 1813 WMI_LOGE("WMI handle is NULL"); 1814 return QDF_STATUS_E_FAILURE; 1815 } 1816 1817 soc = wmi_handle->soc; 1818 1819 if (event_id >= wmi_events_max || 1820 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 1821 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1822 "%s: Event id %d is unavailable", 1823 __func__, event_id); 1824 return QDF_STATUS_E_FAILURE; 1825 } 1826 evt_id = wmi_handle->wmi_events[event_id]; 1827 if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) { 1828 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1829 "%s : event handler already registered 0x%x", 1830 __func__, evt_id); 1831 return QDF_STATUS_E_FAILURE; 1832 } 1833 if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) { 1834 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1835 "%s : no more event handlers 0x%x", 1836 __func__, evt_id); 1837 return QDF_STATUS_E_FAILURE; 1838 } 1839 idx = soc->max_event_idx; 1840 wmi_handle->event_handler[idx] = handler_func; 1841 wmi_handle->event_id[idx] = evt_id; 1842 qdf_spin_lock_bh(&soc->ctx_lock); 1843 wmi_handle->ctx[idx] = WMI_RX_UMAC_CTX; 1844 qdf_spin_unlock_bh(&soc->ctx_lock); 1845 soc->max_event_idx++; 1846 1847 return 0; 1848 } 1849 1850 /** 1851 * wmi_unified_register_event_handler() - register wmi event handler 1852 * @wmi_handle: handle to wmi 1853 * @event_id: wmi event id 1854 * @handler_func: wmi event handler function 1855 * @rx_ctx: rx execution context for wmi rx events 1856 * 1857 * This API is to support legacy requirements. Will be deprecated in future. 1858 * Return: 0 on success 1859 */ 1860 int wmi_unified_register_event_handler(wmi_unified_t wmi_handle, 1861 wmi_conv_event_id event_id, 1862 wmi_unified_event_handler handler_func, 1863 uint8_t rx_ctx) 1864 { 1865 uint32_t idx = 0; 1866 uint32_t evt_id; 1867 struct wmi_soc *soc; 1868 1869 if (!wmi_handle) { 1870 WMI_LOGE("WMI handle is NULL"); 1871 return QDF_STATUS_E_FAILURE; 1872 } 1873 1874 soc = wmi_handle->soc; 1875 1876 if (event_id >= wmi_events_max || 1877 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 1878 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1879 "%s: Event id %d is unavailable", 1880 __func__, event_id); 1881 return QDF_STATUS_E_FAILURE; 1882 } 1883 evt_id = wmi_handle->wmi_events[event_id]; 1884 1885 if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) { 1886 WMI_LOGE("event handler already registered 0x%x", 1887 evt_id); 1888 return QDF_STATUS_E_FAILURE; 1889 } 1890 if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) { 1891 WMI_LOGE("no more event handlers 0x%x", 1892 evt_id); 1893 return QDF_STATUS_E_FAILURE; 1894 } 1895 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, 1896 "Registered event handler for event 0x%8x", evt_id); 1897 idx = soc->max_event_idx; 1898 wmi_handle->event_handler[idx] = handler_func; 1899 wmi_handle->event_id[idx] = evt_id; 1900 qdf_spin_lock_bh(&soc->ctx_lock); 1901 wmi_handle->ctx[idx] = rx_ctx; 1902 qdf_spin_unlock_bh(&soc->ctx_lock); 1903 soc->max_event_idx++; 1904 1905 return 0; 1906 } 1907 qdf_export_symbol(wmi_unified_register_event_handler); 1908 1909 /** 1910 * wmi_unified_unregister_event() - unregister wmi event handler 1911 * @wmi_handle: handle to wmi 1912 * @event_id: wmi event id 1913 * 1914 * Return: 0 on success 1915 */ 1916 int wmi_unified_unregister_event(wmi_unified_t wmi_handle, 1917 uint32_t event_id) 1918 { 1919 uint32_t idx = 0; 1920 uint32_t evt_id; 1921 struct wmi_soc *soc = wmi_handle->soc; 1922 1923 if (event_id >= wmi_events_max || 1924 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 1925 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1926 "%s: Event id %d is unavailable", 1927 __func__, event_id); 1928 return QDF_STATUS_E_FAILURE; 1929 } 1930 evt_id = wmi_handle->wmi_events[event_id]; 1931 1932 idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id); 1933 if (idx == -1) { 1934 WMI_LOGE("event handler is not registered: evt id 0x%x", 1935 evt_id); 1936 return QDF_STATUS_E_FAILURE; 1937 } 1938 wmi_handle->event_handler[idx] = NULL; 1939 wmi_handle->event_id[idx] = 0; 1940 --soc->max_event_idx; 1941 wmi_handle->event_handler[idx] = 1942 wmi_handle->event_handler[soc->max_event_idx]; 1943 wmi_handle->event_id[idx] = 1944 wmi_handle->event_id[soc->max_event_idx]; 1945 1946 return 0; 1947 } 1948 1949 /** 1950 * wmi_unified_unregister_event_handler() - unregister wmi event handler 1951 * @wmi_handle: handle to wmi 1952 * @event_id: wmi event id 1953 * 1954 * Return: 0 on success 1955 */ 1956 int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, 1957 wmi_conv_event_id event_id) 1958 { 1959 uint32_t idx = 0; 1960 uint32_t evt_id; 1961 struct wmi_soc *soc; 1962 1963 if (!wmi_handle) { 1964 WMI_LOGE("WMI handle is NULL"); 1965 return QDF_STATUS_E_FAILURE; 1966 } 1967 1968 soc = wmi_handle->soc; 1969 1970 if (event_id >= wmi_events_max || 1971 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 1972 WMI_LOGE("Event id %d is unavailable", 1973 event_id); 1974 return QDF_STATUS_E_FAILURE; 1975 } 1976 evt_id = wmi_handle->wmi_events[event_id]; 1977 1978 idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id); 1979 if (idx == -1) { 1980 WMI_LOGE("event handler is not registered: evt id 0x%x", 1981 evt_id); 1982 return QDF_STATUS_E_FAILURE; 1983 } 1984 wmi_handle->event_handler[idx] = NULL; 1985 wmi_handle->event_id[idx] = 0; 1986 --soc->max_event_idx; 1987 wmi_handle->event_handler[idx] = 1988 wmi_handle->event_handler[soc->max_event_idx]; 1989 wmi_handle->event_id[idx] = 1990 wmi_handle->event_id[soc->max_event_idx]; 1991 1992 return 0; 1993 } 1994 qdf_export_symbol(wmi_unified_unregister_event_handler); 1995 1996 /** 1997 * wmi_process_fw_event_default_ctx() - process in default caller context 1998 * @wmi_handle: handle to wmi 1999 * @htc_packet: pointer to htc packet 2000 * @exec_ctx: execution context for wmi fw event 2001 * 2002 * Event process by below function will be in default caller context. 2003 * wmi internally provides rx work thread processing context. 2004 * 2005 * Return: none 2006 */ 2007 static void wmi_process_fw_event_default_ctx(struct wmi_unified *wmi_handle, 2008 HTC_PACKET *htc_packet, uint8_t exec_ctx) 2009 { 2010 wmi_buf_t evt_buf; 2011 evt_buf = (wmi_buf_t) htc_packet->pPktContext; 2012 2013 wmi_handle->rx_ops.wma_process_fw_event_handler_cbk 2014 (wmi_handle->scn_handle, evt_buf, exec_ctx); 2015 2016 return; 2017 } 2018 2019 void wmi_process_fw_event_worker_thread_ctx(struct wmi_unified *wmi_handle, 2020 void *evt_buf) 2021 { 2022 2023 qdf_spin_lock_bh(&wmi_handle->eventq_lock); 2024 qdf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf); 2025 qdf_spin_unlock_bh(&wmi_handle->eventq_lock); 2026 qdf_queue_work(0, wmi_handle->wmi_rx_work_queue, 2027 &wmi_handle->rx_event_work); 2028 2029 return; 2030 } 2031 2032 qdf_export_symbol(wmi_process_fw_event_worker_thread_ctx); 2033 2034 /** 2035 * wmi_get_pdev_ep: Get wmi handle based on endpoint 2036 * @soc: handle to wmi soc 2037 * @ep: endpoint id 2038 * 2039 * Return: none 2040 */ 2041 static struct wmi_unified *wmi_get_pdev_ep(struct wmi_soc *soc, 2042 HTC_ENDPOINT_ID ep) 2043 { 2044 uint32_t i; 2045 2046 for (i = 0; i < WMI_MAX_RADIOS; i++) 2047 if (soc->wmi_endpoint_id[i] == ep) 2048 break; 2049 2050 if (i == WMI_MAX_RADIOS) 2051 return NULL; 2052 2053 return soc->wmi_pdev[i]; 2054 } 2055 2056 /** 2057 * wmi_mtrace_rx() - Wrappper function for qdf_mtrace api 2058 * @message_id: 32-Bit Wmi message ID 2059 * @vdev_id: Vdev ID 2060 * @data: Actual message contents 2061 * 2062 * This function converts the 32-bit WMI message ID in 15-bit message ID 2063 * format for qdf_mtrace as in qdf_mtrace message there are only 15 2064 * bits reserved for message ID. 2065 * out of these 15-bits, 8-bits (From LSB) specifies the WMI_GRP_ID 2066 * and remaining 7-bits specifies the actual WMI command. With this 2067 * notation there can be maximum 256 groups and each group can have 2068 * max 128 commands can be supported. 2069 * 2070 * Return: None 2071 */ 2072 static void wmi_mtrace_rx(uint32_t message_id, uint16_t vdev_id, uint32_t data) 2073 { 2074 uint16_t mtrace_message_id; 2075 2076 mtrace_message_id = QDF_WMI_MTRACE_CMD_ID(message_id) | 2077 (QDF_WMI_MTRACE_GRP_ID(message_id) << 2078 QDF_WMI_MTRACE_CMD_NUM_BITS); 2079 qdf_mtrace(QDF_MODULE_ID_WMI, QDF_MODULE_ID_WMA, 2080 mtrace_message_id, vdev_id, data); 2081 } 2082 2083 /** 2084 * wmi_control_rx() - process fw events callbacks 2085 * @ctx: handle to wmi 2086 * @htc_packet: pointer to htc packet 2087 * 2088 * Return: none 2089 */ 2090 static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) 2091 { 2092 struct wmi_soc *soc = (struct wmi_soc *) ctx; 2093 struct wmi_unified *wmi_handle; 2094 wmi_buf_t evt_buf; 2095 uint32_t id; 2096 uint32_t idx = 0; 2097 enum wmi_rx_exec_ctx exec_ctx; 2098 2099 evt_buf = (wmi_buf_t) htc_packet->pPktContext; 2100 2101 wmi_handle = wmi_get_pdev_ep(soc, htc_packet->Endpoint); 2102 if (!wmi_handle) { 2103 WMI_LOGE 2104 ("unable to get wmi_handle to Endpoint %d\n", 2105 htc_packet->Endpoint); 2106 qdf_nbuf_free(evt_buf); 2107 return; 2108 } 2109 2110 id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); 2111 idx = wmi_unified_get_event_handler_ix(wmi_handle, id); 2112 if (qdf_unlikely(idx == A_ERROR)) { 2113 wmi_debug("no handler registered for event id 0x%x", id); 2114 qdf_nbuf_free(evt_buf); 2115 return; 2116 } 2117 wmi_mtrace_rx(id, 0xFF, idx); 2118 qdf_spin_lock_bh(&soc->ctx_lock); 2119 exec_ctx = wmi_handle->ctx[idx]; 2120 qdf_spin_unlock_bh(&soc->ctx_lock); 2121 2122 #ifdef WMI_INTERFACE_EVENT_LOGGING 2123 if (wmi_handle->log_info.wmi_logging_enable) { 2124 uint8_t *data; 2125 data = qdf_nbuf_data(evt_buf); 2126 2127 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 2128 /* Exclude 4 bytes of TLV header */ 2129 if (wmi_handle->ops->is_diag_event(id)) { 2130 WMI_DIAG_RX_EVENT_RECORD(wmi_handle, id, 2131 ((uint8_t *) data + 2132 wmi_handle->soc->buf_offset_event)); 2133 } else if (wmi_handle->ops->is_management_record(id)) { 2134 WMI_MGMT_RX_EVENT_RECORD(wmi_handle, id, 2135 ((uint8_t *) data + 2136 wmi_handle->soc->buf_offset_event)); 2137 } else { 2138 WMI_RX_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + 2139 wmi_handle->soc->buf_offset_event)); 2140 } 2141 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 2142 } 2143 #endif 2144 2145 if (exec_ctx == WMI_RX_WORK_CTX) { 2146 wmi_process_fw_event_worker_thread_ctx 2147 (wmi_handle, evt_buf); 2148 } else if (exec_ctx > WMI_RX_WORK_CTX) { 2149 wmi_process_fw_event_default_ctx 2150 (wmi_handle, htc_packet, exec_ctx); 2151 } else { 2152 WMI_LOGE("Invalid event context %d", exec_ctx); 2153 qdf_nbuf_free(evt_buf); 2154 } 2155 2156 } 2157 2158 /** 2159 * wmi_process_fw_event() - process any fw event 2160 * @wmi_handle: wmi handle 2161 * @evt_buf: fw event buffer 2162 * 2163 * This function process fw event in caller context 2164 * 2165 * Return: none 2166 */ 2167 void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) 2168 { 2169 __wmi_control_rx(wmi_handle, evt_buf); 2170 } 2171 2172 /** 2173 * __wmi_control_rx() - process serialize wmi event callback 2174 * @wmi_handle: wmi handle 2175 * @evt_buf: fw event buffer 2176 * 2177 * Return: none 2178 */ 2179 void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) 2180 { 2181 uint32_t id; 2182 uint8_t *data; 2183 uint32_t len; 2184 void *wmi_cmd_struct_ptr = NULL; 2185 #ifndef WMI_NON_TLV_SUPPORT 2186 int tlv_ok_status = 0; 2187 #endif 2188 uint32_t idx = 0; 2189 2190 id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); 2191 2192 wmi_ext_dbg_msg_event_record(wmi_handle, qdf_nbuf_data(evt_buf), 2193 qdf_nbuf_len(evt_buf)); 2194 2195 if (qdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) 2196 goto end; 2197 2198 data = qdf_nbuf_data(evt_buf); 2199 len = qdf_nbuf_len(evt_buf); 2200 2201 #ifndef WMI_NON_TLV_SUPPORT 2202 if (wmi_handle->target_type == WMI_TLV_TARGET) { 2203 /* Validate and pad(if necessary) the TLVs */ 2204 tlv_ok_status = 2205 wmi_handle->ops->wmi_check_and_pad_event(wmi_handle->scn_handle, 2206 data, len, id, 2207 &wmi_cmd_struct_ptr); 2208 if (tlv_ok_status != 0) { 2209 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 2210 "%s: Error: id=0x%x, wmitlv check status=%d", 2211 __func__, id, tlv_ok_status); 2212 goto end; 2213 } 2214 } 2215 #endif 2216 2217 idx = wmi_unified_get_event_handler_ix(wmi_handle, id); 2218 if (idx == A_ERROR) { 2219 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 2220 "%s : event handler is not registered: event id 0x%x", 2221 __func__, id); 2222 goto end; 2223 } 2224 #ifdef WMI_INTERFACE_EVENT_LOGGING 2225 if (wmi_handle->log_info.wmi_logging_enable) { 2226 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 2227 /* Exclude 4 bytes of TLV header */ 2228 if (wmi_handle->ops->is_diag_event(id)) { 2229 /* 2230 * skip diag event logging in WMI event buffer 2231 * as its already logged in WMI RX event buffer 2232 */ 2233 } else if (wmi_handle->ops->is_management_record(id)) { 2234 /* 2235 * skip wmi mgmt event logging in WMI event buffer 2236 * as its already logged in WMI RX event buffer 2237 */ 2238 } else { 2239 WMI_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + 2240 wmi_handle->soc->buf_offset_event)); 2241 } 2242 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 2243 } 2244 #endif 2245 /* Call the WMI registered event handler */ 2246 if (wmi_handle->target_type == WMI_TLV_TARGET) 2247 wmi_handle->event_handler[idx] (wmi_handle->scn_handle, 2248 wmi_cmd_struct_ptr, len); 2249 else 2250 wmi_handle->event_handler[idx] (wmi_handle->scn_handle, 2251 data, len); 2252 2253 end: 2254 /* Free event buffer and allocated event tlv */ 2255 #ifndef WMI_NON_TLV_SUPPORT 2256 if (wmi_handle->target_type == WMI_TLV_TARGET) 2257 wmi_handle->ops->wmi_free_allocated_event(id, &wmi_cmd_struct_ptr); 2258 #endif 2259 2260 qdf_nbuf_free(evt_buf); 2261 2262 } 2263 2264 #define WMI_WQ_WD_TIMEOUT (30 * 1000) /* 30s */ 2265 2266 static inline void wmi_workqueue_watchdog_warn(uint32_t msg_type_id) 2267 { 2268 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 2269 "%s: WLAN_BUG_RCA: Message type %x has exceeded its alloted time of %ds", 2270 __func__, msg_type_id, WMI_WQ_WD_TIMEOUT / 1000); 2271 } 2272 2273 #ifdef CONFIG_SLUB_DEBUG_ON 2274 static void wmi_workqueue_watchdog_bite(void *arg) 2275 { 2276 struct wmi_wq_dbg_info *info = arg; 2277 2278 wmi_workqueue_watchdog_warn(info->wd_msg_type_id); 2279 qdf_print_thread_trace(info->task); 2280 2281 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 2282 "%s: Going down for WMI WQ Watchdog Bite!", __func__); 2283 QDF_BUG(0); 2284 } 2285 #else 2286 static inline void wmi_workqueue_watchdog_bite(void *arg) 2287 { 2288 struct wmi_wq_dbg_info *info = arg; 2289 2290 wmi_workqueue_watchdog_warn(info->wd_msg_type_id); 2291 } 2292 #endif 2293 2294 /** 2295 * wmi_rx_event_work() - process rx event in rx work queue context 2296 * @arg: opaque pointer to wmi handle 2297 * 2298 * This function process any fw event to serialize it through rx worker thread. 2299 * 2300 * Return: none 2301 */ 2302 static void wmi_rx_event_work(void *arg) 2303 { 2304 wmi_buf_t buf; 2305 struct wmi_unified *wmi = arg; 2306 qdf_timer_t wd_timer; 2307 struct wmi_wq_dbg_info info; 2308 2309 /* initialize WMI workqueue watchdog timer */ 2310 qdf_timer_init(NULL, &wd_timer, &wmi_workqueue_watchdog_bite, 2311 &info, QDF_TIMER_TYPE_SW); 2312 qdf_spin_lock_bh(&wmi->eventq_lock); 2313 buf = qdf_nbuf_queue_remove(&wmi->event_queue); 2314 qdf_spin_unlock_bh(&wmi->eventq_lock); 2315 while (buf) { 2316 qdf_timer_start(&wd_timer, WMI_WQ_WD_TIMEOUT); 2317 info.wd_msg_type_id = 2318 WMI_GET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID); 2319 info.wmi_wq = wmi->wmi_rx_work_queue; 2320 info.task = qdf_get_current_task(); 2321 __wmi_control_rx(wmi, buf); 2322 qdf_timer_stop(&wd_timer); 2323 qdf_spin_lock_bh(&wmi->eventq_lock); 2324 buf = qdf_nbuf_queue_remove(&wmi->event_queue); 2325 qdf_spin_unlock_bh(&wmi->eventq_lock); 2326 } 2327 qdf_timer_free(&wd_timer); 2328 } 2329 2330 #ifdef FEATURE_RUNTIME_PM 2331 /** 2332 * wmi_runtime_pm_init() - initialize runtime pm wmi variables 2333 * @wmi_handle: wmi context 2334 */ 2335 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle) 2336 { 2337 qdf_atomic_init(&wmi_handle->runtime_pm_inprogress); 2338 } 2339 2340 /** 2341 * wmi_set_runtime_pm_inprogress() - set runtime pm progress flag 2342 * @wmi_handle: wmi context 2343 * @val: runtime pm progress flag 2344 */ 2345 void wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, A_BOOL val) 2346 { 2347 qdf_atomic_set(&wmi_handle->runtime_pm_inprogress, val); 2348 } 2349 2350 /** 2351 * wmi_get_runtime_pm_inprogress() - get runtime pm progress flag 2352 * @wmi_handle: wmi context 2353 */ 2354 inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle) 2355 { 2356 return qdf_atomic_read(&wmi_handle->runtime_pm_inprogress); 2357 } 2358 #else 2359 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle) 2360 { 2361 } 2362 #endif 2363 2364 /** 2365 * wmi_unified_get_soc_handle: Get WMI SoC handle 2366 * @param wmi_handle: WMI context got from wmi_attach 2367 * 2368 * return: Pointer to Soc handle 2369 */ 2370 void *wmi_unified_get_soc_handle(struct wmi_unified *wmi_handle) 2371 { 2372 return wmi_handle->soc; 2373 } 2374 2375 /** 2376 * wmi_interface_logging_init: Interface looging init 2377 * @param wmi_handle: Pointer to wmi handle object 2378 * 2379 * return: None 2380 */ 2381 #ifdef WMI_INTERFACE_EVENT_LOGGING 2382 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle, 2383 uint32_t pdev_idx) 2384 { 2385 if (QDF_STATUS_SUCCESS == wmi_log_init(wmi_handle)) { 2386 qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); 2387 wmi_debugfs_init(wmi_handle, pdev_idx); 2388 } 2389 } 2390 #else 2391 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle, 2392 uint32_t pdev_idx) 2393 { 2394 } 2395 #endif 2396 2397 /** 2398 * wmi_unified_get_pdev_handle: Get WMI SoC handle 2399 * @param wmi_soc: Pointer to wmi soc object 2400 * @param pdev_idx: pdev index 2401 * 2402 * return: Pointer to wmi handle or NULL on failure 2403 */ 2404 void *wmi_unified_get_pdev_handle(struct wmi_soc *soc, uint32_t pdev_idx) 2405 { 2406 struct wmi_unified *wmi_handle; 2407 2408 if (pdev_idx >= WMI_MAX_RADIOS) 2409 return NULL; 2410 2411 if (!soc->wmi_pdev[pdev_idx]) { 2412 wmi_handle = 2413 (struct wmi_unified *) qdf_mem_malloc( 2414 sizeof(struct wmi_unified)); 2415 if (!wmi_handle) 2416 return NULL; 2417 2418 wmi_handle->scn_handle = soc->scn_handle; 2419 wmi_handle->event_id = soc->event_id; 2420 wmi_handle->event_handler = soc->event_handler; 2421 wmi_handle->ctx = soc->ctx; 2422 wmi_handle->ops = soc->ops; 2423 qdf_spinlock_create(&wmi_handle->eventq_lock); 2424 qdf_nbuf_queue_init(&wmi_handle->event_queue); 2425 2426 qdf_create_work(0, &wmi_handle->rx_event_work, 2427 wmi_rx_event_work, wmi_handle); 2428 wmi_handle->wmi_rx_work_queue = 2429 qdf_alloc_unbound_workqueue("wmi_rx_event_work_queue"); 2430 if (!wmi_handle->wmi_rx_work_queue) { 2431 WMI_LOGE("failed to create wmi_rx_event_work_queue"); 2432 goto error; 2433 } 2434 wmi_handle->wmi_events = soc->wmi_events; 2435 wmi_handle->services = soc->services; 2436 wmi_handle->soc = soc; 2437 wmi_interface_logging_init(wmi_handle, pdev_idx); 2438 qdf_atomic_init(&wmi_handle->pending_cmds); 2439 qdf_atomic_init(&wmi_handle->is_target_suspended); 2440 wmi_handle->target_type = soc->target_type; 2441 wmi_handle->wmi_max_cmds = soc->wmi_max_cmds; 2442 2443 soc->wmi_pdev[pdev_idx] = wmi_handle; 2444 } else 2445 wmi_handle = soc->wmi_pdev[pdev_idx]; 2446 2447 wmi_handle->wmi_stopinprogress = 0; 2448 wmi_handle->wmi_endpoint_id = soc->wmi_endpoint_id[pdev_idx]; 2449 wmi_handle->htc_handle = soc->htc_handle; 2450 wmi_handle->max_msg_len = soc->max_msg_len[pdev_idx]; 2451 2452 return wmi_handle; 2453 2454 error: 2455 qdf_mem_free(wmi_handle); 2456 2457 return NULL; 2458 } 2459 qdf_export_symbol(wmi_unified_get_pdev_handle); 2460 2461 static void (*wmi_attach_register[WMI_MAX_TARGET_TYPE])(wmi_unified_t); 2462 2463 void wmi_unified_register_module(enum wmi_target_type target_type, 2464 void (*wmi_attach)(wmi_unified_t wmi_handle)) 2465 { 2466 if (target_type < WMI_MAX_TARGET_TYPE) 2467 wmi_attach_register[target_type] = wmi_attach; 2468 2469 return; 2470 } 2471 qdf_export_symbol(wmi_unified_register_module); 2472 2473 /** 2474 * wmi_wbuff_register() - register wmi with wbuff 2475 * @wmi_handle: handle to wmi 2476 * 2477 * @Return: void 2478 */ 2479 static void wmi_wbuff_register(struct wmi_unified *wmi_handle) 2480 { 2481 struct wbuff_alloc_request wbuff_alloc[4]; 2482 2483 wbuff_alloc[0].slot = WBUFF_POOL_0; 2484 wbuff_alloc[0].size = WMI_WBUFF_POOL_0_SIZE; 2485 wbuff_alloc[1].slot = WBUFF_POOL_1; 2486 wbuff_alloc[1].size = WMI_WBUFF_POOL_1_SIZE; 2487 wbuff_alloc[2].slot = WBUFF_POOL_2; 2488 wbuff_alloc[2].size = WMI_WBUFF_POOL_2_SIZE; 2489 wbuff_alloc[3].slot = WBUFF_POOL_3; 2490 wbuff_alloc[3].size = WMI_WBUFF_POOL_3_SIZE; 2491 2492 wmi_handle->wbuff_handle = wbuff_module_register(wbuff_alloc, 4, 2493 WMI_MIN_HEAD_ROOM, 4); 2494 } 2495 2496 /** 2497 * wmi_wbuff_deregister() - deregister wmi with wbuff 2498 * @wmi_handle: handle to wmi 2499 * 2500 * @Return: void 2501 */ 2502 static inline void wmi_wbuff_deregister(struct wmi_unified *wmi_handle) 2503 { 2504 wbuff_module_deregister(wmi_handle->wbuff_handle); 2505 wmi_handle->wbuff_handle = NULL; 2506 } 2507 2508 /** 2509 * wmi_unified_attach() - attach for unified WMI 2510 * @scn_handle: handle to SCN 2511 * @osdev: OS device context 2512 * @target_type: TLV or not-TLV based target 2513 * @use_cookie: cookie based allocation enabled/disabled 2514 * @ops: umac rx callbacks 2515 * @psoc: objmgr psoc 2516 * 2517 * @Return: wmi handle. 2518 */ 2519 void *wmi_unified_attach(void *scn_handle, 2520 struct wmi_unified_attach_params *param) 2521 { 2522 struct wmi_unified *wmi_handle; 2523 struct wmi_soc *soc; 2524 2525 soc = (struct wmi_soc *) qdf_mem_malloc(sizeof(struct wmi_soc)); 2526 if (!soc) 2527 return NULL; 2528 2529 wmi_handle = 2530 (struct wmi_unified *) qdf_mem_malloc( 2531 sizeof(struct wmi_unified)); 2532 if (!wmi_handle) { 2533 qdf_mem_free(soc); 2534 return NULL; 2535 } 2536 wmi_handle->soc = soc; 2537 wmi_handle->soc->soc_idx = param->soc_id; 2538 wmi_handle->soc->is_async_ep = param->is_async_ep; 2539 wmi_handle->event_id = soc->event_id; 2540 wmi_handle->event_handler = soc->event_handler; 2541 wmi_handle->ctx = soc->ctx; 2542 wmi_handle->wmi_events = soc->wmi_events; 2543 wmi_handle->services = soc->services; 2544 wmi_handle->scn_handle = scn_handle; 2545 soc->scn_handle = scn_handle; 2546 qdf_atomic_init(&wmi_handle->pending_cmds); 2547 qdf_atomic_init(&wmi_handle->is_target_suspended); 2548 wmi_runtime_pm_init(wmi_handle); 2549 qdf_spinlock_create(&wmi_handle->eventq_lock); 2550 qdf_nbuf_queue_init(&wmi_handle->event_queue); 2551 qdf_create_work(0, &wmi_handle->rx_event_work, 2552 wmi_rx_event_work, wmi_handle); 2553 wmi_handle->wmi_rx_work_queue = 2554 qdf_alloc_unbound_workqueue("wmi_rx_event_work_queue"); 2555 if (!wmi_handle->wmi_rx_work_queue) { 2556 WMI_LOGE("failed to create wmi_rx_event_work_queue"); 2557 goto error; 2558 } 2559 wmi_interface_logging_init(wmi_handle, WMI_HOST_PDEV_ID_0); 2560 /* Attach mc_thread context processing function */ 2561 wmi_handle->rx_ops.wma_process_fw_event_handler_cbk = 2562 param->rx_ops->wma_process_fw_event_handler_cbk; 2563 wmi_handle->target_type = param->target_type; 2564 soc->target_type = param->target_type; 2565 2566 if (param->target_type >= WMI_MAX_TARGET_TYPE) 2567 goto error; 2568 2569 if (wmi_attach_register[param->target_type]) { 2570 wmi_attach_register[param->target_type](wmi_handle); 2571 } else { 2572 WMI_LOGE("wmi attach is not registered"); 2573 goto error; 2574 } 2575 /* Assign target cookie capablity */ 2576 wmi_handle->use_cookie = param->use_cookie; 2577 wmi_handle->osdev = param->osdev; 2578 wmi_handle->wmi_stopinprogress = 0; 2579 wmi_handle->wmi_max_cmds = param->max_commands; 2580 soc->wmi_max_cmds = param->max_commands; 2581 /* Increase the ref count once refcount infra is present */ 2582 soc->wmi_psoc = param->psoc; 2583 qdf_spinlock_create(&soc->ctx_lock); 2584 2585 soc->ops = wmi_handle->ops; 2586 soc->wmi_pdev[0] = wmi_handle; 2587 if (wmi_ext_dbgfs_init(wmi_handle) != QDF_STATUS_SUCCESS) 2588 WMI_LOGE("failed to initialize wmi extended debugfs"); 2589 2590 wmi_wbuff_register(wmi_handle); 2591 2592 return wmi_handle; 2593 2594 error: 2595 qdf_mem_free(soc); 2596 qdf_mem_free(wmi_handle); 2597 2598 return NULL; 2599 } 2600 2601 /** 2602 * wmi_unified_detach() - detach for unified WMI 2603 * 2604 * @wmi_handle : handle to wmi. 2605 * 2606 * @Return: none. 2607 */ 2608 void wmi_unified_detach(struct wmi_unified *wmi_handle) 2609 { 2610 wmi_buf_t buf; 2611 struct wmi_soc *soc; 2612 uint8_t i; 2613 2614 wmi_wbuff_deregister(wmi_handle); 2615 2616 wmi_ext_dbgfs_deinit(wmi_handle); 2617 2618 soc = wmi_handle->soc; 2619 for (i = 0; i < WMI_MAX_RADIOS; i++) { 2620 if (soc->wmi_pdev[i]) { 2621 qdf_flush_workqueue(0, 2622 soc->wmi_pdev[i]->wmi_rx_work_queue); 2623 qdf_destroy_workqueue(0, 2624 soc->wmi_pdev[i]->wmi_rx_work_queue); 2625 wmi_debugfs_remove(soc->wmi_pdev[i]); 2626 buf = qdf_nbuf_queue_remove( 2627 &soc->wmi_pdev[i]->event_queue); 2628 while (buf) { 2629 qdf_nbuf_free(buf); 2630 buf = qdf_nbuf_queue_remove( 2631 &soc->wmi_pdev[i]->event_queue); 2632 } 2633 2634 wmi_log_buffer_free(soc->wmi_pdev[i]); 2635 2636 /* Free events logs list */ 2637 if (soc->wmi_pdev[i]->events_logs_list) 2638 qdf_mem_free( 2639 soc->wmi_pdev[i]->events_logs_list); 2640 2641 qdf_spinlock_destroy(&soc->wmi_pdev[i]->eventq_lock); 2642 qdf_mem_free(soc->wmi_pdev[i]); 2643 } 2644 } 2645 qdf_spinlock_destroy(&soc->ctx_lock); 2646 2647 if (soc->wmi_service_bitmap) { 2648 qdf_mem_free(soc->wmi_service_bitmap); 2649 soc->wmi_service_bitmap = NULL; 2650 } 2651 2652 if (soc->wmi_ext_service_bitmap) { 2653 qdf_mem_free(soc->wmi_ext_service_bitmap); 2654 soc->wmi_ext_service_bitmap = NULL; 2655 } 2656 2657 /* Decrease the ref count once refcount infra is present */ 2658 soc->wmi_psoc = NULL; 2659 qdf_mem_free(soc); 2660 } 2661 2662 /** 2663 * wmi_unified_remove_work() - detach for WMI work 2664 * @wmi_handle: handle to WMI 2665 * 2666 * A function that does not fully detach WMI, but just remove work 2667 * queue items associated with it. This is used to make sure that 2668 * before any other processing code that may destroy related contexts 2669 * (HTC, etc), work queue processing on WMI has already been stopped. 2670 * 2671 * Return: None 2672 */ 2673 void 2674 wmi_unified_remove_work(struct wmi_unified *wmi_handle) 2675 { 2676 wmi_buf_t buf; 2677 2678 qdf_flush_workqueue(0, wmi_handle->wmi_rx_work_queue); 2679 qdf_spin_lock_bh(&wmi_handle->eventq_lock); 2680 buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); 2681 while (buf) { 2682 qdf_nbuf_free(buf); 2683 buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); 2684 } 2685 qdf_spin_unlock_bh(&wmi_handle->eventq_lock); 2686 } 2687 2688 /** 2689 * wmi_htc_tx_complete() - Process htc tx completion 2690 * 2691 * @ctx: handle to wmi 2692 * @htc_packet: pointer to htc packet 2693 * 2694 * @Return: none. 2695 */ 2696 static void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt) 2697 { 2698 struct wmi_soc *soc = (struct wmi_soc *) ctx; 2699 wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); 2700 u_int8_t *buf_ptr; 2701 u_int32_t len; 2702 struct wmi_unified *wmi_handle; 2703 #ifdef WMI_INTERFACE_EVENT_LOGGING 2704 uint32_t cmd_id; 2705 #endif 2706 2707 ASSERT(wmi_cmd_buf); 2708 wmi_handle = wmi_get_pdev_ep(soc, htc_pkt->Endpoint); 2709 if (!wmi_handle) { 2710 WMI_LOGE("%s: Unable to get wmi handle\n", __func__); 2711 QDF_ASSERT(0); 2712 return; 2713 } 2714 #ifdef WMI_INTERFACE_EVENT_LOGGING 2715 if (wmi_handle && wmi_handle->log_info.wmi_logging_enable) { 2716 cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf), 2717 WMI_CMD_HDR, COMMANDID); 2718 2719 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 2720 /* Record 16 bytes of WMI cmd tx complete data 2721 - exclude TLV and WMI headers */ 2722 if (wmi_handle->ops->is_management_record(cmd_id)) { 2723 WMI_MGMT_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id, 2724 qdf_nbuf_data(wmi_cmd_buf) + 2725 wmi_handle->soc->buf_offset_command); 2726 } else { 2727 WMI_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id, 2728 qdf_nbuf_data(wmi_cmd_buf) + 2729 wmi_handle->soc->buf_offset_command); 2730 } 2731 2732 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 2733 } 2734 #endif 2735 buf_ptr = (u_int8_t *) wmi_buf_data(wmi_cmd_buf); 2736 len = qdf_nbuf_len(wmi_cmd_buf); 2737 qdf_mem_zero(buf_ptr, len); 2738 wmi_buf_free(wmi_cmd_buf); 2739 qdf_mem_free(htc_pkt); 2740 qdf_atomic_dec(&wmi_handle->pending_cmds); 2741 } 2742 2743 /** 2744 * wmi_connect_pdev_htc_service() - WMI API to get connect to HTC service 2745 * 2746 * @wmi_handle: handle to WMI. 2747 * @pdev_idx: Pdev index 2748 * 2749 * @Return: QDF_STATUS 2750 */ 2751 static QDF_STATUS wmi_connect_pdev_htc_service(struct wmi_soc *soc, 2752 uint32_t pdev_idx) 2753 { 2754 QDF_STATUS status; 2755 struct htc_service_connect_resp response; 2756 struct htc_service_connect_req connect; 2757 2758 OS_MEMZERO(&connect, sizeof(connect)); 2759 OS_MEMZERO(&response, sizeof(response)); 2760 2761 /* meta data is unused for now */ 2762 connect.pMetaData = NULL; 2763 connect.MetaDataLength = 0; 2764 /* these fields are the same for all service endpoints */ 2765 connect.EpCallbacks.pContext = soc; 2766 connect.EpCallbacks.EpTxCompleteMultiple = 2767 NULL /* Control path completion ar6000_tx_complete */; 2768 connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */; 2769 connect.EpCallbacks.EpRecvRefill = NULL /* ar6000_rx_refill */; 2770 connect.EpCallbacks.EpSendFull = NULL /* ar6000_tx_queue_full */; 2771 connect.EpCallbacks.EpTxComplete = 2772 wmi_htc_tx_complete /* ar6000_tx_queue_full */; 2773 2774 /* connect to control service */ 2775 connect.service_id = soc->svc_ids[pdev_idx]; 2776 status = htc_connect_service(soc->htc_handle, &connect, &response); 2777 2778 if (QDF_IS_STATUS_ERROR(status)) { 2779 WMI_LOGE("Failed to connect to WMI CONTROL service status:%d\n", 2780 status); 2781 return status; 2782 } 2783 2784 if (soc->is_async_ep) 2785 htc_set_async_ep(soc->htc_handle, response.Endpoint, true); 2786 2787 soc->wmi_endpoint_id[pdev_idx] = response.Endpoint; 2788 soc->max_msg_len[pdev_idx] = response.MaxMsgLength; 2789 2790 return QDF_STATUS_SUCCESS; 2791 } 2792 2793 /** 2794 * wmi_unified_connect_htc_service() - WMI API to get connect to HTC service 2795 * 2796 * @wmi_handle: handle to WMI. 2797 * 2798 * @Return: status. 2799 */ 2800 QDF_STATUS 2801 wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle, 2802 void *htc_handle) 2803 { 2804 uint32_t i; 2805 uint8_t wmi_ep_count; 2806 2807 wmi_handle->soc->htc_handle = htc_handle; 2808 2809 wmi_ep_count = htc_get_wmi_endpoint_count(htc_handle); 2810 if (wmi_ep_count > WMI_MAX_RADIOS) 2811 return QDF_STATUS_E_FAULT; 2812 2813 for (i = 0; i < wmi_ep_count; i++) 2814 wmi_connect_pdev_htc_service(wmi_handle->soc, i); 2815 2816 wmi_handle->htc_handle = htc_handle; 2817 wmi_handle->wmi_endpoint_id = wmi_handle->soc->wmi_endpoint_id[0]; 2818 wmi_handle->max_msg_len = wmi_handle->soc->max_msg_len[0]; 2819 2820 return QDF_STATUS_SUCCESS; 2821 } 2822 2823 /** 2824 * wmi_get_host_credits() - WMI API to get updated host_credits 2825 * 2826 * @wmi_handle: handle to WMI. 2827 * 2828 * @Return: updated host_credits. 2829 */ 2830 int wmi_get_host_credits(wmi_unified_t wmi_handle) 2831 { 2832 int host_credits = 0; 2833 2834 htc_get_control_endpoint_tx_host_credits(wmi_handle->htc_handle, 2835 &host_credits); 2836 return host_credits; 2837 } 2838 2839 /** 2840 * wmi_get_pending_cmds() - WMI API to get WMI Pending Commands in the HTC 2841 * queue 2842 * 2843 * @wmi_handle: handle to WMI. 2844 * 2845 * @Return: Pending Commands in the HTC queue. 2846 */ 2847 int wmi_get_pending_cmds(wmi_unified_t wmi_handle) 2848 { 2849 return qdf_atomic_read(&wmi_handle->pending_cmds); 2850 } 2851 2852 /** 2853 * wmi_set_target_suspend() - WMI API to set target suspend state 2854 * 2855 * @wmi_handle: handle to WMI. 2856 * @val: suspend state boolean. 2857 * 2858 * @Return: none. 2859 */ 2860 void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val) 2861 { 2862 qdf_atomic_set(&wmi_handle->is_target_suspended, val); 2863 } 2864 2865 /** 2866 * wmi_is_target_suspended() - WMI API to check target suspend state 2867 * @wmi_handle: handle to WMI. 2868 * 2869 * WMI API to check target suspend state 2870 * 2871 * Return: true if target is suspended, else false. 2872 */ 2873 bool wmi_is_target_suspended(struct wmi_unified *wmi_handle) 2874 { 2875 return qdf_atomic_read(&wmi_handle->is_target_suspended); 2876 } 2877 2878 /** 2879 * WMI API to set crash injection state 2880 * @param wmi_handle: handle to WMI. 2881 * @param val: crash injection state boolean. 2882 */ 2883 void wmi_tag_crash_inject(wmi_unified_t wmi_handle, A_BOOL flag) 2884 { 2885 wmi_handle->tag_crash_inject = flag; 2886 } 2887 2888 /** 2889 * WMI API to set bus suspend state 2890 * @param wmi_handle: handle to WMI. 2891 * @param val: suspend state boolean. 2892 */ 2893 void wmi_set_is_wow_bus_suspended(wmi_unified_t wmi_handle, A_BOOL val) 2894 { 2895 qdf_atomic_set(&wmi_handle->is_wow_bus_suspended, val); 2896 } 2897 2898 void wmi_set_tgt_assert(wmi_unified_t wmi_handle, bool val) 2899 { 2900 wmi_handle->tgt_force_assert_enable = val; 2901 } 2902 2903 /** 2904 * wmi_stop() - generic function to block unified WMI command 2905 * @wmi_handle: handle to WMI. 2906 * 2907 * @Return: success always. 2908 */ 2909 int 2910 wmi_stop(wmi_unified_t wmi_handle) 2911 { 2912 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, 2913 "WMI Stop"); 2914 wmi_handle->wmi_stopinprogress = 1; 2915 return 0; 2916 } 2917 2918 #ifndef CONFIG_MCL 2919 /** 2920 * API to flush all the previous packets associated with the wmi endpoint 2921 * 2922 * @param wmi_handle : handle to WMI. 2923 */ 2924 void 2925 wmi_flush_endpoint(wmi_unified_t wmi_handle) 2926 { 2927 htc_flush_endpoint(wmi_handle->htc_handle, 2928 wmi_handle->wmi_endpoint_id, 0); 2929 } 2930 qdf_export_symbol(wmi_flush_endpoint); 2931 2932 /** 2933 * wmi_pdev_id_conversion_enable() - API to enable pdev_id conversion in WMI 2934 * By default pdev_id conversion is not done in WMI. 2935 * This API can be used enable conversion in WMI. 2936 * @param wmi_handle : handle to WMI 2937 * Return none 2938 */ 2939 void wmi_pdev_id_conversion_enable(wmi_unified_t wmi_handle) 2940 { 2941 if (wmi_handle->target_type == WMI_TLV_TARGET) 2942 wmi_handle->ops->wmi_pdev_id_conversion_enable(wmi_handle); 2943 } 2944 2945 #endif 2946