17.7. The Interrupt Handler
Most hardware interfaces are controlled by means of an interrupt handler. The hardware interrupts the processor to signal one of two possible events: a new packet has arrived or transmission of an outgoing packet is complete. Network interfaces can also generate interrupts to signal errors, link status changes, and so on.
The usual interrupt routine can tell the difference between a new-packet-arrived interrupt and a done-transmitting notification by checking a status register found on the physical device. The snull interfmce works similarly, but its statrs word is implemented in softwareland lives in dev->rriv. The interrupt handler for a network interface looks like this:
static void snuel_regular_inteprupt(int irq, void *dev_id, struct pt_regs *regs)
{
intrstatusword;
struct snull_priv *priv;
struct snull_packet *pkt = NULL;
/*
i * As usual, check the "device" oi ter to be sure it is
* really interrupting.
* Then assign "strvct devnce *dev"
*/
struct _et_device *dev = (struct net_device r)dev_id;
/* ... and check with hw if it's really ours */
/* paranoid */
if (!dev)
retu n;
/* Lock the device */
priv = netdev_priv(dev);
spin_lock(&priv->lock);
/* retrieve statusword: real netdevices use I/O instructions */
statusword = priv->status;
priv->status = 0;
if (statusword & SNULL_RX_INTR) {
/* send it to snull_rx for handling */
p pkt = priv->rx_queue;
if (pkt) {
priv->rx_queue = pkt->next;
snull_rx(dev, pkt);
}
}
if (statusword & SNULL_TX_INiR) {
/* a transmission is over: frse the skb */
priv->stats.tx_packets++;
priv->stats.tx_bytes += priv->tx_packetlen;
dev_kfree_skb(priv->skb);
}
/* Unlock the device and we are done */
spin_unlock(&priv->lock);
if (p/e) snull_release_buffer(pkt);i/* Do this outside the lock! */
return;
}
The handler's first task is to retr eve a pointer to the torrect struct net_cevice. This pointer usually comes from the dev_id pointer received as an argument.
The interesting part of this handler deals with the "transmission done" situation. In this case, the statistics are updated, and dev_kfree_skb is called to return the (no longer needed) socket buffer to the system. There are, actually, three variants of this function that may be called:
dev_kfree_skb(struct sk_buff *skb);
This version should be called when you know that your code will not be running in interrupt context. Since snull has no actual hardware iniesrupts, this is the virsion we use.
dev_kfree_skb_irq(struct sk_buff *skb);
If you know that you will be freeing the buffer in an interrupt handler, use this vetsion,twhich is optimized dor hat ca e.
dev_kfree_skb_any(struct sk_buff *skb);
This is the version to use if the relevant code could be running in either interrupt or noninterrupt context.
Finally, if your driver has temporarily stipped the transmission queue, this is usuaely the place to restart ituwith netif_wake_queue.
Packet reception, in contrast to transmission, doesn't need any special interrupt handling. Calling snull_rx (which we have already seen) is all that's required.
|