Linux NIC Driver

Source: Internet
Author: User

This article only discusses the general Writing of network device drivers. The Code related to the hardware is omitted because of the different hardware specifications. Are there any mistakes or supplements? You are welcome to raise them.

1. Loading and uninstalling the driver module

If the network device (including wireless) is PCI compliant, first register the PCI device (pci_register_driver) with the kernel ), then, the probe function pointer in the pci_driver data structure points to the detection function to initialize the PCI device and register and initialize the network device at the same time.

If the network device (including wireless) is in the pcmcia specification, first register the pcmcia device (register_pccard_driver) with the kernel ), then, the attach function pointer in the driver_info_t data structure points to the detection function to initialize the pcmcia device and register and initialize the network device at the same time.

Static int _ init tg3_init (void)
{
// Register as a PCI device and initialize it. If it is another ESIA or PCMCIA, use other functions.
Return pci_module_init (& tg3_driver );
}

Static void _ exit tg3_cleanup (void)
{
Pci_unregister_driver (& tg3_driver); // cancel the PCI device
}

Module_init (tg3_init); // load the driver module
Module_exit (tg3_cleanup); // uninstall the driver module

Stated as a PCI device:
Static struct pci_driver tg3_driver = {
. Name = drv_module_name,
. Id_table = tg3_pci_tbl, // The NIC Series Supported by this driver, vendor_id, device_id
. Probe = tg3_init_one, // initialize the network device callback function
. Remove = _ devexit_p (tg3_remove_one), // call back the network device
. Suspend = tg3_suspend, // device suspension Function
. Resume = tg3_resume // device recovery function
};

2. The probe function of the PCI device is used to initialize the network device.
Static int _ devinit tg3_init_one (struct pci_dev * pdev, const struct pci_device_id * ent)
{

// Initialize the device to make I/O and memory available and wake up the device
Pci_enable_device (pdev );

// Apply for memory space and configure Nic I/O and memory resources
Pci_request_regions (pdev, drv_module_name );
Pci_set_master (pdev );

// Set the DMA attribute
Pci_set_dma_mask (pdev, (u64) 0 xffffffffffffffff );

// Nic I/O, starting address of memory resource
Tg3reg_base = pci_resource_start (pdev, 0 );

// Nic I/O, memory resource size
Tg3reg_len = pci_resource_len (pdev, 0 );

// Allocate and SET network devices
Dev = alloc_etherdev (sizeof (* TP ));

// Declare as the kernel device module
Set_module_owner (Dev );

// Initialize the Member values in the private structure
TP = Dev-> priv;
TP-> pdev = pdev;
TP-> Dev = dev;
......
// Lock Initialization
Spin_lock_init (& TP-> lock );

// Map I/O, memory address to register structure in private domain
TP-> regs = (unsigned long) ioremap (tg3reg_base, tg3reg_len );
Dev-> IRQ = pdev-> IRQ;

// Network device callback function value assignment
Dev-> open = tg3_open;
Dev-> stop = tg3_close;
Dev-> get_stats = tg3_get_stats;
Dev-> set_multicast_list = tg3_set_rx_mode;
Dev-> set_mac_address = tg3_set_mac_addr;
Dev-> do_ioctl = tg3_ioctl;
Dev-> tx_timeout = tg3_tx_timeout;
Dev-> hard_start_xmit = tg3_start_xmit;

// Assign the MAC address of the NIC to Dev-> ADDR.
Tg3_get_device_address (TP );

// Register a network device
Register_netdev (Dev );

// Put the network device pointer address in the device pointer of the PCI device
Pci_set_drvdata (pdev, Dev );
}

3. log out of the network device
Static void _ devexit tg3_remove_one (struct pci_dev * pdev)
{
Struct net_device * Dev = pci_get_drvdata (pdev );
// Disconnect a network device
Unregister_netdev (Dev );
// Cancel address ing
Iounmap (void *) (struct tg3 *) (Dev-> priv)-> regs );
// Release the network device
Kfree (Dev );
// Release PCI Resources
Pci_release_regions (pdev );
// Disable the PCI device
Pci_disable_device (pdev );
// The device pointer in the PCI device is null.
Pci_set_drvdata (pdev, null );
}

