1 /* 2 * Copyright (c) 2015-2020 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 #include "qdf_atomic.h" 31 #endif 32 33 #ifndef WMI_NON_TLV_SUPPORT 34 #include "wmi_tlv_helper.h" 35 #endif 36 37 #include <linux/debugfs.h> 38 #include <target_if.h> 39 40 /* This check for CONFIG_WIN temporary added due to redeclaration compilation 41 error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h 42 which gets included here through ol_if_athvar.h. Eventually it is expected that 43 wmi.h will be removed from wmi_unified_api.h after cleanup, which will need 44 WMI_CMD_HDR to be defined here. */ 45 /* Copied from wmi.h */ 46 #undef MS 47 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) 48 #undef SM 49 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) 50 #undef WO 51 #define WO(_f) ((_f##_OFFSET) >> 2) 52 53 #undef GET_FIELD 54 #define GET_FIELD(_addr, _f) MS(*((uint32_t *)(_addr) + WO(_f)), _f) 55 #undef SET_FIELD 56 #define SET_FIELD(_addr, _f, _val) \ 57 (*((uint32_t *)(_addr) + WO(_f)) = \ 58 (*((uint32_t *)(_addr) + WO(_f)) & ~_f##_MASK) | SM(_val, _f)) 59 60 #define WMI_GET_FIELD(_msg_buf, _msg_type, _f) \ 61 GET_FIELD(_msg_buf, _msg_type ## _ ## _f) 62 63 #define WMI_SET_FIELD(_msg_buf, _msg_type, _f, _val) \ 64 SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val) 65 66 #define WMI_EP_APASS 0x0 67 #define WMI_EP_LPASS 0x1 68 #define WMI_EP_SENSOR 0x2 69 70 /* 71 * * Control Path 72 * */ 73 typedef PREPACK struct { 74 uint32_t commandId:24, 75 reserved:2, /* used for WMI endpoint ID */ 76 plt_priv:6; /* platform private */ 77 } POSTPACK WMI_CMD_HDR; /* used for commands and events */ 78 79 #define WMI_CMD_HDR_COMMANDID_LSB 0 80 #define WMI_CMD_HDR_COMMANDID_MASK 0x00ffffff 81 #define WMI_CMD_HDR_COMMANDID_OFFSET 0x00000000 82 #define WMI_CMD_HDR_WMI_ENDPOINTID_MASK 0x03000000 83 #define WMI_CMD_HDR_WMI_ENDPOINTID_OFFSET 24 84 #define WMI_CMD_HDR_PLT_PRIV_LSB 24 85 #define WMI_CMD_HDR_PLT_PRIV_MASK 0xff000000 86 #define WMI_CMD_HDR_PLT_PRIV_OFFSET 0x00000000 87 /* end of copy wmi.h */ 88 89 #define WMI_MIN_HEAD_ROOM 64 90 91 /* WBUFF pool sizes for WMI */ 92 /* Allocation of size 256 bytes */ 93 #define WMI_WBUFF_POOL_0_SIZE 128 94 /* Allocation of size 512 bytes */ 95 #define WMI_WBUFF_POOL_1_SIZE 16 96 /* Allocation of size 1024 bytes */ 97 #define WMI_WBUFF_POOL_2_SIZE 8 98 /* Allocation of size 2048 bytes */ 99 #define WMI_WBUFF_POOL_3_SIZE 8 100 101 #ifdef WMI_INTERFACE_EVENT_LOGGING 102 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) 103 /* TODO Cleanup this backported function */ 104 static int wmi_bp_seq_printf(struct seq_file *m, const char *f, ...) 105 { 106 va_list args; 107 108 va_start(args, f); 109 seq_vprintf(m, f, args); 110 va_end(args); 111 112 return 0; 113 } 114 #else 115 #define wmi_bp_seq_printf(m, fmt, ...) seq_printf((m), fmt, ##__VA_ARGS__) 116 #endif 117 118 #ifndef MAX_WMI_INSTANCES 119 #define CUSTOM_MGMT_CMD_DATA_SIZE 4 120 #endif 121 122 #ifndef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC 123 /* WMI commands */ 124 uint32_t g_wmi_command_buf_idx = 0; 125 struct wmi_command_debug wmi_command_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 126 127 /* WMI commands TX completed */ 128 uint32_t g_wmi_command_tx_cmp_buf_idx = 0; 129 struct wmi_command_debug 130 wmi_command_tx_cmp_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 131 132 /* WMI events when processed */ 133 uint32_t g_wmi_event_buf_idx = 0; 134 struct wmi_event_debug wmi_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 135 136 /* WMI events when queued */ 137 uint32_t g_wmi_rx_event_buf_idx = 0; 138 struct wmi_event_debug wmi_rx_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; 139 #endif 140 141 #define WMI_COMMAND_RECORD(h, a, b) { \ 142 if (wmi_log_max_entry <= \ 143 *(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)) \ 144 *(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx) = 0;\ 145 ((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\ 146 [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)]\ 147 .command = a; \ 148 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 149 wmi_command_log_buf_info.buf) \ 150 [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].data,\ 151 b, wmi_record_max_length); \ 152 ((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\ 153 [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].\ 154 time = qdf_get_log_timestamp(); \ 155 (*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx))++; \ 156 h->log_info.wmi_command_log_buf_info.length++; \ 157 } 158 159 #define WMI_COMMAND_TX_CMP_RECORD(h, a, b) { \ 160 if (wmi_log_max_entry <= \ 161 *(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))\ 162 *(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 163 p_buf_tail_idx) = 0; \ 164 ((struct wmi_command_debug *)h->log_info. \ 165 wmi_command_tx_cmp_log_buf_info.buf) \ 166 [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 167 p_buf_tail_idx)]. \ 168 command = a; \ 169 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 170 wmi_command_tx_cmp_log_buf_info.buf) \ 171 [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 172 p_buf_tail_idx)]. \ 173 data, b, wmi_record_max_length); \ 174 ((struct wmi_command_debug *)h->log_info. \ 175 wmi_command_tx_cmp_log_buf_info.buf) \ 176 [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ 177 p_buf_tail_idx)]. \ 178 time = qdf_get_log_timestamp(); \ 179 (*(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))++;\ 180 h->log_info.wmi_command_tx_cmp_log_buf_info.length++; \ 181 } 182 183 #define WMI_EVENT_RECORD(h, a, b) { \ 184 if (wmi_log_max_entry <= \ 185 *(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)) \ 186 *(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx) = 0;\ 187 ((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\ 188 [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)]. \ 189 event = a; \ 190 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 191 wmi_event_log_buf_info.buf) \ 192 [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].data, b,\ 193 wmi_record_max_length); \ 194 ((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\ 195 [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].time =\ 196 qdf_get_log_timestamp(); \ 197 (*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx))++; \ 198 h->log_info.wmi_event_log_buf_info.length++; \ 199 } 200 201 #define WMI_RX_EVENT_RECORD(h, a, b) { \ 202 if (wmi_log_max_entry <= \ 203 *(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))\ 204 *(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx) = 0;\ 205 ((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\ 206 [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ 207 event = a; \ 208 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 209 wmi_rx_event_log_buf_info.buf) \ 210 [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ 211 data, b, wmi_record_max_length); \ 212 ((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\ 213 [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ 214 time = qdf_get_log_timestamp(); \ 215 (*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))++; \ 216 h->log_info.wmi_rx_event_log_buf_info.length++; \ 217 } 218 219 #ifndef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC 220 uint32_t g_wmi_mgmt_command_buf_idx = 0; 221 struct 222 wmi_command_debug wmi_mgmt_command_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; 223 224 /* wmi_mgmt commands TX completed */ 225 uint32_t g_wmi_mgmt_command_tx_cmp_buf_idx = 0; 226 struct wmi_command_debug 227 wmi_mgmt_command_tx_cmp_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; 228 229 /* wmi_mgmt events when received */ 230 uint32_t g_wmi_mgmt_rx_event_buf_idx = 0; 231 struct wmi_event_debug 232 wmi_mgmt_rx_event_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; 233 234 /* wmi_diag events when received */ 235 uint32_t g_wmi_diag_rx_event_buf_idx = 0; 236 struct wmi_event_debug 237 wmi_diag_rx_event_log_buffer[WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY]; 238 #endif 239 240 #define WMI_MGMT_COMMAND_RECORD(h, a, b) { \ 241 if (wmi_mgmt_log_max_entry <= \ 242 *(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)) \ 243 *(h->log_info.wmi_mgmt_command_log_buf_info. \ 244 p_buf_tail_idx) = 0; \ 245 ((struct wmi_command_debug *)h->log_info. \ 246 wmi_mgmt_command_log_buf_info.buf) \ 247 [*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\ 248 command = a; \ 249 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 250 wmi_mgmt_command_log_buf_info.buf) \ 251 [*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\ 252 data, b, \ 253 wmi_record_max_length); \ 254 ((struct wmi_command_debug *)h->log_info. \ 255 wmi_mgmt_command_log_buf_info.buf) \ 256 [*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\ 257 time = qdf_get_log_timestamp(); \ 258 (*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx))++;\ 259 h->log_info.wmi_mgmt_command_log_buf_info.length++; \ 260 } 261 262 #define WMI_MGMT_COMMAND_TX_CMP_RECORD(h, a, b) { \ 263 if (wmi_mgmt_log_max_entry <= \ 264 *(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 265 p_buf_tail_idx)) \ 266 *(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 267 p_buf_tail_idx) = 0; \ 268 ((struct wmi_command_debug *)h->log_info. \ 269 wmi_mgmt_command_tx_cmp_log_buf_info.buf) \ 270 [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 271 p_buf_tail_idx)].command = a; \ 272 qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ 273 wmi_mgmt_command_tx_cmp_log_buf_info.buf)\ 274 [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 275 p_buf_tail_idx)].data, b, \ 276 wmi_record_max_length); \ 277 ((struct wmi_command_debug *)h->log_info. \ 278 wmi_mgmt_command_tx_cmp_log_buf_info.buf) \ 279 [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 280 p_buf_tail_idx)].time = \ 281 qdf_get_log_timestamp(); \ 282 (*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ 283 p_buf_tail_idx))++; \ 284 h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.length++; \ 285 } 286 287 #define WMI_MGMT_RX_EVENT_RECORD(h, a, b) do { \ 288 if (wmi_mgmt_log_max_entry <= \ 289 *(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))\ 290 *(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx) = 0;\ 291 ((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\ 292 [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)]\ 293 .event = a; \ 294 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 295 wmi_mgmt_event_log_buf_info.buf) \ 296 [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\ 297 data, b, wmi_record_max_length); \ 298 ((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\ 299 [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\ 300 time = qdf_get_log_timestamp(); \ 301 (*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))++; \ 302 h->log_info.wmi_mgmt_event_log_buf_info.length++; \ 303 } while (0); 304 305 #define WMI_DIAG_RX_EVENT_RECORD(h, a, b) do { \ 306 if (wmi_diag_log_max_entry <= \ 307 *(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx))\ 308 *(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx) = 0;\ 309 ((struct wmi_event_debug *)h->log_info.wmi_diag_event_log_buf_info.buf)\ 310 [*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)]\ 311 .event = a; \ 312 qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ 313 wmi_diag_event_log_buf_info.buf) \ 314 [*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)].\ 315 data, b, wmi_record_max_length); \ 316 ((struct wmi_event_debug *)h->log_info.wmi_diag_event_log_buf_info.buf)\ 317 [*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)].\ 318 time = qdf_get_log_timestamp(); \ 319 (*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx))++; \ 320 h->log_info.wmi_diag_event_log_buf_info.length++; \ 321 } while (0); 322 323 /* These are defined to made it as module param, which can be configured */ 324 uint32_t wmi_log_max_entry = WMI_EVENT_DEBUG_MAX_ENTRY; 325 uint32_t wmi_mgmt_log_max_entry = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; 326 uint32_t wmi_diag_log_max_entry = WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY; 327 uint32_t wmi_record_max_length = WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH; 328 uint32_t wmi_display_size = 100; 329 330 #ifdef WMI_EXT_DBG 331 332 /** 333 * wmi_ext_dbg_msg_enqueue() - enqueue wmi message 334 * 335 * @wmi_handle: wmi handler 336 * 337 * Return: size of wmi message queue after enqueue 338 */ 339 static uint32_t wmi_ext_dbg_msg_enqueue(struct wmi_unified *wmi_handle, 340 struct wmi_ext_dbg_msg *msg) 341 { 342 uint32_t list_size; 343 344 qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 345 qdf_list_insert_back_size(&wmi_handle->wmi_ext_dbg_msg_queue, 346 &msg->node, &list_size); 347 qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 348 349 return list_size; 350 } 351 352 /** 353 * wmi_ext_dbg_msg_dequeue() - dequeue wmi message 354 * 355 * @wmi_handle: wmi handler 356 * 357 * Return: wmi msg on success else NULL 358 */ 359 static struct wmi_ext_dbg_msg *wmi_ext_dbg_msg_dequeue(struct wmi_unified 360 *wmi_handle) 361 { 362 qdf_list_node_t *list_node = NULL; 363 364 qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 365 qdf_list_remove_front(&wmi_handle->wmi_ext_dbg_msg_queue, &list_node); 366 qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 367 368 if (!list_node) 369 return NULL; 370 371 return qdf_container_of(list_node, struct wmi_ext_dbg_msg, node); 372 } 373 374 /** 375 * wmi_ext_dbg_msg_record() - record wmi messages 376 * 377 * @wmi_handle: wmi handler 378 * @buf: wmi message buffer 379 * @len: wmi message length 380 * @type: wmi message type 381 * 382 * Return: QDF_STATUS_SUCCESS on successful recording else failure. 383 */ 384 static QDF_STATUS wmi_ext_dbg_msg_record(struct wmi_unified *wmi_handle, 385 uint8_t *buf, uint32_t len, 386 enum WMI_MSG_TYPE type) 387 { 388 struct wmi_ext_dbg_msg *msg; 389 uint32_t list_size; 390 391 msg = wmi_ext_dbg_msg_get(len); 392 if (!msg) 393 return QDF_STATUS_E_NOMEM; 394 395 msg->len = len; 396 msg->type = type; 397 qdf_mem_copy(msg->buf, buf, len); 398 msg->ts = qdf_get_log_timestamp(); 399 list_size = wmi_ext_dbg_msg_enqueue(wmi_handle, msg); 400 401 if (list_size >= wmi_handle->wmi_ext_dbg_msg_queue_size) { 402 msg = wmi_ext_dbg_msg_dequeue(wmi_handle); 403 wmi_ext_dbg_msg_put(msg); 404 } 405 406 return QDF_STATUS_SUCCESS; 407 } 408 409 /** 410 * wmi_ext_dbg_msg_cmd_record() - record wmi command messages 411 * 412 * @wmi_handle: wmi handler 413 * @buf: wmi command buffer 414 * @len: wmi command message length 415 * 416 * Return: QDF_STATUS_SUCCESS on successful recording else failure. 417 */ 418 static QDF_STATUS wmi_ext_dbg_msg_cmd_record(struct wmi_unified *wmi_handle, 419 uint8_t *buf, uint32_t len) 420 { 421 return wmi_ext_dbg_msg_record(wmi_handle, buf, len, 422 WMI_MSG_TYPE_CMD); 423 } 424 425 /** 426 * wmi_ext_dbg_msg_event_record() - record wmi event messages 427 * 428 * @wmi_handle: wmi handler 429 * @buf: wmi event buffer 430 * @len: wmi event message length 431 * 432 * Return: QDF_STATUS_SUCCESS on successful recording else failure. 433 */ 434 static QDF_STATUS wmi_ext_dbg_msg_event_record(struct wmi_unified *wmi_handle, 435 uint8_t *buf, uint32_t len) 436 { 437 uint32_t id; 438 439 id = WMI_GET_FIELD(buf, WMI_CMD_HDR, COMMANDID); 440 if (id != wmi_handle->wmi_events[wmi_diag_event_id]) 441 return wmi_ext_dbg_msg_record(wmi_handle, buf, len, 442 WMI_MSG_TYPE_EVENT); 443 444 return QDF_STATUS_SUCCESS; 445 } 446 447 /** 448 * wmi_ext_dbg_msg_queue_init() - create debugfs queue and associated lock 449 * 450 * @wmi_handle: wmi handler 451 * 452 * Return: none 453 */ 454 static void wmi_ext_dbg_msg_queue_init(struct wmi_unified *wmi_handle) 455 { 456 qdf_list_create(&wmi_handle->wmi_ext_dbg_msg_queue, 457 wmi_handle->wmi_ext_dbg_msg_queue_size); 458 qdf_spinlock_create(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 459 } 460 461 /** 462 * wmi_ext_dbg_msg_queue_deinit() - destroy debugfs queue and associated lock 463 * 464 * @wmi_handle: wmi handler 465 * 466 * Return: none 467 */ 468 static void wmi_ext_dbg_msg_queue_deinit(struct wmi_unified *wmi_handle) 469 { 470 qdf_list_destroy(&wmi_handle->wmi_ext_dbg_msg_queue); 471 qdf_spinlock_destroy(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 472 } 473 474 /** 475 * wmi_ext_dbg_msg_show() - debugfs function to display whole content of 476 * wmi command/event messages including headers. 477 * 478 * @file: qdf debugfs file handler 479 * @arg: pointer to wmi handler 480 * 481 * Return: QDF_STATUS_SUCCESS if all the messages are shown successfully, 482 * else QDF_STATUS_E_AGAIN if more data to show. 483 */ 484 static QDF_STATUS wmi_ext_dbg_msg_show(qdf_debugfs_file_t file, void *arg) 485 { 486 struct wmi_unified *wmi_handle = (struct wmi_unified *)arg; 487 struct wmi_ext_dbg_msg *msg; 488 uint64_t secs, usecs; 489 490 msg = wmi_ext_dbg_msg_dequeue(wmi_handle); 491 if (!msg) 492 return QDF_STATUS_SUCCESS; 493 494 qdf_debugfs_printf(file, "%s: 0x%x\n", 495 msg->type == WMI_MSG_TYPE_CMD ? "COMMAND" : 496 "EVENT", WMI_GET_FIELD(msg->buf, WMI_CMD_HDR, 497 COMMANDID)); 498 qdf_log_timestamp_to_secs(msg->ts, &secs, &usecs); 499 qdf_debugfs_printf(file, "Time: %llu.%llu\n", secs, usecs); 500 qdf_debugfs_printf(file, "Length:%d\n", msg->len); 501 qdf_debugfs_hexdump(file, msg->buf, msg->len, 502 WMI_EXT_DBG_DUMP_ROW_SIZE, 503 WMI_EXT_DBG_DUMP_GROUP_SIZE); 504 qdf_debugfs_printf(file, "\n"); 505 506 if (qdf_debugfs_overflow(file)) { 507 qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 508 qdf_list_insert_front(&wmi_handle->wmi_ext_dbg_msg_queue, 509 &msg->node); 510 qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock); 511 512 } else { 513 wmi_ext_dbg_msg_put(msg); 514 } 515 516 return QDF_STATUS_E_AGAIN; 517 } 518 519 /** 520 * wmi_ext_dbg_msg_write() - debugfs write not supported 521 * 522 * @priv: private data 523 * @buf: received data buffer 524 * @len: length of received buffer 525 * 526 * Return: QDF_STATUS_E_NOSUPPORT. 527 */ 528 static QDF_STATUS wmi_ext_dbg_msg_write(void *priv, const char *buf, 529 qdf_size_t len) 530 { 531 return QDF_STATUS_E_NOSUPPORT; 532 } 533 534 static struct qdf_debugfs_fops wmi_ext_dbgfs_ops = { 535 .show = wmi_ext_dbg_msg_show, 536 .write = wmi_ext_dbg_msg_write, 537 .priv = NULL, 538 }; 539 540 /** 541 * wmi_ext_debugfs_init() - init debugfs items for extended wmi dump. 542 * 543 * @wmi_handle: wmi handler 544 * 545 * Return: QDF_STATUS_SUCCESS if debugfs is initialized else 546 * QDF_STATUS_E_FAILURE 547 */ 548 static QDF_STATUS wmi_ext_dbgfs_init(struct wmi_unified *wmi_handle) 549 { 550 qdf_dentry_t dentry; 551 552 dentry = qdf_debugfs_create_dir(WMI_EXT_DBG_DIR, NULL); 553 if (!dentry) { 554 WMI_LOGE("error while creating extended wmi debugfs dir"); 555 return QDF_STATUS_E_FAILURE; 556 } 557 558 wmi_ext_dbgfs_ops.priv = wmi_handle; 559 if (!qdf_debugfs_create_file(WMI_EXT_DBG_FILE, WMI_EXT_DBG_FILE_PERM, 560 dentry, &wmi_ext_dbgfs_ops)) { 561 qdf_debugfs_remove_dir(dentry); 562 WMI_LOGE("error while creating extended wmi debugfs file"); 563 return QDF_STATUS_E_FAILURE; 564 } 565 566 wmi_handle->wmi_ext_dbg_dentry = dentry; 567 wmi_handle->wmi_ext_dbg_msg_queue_size = WMI_EXT_DBG_QUEUE_SIZE; 568 wmi_ext_dbg_msg_queue_init(wmi_handle); 569 570 return QDF_STATUS_SUCCESS; 571 } 572 573 /** 574 * wmi_ext_debugfs_deinit() - cleanup/deinit debugfs items of extended wmi dump. 575 * 576 * @wmi_handle: wmi handler 577 * 578 * Return: QDF_STATUS_SUCCESS if cleanup is successful 579 */ 580 static QDF_STATUS wmi_ext_dbgfs_deinit(struct wmi_unified *wmi_handle) 581 { 582 struct wmi_ext_dbg_msg *msg; 583 584 while ((msg = wmi_ext_dbg_msg_dequeue(wmi_handle))) 585 wmi_ext_dbg_msg_put(msg); 586 587 wmi_ext_dbg_msg_queue_deinit(wmi_handle); 588 qdf_debugfs_remove_dir_recursive(wmi_handle->wmi_ext_dbg_dentry); 589 590 return QDF_STATUS_SUCCESS; 591 } 592 593 #endif /*WMI_EXT_DBG */ 594 595 /** 596 * wmi_log_init() - Initialize WMI event logging 597 * @wmi_handle: WMI handle. 598 * 599 * Return: Initialization status 600 */ 601 #ifndef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC 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 #ifdef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC 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 #ifndef WMI_CMD_STRINGS 1612 static uint8_t *wmi_id_to_name(uint32_t wmi_command) 1613 { 1614 return "Invalid WMI cmd"; 1615 } 1616 #endif 1617 1618 static inline void wmi_log_cmd_id(uint32_t cmd_id, uint32_t tag) 1619 { 1620 WMI_LOGD("Send WMI command:%s command_id:%d htc_tag:%d\n", 1621 wmi_id_to_name(cmd_id), cmd_id, tag); 1622 } 1623 1624 /** 1625 * wmi_is_pm_resume_cmd() - check if a cmd is part of the resume sequence 1626 * @cmd_id: command to check 1627 * 1628 * Return: true if the command is part of the resume sequence. 1629 */ 1630 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD 1631 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id) 1632 { 1633 switch (cmd_id) { 1634 case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID: 1635 case WMI_PDEV_RESUME_CMDID: 1636 return true; 1637 1638 default: 1639 return false; 1640 } 1641 } 1642 1643 #else 1644 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id) 1645 { 1646 return false; 1647 } 1648 1649 #endif 1650 1651 #ifdef FEATURE_WLAN_D0WOW 1652 static bool wmi_is_legacy_d0wow_disable_cmd(wmi_buf_t buf, uint32_t cmd_id) 1653 { 1654 wmi_d0_wow_enable_disable_cmd_fixed_param *cmd; 1655 1656 if (cmd_id == WMI_D0_WOW_ENABLE_DISABLE_CMDID) { 1657 cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *) 1658 wmi_buf_data(buf); 1659 if (!cmd->enable) 1660 return true; 1661 else 1662 return false; 1663 } 1664 1665 return false; 1666 } 1667 #else 1668 static bool wmi_is_legacy_d0wow_disable_cmd(wmi_buf_t buf, uint32_t cmd_id) 1669 { 1670 return false; 1671 } 1672 1673 #endif 1674 1675 static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle) 1676 { 1677 wmi_nofl_err("Endpoint ID = %d, Tx Queue Depth = %d, soc_id = %u, target type = %s", 1678 wmi_handle->wmi_endpoint_id, 1679 htc_get_tx_queue_depth(wmi_handle->htc_handle, 1680 wmi_handle->wmi_endpoint_id), 1681 wmi_handle->soc->soc_idx, 1682 (wmi_handle->target_type == 1683 WMI_TLV_TARGET ? "WMI_TLV_TARGET" : 1684 "WMI_NON_TLV_TARGET")); 1685 } 1686 1687 #ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI 1688 QDF_STATUS wmi_unified_cmd_send_over_qmi(struct wmi_unified *wmi_handle, 1689 wmi_buf_t buf, uint32_t buflen, 1690 uint32_t cmd_id) 1691 { 1692 QDF_STATUS status; 1693 int32_t ret; 1694 1695 if (!qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR))) { 1696 wmi_err("Failed to send cmd %x, no memory", cmd_id); 1697 return QDF_STATUS_E_NOMEM; 1698 } 1699 1700 qdf_mem_zero(qdf_nbuf_data(buf), sizeof(WMI_CMD_HDR)); 1701 WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id); 1702 wmi_debug("Sending WMI_CMD_ID: %d over qmi", cmd_id); 1703 status = qdf_wmi_send_recv_qmi(qdf_nbuf_data(buf), 1704 buflen + sizeof(WMI_CMD_HDR), 1705 wmi_handle, 1706 wmi_process_qmi_fw_event); 1707 if (QDF_IS_STATUS_ERROR(status)) { 1708 qdf_nbuf_pull_head(buf, sizeof(WMI_CMD_HDR)); 1709 wmi_warn("WMI send on QMI failed. Retrying WMI on HTC"); 1710 } else { 1711 ret = qdf_atomic_inc_return(&wmi_handle->num_stats_over_qmi); 1712 wmi_debug("num stats over qmi: %d", ret); 1713 wmi_buf_free(buf); 1714 } 1715 1716 return status; 1717 } 1718 1719 static int __wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len) 1720 { 1721 struct wmi_unified *wmi_handle = wmi_cb_ctx; 1722 wmi_buf_t evt_buf; 1723 uint32_t evt_id; 1724 1725 if (!wmi_handle || !buf) 1726 return -EINVAL; 1727 1728 evt_buf = wmi_buf_alloc(wmi_handle, len); 1729 if (!evt_buf) 1730 return -ENOMEM; 1731 1732 qdf_mem_copy(qdf_nbuf_data(evt_buf), buf, len); 1733 evt_id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); 1734 wmi_debug("Received WMI_EVT_ID: %d over qmi", evt_id); 1735 wmi_process_fw_event(wmi_handle, evt_buf); 1736 1737 return 0; 1738 } 1739 1740 int wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len) 1741 { 1742 struct qdf_op_sync *op_sync; 1743 int ret; 1744 1745 if (qdf_op_protect(&op_sync)) 1746 return -EINVAL; 1747 ret = __wmi_process_qmi_fw_event(wmi_cb_ctx, buf, len); 1748 qdf_op_unprotect(op_sync); 1749 1750 return ret; 1751 } 1752 #endif 1753 1754 QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, 1755 uint32_t len, uint32_t cmd_id, 1756 const char *func, uint32_t line) 1757 { 1758 HTC_PACKET *pkt; 1759 QDF_STATUS status; 1760 uint16_t htc_tag = 0; 1761 1762 if (wmi_get_runtime_pm_inprogress(wmi_handle)) { 1763 htc_tag = wmi_handle->ops->wmi_set_htc_tx_tag(wmi_handle, buf, 1764 cmd_id); 1765 } else if (qdf_atomic_read(&wmi_handle->is_target_suspended) && 1766 !wmi_is_pm_resume_cmd(cmd_id) && 1767 !wmi_is_legacy_d0wow_disable_cmd(buf, cmd_id)) { 1768 wmi_nofl_err("Target is suspended (via %s:%u)", 1769 func, line); 1770 return QDF_STATUS_E_BUSY; 1771 } 1772 1773 if (wmi_handle->wmi_stopinprogress) { 1774 wmi_nofl_err("%s:%d, WMI stop in progress, wmi_handle:%pK", 1775 func, line, wmi_handle); 1776 return QDF_STATUS_E_INVAL; 1777 } 1778 1779 #ifndef WMI_NON_TLV_SUPPORT 1780 /* Do sanity check on the TLV parameter structure */ 1781 if (wmi_handle->target_type == WMI_TLV_TARGET) { 1782 void *buf_ptr = (void *)qdf_nbuf_data(buf); 1783 1784 if (wmi_handle->ops->wmi_check_command_params(NULL, buf_ptr, len, cmd_id) 1785 != 0) { 1786 wmi_nofl_err("%s:%d, Invalid WMI Param Buffer for Cmd:%d", 1787 func, line, cmd_id); 1788 return QDF_STATUS_E_INVAL; 1789 } 1790 } 1791 #endif 1792 1793 if (qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR)) == NULL) { 1794 wmi_nofl_err("%s:%d, Failed to send cmd %x, no memory", 1795 func, line, cmd_id); 1796 return QDF_STATUS_E_NOMEM; 1797 } 1798 1799 qdf_mem_zero(qdf_nbuf_data(buf), sizeof(WMI_CMD_HDR)); 1800 WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id); 1801 1802 qdf_atomic_inc(&wmi_handle->pending_cmds); 1803 if (qdf_atomic_read(&wmi_handle->pending_cmds) >= 1804 wmi_handle->wmi_max_cmds) { 1805 wmi_nofl_err("hostcredits = %d", 1806 wmi_get_host_credits(wmi_handle)); 1807 htc_dump_counter_info(wmi_handle->htc_handle); 1808 qdf_atomic_dec(&wmi_handle->pending_cmds); 1809 wmi_nofl_err("%s:%d, MAX %d WMI Pending cmds reached", 1810 func, line, wmi_handle->wmi_max_cmds); 1811 wmi_unified_debug_dump(wmi_handle); 1812 htc_ce_tasklet_debug_dump(wmi_handle->htc_handle); 1813 qdf_trigger_self_recovery(QDF_WMI_EXCEED_MAX_PENDING_CMDS); 1814 return QDF_STATUS_E_BUSY; 1815 } 1816 1817 pkt = qdf_mem_malloc_fl(sizeof(*pkt), func, line); 1818 if (!pkt) { 1819 qdf_atomic_dec(&wmi_handle->pending_cmds); 1820 return QDF_STATUS_E_NOMEM; 1821 } 1822 1823 SET_HTC_PACKET_INFO_TX(pkt, 1824 NULL, 1825 qdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR), 1826 wmi_handle->wmi_endpoint_id, htc_tag); 1827 1828 SET_HTC_PACKET_NET_BUF_CONTEXT(pkt, buf); 1829 wmi_log_cmd_id(cmd_id, htc_tag); 1830 wmi_ext_dbg_msg_cmd_record(wmi_handle, 1831 qdf_nbuf_data(buf), qdf_nbuf_len(buf)); 1832 #ifdef WMI_INTERFACE_EVENT_LOGGING 1833 if (wmi_handle->log_info.wmi_logging_enable) { 1834 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 1835 /* 1836 * Record 16 bytes of WMI cmd data - 1837 * exclude TLV and WMI headers 1838 * 1839 * WMI mgmt command already recorded in wmi_mgmt_cmd_record 1840 */ 1841 if (wmi_handle->ops->is_management_record(cmd_id) == false) { 1842 WMI_COMMAND_RECORD(wmi_handle, cmd_id, 1843 qdf_nbuf_data(buf) + 1844 wmi_handle->soc->buf_offset_command); 1845 } 1846 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 1847 } 1848 #endif 1849 1850 status = htc_send_pkt(wmi_handle->htc_handle, pkt); 1851 1852 if (QDF_STATUS_SUCCESS != status) { 1853 qdf_atomic_dec(&wmi_handle->pending_cmds); 1854 wmi_nofl_err("%s:%d, htc_send_pkt failed, status:%d", 1855 func, line, status); 1856 qdf_mem_free(pkt); 1857 return status; 1858 } 1859 1860 return QDF_STATUS_SUCCESS; 1861 } 1862 qdf_export_symbol(wmi_unified_cmd_send_fl); 1863 1864 /** 1865 * wmi_unified_get_event_handler_ix() - gives event handler's index 1866 * @wmi_handle: handle to wmi 1867 * @event_id: wmi event id 1868 * 1869 * Return: event handler's index 1870 */ 1871 static int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle, 1872 uint32_t event_id) 1873 { 1874 uint32_t idx = 0; 1875 int32_t invalid_idx = -1; 1876 struct wmi_soc *soc = wmi_handle->soc; 1877 1878 for (idx = 0; (idx < soc->max_event_idx && 1879 idx < WMI_UNIFIED_MAX_EVENT); ++idx) { 1880 if (wmi_handle->event_id[idx] == event_id && 1881 wmi_handle->event_handler[idx]) { 1882 return idx; 1883 } 1884 } 1885 1886 return invalid_idx; 1887 } 1888 1889 /** 1890 * wmi_unified_register_event() - register wmi event handler 1891 * @wmi_handle: handle to wmi 1892 * @event_id: wmi event id 1893 * @handler_func: wmi event handler function 1894 * 1895 * Return: 0 on success 1896 */ 1897 int wmi_unified_register_event(wmi_unified_t wmi_handle, 1898 uint32_t event_id, 1899 wmi_unified_event_handler handler_func) 1900 { 1901 uint32_t idx = 0; 1902 uint32_t evt_id; 1903 struct wmi_soc *soc; 1904 1905 if (!wmi_handle) { 1906 WMI_LOGE("WMI handle is NULL"); 1907 return QDF_STATUS_E_FAILURE; 1908 } 1909 1910 soc = wmi_handle->soc; 1911 1912 if (event_id >= wmi_events_max || 1913 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 1914 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1915 "%s: Event id %d is unavailable", 1916 __func__, event_id); 1917 return QDF_STATUS_E_FAILURE; 1918 } 1919 evt_id = wmi_handle->wmi_events[event_id]; 1920 if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) { 1921 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1922 "%s : event handler already registered 0x%x", 1923 __func__, evt_id); 1924 return QDF_STATUS_E_FAILURE; 1925 } 1926 if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) { 1927 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1928 "%s : no more event handlers 0x%x", 1929 __func__, evt_id); 1930 return QDF_STATUS_E_FAILURE; 1931 } 1932 idx = soc->max_event_idx; 1933 wmi_handle->event_handler[idx] = handler_func; 1934 wmi_handle->event_id[idx] = evt_id; 1935 qdf_spin_lock_bh(&soc->ctx_lock); 1936 wmi_handle->ctx[idx] = WMI_RX_UMAC_CTX; 1937 qdf_spin_unlock_bh(&soc->ctx_lock); 1938 soc->max_event_idx++; 1939 1940 return 0; 1941 } 1942 1943 /** 1944 * wmi_unified_register_event_handler() - register wmi event handler 1945 * @wmi_handle: handle to wmi 1946 * @event_id: wmi event id 1947 * @handler_func: wmi event handler function 1948 * @rx_ctx: rx execution context for wmi rx events 1949 * 1950 * This API is to support legacy requirements. Will be deprecated in future. 1951 * Return: 0 on success 1952 */ 1953 int wmi_unified_register_event_handler(wmi_unified_t wmi_handle, 1954 wmi_conv_event_id event_id, 1955 wmi_unified_event_handler handler_func, 1956 uint8_t rx_ctx) 1957 { 1958 uint32_t idx = 0; 1959 uint32_t evt_id; 1960 struct wmi_soc *soc; 1961 1962 if (!wmi_handle) { 1963 WMI_LOGE("WMI handle is NULL"); 1964 return QDF_STATUS_E_FAILURE; 1965 } 1966 1967 soc = wmi_handle->soc; 1968 1969 if (event_id >= wmi_events_max || 1970 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 1971 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 1972 "%s: Event id %d is unavailable", 1973 __func__, event_id); 1974 return QDF_STATUS_E_FAILURE; 1975 } 1976 evt_id = wmi_handle->wmi_events[event_id]; 1977 1978 if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) { 1979 WMI_LOGE("event handler already registered 0x%x", 1980 evt_id); 1981 return QDF_STATUS_E_FAILURE; 1982 } 1983 if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) { 1984 WMI_LOGE("no more event handlers 0x%x", 1985 evt_id); 1986 return QDF_STATUS_E_FAILURE; 1987 } 1988 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, 1989 "Registered event handler for event 0x%8x", evt_id); 1990 idx = soc->max_event_idx; 1991 wmi_handle->event_handler[idx] = handler_func; 1992 wmi_handle->event_id[idx] = evt_id; 1993 qdf_spin_lock_bh(&soc->ctx_lock); 1994 wmi_handle->ctx[idx] = rx_ctx; 1995 qdf_spin_unlock_bh(&soc->ctx_lock); 1996 soc->max_event_idx++; 1997 1998 return 0; 1999 } 2000 qdf_export_symbol(wmi_unified_register_event_handler); 2001 2002 /** 2003 * wmi_unified_unregister_event() - unregister wmi event handler 2004 * @wmi_handle: handle to wmi 2005 * @event_id: wmi event id 2006 * 2007 * Return: 0 on success 2008 */ 2009 int wmi_unified_unregister_event(wmi_unified_t wmi_handle, 2010 uint32_t event_id) 2011 { 2012 uint32_t idx = 0; 2013 uint32_t evt_id; 2014 struct wmi_soc *soc = wmi_handle->soc; 2015 2016 if (event_id >= wmi_events_max || 2017 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 2018 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 2019 "%s: Event id %d is unavailable", 2020 __func__, event_id); 2021 return QDF_STATUS_E_FAILURE; 2022 } 2023 evt_id = wmi_handle->wmi_events[event_id]; 2024 2025 idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id); 2026 if (idx == -1) { 2027 WMI_LOGE("event handler is not registered: evt id 0x%x", 2028 evt_id); 2029 return QDF_STATUS_E_FAILURE; 2030 } 2031 wmi_handle->event_handler[idx] = NULL; 2032 wmi_handle->event_id[idx] = 0; 2033 --soc->max_event_idx; 2034 wmi_handle->event_handler[idx] = 2035 wmi_handle->event_handler[soc->max_event_idx]; 2036 wmi_handle->event_id[idx] = 2037 wmi_handle->event_id[soc->max_event_idx]; 2038 2039 return 0; 2040 } 2041 2042 /** 2043 * wmi_unified_unregister_event_handler() - unregister wmi event handler 2044 * @wmi_handle: handle to wmi 2045 * @event_id: wmi event id 2046 * 2047 * Return: 0 on success 2048 */ 2049 int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, 2050 wmi_conv_event_id event_id) 2051 { 2052 uint32_t idx = 0; 2053 uint32_t evt_id; 2054 struct wmi_soc *soc; 2055 2056 if (!wmi_handle) { 2057 WMI_LOGE("WMI handle is NULL"); 2058 return QDF_STATUS_E_FAILURE; 2059 } 2060 2061 soc = wmi_handle->soc; 2062 2063 if (event_id >= wmi_events_max || 2064 wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { 2065 WMI_LOGE("Event id %d is unavailable", 2066 event_id); 2067 return QDF_STATUS_E_FAILURE; 2068 } 2069 evt_id = wmi_handle->wmi_events[event_id]; 2070 2071 idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id); 2072 if (idx == -1) { 2073 WMI_LOGE("event handler is not registered: evt id 0x%x", 2074 evt_id); 2075 return QDF_STATUS_E_FAILURE; 2076 } 2077 wmi_handle->event_handler[idx] = NULL; 2078 wmi_handle->event_id[idx] = 0; 2079 --soc->max_event_idx; 2080 wmi_handle->event_handler[idx] = 2081 wmi_handle->event_handler[soc->max_event_idx]; 2082 wmi_handle->event_id[idx] = 2083 wmi_handle->event_id[soc->max_event_idx]; 2084 2085 return 0; 2086 } 2087 qdf_export_symbol(wmi_unified_unregister_event_handler); 2088 2089 void wmi_process_fw_event_worker_thread_ctx(struct wmi_unified *wmi_handle, 2090 void *evt_buf) 2091 { 2092 2093 qdf_spin_lock_bh(&wmi_handle->eventq_lock); 2094 qdf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf); 2095 qdf_spin_unlock_bh(&wmi_handle->eventq_lock); 2096 qdf_queue_work(0, wmi_handle->wmi_rx_work_queue, 2097 &wmi_handle->rx_event_work); 2098 2099 return; 2100 } 2101 2102 qdf_export_symbol(wmi_process_fw_event_worker_thread_ctx); 2103 2104 uint32_t wmi_critical_events_in_flight(struct wmi_unified *wmi) 2105 { 2106 return qdf_atomic_read(&wmi->critical_events_in_flight); 2107 } 2108 2109 static bool 2110 wmi_is_event_critical(struct wmi_unified *wmi_handle, uint32_t event_id) 2111 { 2112 if (wmi_handle->wmi_events[wmi_roam_synch_event_id] == event_id) 2113 return true; 2114 2115 return false; 2116 } 2117 2118 static void wmi_discard_fw_event(struct scheduler_msg *msg) 2119 { 2120 struct wmi_process_fw_event_params *event_param; 2121 2122 if (!msg->bodyptr) 2123 return; 2124 2125 event_param = (struct wmi_process_fw_event_params *)msg->bodyptr; 2126 qdf_nbuf_free(event_param->evt_buf); 2127 qdf_mem_free(msg->bodyptr); 2128 msg->bodyptr = NULL; 2129 msg->bodyval = 0; 2130 msg->type = 0; 2131 } 2132 2133 static int wmi_process_fw_event_handler(struct scheduler_msg *msg) 2134 { 2135 struct wmi_process_fw_event_params *params = 2136 (struct wmi_process_fw_event_params *)msg->bodyptr; 2137 struct wmi_unified *wmi_handle; 2138 uint32_t event_id; 2139 2140 wmi_handle = (struct wmi_unified *)params->wmi_handle; 2141 event_id = WMI_GET_FIELD(qdf_nbuf_data(params->evt_buf), 2142 WMI_CMD_HDR, COMMANDID); 2143 wmi_process_fw_event(wmi_handle, params->evt_buf); 2144 2145 if (wmi_is_event_critical(wmi_handle, event_id)) 2146 qdf_atomic_dec(&wmi_handle->critical_events_in_flight); 2147 2148 qdf_mem_free(msg->bodyptr); 2149 2150 return 0; 2151 } 2152 2153 /** 2154 * wmi_process_fw_event_sched_thread_ctx() - common event handler to serialize 2155 * event processing through scheduler thread 2156 * @ctx: wmi context 2157 * @ev: event buffer 2158 * @rx_ctx: rx execution context 2159 * 2160 * Return: 0 on success, errno on failure 2161 */ 2162 static QDF_STATUS 2163 wmi_process_fw_event_sched_thread_ctx(struct wmi_unified *wmi, 2164 void *ev) 2165 { 2166 struct wmi_process_fw_event_params *params_buf; 2167 struct scheduler_msg msg = { 0 }; 2168 uint32_t event_id; 2169 struct target_psoc_info *tgt_hdl; 2170 bool is_wmi_ready = false; 2171 struct wlan_objmgr_psoc *psoc; 2172 2173 psoc = target_if_get_psoc_from_scn_hdl(wmi->scn_handle); 2174 if (!psoc) { 2175 target_if_err("psoc is null"); 2176 qdf_nbuf_free(ev); 2177 return QDF_STATUS_E_INVAL; 2178 } 2179 2180 tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); 2181 if (!tgt_hdl) { 2182 wmi_err("target_psoc_info is null"); 2183 qdf_nbuf_free(ev); 2184 return QDF_STATUS_E_INVAL; 2185 } 2186 2187 is_wmi_ready = target_psoc_get_wmi_ready(tgt_hdl); 2188 if (!is_wmi_ready) { 2189 wmi_debug("fw event recvd before ready event processed"); 2190 wmi_debug("therefore use worker thread"); 2191 wmi_process_fw_event_worker_thread_ctx(wmi, ev); 2192 return QDF_STATUS_E_INVAL; 2193 } 2194 2195 params_buf = qdf_mem_malloc(sizeof(struct wmi_process_fw_event_params)); 2196 if (!params_buf) { 2197 wmi_err("malloc failed"); 2198 qdf_nbuf_free(ev); 2199 return QDF_STATUS_E_NOMEM; 2200 } 2201 2202 params_buf->wmi_handle = wmi; 2203 params_buf->evt_buf = ev; 2204 2205 event_id = WMI_GET_FIELD(qdf_nbuf_data(params_buf->evt_buf), 2206 WMI_CMD_HDR, COMMANDID); 2207 if (wmi_is_event_critical(wmi, event_id)) 2208 qdf_atomic_inc(&wmi->critical_events_in_flight); 2209 2210 msg.bodyptr = params_buf; 2211 msg.bodyval = 0; 2212 msg.callback = wmi_process_fw_event_handler; 2213 msg.flush_callback = wmi_discard_fw_event; 2214 2215 if (QDF_STATUS_SUCCESS != 2216 scheduler_post_message(QDF_MODULE_ID_TARGET_IF, 2217 QDF_MODULE_ID_TARGET_IF, 2218 QDF_MODULE_ID_TARGET_IF, &msg)) { 2219 qdf_nbuf_free(ev); 2220 qdf_mem_free(params_buf); 2221 return QDF_STATUS_E_FAULT; 2222 } 2223 2224 return QDF_STATUS_SUCCESS; 2225 } 2226 2227 /** 2228 * wmi_get_pdev_ep: Get wmi handle based on endpoint 2229 * @soc: handle to wmi soc 2230 * @ep: endpoint id 2231 * 2232 * Return: none 2233 */ 2234 static struct wmi_unified *wmi_get_pdev_ep(struct wmi_soc *soc, 2235 HTC_ENDPOINT_ID ep) 2236 { 2237 uint32_t i; 2238 2239 for (i = 0; i < WMI_MAX_RADIOS; i++) 2240 if (soc->wmi_endpoint_id[i] == ep) 2241 break; 2242 2243 if (i == WMI_MAX_RADIOS) 2244 return NULL; 2245 2246 return soc->wmi_pdev[i]; 2247 } 2248 2249 /** 2250 * wmi_mtrace_rx() - Wrappper function for qdf_mtrace api 2251 * @message_id: 32-Bit Wmi message ID 2252 * @vdev_id: Vdev ID 2253 * @data: Actual message contents 2254 * 2255 * This function converts the 32-bit WMI message ID in 15-bit message ID 2256 * format for qdf_mtrace as in qdf_mtrace message there are only 15 2257 * bits reserved for message ID. 2258 * out of these 15-bits, 8-bits (From LSB) specifies the WMI_GRP_ID 2259 * and remaining 7-bits specifies the actual WMI command. With this 2260 * notation there can be maximum 256 groups and each group can have 2261 * max 128 commands can be supported. 2262 * 2263 * Return: None 2264 */ 2265 static void wmi_mtrace_rx(uint32_t message_id, uint16_t vdev_id, uint32_t data) 2266 { 2267 uint16_t mtrace_message_id; 2268 2269 mtrace_message_id = QDF_WMI_MTRACE_CMD_ID(message_id) | 2270 (QDF_WMI_MTRACE_GRP_ID(message_id) << 2271 QDF_WMI_MTRACE_CMD_NUM_BITS); 2272 qdf_mtrace(QDF_MODULE_ID_WMI, QDF_MODULE_ID_WMA, 2273 mtrace_message_id, vdev_id, data); 2274 } 2275 2276 /** 2277 * wmi_control_rx() - process fw events callbacks 2278 * @ctx: handle to wmi 2279 * @htc_packet: pointer to htc packet 2280 * 2281 * Return: none 2282 */ 2283 static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) 2284 { 2285 struct wmi_soc *soc = (struct wmi_soc *) ctx; 2286 struct wmi_unified *wmi_handle; 2287 wmi_buf_t evt_buf; 2288 uint32_t id; 2289 uint32_t idx = 0; 2290 enum wmi_rx_exec_ctx exec_ctx; 2291 2292 evt_buf = (wmi_buf_t) htc_packet->pPktContext; 2293 2294 wmi_handle = wmi_get_pdev_ep(soc, htc_packet->Endpoint); 2295 if (!wmi_handle) { 2296 WMI_LOGE 2297 ("unable to get wmi_handle to Endpoint %d\n", 2298 htc_packet->Endpoint); 2299 qdf_nbuf_free(evt_buf); 2300 return; 2301 } 2302 2303 id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); 2304 idx = wmi_unified_get_event_handler_ix(wmi_handle, id); 2305 if (qdf_unlikely(idx == A_ERROR)) { 2306 wmi_debug("no handler registered for event id 0x%x", id); 2307 qdf_nbuf_free(evt_buf); 2308 return; 2309 } 2310 wmi_mtrace_rx(id, 0xFF, idx); 2311 qdf_spin_lock_bh(&soc->ctx_lock); 2312 exec_ctx = wmi_handle->ctx[idx]; 2313 qdf_spin_unlock_bh(&soc->ctx_lock); 2314 2315 #ifdef WMI_INTERFACE_EVENT_LOGGING 2316 if (wmi_handle->log_info.wmi_logging_enable) { 2317 uint8_t *data; 2318 data = qdf_nbuf_data(evt_buf); 2319 2320 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 2321 /* Exclude 4 bytes of TLV header */ 2322 if (wmi_handle->ops->is_diag_event(id)) { 2323 WMI_DIAG_RX_EVENT_RECORD(wmi_handle, id, 2324 ((uint8_t *) data + 2325 wmi_handle->soc->buf_offset_event)); 2326 } else if (wmi_handle->ops->is_management_record(id)) { 2327 WMI_MGMT_RX_EVENT_RECORD(wmi_handle, id, 2328 ((uint8_t *) data + 2329 wmi_handle->soc->buf_offset_event)); 2330 } else { 2331 WMI_RX_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + 2332 wmi_handle->soc->buf_offset_event)); 2333 } 2334 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 2335 } 2336 #endif 2337 2338 if (exec_ctx == WMI_RX_WORK_CTX) { 2339 wmi_process_fw_event_worker_thread_ctx 2340 (wmi_handle, evt_buf); 2341 } else if (exec_ctx == WMI_RX_TASKLET_CTX) { 2342 wmi_process_fw_event(wmi_handle, evt_buf); 2343 } else if (exec_ctx == WMI_RX_SERIALIZER_CTX) { 2344 wmi_process_fw_event_sched_thread_ctx(wmi_handle, evt_buf); 2345 } else { 2346 WMI_LOGE("Invalid event context %d", exec_ctx); 2347 qdf_nbuf_free(evt_buf); 2348 } 2349 2350 } 2351 2352 /** 2353 * wmi_process_fw_event() - process any fw event 2354 * @wmi_handle: wmi handle 2355 * @evt_buf: fw event buffer 2356 * 2357 * This function process fw event in caller context 2358 * 2359 * Return: none 2360 */ 2361 void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) 2362 { 2363 __wmi_control_rx(wmi_handle, evt_buf); 2364 } 2365 2366 /** 2367 * __wmi_control_rx() - process serialize wmi event callback 2368 * @wmi_handle: wmi handle 2369 * @evt_buf: fw event buffer 2370 * 2371 * Return: none 2372 */ 2373 void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) 2374 { 2375 uint32_t id; 2376 uint8_t *data; 2377 uint32_t len; 2378 void *wmi_cmd_struct_ptr = NULL; 2379 #ifndef WMI_NON_TLV_SUPPORT 2380 int tlv_ok_status = 0; 2381 #endif 2382 uint32_t idx = 0; 2383 2384 id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); 2385 2386 wmi_ext_dbg_msg_event_record(wmi_handle, qdf_nbuf_data(evt_buf), 2387 qdf_nbuf_len(evt_buf)); 2388 2389 if (qdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) 2390 goto end; 2391 2392 data = qdf_nbuf_data(evt_buf); 2393 len = qdf_nbuf_len(evt_buf); 2394 2395 #ifndef WMI_NON_TLV_SUPPORT 2396 if (wmi_handle->target_type == WMI_TLV_TARGET) { 2397 /* Validate and pad(if necessary) the TLVs */ 2398 tlv_ok_status = 2399 wmi_handle->ops->wmi_check_and_pad_event(wmi_handle->scn_handle, 2400 data, len, id, 2401 &wmi_cmd_struct_ptr); 2402 if (tlv_ok_status != 0) { 2403 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 2404 "%s: Error: id=0x%x, wmitlv check status=%d", 2405 __func__, id, tlv_ok_status); 2406 goto end; 2407 } 2408 } 2409 #endif 2410 2411 idx = wmi_unified_get_event_handler_ix(wmi_handle, id); 2412 if (idx == A_ERROR) { 2413 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, 2414 "%s : event handler is not registered: event id 0x%x", 2415 __func__, id); 2416 goto end; 2417 } 2418 #ifdef WMI_INTERFACE_EVENT_LOGGING 2419 if (wmi_handle->log_info.wmi_logging_enable) { 2420 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 2421 /* Exclude 4 bytes of TLV header */ 2422 if (wmi_handle->ops->is_diag_event(id)) { 2423 /* 2424 * skip diag event logging in WMI event buffer 2425 * as its already logged in WMI RX event buffer 2426 */ 2427 } else if (wmi_handle->ops->is_management_record(id)) { 2428 /* 2429 * skip wmi mgmt event logging in WMI event buffer 2430 * as its already logged in WMI RX event buffer 2431 */ 2432 } else { 2433 WMI_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + 2434 wmi_handle->soc->buf_offset_event)); 2435 } 2436 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 2437 } 2438 #endif 2439 /* Call the WMI registered event handler */ 2440 if (wmi_handle->target_type == WMI_TLV_TARGET) 2441 wmi_handle->event_handler[idx] (wmi_handle->scn_handle, 2442 wmi_cmd_struct_ptr, len); 2443 else 2444 wmi_handle->event_handler[idx] (wmi_handle->scn_handle, 2445 data, len); 2446 2447 end: 2448 /* Free event buffer and allocated event tlv */ 2449 #ifndef WMI_NON_TLV_SUPPORT 2450 if (wmi_handle->target_type == WMI_TLV_TARGET) 2451 wmi_handle->ops->wmi_free_allocated_event(id, &wmi_cmd_struct_ptr); 2452 #endif 2453 2454 qdf_nbuf_free(evt_buf); 2455 2456 } 2457 2458 #define WMI_WQ_WD_TIMEOUT (30 * 1000) /* 30s */ 2459 2460 static inline void wmi_workqueue_watchdog_warn(uint32_t msg_type_id) 2461 { 2462 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 2463 "%s: WLAN_BUG_RCA: Message type %x has exceeded its alloted time of %ds", 2464 __func__, msg_type_id, WMI_WQ_WD_TIMEOUT / 1000); 2465 } 2466 2467 #ifdef CONFIG_SLUB_DEBUG_ON 2468 static void wmi_workqueue_watchdog_bite(void *arg) 2469 { 2470 struct wmi_wq_dbg_info *info = arg; 2471 2472 wmi_workqueue_watchdog_warn(info->wd_msg_type_id); 2473 qdf_print_thread_trace(info->task); 2474 2475 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 2476 "%s: Going down for WMI WQ Watchdog Bite!", __func__); 2477 QDF_BUG(0); 2478 } 2479 #else 2480 static inline void wmi_workqueue_watchdog_bite(void *arg) 2481 { 2482 struct wmi_wq_dbg_info *info = arg; 2483 2484 wmi_workqueue_watchdog_warn(info->wd_msg_type_id); 2485 } 2486 #endif 2487 2488 /** 2489 * wmi_rx_event_work() - process rx event in rx work queue context 2490 * @arg: opaque pointer to wmi handle 2491 * 2492 * This function process any fw event to serialize it through rx worker thread. 2493 * 2494 * Return: none 2495 */ 2496 static void wmi_rx_event_work(void *arg) 2497 { 2498 wmi_buf_t buf; 2499 struct wmi_unified *wmi = arg; 2500 qdf_timer_t wd_timer; 2501 struct wmi_wq_dbg_info info; 2502 2503 /* initialize WMI workqueue watchdog timer */ 2504 qdf_timer_init(NULL, &wd_timer, &wmi_workqueue_watchdog_bite, 2505 &info, QDF_TIMER_TYPE_SW); 2506 qdf_spin_lock_bh(&wmi->eventq_lock); 2507 buf = qdf_nbuf_queue_remove(&wmi->event_queue); 2508 qdf_spin_unlock_bh(&wmi->eventq_lock); 2509 while (buf) { 2510 qdf_timer_start(&wd_timer, WMI_WQ_WD_TIMEOUT); 2511 info.wd_msg_type_id = 2512 WMI_GET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID); 2513 info.wmi_wq = wmi->wmi_rx_work_queue; 2514 info.task = qdf_get_current_task(); 2515 __wmi_control_rx(wmi, buf); 2516 qdf_timer_stop(&wd_timer); 2517 qdf_spin_lock_bh(&wmi->eventq_lock); 2518 buf = qdf_nbuf_queue_remove(&wmi->event_queue); 2519 qdf_spin_unlock_bh(&wmi->eventq_lock); 2520 } 2521 qdf_timer_free(&wd_timer); 2522 } 2523 2524 #ifdef FEATURE_RUNTIME_PM 2525 /** 2526 * wmi_runtime_pm_init() - initialize runtime pm wmi variables 2527 * @wmi_handle: wmi context 2528 */ 2529 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle) 2530 { 2531 qdf_atomic_init(&wmi_handle->runtime_pm_inprogress); 2532 } 2533 2534 /** 2535 * wmi_set_runtime_pm_inprogress() - set runtime pm progress flag 2536 * @wmi_handle: wmi context 2537 * @val: runtime pm progress flag 2538 */ 2539 void wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, A_BOOL val) 2540 { 2541 qdf_atomic_set(&wmi_handle->runtime_pm_inprogress, val); 2542 } 2543 2544 /** 2545 * wmi_get_runtime_pm_inprogress() - get runtime pm progress flag 2546 * @wmi_handle: wmi context 2547 */ 2548 inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle) 2549 { 2550 return qdf_atomic_read(&wmi_handle->runtime_pm_inprogress); 2551 } 2552 #else 2553 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle) 2554 { 2555 } 2556 #endif 2557 2558 /** 2559 * wmi_unified_get_soc_handle: Get WMI SoC handle 2560 * @param wmi_handle: WMI context got from wmi_attach 2561 * 2562 * return: Pointer to Soc handle 2563 */ 2564 void *wmi_unified_get_soc_handle(struct wmi_unified *wmi_handle) 2565 { 2566 return wmi_handle->soc; 2567 } 2568 2569 /** 2570 * wmi_interface_logging_init: Interface looging init 2571 * @param wmi_handle: Pointer to wmi handle object 2572 * 2573 * return: None 2574 */ 2575 #ifdef WMI_INTERFACE_EVENT_LOGGING 2576 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle, 2577 uint32_t pdev_idx) 2578 { 2579 if (QDF_STATUS_SUCCESS == wmi_log_init(wmi_handle)) { 2580 qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); 2581 wmi_debugfs_init(wmi_handle, pdev_idx); 2582 } 2583 } 2584 #else 2585 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle, 2586 uint32_t pdev_idx) 2587 { 2588 } 2589 #endif 2590 2591 /** 2592 * wmi_unified_get_pdev_handle: Get WMI SoC handle 2593 * @param wmi_soc: Pointer to wmi soc object 2594 * @param pdev_idx: pdev index 2595 * 2596 * return: Pointer to wmi handle or NULL on failure 2597 */ 2598 void *wmi_unified_get_pdev_handle(struct wmi_soc *soc, uint32_t pdev_idx) 2599 { 2600 struct wmi_unified *wmi_handle; 2601 2602 if (pdev_idx >= WMI_MAX_RADIOS) 2603 return NULL; 2604 2605 if (!soc->wmi_pdev[pdev_idx]) { 2606 wmi_handle = 2607 (struct wmi_unified *) qdf_mem_malloc( 2608 sizeof(struct wmi_unified)); 2609 if (!wmi_handle) 2610 return NULL; 2611 2612 wmi_handle->scn_handle = soc->scn_handle; 2613 wmi_handle->event_id = soc->event_id; 2614 wmi_handle->event_handler = soc->event_handler; 2615 wmi_handle->ctx = soc->ctx; 2616 wmi_handle->ops = soc->ops; 2617 qdf_spinlock_create(&wmi_handle->eventq_lock); 2618 qdf_nbuf_queue_init(&wmi_handle->event_queue); 2619 2620 qdf_create_work(0, &wmi_handle->rx_event_work, 2621 wmi_rx_event_work, wmi_handle); 2622 wmi_handle->wmi_rx_work_queue = 2623 qdf_alloc_unbound_workqueue("wmi_rx_event_work_queue"); 2624 if (!wmi_handle->wmi_rx_work_queue) { 2625 WMI_LOGE("failed to create wmi_rx_event_work_queue"); 2626 goto error; 2627 } 2628 wmi_handle->wmi_events = soc->wmi_events; 2629 wmi_handle->services = soc->services; 2630 wmi_handle->soc = soc; 2631 wmi_handle->cmd_pdev_id_map = soc->cmd_pdev_id_map; 2632 wmi_handle->evt_pdev_id_map = soc->evt_pdev_id_map; 2633 wmi_interface_logging_init(wmi_handle, pdev_idx); 2634 qdf_atomic_init(&wmi_handle->pending_cmds); 2635 qdf_atomic_init(&wmi_handle->is_target_suspended); 2636 wmi_handle->target_type = soc->target_type; 2637 wmi_handle->wmi_max_cmds = soc->wmi_max_cmds; 2638 2639 soc->wmi_pdev[pdev_idx] = wmi_handle; 2640 } else 2641 wmi_handle = soc->wmi_pdev[pdev_idx]; 2642 2643 wmi_handle->wmi_stopinprogress = 0; 2644 wmi_handle->wmi_endpoint_id = soc->wmi_endpoint_id[pdev_idx]; 2645 wmi_handle->htc_handle = soc->htc_handle; 2646 wmi_handle->max_msg_len = soc->max_msg_len[pdev_idx]; 2647 2648 return wmi_handle; 2649 2650 error: 2651 qdf_mem_free(wmi_handle); 2652 2653 return NULL; 2654 } 2655 qdf_export_symbol(wmi_unified_get_pdev_handle); 2656 2657 static void (*wmi_attach_register[WMI_MAX_TARGET_TYPE])(wmi_unified_t); 2658 2659 void wmi_unified_register_module(enum wmi_target_type target_type, 2660 void (*wmi_attach)(wmi_unified_t wmi_handle)) 2661 { 2662 if (target_type < WMI_MAX_TARGET_TYPE) 2663 wmi_attach_register[target_type] = wmi_attach; 2664 2665 return; 2666 } 2667 qdf_export_symbol(wmi_unified_register_module); 2668 2669 /** 2670 * wmi_wbuff_register() - register wmi with wbuff 2671 * @wmi_handle: handle to wmi 2672 * 2673 * @Return: void 2674 */ 2675 static void wmi_wbuff_register(struct wmi_unified *wmi_handle) 2676 { 2677 struct wbuff_alloc_request wbuff_alloc[4]; 2678 2679 wbuff_alloc[0].slot = WBUFF_POOL_0; 2680 wbuff_alloc[0].size = WMI_WBUFF_POOL_0_SIZE; 2681 wbuff_alloc[1].slot = WBUFF_POOL_1; 2682 wbuff_alloc[1].size = WMI_WBUFF_POOL_1_SIZE; 2683 wbuff_alloc[2].slot = WBUFF_POOL_2; 2684 wbuff_alloc[2].size = WMI_WBUFF_POOL_2_SIZE; 2685 wbuff_alloc[3].slot = WBUFF_POOL_3; 2686 wbuff_alloc[3].size = WMI_WBUFF_POOL_3_SIZE; 2687 2688 wmi_handle->wbuff_handle = wbuff_module_register(wbuff_alloc, 4, 2689 WMI_MIN_HEAD_ROOM, 4); 2690 } 2691 2692 /** 2693 * wmi_wbuff_deregister() - deregister wmi with wbuff 2694 * @wmi_handle: handle to wmi 2695 * 2696 * @Return: void 2697 */ 2698 static inline void wmi_wbuff_deregister(struct wmi_unified *wmi_handle) 2699 { 2700 wbuff_module_deregister(wmi_handle->wbuff_handle); 2701 wmi_handle->wbuff_handle = NULL; 2702 } 2703 2704 /** 2705 * wmi_unified_attach() - attach for unified WMI 2706 * @scn_handle: handle to SCN 2707 * @osdev: OS device context 2708 * @target_type: TLV or not-TLV based target 2709 * @use_cookie: cookie based allocation enabled/disabled 2710 * @ops: umac rx callbacks 2711 * @psoc: objmgr psoc 2712 * 2713 * @Return: wmi handle. 2714 */ 2715 void *wmi_unified_attach(void *scn_handle, 2716 struct wmi_unified_attach_params *param) 2717 { 2718 struct wmi_unified *wmi_handle; 2719 struct wmi_soc *soc; 2720 2721 soc = (struct wmi_soc *) qdf_mem_malloc(sizeof(struct wmi_soc)); 2722 if (!soc) 2723 return NULL; 2724 2725 wmi_handle = 2726 (struct wmi_unified *) qdf_mem_malloc( 2727 sizeof(struct wmi_unified)); 2728 if (!wmi_handle) { 2729 qdf_mem_free(soc); 2730 return NULL; 2731 } 2732 wmi_handle->soc = soc; 2733 wmi_handle->soc->soc_idx = param->soc_id; 2734 wmi_handle->soc->is_async_ep = param->is_async_ep; 2735 wmi_handle->event_id = soc->event_id; 2736 wmi_handle->event_handler = soc->event_handler; 2737 wmi_handle->ctx = soc->ctx; 2738 wmi_handle->wmi_events = soc->wmi_events; 2739 wmi_handle->services = soc->services; 2740 wmi_handle->scn_handle = scn_handle; 2741 wmi_handle->cmd_pdev_id_map = soc->cmd_pdev_id_map; 2742 wmi_handle->evt_pdev_id_map = soc->evt_pdev_id_map; 2743 soc->scn_handle = scn_handle; 2744 qdf_atomic_init(&wmi_handle->pending_cmds); 2745 qdf_atomic_init(&wmi_handle->is_target_suspended); 2746 qdf_atomic_init(&wmi_handle->num_stats_over_qmi); 2747 wmi_runtime_pm_init(wmi_handle); 2748 qdf_spinlock_create(&wmi_handle->eventq_lock); 2749 qdf_nbuf_queue_init(&wmi_handle->event_queue); 2750 qdf_create_work(0, &wmi_handle->rx_event_work, 2751 wmi_rx_event_work, wmi_handle); 2752 wmi_handle->wmi_rx_work_queue = 2753 qdf_alloc_unbound_workqueue("wmi_rx_event_work_queue"); 2754 if (!wmi_handle->wmi_rx_work_queue) { 2755 WMI_LOGE("failed to create wmi_rx_event_work_queue"); 2756 goto error; 2757 } 2758 wmi_interface_logging_init(wmi_handle, WMI_HOST_PDEV_ID_0); 2759 wmi_handle->target_type = param->target_type; 2760 soc->target_type = param->target_type; 2761 2762 if (param->target_type >= WMI_MAX_TARGET_TYPE) 2763 goto error; 2764 2765 if (wmi_attach_register[param->target_type]) { 2766 wmi_attach_register[param->target_type](wmi_handle); 2767 } else { 2768 WMI_LOGE("wmi attach is not registered"); 2769 goto error; 2770 } 2771 /* Assign target cookie capablity */ 2772 wmi_handle->use_cookie = param->use_cookie; 2773 wmi_handle->osdev = param->osdev; 2774 wmi_handle->wmi_stopinprogress = 0; 2775 wmi_handle->wmi_max_cmds = param->max_commands; 2776 soc->wmi_max_cmds = param->max_commands; 2777 /* Increase the ref count once refcount infra is present */ 2778 soc->wmi_psoc = param->psoc; 2779 qdf_spinlock_create(&soc->ctx_lock); 2780 2781 soc->ops = wmi_handle->ops; 2782 soc->wmi_pdev[0] = wmi_handle; 2783 if (wmi_ext_dbgfs_init(wmi_handle) != QDF_STATUS_SUCCESS) 2784 WMI_LOGE("failed to initialize wmi extended debugfs"); 2785 2786 wmi_wbuff_register(wmi_handle); 2787 2788 return wmi_handle; 2789 2790 error: 2791 qdf_mem_free(soc); 2792 qdf_mem_free(wmi_handle); 2793 2794 return NULL; 2795 } 2796 2797 /** 2798 * wmi_unified_detach() - detach for unified WMI 2799 * 2800 * @wmi_handle : handle to wmi. 2801 * 2802 * @Return: none. 2803 */ 2804 void wmi_unified_detach(struct wmi_unified *wmi_handle) 2805 { 2806 wmi_buf_t buf; 2807 struct wmi_soc *soc; 2808 uint8_t i; 2809 2810 wmi_wbuff_deregister(wmi_handle); 2811 2812 wmi_ext_dbgfs_deinit(wmi_handle); 2813 2814 soc = wmi_handle->soc; 2815 for (i = 0; i < WMI_MAX_RADIOS; i++) { 2816 if (soc->wmi_pdev[i]) { 2817 qdf_flush_workqueue(0, 2818 soc->wmi_pdev[i]->wmi_rx_work_queue); 2819 qdf_destroy_workqueue(0, 2820 soc->wmi_pdev[i]->wmi_rx_work_queue); 2821 wmi_debugfs_remove(soc->wmi_pdev[i]); 2822 buf = qdf_nbuf_queue_remove( 2823 &soc->wmi_pdev[i]->event_queue); 2824 while (buf) { 2825 qdf_nbuf_free(buf); 2826 buf = qdf_nbuf_queue_remove( 2827 &soc->wmi_pdev[i]->event_queue); 2828 } 2829 2830 wmi_log_buffer_free(soc->wmi_pdev[i]); 2831 2832 /* Free events logs list */ 2833 if (soc->wmi_pdev[i]->events_logs_list) 2834 qdf_mem_free( 2835 soc->wmi_pdev[i]->events_logs_list); 2836 2837 qdf_spinlock_destroy(&soc->wmi_pdev[i]->eventq_lock); 2838 qdf_mem_free(soc->wmi_pdev[i]); 2839 } 2840 } 2841 qdf_spinlock_destroy(&soc->ctx_lock); 2842 2843 if (soc->wmi_service_bitmap) { 2844 qdf_mem_free(soc->wmi_service_bitmap); 2845 soc->wmi_service_bitmap = NULL; 2846 } 2847 2848 if (soc->wmi_ext_service_bitmap) { 2849 qdf_mem_free(soc->wmi_ext_service_bitmap); 2850 soc->wmi_ext_service_bitmap = NULL; 2851 } 2852 2853 /* Decrease the ref count once refcount infra is present */ 2854 soc->wmi_psoc = NULL; 2855 qdf_mem_free(soc); 2856 } 2857 2858 /** 2859 * wmi_unified_remove_work() - detach for WMI work 2860 * @wmi_handle: handle to WMI 2861 * 2862 * A function that does not fully detach WMI, but just remove work 2863 * queue items associated with it. This is used to make sure that 2864 * before any other processing code that may destroy related contexts 2865 * (HTC, etc), work queue processing on WMI has already been stopped. 2866 * 2867 * Return: None 2868 */ 2869 void 2870 wmi_unified_remove_work(struct wmi_unified *wmi_handle) 2871 { 2872 wmi_buf_t buf; 2873 2874 qdf_flush_workqueue(0, wmi_handle->wmi_rx_work_queue); 2875 qdf_spin_lock_bh(&wmi_handle->eventq_lock); 2876 buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); 2877 while (buf) { 2878 qdf_nbuf_free(buf); 2879 buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); 2880 } 2881 qdf_spin_unlock_bh(&wmi_handle->eventq_lock); 2882 } 2883 2884 /** 2885 * wmi_htc_tx_complete() - Process htc tx completion 2886 * 2887 * @ctx: handle to wmi 2888 * @htc_packet: pointer to htc packet 2889 * 2890 * @Return: none. 2891 */ 2892 static void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt) 2893 { 2894 struct wmi_soc *soc = (struct wmi_soc *) ctx; 2895 wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); 2896 u_int8_t *buf_ptr; 2897 u_int32_t len; 2898 struct wmi_unified *wmi_handle; 2899 #ifdef WMI_INTERFACE_EVENT_LOGGING 2900 uint32_t cmd_id; 2901 #endif 2902 2903 ASSERT(wmi_cmd_buf); 2904 wmi_handle = wmi_get_pdev_ep(soc, htc_pkt->Endpoint); 2905 if (!wmi_handle) { 2906 WMI_LOGE("%s: Unable to get wmi handle\n", __func__); 2907 QDF_ASSERT(0); 2908 return; 2909 } 2910 #ifdef WMI_INTERFACE_EVENT_LOGGING 2911 if (wmi_handle && wmi_handle->log_info.wmi_logging_enable) { 2912 cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf), 2913 WMI_CMD_HDR, COMMANDID); 2914 2915 qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); 2916 /* Record 16 bytes of WMI cmd tx complete data 2917 - exclude TLV and WMI headers */ 2918 if (wmi_handle->ops->is_management_record(cmd_id)) { 2919 WMI_MGMT_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id, 2920 qdf_nbuf_data(wmi_cmd_buf) + 2921 wmi_handle->soc->buf_offset_command); 2922 } else { 2923 WMI_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id, 2924 qdf_nbuf_data(wmi_cmd_buf) + 2925 wmi_handle->soc->buf_offset_command); 2926 } 2927 2928 qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); 2929 } 2930 #endif 2931 buf_ptr = (u_int8_t *) wmi_buf_data(wmi_cmd_buf); 2932 len = qdf_nbuf_len(wmi_cmd_buf); 2933 qdf_mem_zero(buf_ptr, len); 2934 wmi_buf_free(wmi_cmd_buf); 2935 qdf_mem_free(htc_pkt); 2936 qdf_atomic_dec(&wmi_handle->pending_cmds); 2937 } 2938 2939 #ifdef FEATURE_RUNTIME_PM 2940 /** 2941 * wmi_htc_log_pkt() - Print information of WMI command from HTC packet 2942 * 2943 * @ctx: handle of WMI context 2944 * @htc_pkt: handle of HTC packet 2945 * 2946 * @Return: none 2947 */ 2948 static void wmi_htc_log_pkt(void *ctx, HTC_PACKET *htc_pkt) 2949 { 2950 wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); 2951 uint32_t cmd_id; 2952 2953 ASSERT(wmi_cmd_buf); 2954 cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf), WMI_CMD_HDR, 2955 COMMANDID); 2956 2957 WMI_LOGD("WMI command from HTC packet: %s, ID: %d\n", 2958 wmi_id_to_name(cmd_id), cmd_id); 2959 } 2960 #else 2961 static void wmi_htc_log_pkt(void *ctx, HTC_PACKET *htc_pkt) 2962 { 2963 } 2964 #endif 2965 2966 /** 2967 * wmi_connect_pdev_htc_service() - WMI API to get connect to HTC service 2968 * 2969 * @wmi_handle: handle to WMI. 2970 * @pdev_idx: Pdev index 2971 * 2972 * @Return: QDF_STATUS 2973 */ 2974 static QDF_STATUS wmi_connect_pdev_htc_service(struct wmi_soc *soc, 2975 uint32_t pdev_idx) 2976 { 2977 QDF_STATUS status; 2978 struct htc_service_connect_resp response; 2979 struct htc_service_connect_req connect; 2980 2981 OS_MEMZERO(&connect, sizeof(connect)); 2982 OS_MEMZERO(&response, sizeof(response)); 2983 2984 /* meta data is unused for now */ 2985 connect.pMetaData = NULL; 2986 connect.MetaDataLength = 0; 2987 /* these fields are the same for all service endpoints */ 2988 connect.EpCallbacks.pContext = soc; 2989 connect.EpCallbacks.EpTxCompleteMultiple = 2990 NULL /* Control path completion ar6000_tx_complete */; 2991 connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */; 2992 connect.EpCallbacks.EpRecvRefill = NULL /* ar6000_rx_refill */; 2993 connect.EpCallbacks.EpSendFull = NULL /* ar6000_tx_queue_full */; 2994 connect.EpCallbacks.EpTxComplete = 2995 wmi_htc_tx_complete /* ar6000_tx_queue_full */; 2996 connect.EpCallbacks.ep_log_pkt = wmi_htc_log_pkt; 2997 2998 /* connect to control service */ 2999 connect.service_id = soc->svc_ids[pdev_idx]; 3000 status = htc_connect_service(soc->htc_handle, &connect, &response); 3001 3002 if (QDF_IS_STATUS_ERROR(status)) { 3003 WMI_LOGE("Failed to connect to WMI CONTROL service status:%d\n", 3004 status); 3005 return status; 3006 } 3007 3008 if (soc->is_async_ep) 3009 htc_set_async_ep(soc->htc_handle, response.Endpoint, true); 3010 3011 soc->wmi_endpoint_id[pdev_idx] = response.Endpoint; 3012 soc->max_msg_len[pdev_idx] = response.MaxMsgLength; 3013 3014 return QDF_STATUS_SUCCESS; 3015 } 3016 3017 QDF_STATUS 3018 wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle, 3019 HTC_HANDLE htc_handle) 3020 { 3021 uint32_t i; 3022 uint8_t wmi_ep_count; 3023 3024 wmi_handle->soc->htc_handle = htc_handle; 3025 3026 wmi_ep_count = htc_get_wmi_endpoint_count(htc_handle); 3027 if (wmi_ep_count > WMI_MAX_RADIOS) 3028 return QDF_STATUS_E_FAULT; 3029 3030 for (i = 0; i < wmi_ep_count; i++) 3031 wmi_connect_pdev_htc_service(wmi_handle->soc, i); 3032 3033 wmi_handle->htc_handle = htc_handle; 3034 wmi_handle->wmi_endpoint_id = wmi_handle->soc->wmi_endpoint_id[0]; 3035 wmi_handle->max_msg_len = wmi_handle->soc->max_msg_len[0]; 3036 3037 return QDF_STATUS_SUCCESS; 3038 } 3039 3040 /** 3041 * wmi_get_host_credits() - WMI API to get updated host_credits 3042 * 3043 * @wmi_handle: handle to WMI. 3044 * 3045 * @Return: updated host_credits. 3046 */ 3047 int wmi_get_host_credits(wmi_unified_t wmi_handle) 3048 { 3049 int host_credits = 0; 3050 3051 htc_get_control_endpoint_tx_host_credits(wmi_handle->htc_handle, 3052 &host_credits); 3053 return host_credits; 3054 } 3055 3056 /** 3057 * wmi_get_pending_cmds() - WMI API to get WMI Pending Commands in the HTC 3058 * queue 3059 * 3060 * @wmi_handle: handle to WMI. 3061 * 3062 * @Return: Pending Commands in the HTC queue. 3063 */ 3064 int wmi_get_pending_cmds(wmi_unified_t wmi_handle) 3065 { 3066 return qdf_atomic_read(&wmi_handle->pending_cmds); 3067 } 3068 3069 /** 3070 * wmi_set_target_suspend() - WMI API to set target suspend state 3071 * 3072 * @wmi_handle: handle to WMI. 3073 * @val: suspend state boolean. 3074 * 3075 * @Return: none. 3076 */ 3077 void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val) 3078 { 3079 qdf_atomic_set(&wmi_handle->is_target_suspended, val); 3080 } 3081 3082 /** 3083 * wmi_is_target_suspended() - WMI API to check target suspend state 3084 * @wmi_handle: handle to WMI. 3085 * 3086 * WMI API to check target suspend state 3087 * 3088 * Return: true if target is suspended, else false. 3089 */ 3090 bool wmi_is_target_suspended(struct wmi_unified *wmi_handle) 3091 { 3092 return qdf_atomic_read(&wmi_handle->is_target_suspended); 3093 } 3094 3095 /** 3096 * WMI API to set crash injection state 3097 * @param wmi_handle: handle to WMI. 3098 * @param val: crash injection state boolean. 3099 */ 3100 void wmi_tag_crash_inject(wmi_unified_t wmi_handle, A_BOOL flag) 3101 { 3102 wmi_handle->tag_crash_inject = flag; 3103 } 3104 3105 /** 3106 * WMI API to set bus suspend state 3107 * @param wmi_handle: handle to WMI. 3108 * @param val: suspend state boolean. 3109 */ 3110 void wmi_set_is_wow_bus_suspended(wmi_unified_t wmi_handle, A_BOOL val) 3111 { 3112 qdf_atomic_set(&wmi_handle->is_wow_bus_suspended, val); 3113 } 3114 3115 void wmi_set_tgt_assert(wmi_unified_t wmi_handle, bool val) 3116 { 3117 wmi_handle->tgt_force_assert_enable = val; 3118 } 3119 3120 /** 3121 * wmi_stop() - generic function to block unified WMI command 3122 * @wmi_handle: handle to WMI. 3123 * 3124 * @Return: success always. 3125 */ 3126 int 3127 wmi_stop(wmi_unified_t wmi_handle) 3128 { 3129 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, 3130 "WMI Stop"); 3131 wmi_handle->wmi_stopinprogress = 1; 3132 return 0; 3133 } 3134 3135 /** 3136 * wmi_start() - generic function to allow unified WMI command 3137 * @wmi_handle: handle to WMI. 3138 * 3139 * @Return: success always. 3140 */ 3141 int 3142 wmi_start(wmi_unified_t wmi_handle) 3143 { 3144 QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, 3145 "WMI Start"); 3146 wmi_handle->wmi_stopinprogress = 0; 3147 return 0; 3148 } 3149 3150 /** 3151 * API to flush all the previous packets associated with the wmi endpoint 3152 * 3153 * @param wmi_handle : handle to WMI. 3154 */ 3155 void 3156 wmi_flush_endpoint(wmi_unified_t wmi_handle) 3157 { 3158 htc_flush_endpoint(wmi_handle->htc_handle, 3159 wmi_handle->wmi_endpoint_id, 0); 3160 } 3161 qdf_export_symbol(wmi_flush_endpoint); 3162 3163 /** 3164 * wmi_pdev_id_conversion_enable() - API to enable pdev_id conversion in WMI 3165 * By default pdev_id conversion is not done in WMI. 3166 * This API can be used enable conversion in WMI. 3167 * @param wmi_handle : handle to WMI 3168 * @param pdev_map : pointer to pdev_map 3169 * @size : size of pdev_id_map 3170 * Return none 3171 */ 3172 void wmi_pdev_id_conversion_enable(wmi_unified_t wmi_handle, 3173 uint32_t *pdev_id_map, uint8_t size) 3174 { 3175 if (wmi_handle->target_type == WMI_TLV_TARGET) 3176 wmi_handle->ops->wmi_pdev_id_conversion_enable(wmi_handle, 3177 pdev_id_map, 3178 size); 3179 } 3180