网络设备驱动

一、网络驱动结构

应用 (socket)
  ↓
AF_INET / AF_PACKET
  ↓
TCP / UDP / IP / ...
  ↓
邻居子系统、L3 处理
  ↓
dev_queue_xmit(发送)
  ↓
NAPI / netif_rx(接收)
  ↓
驱动
  ↓
网卡硬件

二、关键数据结构

1. struct net_device

struct net_device {
    char name[IFNAMSIZ];          // eth0, wlan0...
    unsigned long state;
    struct net_device_stats stats;  // 统计
    const struct net_device_ops *netdev_ops;
    const struct ethtool_ops *ethtool_ops;
    struct list_head dev_list;
    // ...
};

2. struct sk_buff(socket buffer)

struct sk_buff {
    struct net_device *dev;
    __u16 protocol;              // ETH_P_IP...
    __be16 layer_4_proto;        // TCP/UDP
    unsigned int len;
    unsigned int data_len;
    __u8 *data;                  // 当前指针
    __u8 *head;
    __u8 *tail;
    __u8 *end;
    struct sk_buff *next;
    // ...
};

3. struct net_device_ops

struct net_device_ops {
    int (*ndo_open)(struct net_device *dev);
    int (*ndo_stop)(struct net_device *dev);
    netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev);
    void (*ndo_set_rx_mode)(struct net_device *dev);
    int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
    int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
    // ...
};

4. ethtool_ops(可选)

struct ethtool_ops {
    int (*get_settings)(struct net_device *, struct ethtool_cmd *);
    int (*set_settings)(struct net_device *, struct ethtool_cmd *);
    void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
    // ...
};

三、注册网络设备

static int my_init(void)
{
    struct net_device *ndev = alloc_etherdev(sizeof(struct my_priv));
    // alloc_etherdev = alloc_netdev(sizeof_priv, "eth%d", NET_NAME_UNKNOWN, ether_setup);

    my_priv = netdev_priv(ndev);
    ndev->netdev_ops = &my_netdev_ops;
    ndev->ethtool_ops = &my_ethtool_ops;
    ndev->flags |= IFF_NOARP;       // 或不设
    register_netdev(ndev);
    return 0;
}

四、发送

static netdev_tx_t my_xmit(struct sk_buff *skb, struct net_device *dev)
{
    // 1. 检查硬件队列
    if (!netif_carrier_ok(dev) || !netif_running(dev)) {
        dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
    }
    if (netif_queue_stopped(dev)) {
        return NETDEV_TX_BUSY;
    }

    // 2. 准备 DMA:把 skb 映射到 DMA 地址
    dma_addr_t dma = dma_map_single(dev->dev.parent, skb->data, skb->len,
                                     DMA_TO_DEVICE);
    if (dma_mapping_error(dev->dev.parent, dma)) {
        dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
    }

    // 3. 写入 DMA 描述符 / 触发硬件
    hw_send_packet(dma, skb->len);

    // 4. 记账
    dev->stats.tx_packets++;
    dev->stats.tx_bytes += skb->len;
    return NETDEV_TX_OK;
}

五、接收(NAPI 模式)

// 中断中
static irqreturn_t my_irq(int irq, void *dev_id)
{
    struct my_priv *priv = netdev_priv(dev);
    if (likely(napi_schedule_prep(&priv->napi))) {
        __napi_schedule(&priv->napi);
        // 关中断
    }
    return IRQ_HANDLED;
}

// NAPI poll
static int my_poll(struct napi_struct *napi, int budget)
{
    struct my_priv *priv = container_of(napi, struct my_priv, napi);
    int work_done = 0;

    while (work_done < budget) {
        struct sk_buff *skb = rx_one_packet(priv);
        if (!skb) break;
        skb->protocol = eth_type_trans(skb, dev);
        napi_gro_receive(napi, skb);
        work_done++;
    }

    if (work_done < budget) {
        napi_complete_done(napi, work_done);
        // 开中断
    }
    return work_done;
}

// 初始化
netif_napi_add(dev, &priv->napi, my_poll, 64);
napi_enable(&priv->napi);

六、netif 操作

netif_start_queue(dev);
netif_stop_queue(dev);
netif_wake_queue(dev);
netif_carrier_on(dev);
netif_carrier_off(dev);
netif_queue_stopped(dev);

七、统计

dev->stats.rx_packets++;
dev->stats.tx_packets++;
dev->stats.rx_bytes++;
dev->stats.tx_bytes++;
dev->stats.rx_errors++;
dev->stats.tx_errors++;
dev->stats.collisions++;
dev->stats.rx_dropped++;

八、设备树

ethernet0: ethernet@40000000 {
    compatible = "myvendor,myeth";
    reg = <0x40000000 0x10000>;
    interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clks 17>;
    phy-mode = "rgmii";
    pinctrl-0 = <&pinctrl_eth0>;
    #address-cells = <1>;
    #size-cells = <0>;

    phy0: ethernet-phy@1 {
        reg = <1>;
        device_type = "ethernet-phy";
    };
};

驱动中:

struct device_node *np = dev->of_node;
struct device_node *phy_np = of_parse_phandle(np, "phy-handle", 0);
priv->phy = of_phy_connect(ndev, phy_np, &my_adjust_link, 0, priv->phy_mode);
struct phy_device *phy = phy_find_first(mii_bus);
phy_connect_direct(dev, phy, &adjust_link, PHY_INTERFACE_MODE_RGMII);
phy_start(phy);

十、Socket buffer 操作

// 分配
struct sk_buff *skb = dev_alloc_skb(len + NET_IP_ALIGN);
skb_reserve(skb, NET_IP_ALIGN);   // 预留对齐空间
skb_put(skb, len);                // 数据入尾
memcpy(skb->data, data, len);     // 填充

// 释放
dev_kfree_skb(skb);                // 发送失败
consume_skb(skb);                  // 发送成功
kfree_skb(skb);                    // 接收时申请后失败

// 推入头
skb_push(skb, hlen);              // 给协议头留空间
// 拉出尾
skb_trim(skb, newlen);

十一、嵌入式网络要点