aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/bfin_mac.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 2b364ba6b62e..9e010d69f34a 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -985,6 +985,7 @@ out:
985 return NETDEV_TX_OK; 985 return NETDEV_TX_OK;
986} 986}
987 987
988#define IP_HEADER_OFF 0
988#define RX_ERROR_MASK (RX_LONG | RX_ALIGN | RX_CRC | RX_LEN | \ 989#define RX_ERROR_MASK (RX_LONG | RX_ALIGN | RX_CRC | RX_LEN | \
989 RX_FRAG | RX_ADDR | RX_DMAO | RX_PHY | RX_LATE | RX_RANGE) 990 RX_FRAG | RX_ADDR | RX_DMAO | RX_PHY | RX_LATE | RX_RANGE)
990 991
@@ -993,6 +994,10 @@ static void bfin_mac_rx(struct net_device *dev)
993 struct sk_buff *skb, *new_skb; 994 struct sk_buff *skb, *new_skb;
994 unsigned short len; 995 unsigned short len;
995 struct bfin_mac_local *lp __maybe_unused = netdev_priv(dev); 996 struct bfin_mac_local *lp __maybe_unused = netdev_priv(dev);
997#if defined(BFIN_MAC_CSUM_OFFLOAD)
998 unsigned int i;
999 unsigned char fcs[ETH_FCS_LEN + 1];
1000#endif
996 1001
997 /* check if frame status word reports an error condition 1002 /* check if frame status word reports an error condition
998 * we which case we simply drop the packet 1003 * we which case we simply drop the packet
@@ -1026,6 +1031,8 @@ static void bfin_mac_rx(struct net_device *dev)
1026 current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2; 1031 current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
1027 1032
1028 len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN); 1033 len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
1034 /* Deduce Ethernet FCS length from Ethernet payload length */
1035 len -= ETH_FCS_LEN;
1029 skb_put(skb, len); 1036 skb_put(skb, len);
1030 1037
1031 skb->protocol = eth_type_trans(skb, dev); 1038 skb->protocol = eth_type_trans(skb, dev);
@@ -1033,8 +1040,32 @@ static void bfin_mac_rx(struct net_device *dev)
1033 bfin_rx_hwtstamp(dev, skb); 1040 bfin_rx_hwtstamp(dev, skb);
1034 1041
1035#if defined(BFIN_MAC_CSUM_OFFLOAD) 1042#if defined(BFIN_MAC_CSUM_OFFLOAD)
1036 skb->csum = current_rx_ptr->status.ip_payload_csum; 1043 /* Checksum offloading only works for IPv4 packets with the standard IP header
1037 skb->ip_summed = CHECKSUM_COMPLETE; 1044 * length of 20 bytes, because the blackfin MAC checksum calculation is
1045 * based on that assumption. We must NOT use the calculated checksum if our
1046 * IP version or header break that assumption.
1047 */
1048 if (skb->data[IP_HEADER_OFF] == 0x45) {
1049 skb->csum = current_rx_ptr->status.ip_payload_csum;
1050 /*
1051 * Deduce Ethernet FCS from hardware generated IP payload checksum.
1052 * IP checksum is based on 16-bit one's complement algorithm.
1053 * To deduce a value from checksum is equal to add its inversion.
1054 * If the IP payload len is odd, the inversed FCS should also
1055 * begin from odd address and leave first byte zero.
1056 */
1057 if (skb->len % 2) {
1058 fcs[0] = 0;
1059 for (i = 0; i < ETH_FCS_LEN; i++)
1060 fcs[i + 1] = ~skb->data[skb->len + i];
1061 skb->csum = csum_partial(fcs, ETH_FCS_LEN + 1, skb->csum);
1062 } else {
1063 for (i = 0; i < ETH_FCS_LEN; i++)
1064 fcs[i] = ~skb->data[skb->len + i];
1065 skb->csum = csum_partial(fcs, ETH_FCS_LEN, skb->csum);
1066 }
1067 skb->ip_summed = CHECKSUM_COMPLETE;
1068 }
1038#endif 1069#endif
1039 1070
1040 netif_rx(skb); 1071 netif_rx(skb);