• 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
    ", 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
    ", 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;
    }
  • 相关阅读:
    js中new的本质
    js中真伪数组转换
    2 DC电参数测试 (1)
    1 开短路测试
    2月书单 《编码隐匿在计算机软硬件背后的语言》 21-25章
    2月书单 《编码隐匿在计算机软硬件背后的语言》 17-20章
    时间的掌控
    数码管的秘密
    会眨眼的小灯
    点亮一盏灯
  • 原文地址:https://www.cnblogs.com/dream397/p/13614467.html
Copyright © 2020-2023  润新知