Готовый перевод 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

Настройки

Готово:

100.00% КП = 1.0