The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Обработчик прерывания

Обработчик прерывания

Предыдущая  Содержание  Следующая V*D*V

Большинство аппаратных интерфейсов управляются посредством обработчика прерывания. Оборудование прерывает процессор, чтобы просигнализировать об одном из двух возможных событий: прибыл новый пакет или завершена передача исходящего пакета. Сетевые интерфейсы могут также генерировать прерывания для сигнализации об ошибках, изменениях состояния соединения и так далее.

 

Обычная процедура прерывания может определить отличие между прерыванием прибытия нового пакета и уведомлением о выполнении передачи, проверяя регистр статуса находящийся на физическом устройстве. Интерфейс snull работает аналогично, но его слово статуса реализовано в программном обеспечении и находится в dev->priv. Обработчик прерывания для сетевого интерфейса выглядит следующим образом:

 

static irqreturn_t snull_regular_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{

    int statusword;

    struct snull_priv *priv;

    struct snull_packet *pkt = NULL;

    /*

     * Как обычно, проверяем указатель "устройства" для уверенности,

     * что прервало действительно оно.

     * Затем присваиваем "struct device *dev"

     */

    struct net_device *dev = (struct net_device *)dev_id;

    /* ... и проверяем оборудование, если оно действительно наше */

 

    /* параноидальность */

    if (!dev)

        return;

 

    /* Блокируем устройство */

    priv = netdev_priv(dev);

    spin_lock(&priv->lock);

 

    /* получаем статусное слово: настоящее сетевое устройство использует инструкции ввода/вывода */

    statusword = priv->status;

    priv->status = 0;

    if (statusword & SNULL_RX_INTR) {

        /* отправляем его в 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 IRQ_HANDLED;

}

 

Первой задачей обработчика является получение указателя на корректную struct net_device. Этот указатель обычно поступает от указателя dev_id, полученного в качестве аргумента.

 

С ситуацией "передача завершена" имеет дело интересная часть этого обработчика. В этом случае обновляется статистика и вызывается dev_kfree_skb, чтобы вернуть системе (больше не требуемый) буфер сокет. На самом деле есть три варианта этой функции, которые могут быть вызваны:

 

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 (который мы уже видели).

Предыдущая  Содержание  Следующая