第十八期 U-Boot 网络原理分析《路由器就是开发板》

来源:互联网 发布:淘宝店铺的流量是什么 编辑:程序博客网 时间:2024/06/16 16:38
转载地址:http://blog.csdn.net/aggresss/article/details/52712415
上一期在写入flash时用到了tftp服务tftpboot 0x80100000 uboot.bin,也就是通过网络传输协议,这一期我们来分析一下U-Boot是怎么控制hg255d进行网络传输的。
首先,在common/cmd_net.c 文件中找到tftpboot的定义,
[cpp] view plain copy
  1. U_BOOT_CMD(  
  2.     tftpboot,   3,  1,  do_tftpb,  
  3.     "tftpboot- boot image via network using TFTP protocol\n",  
  4.     "[loadAddress] [bootfilename]\n"  
  5. );  
这个命令是通过调用do_tftpb函数来完成的
[cpp] view plain copy
  1. int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  
  2. {  
  3. #ifdef DEBUG  
  4.    printf("File: %s, Func: %s, Line: %d\n", __FILE__,__FUNCTION__ , __LINE__);  
  5. #endif     
  6.     return netboot_common (TFTP, cmdtp, argc, argv);  
  7. }  
do_tftpb又是通过调用netboot_common来实现的,看一下它的原型:
static int netboot_common (int proto, cmd_tbl_t *cmdtp, int argc, char *argv[]);
这个函数的第一个参数是网络启动的协议类型,第190行 if ((size = NetLoop(proto)) < 0) 中发现,NetLoop函数来调用相应的协议,跟进NetLoop函数,在函数的注释部分说明为:Main network processing loop. 可见他就是U-Boot实现网络功能的主要函数。这个函数比较长,大约有400行,这里就不贴出来了,这个函数的大体原理就是首先进行一些变量的初始化,读取系统变量中的IP配置信息,然后根据传入参数选择具体的协议,最后在517行进入一个for循环,在循环中可以发现eth_rx()这个函数用来接收数据,果断跟进发现在/net/eth.c中定义,开始分析这个文件:
[cpp] view plain copy
  1. int eth_send(volatile void *packet, int length)  
  2. {  
  3.     if (!eth_current)  
  4.         return -1;  
  5.   
  6.     return eth_current->send(eth_current, packet, length);  
  7. }  
  8.   
  9. int eth_rx(void)  
  10. {  
  11.     if (!eth_current)  
  12.         return -1;  
  13.   
  14.     return eth_current->recv(eth_current);  
  15. }  
数据的收发都是通过这两个函数来进行的,可以发现网卡设备也就是eth_device在U-Boot中被抽象成一个结构体:
[cpp] view plain copy
  1. struct eth_device {  
  2.     char name[NAMESIZE];  
  3.     unsigned char enetaddr[6];  
  4.     int iobase;  
  5.     int state;  
  6.   
  7.     int  (*init) (struct eth_device*, bd_t*);  
  8.     int  (*send) (struct eth_device*, volatile void* pachet, int length);  
  9.     int  (*recv) (struct eth_device*);  
  10.     void (*halt) (struct eth_device*);  
  11.   
  12.     struct eth_device *next;  
  13.     void *priv;  
  14. };  
