aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDale Farnsworth <dale@farnsworth.org>2005-08-22 18:53:29 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-08-23 00:51:34 -0400
commit2600636065406dc14948ac2d2913c66c51be80d5 (patch)
tree954eea2e62f50366c8a63681571f50f98bd83a55
parente960fc5c7d9144b1ce80dda9891ca7dfc656c078 (diff)
[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>
-rw-r--r--drivers/net/mv643xx_eth.c29
-rw-r--r--drivers/net/mv643xx_eth.h4
2 files changed, 21 insertions, 12 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 0405e1f0d3df..fb6b232069d6 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1157,16 +1157,20 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
1157 if (!skb_shinfo(skb)->nr_frags) { 1157 if (!skb_shinfo(skb)->nr_frags) {
1158linear: 1158linear:
1159 if (skb->ip_summed != CHECKSUM_HW) { 1159 if (skb->ip_summed != CHECKSUM_HW) {
1160 /* Errata BTS #50, IHL must be 5 if no HW checksum */
1160 pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | 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 pkt_info.l4i_chk = 0; 1165 pkt_info.l4i_chk = 0;
1163 } else { 1166 } else {
1164 u32 ipheader = skb->nh.iph->ihl << 11;
1165 1167
1166 pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | 1168 pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
1167 ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC | 1169 ETH_TX_FIRST_DESC |
1168 ETH_GEN_TCP_UDP_CHECKSUM | 1170 ETH_TX_LAST_DESC |
1169 ETH_GEN_IP_V_4_CHECKSUM | ipheader; 1171 ETH_GEN_TCP_UDP_CHECKSUM |
1172 ETH_GEN_IP_V_4_CHECKSUM |
1173 skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
1170 /* CPU already calculated pseudo header checksum. */ 1174 /* CPU already calculated pseudo header checksum. */
1171 if (skb->nh.iph->protocol == IPPROTO_UDP) { 1175 if (skb->nh.iph->protocol == IPPROTO_UDP) {
1172 pkt_info.cmd_sts |= ETH_UDP_FRAME; 1176 pkt_info.cmd_sts |= ETH_UDP_FRAME;
@@ -1193,7 +1197,6 @@ linear:
1193 stats->tx_bytes += pkt_info.byte_cnt; 1197 stats->tx_bytes += pkt_info.byte_cnt;
1194 } else { 1198 } else {
1195 unsigned int frag; 1199 unsigned int frag;
1196 u32 ipheader;
1197 1200
1198 /* Since hardware can't handle unaligned fragments smaller 1201 /* Since hardware can't handle unaligned fragments smaller
1199 * than 9 bytes, if we find any, we linearize the skb 1202 * than 9 bytes, if we find any, we linearize the skb
@@ -1222,12 +1225,16 @@ linear:
1222 DMA_TO_DEVICE); 1225 DMA_TO_DEVICE);
1223 pkt_info.l4i_chk = 0; 1226 pkt_info.l4i_chk = 0;
1224 pkt_info.return_info = 0; 1227 pkt_info.return_info = 0;
1225 pkt_info.cmd_sts = ETH_TX_FIRST_DESC;
1226 1228
1227 if (skb->ip_summed == CHECKSUM_HW) { 1229 if (skb->ip_summed != CHECKSUM_HW)
1228 ipheader = skb->nh.iph->ihl << 11; 1230 /* Errata BTS #50, IHL must be 5 if no HW checksum */
1229 pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | 1231 pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
1230 ETH_GEN_IP_V_4_CHECKSUM | ipheader; 1232 5 << ETH_TX_IHL_SHIFT;
1233 else {
1234 pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
1235 ETH_GEN_TCP_UDP_CHECKSUM |
1236 ETH_GEN_IP_V_4_CHECKSUM |
1237 skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
1231 /* CPU already calculated pseudo header checksum. */ 1238 /* CPU already calculated pseudo header checksum. */
1232 if (skb->nh.iph->protocol == IPPROTO_UDP) { 1239 if (skb->nh.iph->protocol == IPPROTO_UDP) {
1233 pkt_info.cmd_sts |= ETH_UDP_FRAME; 1240 pkt_info.cmd_sts |= ETH_UDP_FRAME;
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 57c4f8fbfdb6..7678b59c2952 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -49,7 +49,7 @@
49/* Checksum offload for Tx works for most packets, but 49/* Checksum offload for Tx works for most packets, but
50 * fails if previous packet sent did not use hw csum 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#define MV643XX_NAPI 53#define MV643XX_NAPI
54#define MV643XX_TX_FAST_REFILL 54#define MV643XX_TX_FAST_REFILL
55#undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */ 55#undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */
@@ -217,6 +217,8 @@
217#define ETH_TX_ENABLE_INTERRUPT (BIT23) 217#define ETH_TX_ENABLE_INTERRUPT (BIT23)
218#define ETH_AUTO_MODE (BIT30) 218#define ETH_AUTO_MODE (BIT30)
219 219
220#define ETH_TX_IHL_SHIFT 11
221
220/* typedefs */ 222/* typedefs */
221 223
222typedef enum _eth_func_ret_status { 224typedef enum _eth_func_ret_status {