MTK eCos系統的有線驅動收包流程

普朗克常量發表於2019-01-08

驅動裝置註冊

如下,註冊了ra305x_eth_netdev1,關聯ra305x_eth_sc1方法,ra305x_eth_sc1定義時關聯了eth_drv_funs。if_ra305x_init將在cyg_net_init_devs中被呼叫。if_ra305x_init初始化時呼叫ra305x_init,其中呼叫cyg_drv_interrupt_create註冊了中斷處理函式ra305x_isr和ra305x_dsr。至此,中斷處理,物理裝置處理,邏輯裝置處理關聯已經完成。

/* 裝置定義,定義一個全域性變數 */
#define ETH_DRV_SC(sc,priv,name,start,stop,control,can_send,send,recv,deliver,poll,int_vector) \
static void start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags); \
static void stop(struct eth_drv_sc *sc); \
static int  control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length); \
static int  can_send(struct eth_drv_sc *sc); \
static void send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total, unsigned long key); \
static void recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len); \
static void deliver(struct eth_drv_sc *sc); \
static void poll(struct eth_drv_sc *sc); \
static int  int_vector(struct eth_drv_sc *sc); \
static struct eth_hwr_funs sc##_funs = {        \
    start,                                      \
    stop,                                       \
    control,                                    \
    can_send,                                   \
    send,                                       \
    recv,                                       \
    deliver,                                    \
    poll,                                       \
    int_vector,                                 \
    &eth_drv_funs,                              \       //關聯了通用邏輯裝置方法
    (struct eth_drv_funs *)0 };                 \
struct eth_drv_sc sc = {&sc##_funs, priv, name};

// 通用邏輯裝置方法註冊
struct eth_drv_funs eth_drv_funs = {eth_drv_init, eth_drv_recv, eth_drv_tx_done};

// 物理裝置方法註冊
ETH_DRV_SC(ra305x_eth_sc1,
	   &ra305x_eth1_priv_data,			/*  Driver specific data  */
	   CYGDAT_DEVS_ETH_MIPS_RA305X_ETH1_NAME,	/*  Name of device  */
	   if_ra305x_start,
	   if_ra305x_stop,
	   if_ra305x_ioctl,
	   if_ra305x_cansend,
	   if_ra305x_send,
	   if_ra305x_recv,
	   if_ra305x_deliver,
	   if_ra305x_poll,
	   if_ra305x_intvector);

// 初始化
NETDEVTAB_ENTRY(ra305x_eth_netdev1,
	"ra305x_" CYGDAT_DEVS_ETH_MIPS_RA305X_ETH1_NAME,
	if_ra305x_init,
	&ra305x_eth_sc1);

// 物理裝置中斷處理方法註冊
cyg_drv_interrupt_create(pra305x->vector,
			0,				/*  Priority  */
			(CYG_ADDRWORD) pra305x, 	/*  interupt context  */
			ra305x_isr,			/*  ISR function  */
			ra305x_dsr,			/*  DSR function  */
			&pra305x->int_hdl,		/*  interrupt handle  */
			&pra305x->int_obj);		/*  interrupt object  */

中斷處理

ra305x_dsr
  eth_drv_funs
    ecos_synch_eth_drv_dsr
      調cyg_flag_setbits( &alarm_flag, 2 );喚醒Network alarm support執行緒

Network alarm support執行緒處理

執行緒入口函式為alarm_thread,發現alarm_flag標誌為2,執行
eth_drv_run_deliveries
  (*sc->funs->deliver)(sc),即執行if_ra305x_deliver函式
    ra305x_rxint
      eth_drv_recv 通過(pifra305x->sc->funs->eth_drv->recv)() 呼叫
        分配mbuf結構體
        if_ra305x_recv 通過(sc->funs->recv)(sc, sg_list, sg_len) 呼叫物理裝置的recv函式
          拷貝資料
        ether_input
          ether_demux
             這裡會進行fastpath,資料包過濾。
             然後呼叫schednetisr(NETISR_SNIFFER)喚醒Network support執行緒進行協議棧處理。然後將資料包通過IF_ENQUEUE放入佇列。

Network support執行緒處理

執行緒入口函式為cyg_netint
這裡主要是協議棧處理,我們以ip協議為例,說下,如何調到ip_input的。
在in_proto.c裡面的全域性變數裡註冊了很多協議,這裡擷取部分

struct protosw inetsw[] = {
{ 0,		&inetdomain,	0,		0,
  0,		0,		0,		0,
  0,
  ip_init,	0,		ip_slowtimo,	ip_drain,
  &nousrreqs
},
{ SOCK_DGRAM,	&inetdomain,	IPPROTO_UDP,	PR_ATOMIC|PR_ADDR,
  udp_input,	0,		udp_ctlinput,	ip_ctloutput,
  0,
  udp_init,	0,		0,		0,
  &udp_usrreqs
},
{ SOCK_STREAM,	&inetdomain,	IPPROTO_TCP,
	PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD,
  tcp_input,	0,		tcp_ctlinput,	tcp_ctloutput,
  0,
  tcp_init,	0,		tcp_slowtimo,	tcp_drain,
  &tcp_usrreqs
},
{ SOCK_RAW,	&inetdomain,	IPPROTO_RAW,	PR_ATOMIC|PR_ADDR,
  rip_input,	0,		rip_ctlinput,	rip_ctloutput,
  0,
  0,		0,		0,		0,
  &rip_usrreqs
},
}

其中就註冊了IP協議,初始化函式為ip_init,其中通過register_netisr(NETISR_IP, ipintr);註冊了網路的isr,ipintr中呼叫IF_DEQUEUE取出資料包,然後呼叫ip_input函式。

相關文章