这个结构体包含名称,mac地址,寄存器基址,状态信息,和初始化,发送,接收,暂停的函数指针,具体这个结构体是怎么被实例化的我们还要分析U-Boot的初始化过程,在board.c文件第1627行的board_init_r()函数中eth_initialize()函数来实现这个网络设备初始化的操作,这个函数主要作用是根据CONFIG_的配置信息来选择具体的初始化函数,因为RT3052内部集成了ehernet控制器,所以调用rt2880_eth_initialize(bis);函数来初始化网络控制器:
[cpp] view plain copy
  1. int rt2880_eth_initialize(bd_t *bis)  
  2. {  
  3.     struct  eth_device*     dev;  
  4.     int i;  
  5.     u32 regValue;  
  6.   
  7.     if (!(dev = (struct eth_device *) malloc (sizeof *dev))) {  
  8.         printf("Failed to allocate memory\n");  
  9.         return 0;  
  10.     }  
  11.   
  12.     memset(dev, 0, sizeof(*dev));  
  13.   
  14.     sprintf(dev->name, "Eth0 (10/100-M)");  
  15.   
  16.     dev->iobase = RALINK_FRAME_ENGINE_BASE;  
  17.     dev->init   = rt2880_eth_init;  
  18.     dev->halt   = rt2880_eth_halt;  
  19.     dev->send   = rt2880_eth_send;  
  20.     dev->recv   = rt2880_eth_recv;  
  21.   
  22.     eth_register(dev);  
  23.     eth_loopback_mode = 0;  
  24.     rt2880_pdev = dev;  
  25.     loopback_protect = 0;  
  26.   
  27.     force_queue_n = 3;  
  28.     sdp0_alig_16n_x = 0;  
  29.     sdp1_alig_16n_x = 0;  
  30.     rt2880_eth_initd =0;  
  31.     rt2880_size_of_mem = 0;  
  32.     rt2880_esram_gear = ESRAM_OFF;  
  33.     internal_loopback_test = INTERNAL_LOOPBACK_DISABLE;  
  34.     header_payload_scatter_en = DISABLE;  
  35.     rt2880_buf_in_esram_en = DISABLE;  
  36.     rt2880_desc_in_esram = DISABLE;  
  37.     rt2880_sdp0_buf_in_esram_en = DISABLE;  
  38.     PktBuf = Pkt_Buf_Pool;  
  39.     PKT_HEADER_Buf = PKT_HEADER_Buf_Pool;  
  40.     is_internal_loopback_test = 0;  
  41.     rt2880_hdrlen = 20;  
  42.     NetTxPacket = NULL;  
  43.     rt2880_debug_en = DISABLE;  
  44.     rx_ring = (struct PDMA_rxdesc *)KSEG1ADDR((ulong)&rx_ring_cache[0]);  
  45.     tx_ring0 = (struct PDMA_txdesc *)KSEG1ADDR((ulong)&tx_ring0_cache[0]);  
  46.   
  47.     rt2880_free_buf_list.head = NULL;  
  48.     rt2880_free_buf_list.tail = NULL;  
  49.   
  50.     rt2880_busing_buf_list.head = NULL;  
  51.     rt2880_busing_buf_list.tail = NULL;  
  52.   
  53.     //2880_free_buf  
  54.   
  55.     /* 
  56.      *  Setup packet buffers, aligned correctly. 
  57.      */  
  58.     rt2880_free_buf[0].pbuf = (unsigned char *)(&PktBuf[0] + (PKTALIGN - 1));  
  59.     rt2880_free_buf[0].pbuf -= (ulong)rt2880_free_buf[0].pbuf % PKTALIGN;  
  60.     rt2880_free_buf[0].next = NULL;  
  61.   
  62.     rt2880_free_buf_entry_enqueue(&rt2880_free_buf_list,&rt2880_free_buf[0]);  
  63.   
  64. #ifdef DEBUG  
  65.     printf("\n rt2880_free_buf[0].pbuf = 0x%08X \n",rt2880_free_buf[0].pbuf);  
  66. #endif  
  67.     for (i = 1; i < PKTBUFSRX; i++) {  
  68.         rt2880_free_buf[i].pbuf = rt2880_free_buf[0].pbuf + (i)*PKTSIZE_ALIGN;  
  69.         rt2880_free_buf[i].next = NULL;  
  70. #ifdef DEBUG  
  71.         printf("\n rt2880_free_buf[%d].pbuf = 0x%08X\n",i,rt2880_free_buf[i].pbuf);  
  72. #endif  
  73.         rt2880_free_buf_entry_enqueue(&rt2880_free_buf_list,&rt2880_free_buf[i]);  
  74.     }  
  75.   
  76.     for (i = 0; i < PKTBUFSRX; i++)  
  77.     {  
  78.         rt2880_free_buf[i].tx_idx = NUM_TX_DESC;  
  79. #ifdef DEBUG  
  80.         printf("\n rt2880_free_buf[%d] = 0x%08X,rt2880_free_buf[%d].next=0x%08X \n",i,&rt2880_free_buf[i],i,rt2880_free_buf[i].next);  
  81. #endif  
  82.     }  
  83.           
  84.       
  85.     //set clock resolution  
  86.     extern unsigned long mips_bus_feq;  
  87.     regValue = le32_to_cpu(*(volatile u_long *)(RALINK_FRAME_ENGINE_BASE + 0x0008));  
  88.     regValue |=  ((mips_bus_feq/1000000) << 8);  
  89.     *((volatile u_long *)(RALINK_FRAME_ENGINE_BASE + 0x0008)) = cpu_to_le32(regValue);  
  90.       
  91.     return 1;  
  92. }  
到这里,如果您一直在跟进,大概就能了解顶层函数是怎样一步一步的最底层的硬件进行控制的,分析U-Boot这样的软件对于将来做架构方面的转型很有帮助,因为U-Boot中的universual就是靠出色的架构来兼容各种硬件设备。
像ethernet这种设备都是分层工作的我们只要控制寄存器就行,具体的phy层次的操作都是有芯片厂商通过硬件有限状态机的模式实现。
#define RALINK_FRAME_ENGINE_BASE 0xB0100000
我们来查看ralink_RT3052的Datasheet的3.17节:


关于Frame Engine 这一节的内容还是比较多的,而且比较复杂,如果讲详细,我相信可以出一本书了,我这里讲解一下分析思路,希望大家再进行更深层次的拓展学习。
----------------------------------------------------
SDK下载地址:   https://github.com/aggresss/RFDemo
阅读全文
0 0