tx_buf = &txr->tx_buf_ring[sw_ring_cons];
                skb = tx_buf->skb;
 
+               /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
+               prefetch(&skb->end);
+
                /* partial BD completions possible with TSO packets */
-               if (skb_is_gso(skb)) {
+               if (tx_buf->is_gso) {
                        u16 last_idx, last_ring_idx;
 
-                       last_idx = sw_cons +
-                               skb_shinfo(skb)->nr_frags + 1;
-                       last_ring_idx = sw_ring_cons +
-                               skb_shinfo(skb)->nr_frags + 1;
+                       last_idx = sw_cons + tx_buf->nr_frags + 1;
+                       last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
                        if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
                                last_idx++;
                        }
                skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
 
                tx_buf->skb = NULL;
-               last = skb_shinfo(skb)->nr_frags;
+               last = tx_buf->nr_frags;
 
                for (i = 0; i < last; i++) {
                        sw_cons = NEXT_TX_BD(sw_cons);
                if (tx_pkt == budget)
                        break;
 
-               hw_cons = bnx2_get_hw_tx_cons(bnapi);
+               if (hw_cons == sw_cons)
+                       hw_cons = bnx2_get_hw_tx_cons(bnapi);
        }
 
        txr->hw_tx_cons = hw_cons;
        txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
 
        last_frag = skb_shinfo(skb)->nr_frags;
+       tx_buf->nr_frags = last_frag;
+       tx_buf->is_gso = skb_is_gso(skb);
 
        for (i = 0; i < last_frag; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];