zoukankan      html  css  js  c++  java
  • 网卡 dma 屏障指令

    我们看一个wmb()和rmb()的使用例子。我们需要到设备驱动中寻找,就顺便选一个我也不清楚的网卡驱动吧(drivers/net/8139too.c)。

    static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
                           struct net_device *dev)
    {
        /*
         * Writing to TxStatus triggers a DMA transfer of the data
         * copied to tp->tx_buf[entry] above. Use a memory barrier
         * to make sure that the device sees the updated data.
         */
        wmb();
        RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
               tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
    }

    从这里的注释我们其实可以看出RTL_W32_F()操作应该是发起一次设备DMA操作(通过写硬件寄存器实现)。wmb()的作用是保证写入DMA发起操作命令之前写入内存的数据都已经写入内存,保证DMA操作时可以看见最新的数据。简单思考就是保证寄存器操作必须是最后发生的。我们继续找个rmb()的例子(drivers/net/bnx2.c)。

    static int bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
    {
        sw_cons = rxr->rx_cons;
        sw_prod = rxr->rx_prod;
        /* Memory barrier necessary as speculative reads of the rx
         * buffer can be ahead of the index in the status block
         */
        rmb();
        while (sw_cons != hw_cons) {
    }

    这里的rmb()就是为了防止while循环里面的load操作在rmb()之前发生。也就说这里是有顺序要求的。设备方面的例子就不多说了,毕竟不是我们关注的重点。

    static void macb_tx_interrupt(struct macb_queue *queue)
    {
        unsigned int tail;
        unsigned int head;
        u32 status;
        struct macb *bp = queue->bp;
        u16 queue_index = queue - bp->queues;
    
        status = macb_readl(bp, TSR);
        macb_writel(bp, TSR, status);
    
        if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
            queue_writel(queue, ISR, MACB_BIT(TCOMP));
    
        netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n",
                (unsigned long)status);
    
        head = queue->tx_head;
        for (tail = queue->tx_tail; tail != head; tail++) {
            struct macb_tx_skb    *tx_skb;
            struct sk_buff        *skb;
            struct macb_dma_desc    *desc;
            u32            ctrl;
    
            desc = macb_tx_desc(queue, tail);
    
            /* Make hw descriptor updates visible to CPU */
            rmb();
    
            ctrl = desc->ctrl;
    
            /* TX_USED bit is only set by hardware on the very first buffer
             * descriptor of the transmitted frame.
             */
            if (!(ctrl & MACB_BIT(TX_USED)))
                break;
    
            /* Process all buffers of the current transmitted frame */
            for (;; tail++) {
                tx_skb = macb_tx_skb(queue, tail);
                skb = tx_skb->skb;
    
                /* First, update TX stats if needed */
                if (skb) {
                    netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
                            macb_tx_ring_wrap(tail), skb->data);
                    bp->stats.tx_packets++;
                    bp->stats.tx_bytes += skb->len;
                }
    
                /* Now we can safely release resources */
                macb_tx_unmap(bp, tx_skb);
    
                /* skb is set only for the last buffer of the frame.
                 * WARNING: at this point skb has been freed by
                 * macb_tx_unmap().
                 */
                if (skb)
                    break;
            }
        }
    
        queue->tx_tail = tail;
        if (__netif_subqueue_stopped(bp->dev, queue_index) &&
            CIRC_CNT(queue->tx_head, queue->tx_tail,
                 TX_RING_SIZE) <= MACB_TX_WAKEUP_THRESH)
            netif_wake_subqueue(bp->dev, queue_index);
    }

    如何使用屏障指令

  • 相关阅读:
    八、比卦
    七、师卦
    六、讼卦
    五、需卦
    力扣-两数之和
    什么是3NF (范式) ?
    SQL事务4个特性
    什么是索引?
    假设把只包含01的数组(如{0,0,1,1,1,0,1,0,0,1})按照升序排序,可以任意交换两个数的位置,请输出最少需要交换的次数。
    找规律并用编程实现如下数列(数值超过10000停止打印) 1,1,2,2,3,2,5,4,8,8
  • 原文地址:https://www.cnblogs.com/dream397/p/15665746.html
Copyright © 2011-2022 走看看