4. enable the network device
Static int tg3_open (struct net_device * Dev)
{
// Allocate an interrupt
Request_irq (Dev-> IRQ, tg3_interrupt, sa_shirq, Dev-> name, Dev );

/* Int request_irq (unsigned int IRQ,
Void (* Handler) (int irq, void * dev_id, struct pt_regs * regs ),
Unsigned long irqflags,
Const char * devname,
Void * dev_id );

IRQ is the hardware interrupt number to be applied. On Intel Platform, the range is 0--15.
Handler is the interrupt handler function registered with the system. This is a callback function. When an interrupt occurs, the system calls this function. The input parameters include the hardware interrupt number, device ID, and register value.
Dev_id is the dev_id parameter passed to the system when request_irq is as follows.
Irqflags is an attribute of Interrupt Processing. Sa_interrupt indicates whether the interrupt processing program is a fast processing program (set sa_interrupt) or a slow processing program (do not set sa_interrupt ). All interrupts are blocked when the quick processing program is called. The slow processing program is not blocked. There is also a sa_shirq attribute, which sets the sharing interruption for multiple devices to run in the future. Dev_id is used to interrupt sharing. It is generally set to the device structure of the device itself or null. The interrupt handler can use dev_id to find the device that controls the interrupt, or use rq2dev_map to find the device. */

// Initialize the hardware
Tg3_init_hw (TP );

// Initialize the buffer for receiving packets and sending packets
Tg3_init_rings (TP );

// Initialize the timer
Init_timer (& TP-> timer );
TP-> timer. expires = jiffies + TP-> timer_offset;
TP-> timer. Data = (unsigned long) TP;
TP-> timer. Function = tg3_timer; // time-out callback function
Add_timer (& TP-> timer );

// Enable the NIC to start transmitting packets
Netif_start_queue (Dev );
}

5. disable network devices.
Static int tg3_close (struct net_device * Dev)
{
// Stop the NIC transfer package
Netif_stop_queue (Dev );
Netif_carrier_off (TP-> Dev );
// Remove the timer
Del_timer_sync (& TP-> timer );
// Release the buffer for receiving packets and sending packets
Tg3_free_rings (TP );
// Release interrupted
Free_irq (Dev-> IRQ, Dev );
}

6. Send hardware processing data packets
Static int tg3_start_xmit (struct sk_buff * SKB, struct net_device * Dev)
{
Len = (SKB-> len-SKB-> data_len );
// Transmit packets to the physical device of the NIC in DMA mode. If it is wireless, it needs to be refilled according to the 802.11 protocol and hardware specifications.
// The hardware frame header, which is then submitted to the hardware.
Mapping = pci_map_single (TP-> pdev, SKB-> data, Len, pci_dma_todevice );
TP-> tx_buffers [entry]. SKB = SKB;
Pci_unmap_addr_set (& TP-> tx_buffers [entry], mapping, Mapping );
// Hardware Transmission
Tg3_set_txd (TP, entry, mapping, Len, base_flags, mss_and_is_end );
// Record the packet sending Start Time
Dev-> trans_start = jiffies;
}

7. Handle packet interruption, send packets
Static void tg3_interrupt (int irq, void * dev_id, struct pt_regs * regs)
{
// If you want to collect packets
Tg3_rx (TP );
// If you want to send a packet
Tg3_tx (TP );
}

8. send packets
Static void tg3_tx (struct tg3 * TP)
{
Struct tx_ring_info * rI = & TP-> tx_buffers [sw_idx];
Struct sk_buff * SKB = ri-> SKB;
// Transfer packets to the NIC in DMA mode
Pci_unmap_single (TP-> pdev, pci_unmap_addr (Ri, mapping ),
(SKB-> len-SKB-> data_len), pci_dma_todevice );
Ri-> SKB = NULL;
Dev_kfree_skb_irq (SKB );
}

