#ifdef CONFIG_GENERIC_CSUM
 #include <asm-generic/checksum.h>
 #else
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-extern __wsum csum_partial(const void *buff, int len, __wsum sum);
-
 /*
  * Computes the checksum of a memory block at src, length len,
  * and adds in "sum" (32-bit), while copying the block to dst.
        return (__force __sum16)(~((__force u32)sum + tmp) >> 16);
 }
 
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-static inline __sum16 ip_compute_csum(const void *buff, int len)
-{
-       return csum_fold(csum_partial(buff, len, 0));
-}
-
 static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
                                      unsigned short len,
                                      unsigned short proto,
        return csum_fold(ip_fast_csum_nofold(iph, ihl));
 }
 
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+__wsum __csum_partial(const void *buff, int len, __wsum sum);
+
+static inline __wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+       if (__builtin_constant_p(len) && len <= 16 && (len & 1) == 0) {
+               if (len == 2)
+                       sum = csum_add(sum, (__force __wsum)*(const u16 *)buff);
+               if (len >= 4)
+                       sum = csum_add(sum, (__force __wsum)*(const u32 *)buff);
+               if (len == 6)
+                       sum = csum_add(sum, (__force __wsum)
+                                           *(const u16 *)(buff + 4));
+               if (len >= 8)
+                       sum = csum_add(sum, (__force __wsum)
+                                           *(const u32 *)(buff + 4));
+               if (len == 10)
+                       sum = csum_add(sum, (__force __wsum)
+                                           *(const u16 *)(buff + 8));
+               if (len >= 12)
+                       sum = csum_add(sum, (__force __wsum)
+                                           *(const u32 *)(buff + 8));
+               if (len == 14)
+                       sum = csum_add(sum, (__force __wsum)
+                                           *(const u16 *)(buff + 12));
+               if (len >= 16)
+                       sum = csum_add(sum, (__force __wsum)
+                                           *(const u32 *)(buff + 12));
+       } else if (__builtin_constant_p(len) && (len & 3) == 0) {
+               sum = csum_add(sum, ip_fast_csum_nofold(buff, len >> 2));
+       } else {
+               sum = __csum_partial(buff, len, sum);
+       }
+       return sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline __sum16 ip_compute_csum(const void *buff, int len)
+{
+       return csum_fold(csum_partial(buff, len, 0));
+}
+
 #endif
 #endif /* __KERNEL__ */
 #endif