Готовый перевод Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 17.7. The Interrupt Handler
17.7. Обработка прерываний
Управление большинством устройств осуществляется через
прерывания. Аппаратное прерывание процессору сигнализирует об одном
из двух возможных событий: прибытие нового пакета или завершение
передачи пакета. Сетевой интерфейс может так же генерировать
прерывания при ошибках, изменении статуса соединения и т.д.
Обычно обработчик прерывания проверяет регистр состояния
устройства, для определения причины прерывания. Аналогично работает
интерфейс snull, но слово состояния реализовано программно и
находится в dev->priv. Обработчик прерывания сетевого интерфейса
выглядит примерно так:
static void snull_regular_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int statusword;
struct snull_priv *priv;
struct snull_packet *pkt = NULL;
/*
* как обычно проверяем указатель "device"
* чтобы убедится, что это действительно прерывание
* затем присваиваем "struct device *dev"
*/
struct net_device *dev = (struct net_device *)dev_id;
/* ... и проверяем аппаратуру*/
/* paranoid */
if (!dev)
return;
/* блокируем устройство */
priv = netdev_priv(dev);
spin_lock(&priv->lock);
/* Находим слово состояния: настоящее устройство использует */
/* инструкции ввода-вывода */
statusword = priv->status;
priv->status = 0;
if (statusword & SNULL_RX_INTR) {
/* send it to snull_rx for handling */
/* выполняем snull_rx для обработки */
pkt = priv->rx_queue;
if (pkt) {
priv->rx_queue = pkt->next;
snull_rx(dev, pkt);
}
}
if (statusword & SNULL_TX_INTR) {
/* передача завершена, освобождаем skb*/
priv->stats.tx_packets++;
priv->stats.tx_bytes += priv->tx_packetlen;
dev_kfree_skb(priv->skb);
}
/* разблокируем устройство */
spin_unlock(&priv->lock);
if (pkt) snull_release_buffer(pkt); /* выполняется вне блокировки*/
return;
}
В первую очередь, обработчик убеждается в корректном значении
указателя на структуру net_device. Этот указатель приходит как
аргумент.
Рассмотрим происходящее при завершении передачи пакета. В этом
случае обновляется статистика, и вызывается dev_kfree_skb для возврата,
более не нужного, буфера сокета системе. Есть 3 варианта этой функции.
dev_kfree_skb(struct sk_buff *skb);
Эта версия вызывается, если вы точно знаете, что не работаете в
контексте прерывания. Так как snull не имеет аппаратных
прерываний, мы используем эту версию.
dev_kfree_skb_irq(struct sk_buff *skb);
Если вы знаете что работаете в
используйте эту версию функции.
dev_kfree_skb_any(struct sk_buff *skb);
Эта версия может использоваться как в контексте прерывания, так и
вне его.
В конце, если ваш драйвер приостанавливает очередь передачи, как
правило производят и повторный старт netif_wake_queue.
Прием пакетов, в противоположность передачи, не нуждается в
специальной обработке прерывания. Все что требуется это вызов
snull_rx (который мы уже рассмотрели).
Внимание! Этот перевод, возможно, ещё не готов.
Его статус: перевод редактируется
Переведено на Нотабеноиде
http://notabenoid.org/book/11832/38388
Переводчики: hardorsoft
Настройки
Готово:
