ixgb 中断

 

https://blog.csdn.net/hz5034/article/details/79794343?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-1-79794343.nonecase&utm_term=ixgbe%E9%A9%B1%E5%8A%A8

 

ixgbe_up_complete() -> ixgbe_configure_msix() -> ixgbe_set_ivar() ixgbe_napi_enable_all() -> napi_enable() ixgbe_irq_enable() -> ixgbe_irq_enable_queues() netif_tx_start_all_queues() -> netif_tx_start_queue()

 

 

+struct ixgbe_ring {
+    struct ixgbe_adapter *adapter;    /* backlink */
+    void *desc;            /* descriptor ring memory */
+    dma_addr_t dma;            /* phys. address of descriptor ring */
+    unsigned int size;        /* length in bytes */
+    unsigned int count;        /* amount of descriptors */
+    unsigned int next_to_use;
+    unsigned int next_to_clean;
+
+    union {
+        struct ixgbe_tx_buffer *tx_buffer_info;
+        struct ixgbe_rx_buffer *rx_buffer_info;
+    };
+
+    u16 head;
+    u16 tail;
+
+    /* To protect race between sender and clean_tx_irq */
+    spinlock_t tx_lock;
+
+    struct ixgbe_queue_stats stats;
+
+    u32 eims_value;
+    u32 itr_val;
+    u16 itr_range;
+    u16 itr_register;
+
+    char name[IFNAMSIZ + 5];
+};

 

+static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
+{
+    int i, vector = 0;
+
+    for (i = 0; i < adapter->num_tx_queues; i++) {
+        ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i),
+                   IXGBE_MSIX_VECTOR(vector));
+        if (adapter->tx_eitr != 0)
+            writel(1000000000 / (adapter->tx_eitr * 256),
+                   adapter->hw.hw_addr +
+                   adapter->tx_ring[i].itr_register);
+        else
+            writel(0, adapter->hw.hw_addr +
+                   adapter->tx_ring[i].itr_register);
+        vector++;
+    }
+
+    for (i = 0; i < adapter->num_rx_queues; i++) {
+        ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i),
+                   IXGBE_MSIX_VECTOR(vector));
+        if (adapter->rx_eitr != 0)
+            writel(1000000000 / (adapter->rx_eitr * 256),
+                   adapter->hw.hw_addr +
+                   adapter->rx_ring[i].itr_register);
+        else
+            writel(0, adapter->hw.hw_addr +
+                   adapter->rx_ring[i].itr_register);
+        vector++;
+    }
+
+    vector = adapter->num_tx_queues + adapter->num_rx_queues;
+    ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX,
+               IXGBE_MSIX_VECTOR(vector));
+    IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(vector), 1950);
+}

 

 

 

/*
 * ixgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors
 * @adapter: pointer to adapter struct
 * @direction: 0 for Rx, 1 for Tx, -1 for other causes
 * @queue: queue to map the corresponding interrupt to
 * @msix_vector: the vector to map to the corresponding queue
 *
 */
static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
                       u8 queue, u8 msix_vector)
{
    u32 ivar, index;
    struct ixgbe_hw *hw = &adapter->hw;
    switch (hw->mac.type) {
    case ixgbe_mac_82598EB:
        msix_vector |= IXGBE_IVAR_ALLOC_VAL;
        if (direction == -1)
            direction = 0;
        index = (((direction * 64) + queue) >> 2) & 0x1F;
        ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
        ivar &= ~(0xFF << (8 * (queue & 0x3)));
        ivar |= (msix_vector << (8 * (queue & 0x3)));
        IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
        break;
    case ixgbe_mac_82599EB:
        if (direction == -1) {
            /* other causes */
            msix_vector |= IXGBE_IVAR_ALLOC_VAL;
            index = ((queue & 1) * 8);
            ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR_MISC);
            ivar &= ~(0xFF << index);
            ivar |= (msix_vector << index);
            IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR_MISC, ivar);
            break;
        } else {
            /* tx or rx causes */
            msix_vector |= IXGBE_IVAR_ALLOC_VAL;
            index = ((16 * (queue & 1)) + (8 * direction));
            ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(queue >> 1));
            ivar &= ~(0xFF << index);
            ivar |= (msix_vector << index);
            IXGBE_WRITE_REG(hw, IXGBE_IVAR(queue >> 1), ivar);
            break;
        }
    default:
        break;
    }
}

https://tech.meituan.com/2018/03/16/redis-high-concurrency-optimization.html

(1)注册中断号及中断处理程序,根据网卡是否支持MSI/MSIX,结果为:MSIX → ixgbe_msix_clean_ringsMSI → ixgbe_intr,都不支持 → ixgbe_intr

/**
 * 文件:ixgbe_main.c
 * ixgbe_request_irq - initialize interrupts
 * @adapter: board private structure
 *
 * Attempts to configure interrupts using the best available
 * capabilities of the hardware and kernel.
 **/
static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
{
    struct net_device *netdev = adapter->netdev;
    int err;
 
    /* 支持MSIX,调用 ixgbe_request_msix_irqs 设置中断处理程序*/
    if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
        err = ixgbe_request_msix_irqs(adapter);
    /* 支持MSI,直接设置 ixgbe_intr 为中断处理程序 */
    else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED)
        err = request_irq(adapter->pdev->irq, &ixgbe_intr, 0,
                  netdev->name, adapter);
    /* 都不支持的情况,直接设置 ixgbe_intr 为中断处理程序 */
    else 
        err = request_irq(adapter->pdev->irq, &ixgbe_intr, IRQF_SHARED,
                  netdev->name, adapter);
 
    if (err)
        e_err(probe, "request_irq failed, Error %d\n", err);
 
    return err;
}
  
/**
 * 文件:ixgbe_main.c
 * ixgbe_request_msix_irqs - Initialize MSI-X interrupts
 * @adapter: board private structure
 *
 * ixgbe_request_msix_irqs allocates MSI-X vectors and requests
 * interrupts from the kernel.
 **/
static int (struct ixgbe_adapter *adapter)
{
    …
    for (vector = 0; vector < adapter->num_q_vectors; vector++) {
        struct ixgbe_q_vector *q_vector = adapter->q_vector[vector];
        struct msix_entry *entry = &adapter->msix_entries[vector];
 
        /* 设置中断处理入口函数为 ixgbe_msix_clean_rings */
        err = request_irq(entry->vector, &ixgbe_msix_clean_rings, 0,
                  q_vector->name, q_vector);
        if (err) {
            e_err(probe, "request_irq failed for MSIX interrupt '%s' "
                  "Error: %d\n", q_vector->name, err);
            goto free_queue_irqs;
        }
    …
    }
}

(2)线上的多队列网卡均支持MSIX,中断处理程序入口为ixgbe_msix_clean_rings,里面调用了函数napi_schedule(&q_vector->napi)

/**
 * 文件:ixgbe_main.c
 **/
static irqreturn_t ixgbe_msix_clean_rings(int irq, void *data)
{
    struct ixgbe_q_vector *q_vector = data;
 
    /* EIAM disabled interrupts (on this vector) for us */
 
    if (q_vector->rx.ring || q_vector->tx.ring)
        napi_schedule(&q_vector->napi);
 
    return IRQ_HANDLED;
}

 

posted on 2020-09-04 16:11  tycoon3  阅读(294)  评论(0编辑  收藏  举报

导航