<div dir="ltr"><div>Dear Sir.<br><br></div><div>have any suggestion?<br></div><div><br></div>Best Regards.<br></div><div class="gmail_extra"><br><div class="gmail_quote">2015-06-05 18:09 GMT+08:00 Mingyu Li <span dir="ltr"><<a href="mailto:igvtee@gmail.com" target="_blank">igvtee@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>this feature i reference tg3.c driver at function tg3_start_xmit.<br></div><div>it says therer is a small possibility that start_xmit will miss it<br></div><div>and cause the queue to be stopped forever.<br></div><div><br></div>below is the tg3 drivers code<br></div>=== function tg3_tx ===<br> tnapi->tx_cons = sw_idx;<br><br> /* Need to make the tx_cons update visible to tg3_start_xmit()<br> * before checking for netif_queue_stopped(). Without the<br> * memory barrier, there is a small possibility that tg3_start_xmit()<br> * will miss it and cause the queue to be stopped forever.<br> */<br> smp_mb();<br><br> if (unlikely(netif_tx_queue_stopped(txq) &&<br> (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))) {<br> __netif_tx_lock(txq, smp_processor_id());<br> if (netif_tx_queue_stopped(txq) &&<br> (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))<br> netif_tx_wake_queue(txq);<br> __netif_tx_unlock(txq);<br> }<br><br>=== tg3_start_xmit ===<br> budget = tg3_tx_avail(tnapi);<br> <br> /* We are running in BH disabled context with netif_tx_lock<br> * and TX reclaim runs via tp->napi.poll inside of a software<br> * interrupt. Furthermore, IRQ processing runs lockless so we have<br> * no IRQ context deadlocks to worry about either. Rejoice!<br> */<br> if (unlikely(budget <= (skb_shinfo(skb)->nr_frags + 1))) {<br> if (!netif_tx_queue_stopped(txq)) {<br> netif_tx_stop_queue(txq);<br> <br> /* This is a hard error, log it. */<br> netdev_err(dev,<br> "BUG! Tx Ring full when queue awake!\n");<br> } <br> return NETDEV_TX_BUSY;<br> }<br><br></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">2015-06-05 16:40 GMT+08:00 Felix Fietkau <span dir="ltr"><<a href="mailto:nbd@openwrt.org" target="_blank">nbd@openwrt.org</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>On 2015-06-02 15:06, michael lee wrote:<br>
> use pktgen to verify on rt3662. can improve transmit rate.<br>
> pkt_size 1500<br>
> burst 1 : 807Mb/sec<br>
> burst 8 : 984Mb/sec<br>
><br>
> pkt_size 60<br>
> burst 1 : 57Mb/sec<br>
> burst 8 : 236Mb/sec<br>
><br>
> Signed-off-by: michael lee <<a href="mailto:igvtee@gmail.com" target="_blank">igvtee@gmail.com</a>><br>
> ---<br>
> .../drivers/net/ethernet/ralink/ralink_soc_eth.c | 51 +++++++++++++---------<br>
> .../drivers/net/ethernet/ralink/ralink_soc_eth.h | 2 +<br>
> 2 files changed, 33 insertions(+), 20 deletions(-)<br>
><br>
> 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<br>
> index b2304bb..4b39825 100644<br>
> --- a/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c<br>
> +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c<br>
> @@ -337,6 +337,8 @@ static int fe_alloc_tx(struct fe_priv *priv)<br>
> struct fe_tx_ring *ring = &priv->tx_ring;<br>
><br>
> ring->tx_free_idx = 0;<br>
> + ring->tx_next_idx = 0;<br>
> + ring->tx_thresh = max((unsigned long)ring->tx_ring_size >> 2, MAX_SKB_FRAGS);<br>
><br>
> ring->tx_buf = kcalloc(ring->tx_ring_size, sizeof(*ring->tx_buf),<br>
> GFP_KERNEL);<br>
> @@ -525,8 +527,16 @@ static int fe_vlan_rx_kill_vid(struct net_device *dev,<br>
> return 0;<br>
> }<br>
><br>
> +static inline u32 fe_empty_txd(struct fe_tx_ring *ring)<br>
> +{<br>
> + barrier();<br>
</div></div>What is this barrier for?<br>
<span><br>
> + return (u32)(ring->tx_ring_size -<br>
> + ((ring->tx_next_idx - ring->tx_free_idx) &<br>
> + (ring->tx_ring_size - 1)));<br>
> +}<br>
> +<br>
> static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,<br>
> - int idx, int tx_num, struct fe_tx_ring *ring)<br>
> + int tx_num, struct fe_tx_ring *ring)<br>
> {<br>
> struct fe_priv *priv = netdev_priv(dev);<br>
> struct skb_frag_struct *frag;<br>
</span><span>> @@ -649,14 +659,22 @@ static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,<br>
> netdev_sent_queue(dev, skb->len);<br>
> skb_tx_timestamp(skb);<br>
><br>
> - j = NEXT_TX_DESP_IDX(j);<br>
> + ring->tx_next_idx = NEXT_TX_DESP_IDX(j);<br>
> wmb();<br>
> - fe_reg_w32(j, FE_REG_TX_CTX_IDX0);<br>
> + if (unlikely(fe_empty_txd(ring) <= ring->tx_thresh)) {<br>
> + netif_stop_queue(dev);<br>
> + smp_mb();<br>
> + if (unlikely(fe_empty_txd(ring) > ring->tx_thresh))<br>
> + netif_wake_queue(dev);<br>
</span>Why do that queue wake check here, when it's already being done during<br>
tx cleanup.<br>
<div><div><br>
> + }<br>
> +<br>
> + if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !skb->xmit_more)<br>
> + fe_reg_w32(ring->tx_next_idx, FE_REG_TX_CTX_IDX0);<br>
><br>
> return 0;<br>
><br>
> err_dma:<br>
> - j = idx;<br>
> + j = ring->tx_next_idx;<br>
> for (i = 0; i < tx_num; i++) {<br>
> ptxd = &ring->tx_dma[j];<br>
> tx_buf = &ring->tx_buf[j];<br>
<br>
</div></div><span><font color="#888888">- Felix<br>
</font></span></blockquote></div><br></div>
</div></div></blockquote></div><br></div>