Commit 26006360 authored by Dale Farnsworth's avatar Dale Farnsworth Committed by Jeff Garzik

[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: default avatarDale Farnsworth <dale@farnsworth.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent e960fc5c
...@@ -1157,16 +1157,20 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1157,16 +1157,20 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb_shinfo(skb)->nr_frags) { if (!skb_shinfo(skb)->nr_frags) {
linear: linear:
if (skb->ip_summed != CHECKSUM_HW) { if (skb->ip_summed != CHECKSUM_HW) {
/* Errata BTS #50, IHL must be 5 if no HW checksum */
pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; ETH_TX_FIRST_DESC |
ETH_TX_LAST_DESC |
5 << ETH_TX_IHL_SHIFT;
pkt_info.l4i_chk = 0; pkt_info.l4i_chk = 0;
} else { } else {
u32 ipheader = skb->nh.iph->ihl << 11;
pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC | ETH_TX_FIRST_DESC |
ETH_TX_LAST_DESC |
ETH_GEN_TCP_UDP_CHECKSUM | ETH_GEN_TCP_UDP_CHECKSUM |
ETH_GEN_IP_V_4_CHECKSUM | ipheader; ETH_GEN_IP_V_4_CHECKSUM |
skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
/* CPU already calculated pseudo header checksum. */ /* CPU already calculated pseudo header checksum. */
if (skb->nh.iph->protocol == IPPROTO_UDP) { if (skb->nh.iph->protocol == IPPROTO_UDP) {
pkt_info.cmd_sts |= ETH_UDP_FRAME; pkt_info.cmd_sts |= ETH_UDP_FRAME;
...@@ -1193,7 +1197,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1193,7 +1197,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
stats->tx_bytes += pkt_info.byte_cnt; stats->tx_bytes += pkt_info.byte_cnt;
} else { } else {
unsigned int frag; unsigned int frag;
u32 ipheader;
/* Since hardware can't handle unaligned fragments smaller /* Since hardware can't handle unaligned fragments smaller
* than 9 bytes, if we find any, we linearize the skb * than 9 bytes, if we find any, we linearize the skb
...@@ -1222,12 +1225,16 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1222,12 +1225,16 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
DMA_TO_DEVICE); DMA_TO_DEVICE);
pkt_info.l4i_chk = 0; pkt_info.l4i_chk = 0;
pkt_info.return_info = 0; pkt_info.return_info = 0;
pkt_info.cmd_sts = ETH_TX_FIRST_DESC;
if (skb->ip_summed == CHECKSUM_HW) { if (skb->ip_summed != CHECKSUM_HW)
ipheader = skb->nh.iph->ihl << 11; /* Errata BTS #50, IHL must be 5 if no HW checksum */
pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
ETH_GEN_IP_V_4_CHECKSUM | ipheader; 5 << ETH_TX_IHL_SHIFT;
else {
pkt_info.cmd_sts = ETH_TX_FIRST_DESC |
ETH_GEN_TCP_UDP_CHECKSUM |
ETH_GEN_IP_V_4_CHECKSUM |
skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
/* CPU already calculated pseudo header checksum. */ /* CPU already calculated pseudo header checksum. */
if (skb->nh.iph->protocol == IPPROTO_UDP) { if (skb->nh.iph->protocol == IPPROTO_UDP) {
pkt_info.cmd_sts |= ETH_UDP_FRAME; pkt_info.cmd_sts |= ETH_UDP_FRAME;
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
/* Checksum offload for Tx works for most packets, but /* Checksum offload for Tx works for most packets, but
* fails if previous packet sent did not use hw csum * fails if previous packet sent did not use hw csum
*/ */
#undef MV643XX_CHECKSUM_OFFLOAD_TX #define MV643XX_CHECKSUM_OFFLOAD_TX
#define MV643XX_NAPI #define MV643XX_NAPI
#define MV643XX_TX_FAST_REFILL #define MV643XX_TX_FAST_REFILL
#undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */ #undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */
...@@ -217,6 +217,8 @@ ...@@ -217,6 +217,8 @@
#define ETH_TX_ENABLE_INTERRUPT (BIT23) #define ETH_TX_ENABLE_INTERRUPT (BIT23)
#define ETH_AUTO_MODE (BIT30) #define ETH_AUTO_MODE (BIT30)
#define ETH_TX_IHL_SHIFT 11
/* typedefs */ /* typedefs */
typedef enum _eth_func_ret_status { typedef enum _eth_func_ret_status {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment