xen-netback: use new skb_checksum_setup function
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / net / xen-netback / netback.c
index 611aebe..6b62c3e 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/udp.h>
 
 #include <net/tcp.h>
-#include <net/ip6_checksum.h>
 
 #include <xen/xen.h>
 #include <xen/events.h>
@@ -476,7 +475,8 @@ static void xenvif_rx_action(struct xenvif *vif)
        int ret;
        unsigned long offset;
        struct skb_cb_overlay *sco;
-       int need_to_notify = 0;
+       bool need_to_notify = false;
+       bool ring_full = false;
 
        struct netrx_pending_operations npo = {
                .copy  = vif->grant_copy_op,
@@ -508,7 +508,8 @@ static void xenvif_rx_action(struct xenvif *vif)
                /* If the skb may not fit then bail out now */
                if (!xenvif_rx_ring_slots_available(vif, max_slots_needed)) {
                        skb_queue_head(&vif->rx_queue, skb);
-                       need_to_notify = 1;
+                       need_to_notify = true;
+                       ring_full = true;
                        break;
                }
 
@@ -521,10 +522,12 @@ static void xenvif_rx_action(struct xenvif *vif)
 
        BUG_ON(npo.meta_prod > ARRAY_SIZE(vif->meta));
 
+       vif->rx_queue_stopped = !npo.copy_prod && ring_full;
+
        if (!npo.copy_prod)
                goto done;
 
-       BUG_ON(npo.copy_prod > ARRAY_SIZE(vif->grant_copy_op));
+       BUG_ON(npo.copy_prod > MAX_GRANT_COPY_OPS);
        gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod);
 
        while ((skb = __skb_dequeue(&rxq)) != NULL) {
@@ -592,8 +595,7 @@ static void xenvif_rx_action(struct xenvif *vif)
 
                RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
 
-               if (ret)
-                       need_to_notify = 1;
+               need_to_notify |= !!ret;
 
                npo.meta_cons += sco->meta_slots_used;
                dev_kfree_skb(skb);
@@ -1048,249 +1050,9 @@ static int xenvif_set_skb_gso(struct xenvif *vif,
        return 0;
 }
 
-static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len,
-                                 unsigned int max)
-{
-       if (skb_headlen(skb) >= len)
-               return 0;
-
-       /* If we need to pullup then pullup to the max, so we
-        * won't need to do it again.
-        */
-       if (max > skb->len)
-               max = skb->len;
-
-       if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL)
-               return -ENOMEM;
-
-       if (skb_headlen(skb) < len)
-               return -EPROTO;
-
-       return 0;
-}
-
-/* This value should be large enough to cover a tagged ethernet header plus
- * maximally sized IP and TCP or UDP headers.
- */
-#define MAX_IP_HDR_LEN 128
-
-static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
-                            int recalculate_partial_csum)
-{
-       unsigned int off;
-       bool fragment;
-       int err;
-
-       fragment = false;
-
-       err = maybe_pull_tail(skb,
-                             sizeof(struct iphdr),
-                             MAX_IP_HDR_LEN);
-       if (err < 0)
-               goto out;
-
-       if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF))
-               fragment = true;
-
-       off = ip_hdrlen(skb);
-
-       err = -EPROTO;
-
-       if (fragment)
-               goto out;
-
-       switch (ip_hdr(skb)->protocol) {
-       case IPPROTO_TCP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct tcphdr),
-                                     MAX_IP_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct tcphdr, check)))
-                       goto out;
-
-               if (recalculate_partial_csum)
-                       tcp_hdr(skb)->check =
-                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-                                                  ip_hdr(skb)->daddr,
-                                                  skb->len - off,
-                                                  IPPROTO_TCP, 0);
-               break;
-       case IPPROTO_UDP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct udphdr),
-                                     MAX_IP_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct udphdr, check)))
-                       goto out;
-
-               if (recalculate_partial_csum)
-                       udp_hdr(skb)->check =
-                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-                                                  ip_hdr(skb)->daddr,
-                                                  skb->len - off,
-                                                  IPPROTO_UDP, 0);
-               break;
-       default:
-               goto out;
-       }
-
-       err = 0;
-
-out:
-       return err;
-}
-
-/* This value should be large enough to cover a tagged ethernet header plus
- * an IPv6 header, all options, and a maximal TCP or UDP header.
- */
-#define MAX_IPV6_HDR_LEN 256
-
-#define OPT_HDR(type, skb, off) \
-       (type *)(skb_network_header(skb) + (off))
-
-static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
-                              int recalculate_partial_csum)
-{
-       int err;
-       u8 nexthdr;
-       unsigned int off;
-       unsigned int len;
-       bool fragment;
-       bool done;
-
-       fragment = false;
-       done = false;
-
-       off = sizeof(struct ipv6hdr);
-
-       err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN);
-       if (err < 0)
-               goto out;
-
-       nexthdr = ipv6_hdr(skb)->nexthdr;
-
-       len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
-       while (off <= len && !done) {
-               switch (nexthdr) {
-               case IPPROTO_DSTOPTS:
-               case IPPROTO_HOPOPTS:
-               case IPPROTO_ROUTING: {
-                       struct ipv6_opt_hdr *hp;
-
-                       err = maybe_pull_tail(skb,
-                                             off +
-                                             sizeof(struct ipv6_opt_hdr),
-                                             MAX_IPV6_HDR_LEN);
-                       if (err < 0)
-                               goto out;
-
-                       hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
-                       nexthdr = hp->nexthdr;
-                       off += ipv6_optlen(hp);
-                       break;
-               }
-               case IPPROTO_AH: {
-                       struct ip_auth_hdr *hp;
-
-                       err = maybe_pull_tail(skb,
-                                             off +
-                                             sizeof(struct ip_auth_hdr),
-                                             MAX_IPV6_HDR_LEN);
-                       if (err < 0)
-                               goto out;
-
-                       hp = OPT_HDR(struct ip_auth_hdr, skb, off);
-                       nexthdr = hp->nexthdr;
-                       off += ipv6_authlen(hp);
-                       break;
-               }
-               case IPPROTO_FRAGMENT: {
-                       struct frag_hdr *hp;
-
-                       err = maybe_pull_tail(skb,
-                                             off +
-                                             sizeof(struct frag_hdr),
-                                             MAX_IPV6_HDR_LEN);
-                       if (err < 0)
-                               goto out;
-
-                       hp = OPT_HDR(struct frag_hdr, skb, off);
-
-                       if (hp->frag_off & htons(IP6_OFFSET | IP6_MF))
-                               fragment = true;
-
-                       nexthdr = hp->nexthdr;
-                       off += sizeof(struct frag_hdr);
-                       break;
-               }
-               default:
-                       done = true;
-                       break;
-               }
-       }
-
-       err = -EPROTO;
-
-       if (!done || fragment)
-               goto out;
-
-       switch (nexthdr) {
-       case IPPROTO_TCP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct tcphdr),
-                                     MAX_IPV6_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct tcphdr, check)))
-                       goto out;
-
-               if (recalculate_partial_csum)
-                       tcp_hdr(skb)->check =
-                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                &ipv6_hdr(skb)->daddr,
-                                                skb->len - off,
-                                                IPPROTO_TCP, 0);
-               break;
-       case IPPROTO_UDP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct udphdr),
-                                     MAX_IPV6_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct udphdr, check)))
-                       goto out;
-
-               if (recalculate_partial_csum)
-                       udp_hdr(skb)->check =
-                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                &ipv6_hdr(skb)->daddr,
-                                                skb->len - off,
-                                                IPPROTO_UDP, 0);
-               break;
-       default:
-               goto out;
-       }
-
-       err = 0;
-
-out:
-       return err;
-}
-
 static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
 {
-       int err = -EPROTO;
-       int recalculate_partial_csum = 0;
+       bool recalculate_partial_csum = false;
 
        /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
         * peers can fail to set NETRXF_csum_blank when sending a GSO
@@ -1300,19 +1062,14 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
        if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
                vif->rx_gso_checksum_fixup++;
                skb->ip_summed = CHECKSUM_PARTIAL;
-               recalculate_partial_csum = 1;
+               recalculate_partial_csum = true;
        }
 
        /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return 0;
 
-       if (skb->protocol == htons(ETH_P_IP))
-               err = checksum_setup_ip(vif, skb, recalculate_partial_csum);
-       else if (skb->protocol == htons(ETH_P_IPV6))
-               err = checksum_setup_ipv6(vif, skb, recalculate_partial_csum);
-
-       return err;
+       return skb_checksum_setup(skb, recalculate_partial_csum);
 }
 
 static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
@@ -1716,7 +1473,8 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
 
 static inline int rx_work_todo(struct xenvif *vif)
 {
-       return !skb_queue_empty(&vif->rx_queue) || vif->rx_event;
+       return (!skb_queue_empty(&vif->rx_queue) && !vif->rx_queue_stopped) ||
+               vif->rx_event;
 }
 
 static inline int tx_work_todo(struct xenvif *vif)