Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] mv643xx: add workaround for HW checksum generation bug

[PATCH] [NET] mv643xx: add workaround for HW checksum generation bug

The hardware checksum generator on the mv64xxx occasionally generates
an incorrect checksum. This patch works around the issue and enables
hardware checksum generation.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>

authored by

Dale Farnsworth and committed by
Jeff Garzik
26006360 e960fc5c

+21 -12
+18 -11
drivers/net/mv643xx_eth.c
··· 1157 1157 if (!skb_shinfo(skb)->nr_frags) { 1158 1158 linear: 1159 1159 if (skb->ip_summed != CHECKSUM_HW) { 1160 + /* Errata BTS #50, IHL must be 5 if no HW checksum */ 1160 1161 pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | 1161 - ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; 1162 + ETH_TX_FIRST_DESC | 1163 + ETH_TX_LAST_DESC | 1164 + 5 << ETH_TX_IHL_SHIFT; 1162 1165 pkt_info.l4i_chk = 0; 1163 1166 } else { 1164 - u32 ipheader = skb->nh.iph->ihl << 11; 1165 1167 1166 1168 pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | 1167 - ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC | 1168 - ETH_GEN_TCP_UDP_CHECKSUM | 1169 - ETH_GEN_IP_V_4_CHECKSUM | ipheader; 1169 + ETH_TX_FIRST_DESC | 1170 + ETH_TX_LAST_DESC | 1171 + ETH_GEN_TCP_UDP_CHECKSUM | 1172 + ETH_GEN_IP_V_4_CHECKSUM | 1173 + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; 1170 1174 /* CPU already calculated pseudo header checksum. */ 1171 1175 if (skb->nh.iph->protocol == IPPROTO_UDP) { 1172 1176 pkt_info.cmd_sts |= ETH_UDP_FRAME; ··· 1197 1193 stats->tx_bytes += pkt_info.byte_cnt; 1198 1194 } else { 1199 1195 unsigned int frag; 1200 - u32 ipheader; 1201 1196 1202 1197 /* Since hardware can't handle unaligned fragments smaller 1203 1198 * than 9 bytes, if we find any, we linearize the skb ··· 1225 1222 DMA_TO_DEVICE); 1226 1223 pkt_info.l4i_chk = 0; 1227 1224 pkt_info.return_info = 0; 1228 - pkt_info.cmd_sts = ETH_TX_FIRST_DESC; 1229 1225 1230 - if (skb->ip_summed == CHECKSUM_HW) { 1231 - ipheader = skb->nh.iph->ihl << 11; 1232 - pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | 1233 - ETH_GEN_IP_V_4_CHECKSUM | ipheader; 1226 + if (skb->ip_summed != CHECKSUM_HW) 1227 + /* Errata BTS #50, IHL must be 5 if no HW checksum */ 1228 + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | 1229 + 5 << ETH_TX_IHL_SHIFT; 1230 + else { 1231 + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | 1232 + ETH_GEN_TCP_UDP_CHECKSUM | 1233 + ETH_GEN_IP_V_4_CHECKSUM | 1234 + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; 1234 1235 /* CPU already calculated pseudo header checksum. */ 1235 1236 if (skb->nh.iph->protocol == IPPROTO_UDP) { 1236 1237 pkt_info.cmd_sts |= ETH_UDP_FRAME;
+3 -1
drivers/net/mv643xx_eth.h
··· 49 49 /* Checksum offload for Tx works for most packets, but 50 50 * fails if previous packet sent did not use hw csum 51 51 */ 52 - #undef MV643XX_CHECKSUM_OFFLOAD_TX 52 + #define MV643XX_CHECKSUM_OFFLOAD_TX 53 53 #define MV643XX_NAPI 54 54 #define MV643XX_TX_FAST_REFILL 55 55 #undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */ ··· 216 216 #define ETH_GEN_CRC (BIT22) 217 217 #define ETH_TX_ENABLE_INTERRUPT (BIT23) 218 218 #define ETH_AUTO_MODE (BIT30) 219 + 220 + #define ETH_TX_IHL_SHIFT 11 219 221 220 222 /* typedefs */ 221 223