__u8                    encapsulation:1;
        __u8                    encap_hdr_csum:1;
        __u8                    csum_valid:1;
-       /* 4/6 bit hole (depending on ndisc_nodetype presence) */
+       __u8                    csum_complete_sw:1;
+       /* 3/5 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
 
        __sum16 sum;
 
        sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
-       if (likely(!sum)) {
-               if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
-                       netdev_rx_csum_fault(skb->dev);
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-       }
+       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum &&
+           !skb->csum_complete_sw)
+               netdev_rx_csum_fault(skb->dev);
+
+       /* Save checksum complete for later use */
+       skb->csum = sum;
+       skb->ip_summed = CHECKSUM_COMPLETE;
+       skb->csum_complete_sw = 1;
+
        return sum;
 }
 EXPORT_SYMBOL(__skb_checksum_complete_head);
 
                csum_partial(skb->data, skb_gro_offset(skb), 0));
        sum = csum_fold(NAPI_GRO_CB(skb)->csum);
        if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) {
-               if (unlikely(!sum))
+               if (unlikely(!sum) && !skb->csum_complete_sw)
                        netdev_rx_csum_fault(skb->dev);
-       } else
+       } else {
                skb->ip_summed = CHECKSUM_COMPLETE;
+               skb->csum_complete_sw = 1;
+       }
 
        return sum;
 }
 
                return -1;
        if (csum_fold(desc.csum))
                return -1;
-       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
+       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
+           !skb->csum_complete_sw)
                netdev_rx_csum_fault(skb->dev);
        return 0;
 no_checksum: