Open Ethernet IP core 介绍及其 ucLinux 驱动

来源:developerWorks 中国 作者:杨 勇
  
Open Ethernet IP core 是一种支持 10M/100Mbps 以太网的开发源代码 MAC IP core,实现IEEE 802.3 MAC 层功能,对上下接口分别采用 Wishbone 总线和 MII 接口,由于其免费公开,可移植性和可定制性,在 FPGA SOC(System On Chip) 系统及嵌入式系统中被广泛采用,而在 ucLinux 操作系统中也有相应完善的设备驱动支持。在设计中采用 Open Ethernet IP core,可大大降低开发成本和缩短产品上市时间。

Open Ethernet IP core 介绍

Open Ethernet IP core 是一种支持 10M/100Mbps 以太网的 MAC IP core,实现数据链路层的功能,其最大的特点便是公开免费,它不同于常见的 ASIC 网卡芯片,能够很方便的集成到片上系统(SOC)设计中去。

基本结构

MAC, 即 Media Access control, 位于 OSI 七层模型中数据链路部分,主要负责控制与物理层的物理介质通信。Ethernet IP core自身实现MAC收发和控制的功能,本身不具有物理层(PHY)的功能。MAC core 对外接口有两个:和 Host 端采用 Wishbone 总线通信,对外 PHY 芯片采用通用的 MII 接口。

  • MAC 包含接收,发送和控制模块;
  • 支持 MII 管理 (Media Independent Interface Management),MII 串行信号连接至外部PHY;
  • 主机接口采用开放的 Wishbone 总线。

Wishbone 是一种片上(SOC)总线,常见的片上总线有 ARM 的 AMBA, Altera 公司的 Avalon,以及 Silicon公司的 Wishbone。以上三种总线只有 Wishbone是开放并且完全免费的总线标准。 Wishbone 由 Silicon 开发并目前由 Opencores 组织维护。

MII 实际上可分为两部分,分别是数据流和管理流。MIIM(MII Management) 是用于对外围 PHY 芯片的管理所用的,通过 MIIM 串行接口可以查看 PHY 寄存器状态等信息。


图 1. Ethernet MAC core overview
Ethernet MAC core overview

主要特性

Open Ethernet core 处于 Host(CPU) 和外围 PHY 芯片之间,实现了 MAC 层的所有功能,并且采用开放的 wishbone 总线接口,源码公开便于移植,广泛应用于 FPGA SOC(System On Chip) 设计中,Flextronics Semiconductor 公司在设计中就选用了该IP core。该 IP core 的主要特性如下:

  • 实现 IEEE 802.3 以太网 MAC 功能
  • 10M/100Mbps 速率;
  • 全双工支持;
  • IEEE 802.3 MII;
  • Wishbone SOC总线接口;
  • 内部RAM可存放128 TX/RX BD(Buffer Descriptors);
  • 事件触发中断。

MAC registers

MAC register用于MAC操作,提供MAC core控制和状态信息。ucLinux设备驱动需要对这些寄存器进行配置。有关MAC register的操作在后面章节会有描述,在此不再赘述。





Open Ethernet Core在ucLinux-2.6上的设备驱动

目前 ucLinux-2.6已经支持 Open Ethernet MAC,在 make menuconfig 配置菜单中选中

Device driver->Network device support->Ethernet (10 or 100Mbit)->Opencores (Igor) Emac support

这样 Open Ethernet 的设备驱动将会被编译进 ucLinux 内核,负责 MAC 物理网络设备的支持。


图 2. Open Ethernet device driver in ucLinux-2.6
Open Ethernet device driver in ucLinux-2.6

参见 linux/drivers/net/open_eth.c

重要的数据结构

参考 linux-2.6/include/linux/netdevice.h

a) struct net_device;

在 Linux 系统中每一个网络设备接口都对应着一个 net_device 的数据结构体, net_device 记录了网络接口的所有信息,其成员可以分为四类:

  • 全局信息: 接口名字,状态以及初始化函数;
  • 硬件信息:占用内存起始地址,IO 基地址和中断号以及 DMA 使用等;
  • 接口信息:MAC接口本身的信息,比如发送队列长度,MAC地址,和接口标志(UP/BROADCAST/PROMISC) 等;
  • 设备方法:open(), stop(), hard_start_xmit(), tx_timeout(), get_stats(), set_config() 等。

ucLinux 网络设备驱动初始化函数的部分工作便是填充上述结构成员。

b) struct oeth_private是 ucLinux open Ethernet 驱动层用于记录网络数据包的环型缓冲区而建立的数据结构,sk_buff 是用于和上层 TCP/IP 协议处理层交互的,而 oeth_bd 是用于和MAC 硬件层交互的。

