Analysis of Linux network card driver architecture

Source: Internet
Author: User

First, the network card driver architecture

From top to bottom level: Application → system call interface → protocol Independent interface → network protocol stack → device Independent interface → device driver.

II. Important data structures

1. Each NIC in the Linux kernel is described by a net_device structure.

2, network card operation function set: Net_device_ops, this data structure is a member of the above Net_device.

3, network packet: Sk_buff.

Third, network card driver code Analysis

The file used is cs89x0.c, the main analysis of three parts: network card initialization, send data, receive data.

㈠ NIC Initialization

Network card driver initialization is mainly done in function init_module, some of the code is as follows:

int __init init_module (void) {  struct net_device *dev = Alloc_etherdev (sizeof< /c4> (struct  net_local)); struct net_local *LP; int 0;
...
DEV->IRQ = IRQ;
dev->base_addr = IO;
...
ret = cs89x0_probe1 (dev, io, 1);
...
}

The CS89X0_PROBE1 function section code is as follows:

Static int__init Cs89x0_probe1 (structNet_device *dev,intIOADDR,intModular) {structNet_local *LP =Netdev_priv (Dev); Staticunsigned version_printed; inti; inttmp; unsigned rev_type=0;intEeprom_buff[chksum_len];intretval
...
Writeword (Ioaddr, Add_port, pp_chipid);
TMP = Readword (ioaddr, Data_port); Initialization of the hardware
...
  
for (i = 0; i < ETH_ALEN/2; i++)//Initialize MAC address
{
DEV-&GT;DEV_ADDR[I*2] = Eeprom_buff[i];
DEV-&GT;DEV_ADDR[I*2+1] = eeprom_buff[i] >> 8;
}
...
  
Dev->netdev_ops = &net_ops; Initialize Netdev_ops
...
retval = Register_netdev (dev); Registering the NIC driver
}

As you can see from the code

1, define and assign Net_device structure, use Alloc_etherdev function.

2, initialize the Net_device. (including interrupt number, I/O base address, MAC address, Netdev_ops)

3. Initializing hardware

4, register the NIC driver to the kernel, use the function Register_netdev

㈡ sending data

Assign a value of &net_ops to the netdev_ops when initializing it to find the Send function in this structure

  

Static Const structNet_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,};

  The Net_send_packet code is as follows:

Staticnetdev_tx_t Net_send_packet (structSk_buff *SKB,structNet_device *Dev) {    structNet_local *LP =Netdev_priv (Dev); unsignedLongflags; if(Net_debug >3) {PRINTK ("%s:sent%d byte packet of type%x\n", 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 had 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!\n"); returnNetdev_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); returnNetdev_tx_ok;}

This part of the code does these things (highlighted in red)

1, notify the upper layer protocol to stop sending data to the network card

To stop receiving packets because the NIC is now sending out packets

2, the data in the SKB is written into the register and sent away

3. Free SKB Space

But here is not finished, if this is over the upper layer protocol or unable to send data to the network card, the network card does not work properly, obviously this is not normal. So where do you re-allow the upper layer protocol to send packets to the NIC?

In fact, when the network card sent a packet, will enter the network card interrupt program, find REQUEST_IRQ interrupt handler name Net_interrupt

StaticIrqreturn_t Net_interrupt (intIrqvoid*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, notify the upper layer protocol, you can send packets to the network card. Using function Netif_wake_queue

㈢ Data Reception

When the NIC accepts a packet, it enters the NIC interrupt handler

StaticIrqreturn_t Net_interrupt (intIrqvoid*dev_id) {structNet_device *dev =dev_id; structNet_local *LP; intioaddr, status; inthandled =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
}
}
}

The NET_RX function code is as follows

Static voidNet_rx (structNet_device *Dev) {    structSk_buff *SKB; intstatus, length; intIOADDR = 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) {#if0/* Again, this seems a cruel thing to do * *PRINTK (kern_warning"%s:memory squeeze, dropping packet.\n", dev->name);#endifDev->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\n", 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;}

As you can see from the code:

1. Read Receive status

2, read the length of the received data

3, allocation SKB structure, SKB = dev_alloc_skb (length + 2);

4, read data from the hardware register to deposit SKB

5. The packet of the river package is sent up to the protocol stack, using the function Netif_rx

The network card driver architecture has been roughly analyzed here. If you have questions or errors, please note.

Analysis of Linux network card driver architecture

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.