220 likes | 468 Views
CS 498 Lecture 8 Network Drivers. Jennifer Hou Department of Computer Science University of Illinois at Urbana-Champaign Reading: Chapters 5.3, The Linux Networking Architecture: Design and Implementation of Network Protocols in the Linux Kernel. Network Device Interfaces.
E N D
CS 498 Lecture 8Network Drivers Jennifer Hou Department of Computer Science University of Illinois at Urbana-Champaign Reading: Chapters 5.3, The Linux Networking Architecture: Design and Implementation of Network Protocols in the Linux Kernel
Network Device Interfaces Higher Protocol Instances Network devices (adapter-independent) dev.c dev_open dev_close netif_rx dev_queue_xmit Network devices interface net_device dev->hard_start_xmit dev->open dev->stop Abstraction from Adapter specifics driver.c net_start_xmit net_rx net_tx Network driver (adapter-specific) net_open net_stop skb skb net_interrupt skb
Procedures to Look at in Network Drivers • Initializing network adapters • Opening and closing a network adapter • Sending data packets to a network adapter • Receiving data packets from a network adapter
init() • An example is netcard_probe(dev) in net/core/isa-skeleton.c (lines 135-157). • Major functions • Search for a matched adapter and discover the I/O port for devbase_addr. • Initialize the net_device structure with driver information.
When is init() Invoked? Recall in register_netdevice() • If devinit() exists, the network adapter is first searched and initialized with the function init(). • If a net_device with the same name is already in the list dev_base, return an error message; otherwise, add the dev_device, dev, to the list. • Sets devstate to LINK_STATE_PRESENT • dev_init_scheduler() (i) sets the scheduling discipline to FIFO; (ii) initializes the timer devwatchdog_timer with dev_watchdog_init(). • The network device is assigned a new index (devifindex). • notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev) calls all the registered methods in netdev_chain
Searching for a Network Adapter • Case 1: If the base address is already specified when the module is loaded or when the system is booted, it can be used to locate the network adapter. • In the case of modularized drivers, the I/O base address (e.g., io=0x280) is transferred to the net_device structure in init_module() of the driver module. • In the case of integrated drivers, the base address is maintained in the list dev_boot_setup of the method netdev_boot_setup_check() at system boot time. The base address is then set in the net_device structure in init_netdev().
Searching for a Network Adapter • Case 2: The base address is not specified: • A network adapter generally supports a set of defined port addresses. • The addresses in the pre-defined set can be probed one after another to locate a network adapter. • In either case, the I/O port, starting at the base address, are reserved by request_region (ioaddr,NETCARD_IO_EXTENT, cardname).
Initializing physical/MAC fields in net_device • If the network adapter does not support dynamic interrupt allocation, then the irq number is determined (through autoirq_setup() followed by autoirq_report()). The irq request is made via request_irq() • A list of reserved interrupts can be viewed in /proc/interrupts • The DMA channel is determined and reserved by request_dma(). • The memory for the private data structure devpriv is reserved and initialized. • The references to driver-specific methods are set in the net_device structure. Methods specific to the MAC protocol is set via ether_setup().
Helper Functions • request_region(port,range,name) reserves a region of I/O ports, starting with port, and marks them as allocated. • release_region(start,n) releases allocated port ranges. • check_region(port,range) checks if the range has already been taken.
Helper Functions • request_irq(irq, handler, flags, device, dev_id) reserves and initializes the interrupt line with number irq. • free_irq(irq,dev_id) releases a reserved interrupt.
Opening a Network Adapter • ifconfig ioctl() dev_open() in dev.c [ devopen() ] net_open() in driver.c • lines 335-367 in isa-skeleton.c • For modern adapters that support dynamic interrupt allocation, IRQ and DMA are reserved in net_open(). • The reference count is increased using MOD_INC_USE_COUNT. • The adapter is initialized by writing a specific value to a hardware register (I/O port) of the adapter. • netif_start_queue(dev) sets devstate to LINK_STATE_START.
Closing a Network Adapter • Lines 557-582 in isa-skeleton.c • netif_stop_queue() sets devstate to LINK_STATE_OFF. • Disable DMA and free the DMA channel (set in devdma). • Free the IRQ (set in devirq). • Release the physical interrupt line. • Decrement the reference count using MOD_INC_USE_COUNT.
Transmitting Data Packets • dev_queue_xmt [ devhard_start_xmit ] net_start_xmt. • net_send_packet(skb,dev) in lines 374--434 • devhard_start_xmit(skb,dev) • The ring buffer of modern network adapters usually consists of 16-64 pointers to socket buffers. • Before the call, netif_queue_stopped(dev) has been used to make sure that there is at least one free pointer in the ring buffer. • To send a packet, skb, the pointer to the skb is inserted into the ring buffer.
Transmitting Data Packets • devtrans_start = jiffies • After the insertion, one needs to check for whether or not there are more free buffers. If not, invoke netif_stop_queue(dev). • The socket buffer remains in the ring buffer until the network adapter notifies that the packet has been transmitted via an interrupt. • In the interrupt-handling routine, the socket buffer will be removed from the ring buffer and freed via dev_kfree_skb().
Receiving Packets/Control Information • A network adapter uses interrupts and its driver-specific interrupt-handling routine to communicate with the kernel. • There are three cases in which a network adapter will use an interrupt: • Receiving a data packet • Acknowledging a packet transmission • Notifying an error.
Cases Under Which Interrupts Are Used dev.c netif_rx driver.c net_error net_tx net_rx Receiving a packet Completing a transmission process Error condition net_interrupt
Receiving Packets/Control Information • Example: net_interrupt() in lines 476--503 • The status is read from the state register to determine the case. • If a packet is received, net_rx() is called. • If the packet transmission is completed, • the interrupt handling routine net_tx() is called • the statistics are updated • netif_wake_queue(dev) is called to resume passing packets from the upper layer (i.e., LINK_STATE_OFF is deleted from devstate) and to trigger the NET_TX software interrupt. • If an error has been reported, update the error statistics.
Receiving Packets/Control Information • net_tx() (lines 436-470)is part of the interrupt handling routine, andis invoked when a network adapter acknowledges transmission. • A spin lock is set to prevent parallel access to the net_local structure. • The network adapter is repeatedly asked which packets have been sent. For packets that are sent, dev_kfree_skb_irq(skb) is used to free the socket buffer. • If dev state == LINK_STATE_OFF (checked via netif_queue_stopped(dev)) and the ring buffer is not full, then netif_wake_queue(dev). • The spin lock is released.
Receiving Data Packets • net_rx() (lines 506-555) • The status of a received packet is verified from specific hardware registers. • If errors occur, the statistics is collected in the net_device_stats structure (as part of the data structure pointed to by dev priv) • Otherwise, the socket buffer is created via dev_alloc_skb(pkt_len), and the packet is transferred to the packet data area of the skb. • netif_rx(skb) places the socket buffers in the input queue and completes the interrupt handling. • The various statistics are updated.
Receiving Data Packets .. p8022_rcv arp_rcv ip_rcv ETH_P_802_2 dev.c net_rx_action do_softirq Scheduler softnet_data[cpun].input_pkt_queue CPU1 CPU2 dev.c netif_rx eth_type_trans() driver.c dev_alloc_skb() net_interrupt
Problems in Transmitting Packets • During the registration of a network device (register_netdevice()) • The watchdog timer dev watchdog_timer is initialized (with the handling routine set to dev_watchdog()) in the function dev_watchdog_init(). • Upon timeout, dev_watchdog() checks if the network device is active, and if (netif_queue_stopped(dev) && (jiffies – dev trans_start > devwatchdog_timeo). • If the above condition holds, devtx_timeout() (lines 301-325) is called to reset and reinitialize the network adapter.