struct oeth_private {
    struct sk_buff  *rx_skbuff[OETH_RXBD_NUM];
    struct sk_buff  *tx_skbuff[OETH_TXBD_NUM];

    ushort  tx_next;   /* Next buffer to be sent */
    ushort  tx_last;   /* Next buffer to be checked if packet sent */
    ushort  tx_full;   /* Buffer ring full indicator */
    ushort rx_cur; /* Next buffer to be checked if packet received */

    volatile oeth_regs  *regs; /* Address of controller registers. */
    volatile oeth_bd    *rx_bd_base;/* Address of Rx BDs. */
    volatile oeth_bd    *tx_bd_base;/* Address of Tx BDs. */

    struct net_device_stats stats;
    struct tasklet_struct	 oeth_rx_tasklet;
    struct tasklet_struct	 oeth_tx_tasklet;

    struct mii_if_info mii;
    spinlock_t  lock;
};

c) Buffer Descriptor (BD) 结构是是用于 MAC 控制和数据传递的核心数据结构。每个 BD描述 MAC 层收发的数据包,包括 len_status 和 addr 成员,len_status 描述每个数据包的长度和状态信息;addr 表示数据包存放的 RAM 地址,便于设备驱动的访问。MAC core支持最多128个 BD,每 BD 占用64bit。

struct _oeth_bd {
        uint    len_status;
        uint    addr;           /* Buffer address */
} oeth_bd;

下面两个表格分别描述了 len_status 和 addr 的位域信息

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
Packet length
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
RD IRQ WR PAD CRC Reserved UR RTRY[3:0] RL LC DF CS

Fig.3 len_status in struct _oeth_bd

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
Buffer address[31:16]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Buffer address[15:0]

Fig.4 addr in struct _oeth_bd

oeth_private 包含了数据收发 oeth_bd 单向队列,打开设备时驱动必须给每个 oeth_bd addr 分配 RAM 空间, MAC 层接收到数据包会将数据自动放到 BD addr 指向的内存空间,并设置相应 len_status 状态信息,然后(在中断使能的情况下)产生中断;Linux 需要发送数据时,open Ethernet 接口驱动将从上层 TCP/IP 协议驱动层的 skbuff 数据包转移到发送缓冲 BD 的内存地址空间(BD address), 并设置好 len_status 的长度,这样便会触发 MAC 将数据包适当处理后发送出去,并在发送完成后(在中断使能的情况下)产生中断。

open ethernet 设备初始化(Device initialization)

struct net_device * __init oeth_init(int unit);

oeth_init() 是 open Ethernet 设备驱动的入口,它只会在 Linux 初始化时调用一次,之后其占用的空间会被释放掉。oeth_init() 会调用 oeth_probe() 函数分配 IO 空间(通过 iomap())对 MAC 控制器的相关配置寄存器进行设置,比如工作模式,以太帧最大最小长度,TX/RX BD pointer, 设置 MAC 地址,清除状态标志以及中断使能等;然后会调用 register_netdev() 向 Linux 内核注册该网络设备。

这里主要介绍一下 open Ethernet MAC core 几个重要的寄存器,这几个寄存器的配置正确与否直接决定着该网络设备的工作稳定性。

typedef struct _oeth_regs {
        uint    moder;          /* Mode Register */
        uint    int_src;        /* Interrupt Source Register */
        uint    int_mask;       /* Interrupt Mask Register */
        uint    ipgt;           /* Back to Bak Inter Packet Gap Register */
        uint    ipgr1;          /* Non Back to Back Inter Packet Gap Register 1 */
        uint    ipgr2;          /* Non Back to Back Inter Packet Gap Register 2 */
        uint    packet_len;     /* Packet Length Register (min. and max.) */
        uint    collconf;       /* Collision and Retry Configuration Register */
        uint    tx_bd_num;      /* Transmit Buffer Descriptor Number Register */
        uint    ctrlmoder;      /* Control Module Mode Register */
        uint    miimoder;       /* MII Mode Register */
        uint    miicommand;     /* MII Command Register */
        uint    miiaddress;     /* MII Address Register */
        uint    miitx_data;     /* MII Transmit Data Register */
        uint    miirx_data;     /* MII Receive Data Register */
        uint    miistatus;      /* MII Status Register */
        uint    mac_addr0;      /* MAC Individual Address Register 0 */
        uint    mac_addr1;      /* MAC Individual Address Register 1 */
        uint    hash_addr0;     /* Hash Register 0 */
        uint    hash_addr1;     /* Hash Register 1 */                           
} oeth_regs;

参考 ucLinux 代码 Linux-2.6/drivers/net/open_eth.c 中 oeth_probe() 函数有对上述寄存器具体设置。

