[OpenWrt-Devel] [PATCH] [ 4/5] ramips: add xmit_more support

Mingyu Li igvtee at gmail.com
Fri Jun 5 06:09:53 EDT 2015


this feature i reference tg3.c driver at function tg3_start_xmit.
it says therer is a small possibility that start_xmit will miss it
and cause the queue to be stopped forever.

below is the tg3 drivers code
=== function tg3_tx ===
        tnapi->tx_cons = sw_idx;

        /* Need to make the tx_cons update visible to tg3_start_xmit()
         * before checking for netif_queue_stopped().  Without the
         * memory barrier, there is a small possibility that
tg3_start_xmit()
         * will miss it and cause the queue to be stopped forever.
         */
        smp_mb();

        if (unlikely(netif_tx_queue_stopped(txq) &&
                     (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))) {
                __netif_tx_lock(txq, smp_processor_id());
                if (netif_tx_queue_stopped(txq) &&
                    (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))
                        netif_tx_wake_queue(txq);
                __netif_tx_unlock(txq);
        }

=== tg3_start_xmit ===
        budget = tg3_tx_avail(tnapi);

        /* We are running in BH disabled context with netif_tx_lock
         * and TX reclaim runs via tp->napi.poll inside of a software
         * interrupt.  Furthermore, IRQ processing runs lockless so we have
         * no IRQ context deadlocks to worry about either.  Rejoice!
         */
        if (unlikely(budget <= (skb_shinfo(skb)->nr_frags + 1))) {
                if (!netif_tx_queue_stopped(txq)) {
                        netif_tx_stop_queue(txq);

                        /* This is a hard error, log it. */
                        netdev_err(dev,
                                   "BUG! Tx Ring full when queue awake!\n");
                }
                return NETDEV_TX_BUSY;
        }


2015-06-05 16:40 GMT+08:00 Felix Fietkau <nbd at openwrt.org>:

> On 2015-06-02 15:06, michael lee wrote:
> > use pktgen to verify on rt3662. can improve transmit rate.
> > pkt_size 1500
> > burst 1 : 807Mb/sec
> > burst 8 : 984Mb/sec
> >
> > pkt_size 60
> > burst 1 : 57Mb/sec
> > burst 8 : 236Mb/sec
> >
> > Signed-off-by: michael lee <igvtee at gmail.com>
> > ---
> >  .../drivers/net/ethernet/ralink/ralink_soc_eth.c   | 51
> +++++++++++++---------
> >  .../drivers/net/ethernet/ralink/ralink_soc_eth.h   |  2 +
> >  2 files changed, 33 insertions(+), 20 deletions(-)
> >
> > diff --git
> a/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c
> b/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c
> > index b2304bb..4b39825 100644
> > ---
> a/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c
> > +++
> b/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c
> > @@ -337,6 +337,8 @@ static int fe_alloc_tx(struct fe_priv *priv)
> >       struct fe_tx_ring *ring = &priv->tx_ring;
> >
> >       ring->tx_free_idx = 0;
> > +     ring->tx_next_idx = 0;
> > +     ring->tx_thresh = max((unsigned long)ring->tx_ring_size >> 2,
> MAX_SKB_FRAGS);
> >
> >       ring->tx_buf = kcalloc(ring->tx_ring_size, sizeof(*ring->tx_buf),
> >                       GFP_KERNEL);
> > @@ -525,8 +527,16 @@ static int fe_vlan_rx_kill_vid(struct net_device
> *dev,
> >       return 0;
> >  }
> >
> > +static inline u32 fe_empty_txd(struct fe_tx_ring *ring)
> > +{
> > +     barrier();
> What is this barrier for?
>
> > +     return (u32)(ring->tx_ring_size -
> > +                     ((ring->tx_next_idx - ring->tx_free_idx) &
> > +                      (ring->tx_ring_size - 1)));
> > +}
> > +
> >  static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,
> > -             int idx, int tx_num, struct fe_tx_ring *ring)
> > +             int tx_num, struct fe_tx_ring *ring)
> >  {
> >       struct fe_priv *priv = netdev_priv(dev);
> >       struct skb_frag_struct *frag;
> > @@ -649,14 +659,22 @@ static int fe_tx_map_dma(struct sk_buff *skb,
> struct net_device *dev,
> >       netdev_sent_queue(dev, skb->len);
> >       skb_tx_timestamp(skb);
> >
> > -     j = NEXT_TX_DESP_IDX(j);
> > +     ring->tx_next_idx = NEXT_TX_DESP_IDX(j);
> >       wmb();
> > -     fe_reg_w32(j, FE_REG_TX_CTX_IDX0);
> > +     if (unlikely(fe_empty_txd(ring) <= ring->tx_thresh)) {
> > +             netif_stop_queue(dev);
> > +             smp_mb();
> > +             if (unlikely(fe_empty_txd(ring) > ring->tx_thresh))
> > +                     netif_wake_queue(dev);
> Why do that queue wake check here, when it's already being done during
> tx cleanup.
>
> > +     }
> > +
> > +     if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) ||
> !skb->xmit_more)
> > +             fe_reg_w32(ring->tx_next_idx, FE_REG_TX_CTX_IDX0);
> >
> >       return 0;
> >
> >  err_dma:
> > -     j = idx;
> > +     j = ring->tx_next_idx;
> >       for (i = 0; i < tx_num; i++) {
> >               ptxd = &ring->tx_dma[j];
> >               tx_buf = &ring->tx_buf[j];
>
> - Felix
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/openwrt-devel/attachments/20150605/7c0c41dd/attachment.htm>
-------------- next part --------------
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list