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