这里值得一提的是以 mii* 命名开头的寄存器相关设置。MII Management (MIIM) 用于PHY 寄存器控制和相关状态信息的访问,比如 Link status。 与此相应,PHY 便提供了一些寄存器便于这样的操作。MIIM 物理接口包括一根双向数据线 MDIO(Management Data Input/Output) 和一根时钟线 MDC(Management Data Clock),MIIM 操作的命令和数据便通过这串行接口在 MAC 和 PHY 传递。如果使能了 OETH_SYSFS_MDIO_ACCESS,则在 Linux 用户可通过 sysfs 文件系统实现从 userspace 访问 MIIM 管理数据的访问。

open ethernet 设备方法(Device methods)

网络设备的设备方法可以分为两种,基本方法和可选方法。以下代码是初始化函数调用 oeth_probe() 对 net_device * net 结构体成员的填充。

    dev->open = oeth_open;
    dev->hard_start_xmit = oeth_start_xmit;
    dev->stop = oeth_close;
    dev->get_stats = oeth_get_stats;
    dev->set_multicast_list = oeth_set_multicast_list;
    dev->set_mac_address = oeth_set_mac_add;

    bmcr_val = eth_mdread(dev, PHY_ADDRESS, MII_BMCR);
    dev->do_ioctl = mii_ioctl;
    cep->mii.dev = dev;
    cep->mii.mdio_read = eth_mdread;
    cep->mii.mdio_write = eth_mdwrite;

oeth_open() 打开该网络接口。用户命令 ifconfig 激活该网络接口时,该接口函数会被调用。Oeth_open() 向系统注册内存使用空间,申请中断号注册中断处理函数等。中断号宏 MACIRQ_NUM 和寄存器基地址 ETH_BASE_ADD 根据实际的硬件设计相应的设置。

    /*Install eth interrupt handler*/
request_irq(MACIRQ_NUM, oeth_interrupt, 0, "eth", (void *)dev);
    /*Enable receiver and transmitter */
    regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
    /*set tasklet for receiver and transmitter*/
tasklet_init(&cep->oeth_rx_tasklet, oeth_rx, (unsigned long)dev);
    tasklet_init(&cep->oeth_tx_tasklet, oeth_tx, (unsigned long)dev);

通常对于10/100M 的网卡设备,驱动会采用中断方式(对于更高速(10Gb) 的网卡,采用通常意义的中断方式效率较低)。中断处理函数 (ISR) oeth_interrupt 必须精短,只需要做最少的事情,而具体的数据包处理由 taskelet 去完成。在这里, oeth_interrupt 的任务就是根据中断事件标志调度数据收发相应的 tasklet, 如下:

/* Handle receive event in its own function.*/
    if (int_events & (OETH_INT_RXF | OETH_INT_RXE | OETH_INT_BUSY))
        tasklet_schedule(&cep->oeth_rx_tasklet);       
    /* Handle transmit event in its own function. */
    if (int_events & (OETH_INT_TXB | OETH_INT_TXE))
        tasklet_schedule(&cep->oeth_tx_tasklet);       


图 3. oeth interrupt service routine
oeth interrupt service routine

oeth_start_xmit() 是由设备驱动发起数据包的传送。


图 4. oeth_start_xmit()
oeth_start_xmit()

oeth_get_stats() 返回网络接口的统计状态,譬如接收和发送字节数,以及错误丢包等信息。用户用“ifconfig” 命令可以查看到这些统计信息。

此外,还提供了 MIIM 相关的设备方法用于对 PHY 的访问控制。

cep->mii.mdio_read = eth_mdread;//读PHY寄存器
    cep->mii.mdio_write = eth_mdwrite;//写PHY寄存器
    cep->mii.phy_id_mask = 0x1f;
    cep->mii.reg_num_mask = 0x1f;
    cep->mii.phy_id = PHY_ADDRESS;

ucLinux 也提供了通用的 MII 访问方法用于访问修改 PHY 收发器的工作模式,参见 unLinux 源代码<linux/mii.h>





结束语

在嵌入式领域通常需要涉及到软硬件接口的问题,open ethernet MAC core 是一个开放公开的结构,不光是软件可以开源,硬件设计也可以开放,开源,这种硬件的公开性为软件开放提供更多便利性,可以为软件需要定制特定硬件,譬如 TOE(TCP/IP Offload Engine) 技术将传统的 TCP/IP 协议从软件处理搬移到网卡 (NIC) 硬件完成,这种软硬件的开放性必然促进IT技术,尤其是嵌入式系统的创新。(责任编辑:A6)


时间:2009-01-16 15:51 来源:developerWorks 中国 作者:杨 勇 原文链接

好文,顶一下
(0)
0%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量