Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
[sfrench/cifs-2.6.git] / drivers / net / ethernet / intel / i40evf / i40e_txrx.c
index 50864f99446d3a9f22c83c984eaec4f25caa6015..1ba29bb85b6706c15b5d80d760a7128afd31e0fe 100644 (file)
@@ -2012,10 +2012,30 @@ bool __i40evf_chk_linearize(struct sk_buff *skb)
        /* Walk through fragments adding latest fragment, testing it, and
         * then removing stale fragments from the sum.
         */
-       stale = &skb_shinfo(skb)->frags[0];
-       for (;;) {
+       for (stale = &skb_shinfo(skb)->frags[0];; stale++) {
+               int stale_size = skb_frag_size(stale);
+
                sum += skb_frag_size(frag++);
 
+               /* The stale fragment may present us with a smaller
+                * descriptor than the actual fragment size. To account
+                * for that we need to remove all the data on the front and
+                * figure out what the remainder would be in the last
+                * descriptor associated with the fragment.
+                */
+               if (stale_size > I40E_MAX_DATA_PER_TXD) {
+                       int align_pad = -(stale->page_offset) &
+                                       (I40E_MAX_READ_REQ_SIZE - 1);
+
+                       sum -= align_pad;
+                       stale_size -= align_pad;
+
+                       do {
+                               sum -= I40E_MAX_DATA_PER_TXD_ALIGNED;
+                               stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED;
+                       } while (stale_size > I40E_MAX_DATA_PER_TXD);
+               }
+
                /* if sum is negative we failed to make sufficient progress */
                if (sum < 0)
                        return true;
@@ -2023,7 +2043,7 @@ bool __i40evf_chk_linearize(struct sk_buff *skb)
                if (!nr_frags--)
                        break;
 
-               sum -= skb_frag_size(stale++);
+               sum -= stale_size;
        }
 
        return false;