/* WMI Event handler register API */ int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle, WMI_EVT_ID event_id) { u_int32_t idx = 0; for (idx = 0; (idx < wmi_handle->max_event_idx && idx < WMI_UNIFIED_MAX_EVENT); ++idx) { if (wmi_handle->event_id[idx] == event_id && wmi_handle->event_handler[idx] != NULL ) { return idx; } } return -1; } int wmi_unified_register_event_handler(wmi_unified_t wmi_handle, WMI_EVT_ID event_id, wmi_unified_event_handler handler_func) { u_int32_t idx=0; if ( wmi_unified_get_event_handler_ix( wmi_handle, event_id) != -1) { printk("%s : event handler already registered 0x%x \n", __func__, event_id); return -1; } if ( wmi_handle->max_event_idx == WMI_UNIFIED_MAX_EVENT ) { printk("%s : no more event handlers 0x%x \n", __func__, event_id); return -1; } idx=wmi_handle->max_event_idx; wmi_handle->event_handler[idx] = handler_func; wmi_handle->event_id[idx] = event_id; wmi_handle->max_event_idx++; return 0; } int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, WMI_EVT_ID event_id) { u_int32_t idx=0; if ( (idx = wmi_unified_get_event_handler_ix( wmi_handle, event_id)) == -1) { printk("%s : event handler is not registered: event id 0x%x \n", __func__, event_id); return -1; } wmi_handle->event_handler[idx] = NULL; wmi_handle->event_id[idx] = 0; --wmi_handle->max_event_idx; wmi_handle->event_handler[idx] = wmi_handle->event_handler[wmi_handle->max_event_idx]; wmi_handle->event_id[idx] = wmi_handle->event_id[wmi_handle->max_event_idx] ; return 0; } #if 0 /* currently not used */ static int wmi_unified_event_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { u_int32_t id; u_int8_t *event; u_int16_t len; int status = -1; u_int32_t idx = 0; ASSERT(evt_buf != NULL); id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); if (adf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) goto end; idx = wmi_unified_get_event_handler_ix(wmi_handle, id); if (idx == -1) { pr_err("%s : event handler is not registered: event id: 0x%x\n", __func__, id); goto end; } event = adf_nbuf_data(evt_buf); len = adf_nbuf_len(evt_buf); /* Call the WMI registered event handler */ status = wmi_handle->event_handler[idx](wmi_handle->scn_handle, event, len); end: adf_nbuf_free(evt_buf); return status; }
/* * Temporarily added to support older WMI events. We should move all events to unified * when the target is ready to support it. */ void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) { u_int16_t id; u_int8_t *data; u_int32_t len; int status = EOK; wmi_buf_t evt_buf; struct wmi_unified *wmi_handle = (struct wmi_unified *) ctx; evt_buf = (wmi_buf_t) htc_packet->pPktContext; /** * This is a HACK due to a Hack/WAR in HTC !!. * the head of the wbuf still contains the HTC header * but the length excludes htc header. */ wbuf_set_pktlen(evt_buf, htc_packet->ActualLength + HTC_HEADER_LEN); wbuf_pull(evt_buf, HTC_HEADER_LEN); id = WMI_GET_FIELD(wbuf_header(evt_buf), WMI_CMD_HDR, COMMANDID); if ((id >= WMI_START_EVENTID) && (id <= WMI_END_EVENTID)) { status = wmi_unified_event_rx(wmi_handle, evt_buf); return ; } if (wbuf_pull(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) { status = -1; goto end; } data = wbuf_header(evt_buf); len = wbuf_get_pktlen(evt_buf); switch(id) { default: printk("%s: Unhandled WMI command %d\n", __func__, id); break; case WMI_SERVICE_READY_EVENTID: status = wmi_service_ready_event_rx(wmi_handle, data, len); break; case WMI_READY_EVENTID: status = wmi_ready_event_rx(wmi_handle, data, len); break; case WMI_WLAN_VERSION_EVENTID: printk("%s: Handle WMI_VERSION_EVENTID\n", __func__); break; case WMI_REGDOMAIN_EVENTID: printk("%s: Handle WMI_REGDOMAIN_EVENTID\n", __func__); break; case WMI_DEBUG_MESG_EVENTID: dbglog_message_handler(wmi_handle->scn_handle, evt_buf); return; } end: wbuf_free(evt_buf); }
void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt) { struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); #ifdef WMI_INTERFACE_EVENT_LOGGING uint32_t cmd_id; #endif ASSERT(wmi_cmd_buf); #ifdef WMI_INTERFACE_EVENT_LOGGING cmd_id = WMI_GET_FIELD(cdf_nbuf_data(wmi_cmd_buf), WMI_CMD_HDR, COMMANDID); #ifdef QCA_WIFI_3_0_EMU printk("\nSent WMI command:%s command_id:0x%x over dma and recieved tx complete interupt\n", get_wmi_cmd_string(cmd_id), cmd_id); #endif cdf_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Record 16 bytes of WMI cmd tx complete data - exclude TLV and WMI headers */ if (cmd_id == WMI_MGMT_TX_SEND_CMDID) { WMI_MGMT_COMMAND_TX_CMP_RECORD(cmd_id, ((uint32_t *) cdf_nbuf_data(wmi_cmd_buf) + 2)); } else { WMI_COMMAND_TX_CMP_RECORD(cmd_id, ((uint32_t *) cdf_nbuf_data(wmi_cmd_buf) + 2)); } cdf_spin_unlock_bh(&wmi_handle->wmi_record_lock); #endif cdf_nbuf_free(wmi_cmd_buf); cdf_mem_free(htc_pkt); cdf_atomic_dec(&wmi_handle->pending_cmds); }
/* * Temporarily added to support older WMI events. We should move all events to unified * when the target is ready to support it. */ void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) { struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; wmi_buf_t evt_buf; uint32_t id; evt_buf = (wmi_buf_t) htc_packet->pPktContext; id = WMI_GET_FIELD(cdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); switch (id) { /*Event will be handled in tasklet ctx*/ case WMI_TX_PAUSE_EVENTID: case WMI_WOW_WAKEUP_HOST_EVENTID: case WMI_PDEV_RESUME_EVENTID: case WMI_D0_WOW_DISABLE_ACK_EVENTID: wmi_process_fw_event_tasklet_ctx (wmi_handle, htc_packet); break; /*Event will be handled in worker thread ctx*/ case WMI_DEBUG_MESG_EVENTID: case WMI_DFS_RADAR_EVENTID: case WMI_PHYERR_EVENTID: case WMI_PEER_STATE_EVENTID: case WMI_MGMT_RX_EVENTID: case WMI_ROAM_EVENTID: wmi_process_fw_event_worker_thread_ctx (wmi_handle, htc_packet); break; /*Event will be handled in mc_thread ctx*/ default: wmi_process_fw_event_mc_thread_ctx (wmi_handle, htc_packet); break; } }
static int wmi_unified_event_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { u_int16_t id; u_int8_t *event; u_int16_t len; int status = -1; u_int16_t handler_id; ASSERT(evt_buf != NULL); id = WMI_GET_FIELD(wbuf_header(evt_buf), WMI_CMD_HDR, COMMANDID); handler_id = (id - WMI_START_EVENTID); if (wbuf_pull(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) { //A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 1\n", DBGARG)); //wmip->wmi_stats.cmd_len_err++; goto end; } if (handler_id >= WMI_UNIFIED_MAX_EVENT) { printk("%s : unkown event id : 0x%x event handler id 0x%x \n", __func__, id, handler_id); goto end; } event = wbuf_header(evt_buf); len = wbuf_get_pktlen(evt_buf); if (!wmi_handle->event_handler[handler_id]) { printk("%s : no registered event handler : event id 0x%x \n", __func__, id); goto end; } /* Call the WMI registered event handler */ status = wmi_handle->event_handler[handler_id](wmi_handle->scn_handle, event, len, wmi_handle->event_handler_cookie[handler_id]); end: wbuf_free(evt_buf); return status; }
/* * Event process by below function will be in worker thread context. * Use this method for events which are not critical and not * handled in protocol stack. */ static void wmi_process_fw_event_worker_thread_ctx (struct wmi_unified *wmi_handle, HTC_PACKET *htc_packet) { wmi_buf_t evt_buf; uint32_t id; uint8_t *data; evt_buf = (wmi_buf_t) htc_packet->pPktContext; id = WMI_GET_FIELD(cdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); data = cdf_nbuf_data(evt_buf); cdf_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Exclude 4 bytes of TLV header */ WMI_RX_EVENT_RECORD(id, ((uint8_t *) data + 4)); cdf_spin_unlock_bh(&wmi_handle->wmi_record_lock); cdf_spin_lock_bh(&wmi_handle->eventq_lock); cdf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf); cdf_spin_unlock_bh(&wmi_handle->eventq_lock); schedule_work(&wmi_handle->rx_event_work); return; }
void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt) { struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); #ifdef WMI_INTERFACE_EVENT_LOGGING u_int32_t cmd_id; #endif ASSERT(wmi_cmd_buf); #ifdef WMI_INTERFACE_EVENT_LOGGING cmd_id = WMI_GET_FIELD(adf_nbuf_data(wmi_cmd_buf), WMI_CMD_HDR, COMMANDID); adf_os_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Record 16 bytes of WMI cmd tx complete data - exclude TLV and WMI headers */ WMI_COMMAND_TX_CMP_RECORD(cmd_id, ((u_int32_t *)adf_nbuf_data(wmi_cmd_buf) + 2)); adf_os_spin_unlock_bh(&wmi_handle->wmi_record_lock); #endif adf_nbuf_free(wmi_cmd_buf); adf_os_mem_free(htc_pkt); adf_os_atomic_dec(&wmi_handle->pending_cmds); }
void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { u_int32_t id; u_int8_t *data; u_int32_t len; void *wmi_cmd_struct_ptr = NULL; int tlv_ok_status = 0; id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); if (adf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) goto end; data = adf_nbuf_data(evt_buf); len = adf_nbuf_len(evt_buf); /* Validate and pad(if necessary) the TLVs */ tlv_ok_status = wmitlv_check_and_pad_event_tlvs(wmi_handle->scn_handle, data, len, id, &wmi_cmd_struct_ptr); if (tlv_ok_status != 0) { pr_err("%s: Error: id=0x%d, wmitlv_check_and_pad_tlvs ret=%d\n", __func__, id, tlv_ok_status); goto end; } #ifdef FEATURE_WLAN_D0WOW if (wmi_get_d0wow_flag(wmi_handle)) pr_debug("%s: WMI event ID is 0x%x\n", __func__, id); #endif if (id >= WMI_EVT_GRP_START_ID(WMI_GRP_START)) { u_int32_t idx = 0; idx = wmi_unified_get_event_handler_ix(wmi_handle, id) ; if (idx == -1) { pr_err("%s : event handler is not registered: event id 0x%x\n", __func__, id); goto end; } #ifdef WMI_INTERFACE_EVENT_LOGGING adf_os_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Exclude 4 bytes of TLV header */ WMI_EVENT_RECORD(id, ((u_int8_t *)data + 4)); adf_os_spin_unlock_bh(&wmi_handle->wmi_record_lock); #endif /* Call the WMI registered event handler */ wmi_handle->event_handler[idx](wmi_handle->scn_handle, wmi_cmd_struct_ptr, len); goto end; } switch (id) { default: pr_info("%s: Unhandled WMI event %d\n", __func__, id); break; case WMI_SERVICE_READY_EVENTID: pr_info("%s: WMI UNIFIED SERVICE READY event\n", __func__); wma_rx_service_ready_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); break; case WMI_READY_EVENTID: pr_info("%s: WMI UNIFIED READY event\n", __func__); wma_rx_ready_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); break; } end: wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); adf_nbuf_free(evt_buf); }
/* * Temporarily added to support older WMI events. We should move all events to unified * when the target is ready to support it. */ void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) { struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; wmi_buf_t evt_buf; u_int32_t len; void *wmi_cmd_struct_ptr = NULL; u_int32_t idx = 0; int tlv_ok_status = 0; #if defined(WMI_INTERFACE_EVENT_LOGGING) || !defined(QCA_CONFIG_SMP) u_int32_t id; u_int8_t *data; #endif evt_buf = (wmi_buf_t) htc_packet->pPktContext; id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); /* TX_PAUSE EVENT should be handled with tasklet context */ if ((WMI_TX_PAUSE_EVENTID == id) || (WMI_WOW_WAKEUP_HOST_EVENTID == id)) { if (adf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) return; data = adf_nbuf_data(evt_buf); len = adf_nbuf_len(evt_buf); tlv_ok_status = wmitlv_check_and_pad_event_tlvs( wmi_handle->scn_handle, data, len, id, &wmi_cmd_struct_ptr); if (tlv_ok_status != 0) { if (tlv_ok_status == 1) { wmi_cmd_struct_ptr = data; } else { return; } } idx = wmi_unified_get_event_handler_ix(wmi_handle, id); if (idx == -1) { wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); adf_nbuf_free(evt_buf); return; } wmi_handle->event_handler[idx](wmi_handle->scn_handle, wmi_cmd_struct_ptr, len); wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); adf_nbuf_free(evt_buf); return; } #ifdef WMI_INTERFACE_EVENT_LOGGING id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); data = adf_nbuf_data(evt_buf); adf_os_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Exclude 4 bytes of TLV header */ WMI_RX_EVENT_RECORD(id, ((u_int8_t *)data + 4)); adf_os_spin_unlock_bh(&wmi_handle->wmi_record_lock); #endif adf_os_spin_lock_bh(&wmi_handle->eventq_lock); adf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf); adf_os_spin_unlock_bh(&wmi_handle->eventq_lock); schedule_work(&wmi_handle->rx_event_work); }
void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { uint32_t id; uint8_t *data; uint32_t len; void *wmi_cmd_struct_ptr = NULL; int tlv_ok_status = 0; id = WMI_GET_FIELD(cdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); if (cdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) goto end; data = cdf_nbuf_data(evt_buf); len = cdf_nbuf_len(evt_buf); /* Validate and pad(if necessary) the TLVs */ tlv_ok_status = wmitlv_check_and_pad_event_tlvs(wmi_handle->scn_handle, data, len, id, &wmi_cmd_struct_ptr); if (tlv_ok_status != 0) { pr_err("%s: Error: id=0x%d, wmitlv_check_and_pad_tlvs ret=%d\n", __func__, id, tlv_ok_status); goto end; } if ((id >= WMI_EVT_GRP_START_ID(WMI_GRP_START)) && /* WMI_SERVICE_READY_EXT_EVENTID is supposed to be part of the * WMI_GRP_START group. Since the group is out of space, FW * has accomodated this in WMI_GRP_VDEV. * WMI_SERVICE_READY_EXT_EVENTID does not have any specific * event handler registered. So, we do not want to go through * the WMI registered event handler path for this event. */ (id != WMI_SERVICE_READY_EXT_EVENTID)) { uint32_t idx = 0; idx = wmi_unified_get_event_handler_ix(wmi_handle, id); if (idx == -1) { pr_err ("%s : event handler is not registered: event id 0x%x\n", __func__, id); goto end; } #ifdef WMI_INTERFACE_EVENT_LOGGING cdf_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Exclude 4 bytes of TLV header */ if (id == WMI_MGMT_TX_COMPLETION_EVENTID) { WMI_MGMT_EVENT_RECORD(id, ((uint8_t *) data + 4)); } else { WMI_EVENT_RECORD(id, ((uint8_t *) data + 4)); } cdf_spin_unlock_bh(&wmi_handle->wmi_record_lock); #endif /* Call the WMI registered event handler */ wmi_handle->event_handler[idx] (wmi_handle->scn_handle, wmi_cmd_struct_ptr, len); goto end; } switch (id) { default: pr_info("%s: Unhandled WMI event %d\n", __func__, id); break; case WMI_SERVICE_READY_EVENTID: pr_info("%s: WMI UNIFIED SERVICE READY event\n", __func__); wma_rx_service_ready_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); break; case WMI_SERVICE_READY_EXT_EVENTID: WMA_LOGA("%s: WMI UNIFIED SERVICE READY Extended event", __func__); wma_rx_service_ready_ext_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); break; case WMI_READY_EVENTID: pr_info("%s: WMI UNIFIED READY event\n", __func__); wma_rx_ready_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); break; } end: wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); cdf_nbuf_free(evt_buf); }