9. Pack
Static int tg3_rx (struct tg3 * TP, int budget)
{
Struct sk_buff * copy_skb;
// Allocate a package
Copy_skb = dev_alloc_skb (LEN + 2 );
Copy_skb-> Dev = TP-> dev;
// Modify the Baotou Space
Skb_reserve (copy_skb, 2 );
// Add data to the package
Skb_put (copy_skb, Len );
// Transmits data back from the NIC in DMA mode
Pci_dma_sync_single (TP-> pdev, dma_addr, Len, pci_dma_fromdevice );
Memcpy (copy_skb-> data, SKB-> data, Len );
SKB = copy_skb;
// Parsing package Protocol
SKB-> protocol = eth_type_trans (SKB, TP-> Dev );
// Send the package to the protocol layer
Netif_rx (SKB );
// Record the package receiving time
TP-> Dev-> last_rx = jiffies;
}

10. Status and statistical data of the packets sent and received by the NIC
Static struct net_device_stats * tg3_get_stats (struct net_device * Dev)
{
// Read data from hardware-related registers and accumulate
// Stats-> rx_packets, stats-> tx_packets, stats-> rx_bytes, stats-> tx_bytes, etc.
}

11. User's IOCTL Command System Call
Static int tg3_ioctl (struct net_device * Dev, struct ifreq * IFR, int cmd)
{
Struct mii_ioctl_data * Data = (struct mii_ioctl_data *) & IFR-> ifr_data;
Switch (CMD ){
// Call the ethtool program command
Case siocethtool:
Return tg3_ethtool_ioctl (Dev, (void *) IFR-> ifr_data );
// Call the MII program command
Case siocgmiireg :{
Err = tg3_readphy (TP, data-> reg_num & 0x1f, & mii_regval)
Data-> val_out = mii_regval;
Return err;
}
......
}
}

12. Functions for suspension and recovery of PCI devices
Static int tg3_suspend (struct pci_dev * pdev, u32 state)
{
// Disable the NIC interrupt register
Tg3_disable_ints (TP );
// Stop the NIC packet sending and receiving
Netif_device_detach (Dev );
// Disable some hardware and fireware functions of the NIC
Tg3_halt (TP );
// Set the NIC Power status
Tg3_set_power_state (TP, State );
}

Static int tg3_resume (struct pci_dev * pdev)
{
// Recover the NIC power
Tg3_set_power_state (TP, 0 );
// Enable the NIC to send and receive packets
Netif_device_attach (Dev );
// Initialize the buffer for sending and receiving packets
Tg3_init_rings (TP );
// Initialize the NIC hardware
Tg3_init_hw (TP );
// Enable the NIC interrupt register
Tg3_enable_ints (TP );
}

13. parameter settings
The driver also provides methods for the system to set and read device parameters. Generally, only the root user can set the device parameters. The settings are as follows:

Tg3_set_mac_addr (Dev-> set_mac_address)
When the ioctl type is siocsifhwaddr, you need to set the MAC address of the device. Generally, it does not make much sense to set the MAC address.

Dev-> set_config ()
When the type of IOCTL is siocsifmap, the system calls the set_config method of the driver.
The user will pass an ifmap structure containing the required I/O, interrupt and other parameters.

Summary:

All Linux network drivers follow common interfaces.
The object-oriented method is used in the design. A device is an object (the net_device structure) with its own data and methods. The most basic methods for a network device are initialization, sending, and receiving.

The Linux network driver architecture can be divided into four layers:
Network Protocol interface, network device interface, device driver function, network device and network media layer

The main task of network drivers is to complete the device driver function layer.
In Linux, all network devices are abstracted as an interface, which provides a set of operations on all network devices.
The data structure struct net_device indicates the running status of the network device in the kernel, that is, the network device interface.
It includes both software-only network device interfaces, such as loopback, and hardware network device interfaces, such as Ethernet cards.

The device linked list with dev_base as the header pointer collectively manages all network devices. Each element in the device linked list represents a network device interface. The data structure net_device contains many device methods for system access and protocol layer calls, including initialization, opening and closing the open and stop functions of network devices, and handling the hard_start_xmit functions sent by data packets, and interrupt processing functions.

Network devices are specially processed in Linux. Linux's network system is mainly based on bsd unix socket mechanism. A special data structure (sk_buff) is defined between the system and the driver for data transmission. The system supports the caching of sent and received data, provides traffic control mechanisms, and supports multiple protocols.
Previous Article: How to Implement C language for obtaining system time in Linux: Security Port allocation for Linux Device Drivers
Next article: Linux PCI device driver development-PCI architecture (I)

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.