diff options
-rw-r--r-- | drivers/net/bfin_mac.c | 35 |
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); |