wmi和htc分析
wmi_control_rx 分析
注册wmi_control_rx
static QDF_STATUS wmi_connect_pdev_htc_service(struct wmi_soc *soc,
uint32_t pdev_idx)
{
struct htc_service_connect_resp response;
struct htc_service_connect_req connect;
connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */; // 注册
status = htc_connect_service(soc->htc_handle, &connect, &response);
}
调用wmi_control_rx
static void do_recv_completion_pkt(HTC_ENDPOINT *pEndpoint,
HTC_PACKET *pPacket)
{
if (!pEndpoint->EpCallBacks.EpRecv) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTC ep %d has NULL recv callback on packet %pK\n",
pEndpoint->Id,
pPacket));
if (pPacket)
qdf_nbuf_free(pPacket->pPktContext);
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("HTC calling ep %d recv callback on packet %pK\n",
pEndpoint->Id, pPacket));
// 实际就是调用 wmi_control_rx
pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext,
pPacket);
}
}
问题谁调用了do_recv_completion_pkt函数,分析如下:
do_recv_completionstatic void do_recv_completion(HTC_ENDPOINT *pEndpoint, HTC_PACKET_QUEUE *pQueueToIndicate) { HTC_PACKET *pPacket; if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { /* nothing to indicate */ return; } while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { pPacket = htc_packet_dequeue(pQueueToIndicate); // 调用地方do_recv_completion_pkt do_recv_completion_pkt(pEndpoint, pPacket); } }
那么谁又调用了
do_recv_completion函数#ifdef HIF_SDIO void epping_refill(void *ctx, HTC_ENDPOINT_ID Endpoint) { if (!HTC_QUEUE_EMPTY(&queue)) { /* add packets */ htc_add_receive_pkt_multiple(pEpping_ctx->HTCHandle, &queue); { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); HTC_PACKET *pFirstPacket = htc_get_pkt_at_head(pPktQueue); pEndpoint = &target->endpoint[pFirstPacket->Endpoint]; /* store receive packets */ HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,pPktQueue); // 调用do_recv_completion地方 do_recv_completion(pEndpoint, pPktQueue); } } } #endif /* HIF_SDIO */
总结,从这里可以看出,这个步骤基本用不到目前,因为需要定义HIF_SDIO宏
htc_rx_completion_handlerQDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf, uint8_t pipeID) { // 调用地方do_recv_completion_pkt do_recv_completion_pkt(pEndpoint, pPacket); }
htc_rx_completion_handler函数是在htc_create函数中注册到htcCallbacks.rxCompletionHandler里面的,如下:HTC_HANDLE htc_create(void *ol_sc, struct htc_init_info *pInfo, qdf_device_t osdev, uint32_t con_mode) { hcCallbacks.Context = target; //注册htc_rx_completion_handler的地方 htcCallbacks.rxCompletionHandler = htc_rx_completion_handler; htcCallbacks.txCompletionHandler = htc_tx_completion_handler; htcCallbacks.txResourceAvailHandler = htc_tx_resource_avail_handler; htcCallbacks.fwEventHandler = htc_fw_event_handler; htcCallbacks.update_bundle_stats = htc_update_rx_bundle_stats; }
下面分析何时调用
htcCallbacks.rxCompletionHandlerstatic inline void hif_ce_do_recv(struct hif_msg_callbacks *msg_callbacks, qdf_nbuf_t netbuf, int nbytes, struct HIF_CE_pipe_info *pipe_info) { if (nbytes <= pipe_info->buf_sz) { qdf_nbuf_set_pktlen(netbuf, nbytes); // 调用 htcCallbacks.rxCompletionHandler的 地方 // 即 实际调用htc_rx_completion_handler的地方 msg_callbacks-> rxCompletionHandler(msg_callbacks->Context, netbuf, pipe_info->pipe_num); } else { hif_err("Invalid Rx msg buf: %pK nbytes: %d", netbuf, nbytes); qdf_nbuf_free(netbuf);c } }
谁又调用
hif_ce_do_recv,接下来分析static void hif_pci_ce_recv_data(struct CE_handle *copyeng, void *ce_context, void *transfer_context, qdf_dma_addr_t CE_data, unsigned int nbytes, unsigned int transfer_id, unsigned int flags) { if (scn->target_status == TARGET_STATUS_RESET)c qdf_nbuf_free(transfer_context); else hif_ce_do_recv(msg_callbacks, transfer_context, nbytes, pipe_info); }
接下来分析谁调用了
hif_pci_ce_recv_data函数注册
hif_pci_ce_recv_data的地方static int hif_completion_thread_startup_by_ceid(struct HIF_CE_state *hif_state,int pipe_num) { ce_recv_cb_register(pipe_info->ce_hdl, hif_pci_ce_recv_data, //注册的地方 pipe_info,attr.flags & CE_ATTR_DISABLE_INTR); { //函数原型 void ce_recv_cb_register(struct CE_handle *copyeng, CE_recv_cb fn_ptr, void *CE_recv_context, int disable_interrupts) { CE_state->recv_context = CE_recv_context; // 赋值的地方 CE_state->recv_cb = hif_pci_ce_recv_data CE_state->recv_cb = fn_ptr; } } }
调用CE_state->recv_cb的地方,即调用
hif_pci_ce_recv_data的地方void ce_engine_service_reg(struct hif_softc *scn, int CE_id) { while (hif_state->ce_services->ce_completed_recv_next_nolock (CE_state, &CE_context, &transfer_context, &buf, &nbytes, &id, &flags) == QDF_STATUS_SUCCESS) { // 调用 hif_pci_ce_recv_data的地方 CE_state->recv_cb((struct CE_handle *)CE_state, CE_context, transfer_context, buf, nbytes, id, flags); } }
接下来分析
ce_engine_service_reg调用的地方注册
struct CE_handle *ce_init(struct hif_softc *scn, unsigned int CE_id, struct CE_attr *attr) { CE_state->scn = scn; CE_state->service = ce_engine_service_reg; // 注册地方 }
调用
int ce_per_engine_service(struct hif_softc *scn, unsigned int CE_id) { // 调用地方,也就是调用ce_engine_service_reg的地方 CE_state->service(scn, CE_id); }
接下来分析
ce_per_engine_service调用地方ce_poll_timeout
static void ce_poll_timeout(void *arg) { struct CE_state *CE_state = (struct CE_state *)arg; if (CE_state->timer_inited) { ce_per_engine_service(CE_state->scn, CE_state->id); qdf_timer_mod(&CE_state->poll_timer, CE_POLL_TIMEOUT); } }
ce_per_engine_service_any
void ce_per_engine_service_any(int irq, struct hif_softc *scn) { int CE_id; uint32_t intr_summary; if (Q_TARGET_ACCESS_BEGIN(scn) < 0) return; if (!qdf_atomic_read(&scn->tasklet_from_intr)) { for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; if (qdf_atomic_read(&CE_state->rx_pending)) { qdf_atomic_set(&CE_state->rx_pending, 0); ce_per_engine_service(scn, CE_id); } } Q_TARGET_ACCESS_END(scn); return; } intr_summary = CE_INTERRUPT_SUMMARY(scn); for (CE_id = 0; intr_summary && (CE_id < scn->ce_count); CE_id++) { if (intr_summary & (1 << CE_id)) intr_summary &= ~(1 << CE_id); else continue; /* no intr pending on this CE */ ce_per_engine_service(scn, CE_id); } Q_TARGET_ACCESS_END(scn); }static void ce_tasklet(unsigned long data)
static void ce_tasklet(unsigned long data) { ce_per_engine_service(scn, tasklet_entry->ce_id); }
tasklet初始化的过程如下:
int hif_pci_bus_configure(struct hif_softc *hif_sc) { status = hif_config_ce(hif_sc); } int hif_config_ce(struct hif_softc *scn) { for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { struct CE_attr *attr; pipe_info = &hif_state->pipe_info[pipe_num]; attr = &hif_state->host_ce_config[pipe_num]; if (attr->flags & CE_ATTR_INIT_ON_DEMAND) continue; if (hif_config_ce_by_id(scn, pipe_num)) goto err; } } int hif_config_ce_by_id(struct hif_softc *scn, int pipe_num) { ce_tasklet_init(hif_state, (1 << pipe_num)); // 初始化的地方 ce_register_irq(hif_state, (1 << pipe_num)); init_tasklet_worker_by_ceid(hif_hdl, pipe_num); }
void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask) { int i; for (i = 0; i < CE_COUNT_MAX; i++) { if (mask & (1 << i)) { hif_ce_state->tasklets[i].ce_id = i; hif_ce_state->tasklets[i].inited = true; hif_ce_state->tasklets[i].hif_ce_state = hif_ce_state; tasklet_init(&hif_ce_state->tasklets[i].intr_tq, ce_tasklet, (unsigned long)&hif_ce_state->tasklets[i]); } } }
ce_poll_reap_by_id
static int ce_poll_reap_by_id(struct hif_softc *scn, enum ce_id_type ce_id) { ce_per_engine_service(scn, ce_id); }
htc_flush_rx_hold_queuevoid htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) { HTC_PACKET *pPacket; LOCK_HTC_RX(target); while (1) { pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue); if (!pPacket) break; UNLOCK_HTC_RX(target); pPacket->Status = QDF_STATUS_E_CANCELED; pPacket->ActualLength = 0; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("Flushing RX packet:%pK, length:%d, ep:%d\n", pPacket, pPacket->BufferLength, pPacket->Endpoint)); /* give the packet back */ // 调用地方do_recv_completion_pkt do_recv_completion_pkt(pEndpoint, pPacket); LOCK_HTC_RX(target); } UNLOCK_HTC_RX(target); }