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函数,分析如下:

  1. do_recv_completion

    static 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宏

  2. htc_rx_completion_handler

    QDF_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.rxCompletionHandler

    static 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);
        }
        
  3. htc_flush_rx_hold_queue

    void 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);
    }