Linuxネットワークカード駆動アーキテクチャ分析
14888 ワード
一、ネットカード駆動アーキテクチャ
アプリケーション→システム呼び出しインターフェース→プロトコル無関係インターフェース→ネットワークプロトコルスタック→デバイス無関係インターフェース→デバイス駆動の順に上から下の階層に進む.
二、重要データ構造
1、Linuxカーネルの中の各ネットカードは1つのネットからできています.device構造を説明します.
2、ネットカードの操作機能集:net_device_ops、このデーター構造は上netです.deviceのメンバーです.
3、ネットパケット:sk_buff
三、ネットカードのドライバコード分析
使用したファイルはcs 89 x 0.cで、主に3つの部分を分析します.インターネットカードは初期化して、データを送信して、データを受信します.
一ネットワークカード初期化
ネットワークカードドライバ初期化は、主に関数init_にあります.moduleで完了しました.一部のコードは以下の通りです.
1、定義して分配するnet_device構造は、alloc_を使用しています.etherdv関数
2、初期化net_device(中断番号、I/Oベースアドレス、MACアドレス、netdevuopsを含む)
3、ハードウェアを初期化する
4、ネットワークカードの駆動をカーネルに登録し、関数registerを使用する.netdev
二送信データ
netdev_を初期化します.opsの時はその賦課を&net_とします.opsは、この構造で送信関数を見つけることができます.
1、上位プロトコルにネットワークカードにデータの送信を停止するよう通知する.
ネットカードは今外に向けてパケットを送りますので、受信を停止します.
2、SKbのデータをレジスタに書き込み、送ります.
3、sky空間を解放する
しかし、ここで計算しきれないです.もしこれで上層部協議が終わったら、やはりネットカードにデータを送ることができなくなります.ネットカードは正常に動作しないです.これは正常ではないです.では、上のプロトコルがネットカードにパケットを送ることをどこで再許可しますか?
実際には、ネットワークカードが送信された後に、ネットワークカードの中断プログラムに入ると、request_を検索します.irqの知的中断処理プログラムの名前はnet_です.interrupt
三数据受信
ネットカードが1つのパケットを受け取ったら、ネットカードの中断処理プログラムに入ります.
1、受信状態を読み取る
2、受信データの長さを読み取る
3、SKb構造、SKb=dev_を割り当てる.alloc_skyb(length+2)
4、ハードレジスターからデータを読み出してskyに預け入れます.
5、江のカプセル化されたデータパッケージを上にプロトコルスタックに送り、関数netif_を使用する.rx
ネットカードの駆動構造はここで大体分析済みです.疑問や間違いがあれば、指摘してください.
アプリケーション→システム呼び出しインターフェース→プロトコル無関係インターフェース→ネットワークプロトコルスタック→デバイス無関係インターフェース→デバイス駆動の順に上から下の階層に進む.
二、重要データ構造
1、Linuxカーネルの中の各ネットカードは1つのネットからできています.device構造を説明します.
2、ネットカードの操作機能集:net_device_ops、このデーター構造は上netです.deviceのメンバーです.
3、ネットパケット:sk_buff
三、ネットカードのドライバコード分析
使用したファイルはcs 89 x 0.cで、主に3つの部分を分析します.インターネットカードは初期化して、データを送信して、データを受信します.
一ネットワークカード初期化
ネットワークカードドライバ初期化は、主に関数init_にあります.moduleで完了しました.一部のコードは以下の通りです.
int __init init_module(void)
{
struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
struct net_local *lp;
int ret = 0;
...
dev->irq = irq;
dev->base_addr = io;
...
ret = cs89x0_probe1(dev, io, 1);
...
}
cs 89 x 0_probe 1関数の部分コードは以下の通りです.static int __init cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
{
struct net_local *lp = netdev_priv(dev);
static unsigned version_printed;
int i;
int tmp;
unsigned rev_type = 0;
int eeprom_buff[CHKSUM_LEN];
int retval;
...
writeword(ioaddr, ADD_PORT, PP_ChipID);
tmp = readword(ioaddr, DATA_PORT); //
...
for (i = 0; i < ETH_ALEN/2; i++) // MAC
{
dev->dev_addr[i*2] = eeprom_buff[i];
dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
}
...
dev->netdev_ops = &net_ops; // netdev_ops
...
retval = register_netdev(dev); //
}
コードで確認できます.1、定義して分配するnet_device構造は、alloc_を使用しています.etherdv関数
2、初期化net_device(中断番号、I/Oベースアドレス、MACアドレス、netdevuopsを含む)
3、ハードウェアを初期化する
4、ネットワークカードの駆動をカーネルに登録し、関数registerを使用する.netdev
二送信データ
netdev_を初期化します.opsの時はその賦課を&net_とします.opsは、この構造で送信関数を見つけることができます.
static const struct net_device_ops net_ops = {
.ndo_open = net_open,
.ndo_stop = net_close,
.ndo_tx_timeout = net_timeout,
.ndo_start_xmit = net_send_packet,
.ndo_get_stats = net_get_stats,
.ndo_set_multicast_list = set_multicast_list,
.ndo_set_mac_address = set_mac_address,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = net_poll_controller,
#endif
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
netsend_packetコードは以下の通りです.static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
unsigned long flags;
if (net_debug > 3) {
printk("%s: sent %d byte packet of type %x
",
dev->name, skb->len,
(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
}
spin_lock_irqsave(&lp->lock, flags);
netif_stop_queue(dev); /* initiate a transmit sequence */
writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd);
writeword(dev->base_addr, TX_LEN_PORT, skb->len);
/* Test to see if the chip has allocated memory for the packet */
if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
spin_unlock_irqrestore(&lp->lock, flags);
if (net_debug) printk("cs89x0: Tx buffer not free!
");
return NETDEV_TX_BUSY;
}
/* Write the contents of the packet */
writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
spin_unlock_irqrestore(&lp->lock, flags);
dev->stats.tx_bytes += skb->len;
dev_kfree_skb (skb); return NETDEV_TX_OK;
}
この部分のコードはこれらのことをしました.(赤色のハイライト部分)1、上位プロトコルにネットワークカードにデータの送信を停止するよう通知する.
ネットカードは今外に向けてパケットを送りますので、受信を停止します.
2、SKbのデータをレジスタに書き込み、送ります.
3、sky空間を解放する
しかし、ここで計算しきれないです.もしこれで上層部協議が終わったら、やはりネットカードにデータを送ることができなくなります.ネットカードは正常に動作しないです.これは正常ではないです.では、上のプロトコルがネットカードにパケットを送ることをどこで再許可しますか?
実際には、ネットワークカードが送信された後に、ネットワークカードの中断プログラムに入ると、request_を検索します.irqの知的中断処理プログラムの名前はnet_です.interrupt
static irqreturn_t net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status;
int handled = 0;
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
while ((status = readword(dev->base_addr, ISQ_PORT)))
{
switch(status & ISQ_EVENT_MASK)
{
...
case ISQ_TRANSMITTER_EVENT:
dev->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
if ((status & ( TX_OK |
TX_LOST_CRS |
TX_SQE_ERROR |
TX_LATE_COL |
TX_16_COL)) != TX_OK) {
if ((status & TX_OK) == 0)
dev->stats.tx_errors++;
if (status & TX_LOST_CRS)
dev->stats.tx_carrier_errors++;
if (status & TX_SQE_ERROR)
dev->stats.tx_heartbeat_errors++;
if (status & TX_LATE_COL)
dev->stats.tx_window_errors++;
if (status & TX_16_COL)
dev->stats.tx_aborted_errors++;
}
break;
...
}
}
}
4、トッププロトコルを通知し、ネットカードにデータパケットを送信することができます.関数netif_を使用しますwakequeue三数据受信
ネットカードが1つのパケットを受け取ったら、ネットカードの中断処理プログラムに入ります.
static irqreturn_t net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status;
int handled = 0;
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
while ((status = readword(dev->base_addr, ISQ_PORT)))
{
switch(status & ISQ_EVENT_MASK)
{
...
case ISQ_RECEIVER_EVENT:
/* Got a packet(s). */
net_rx(dev);
break;
}
}
}
netrx関数コードは以下の通りです.static void net_rx(struct net_device *dev)
{
struct sk_buff *skb;
int status, length;
int ioaddr = dev->base_addr;
status = readword(ioaddr, RX_FRAME_PORT);
length = readword(ioaddr, RX_FRAME_PORT);
if ((status & RX_OK) == 0) {
count_rx_errors(status, dev);
return;
}
/* Malloc up new buffer. */
skb = dev_alloc_skb(length + 2);
if (skb == NULL) {
#if 0 /* Again, this seems a cruel thing to do */
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.
", dev->name);
#endif
dev->stats.rx_dropped++;
return;
}
skb_reserve(skb, 2); /* longword align L3 header */
readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
if (length & 1)
skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT);
if (net_debug > 3) {
printk( "%s: received %d byte packet of type %x
",
dev->name, length,
(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
}
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += length;
}
コードで確認できます.1、受信状態を読み取る
2、受信データの長さを読み取る
3、SKb構造、SKb=dev_を割り当てる.alloc_skyb(length+2)
4、ハードレジスターからデータを読み出してskyに預け入れます.
5、江のカプセル化されたデータパッケージを上にプロトコルスタックに送り、関数netif_を使用する.rx
ネットカードの駆動構造はここで大体分析済みです.疑問や間違いがあれば、指摘してください.