summaryrefslogtreecommitdiffstats
path: root/drivers/net/enc28j60.c
diff options
context:
space:
mode:
authorBaruch Siach <baruch@tkos.co.il>2008-12-02 06:07:01 +0100
committerDavid S. Miller <davem@davemloft.net>2008-12-04 06:16:06 +0100
commit5176da7e5318669220e4d2fa856223054a3efc9f (patch)
tree849303631cc7df172a6ce8c89d8ebfbf18ec42fc /drivers/net/enc28j60.c
parenthysdn: fix writing outside the field on 64 bits (diff)
downloadlinux-5176da7e5318669220e4d2fa856223054a3efc9f.tar.xz
linux-5176da7e5318669220e4d2fa856223054a3efc9f.zip
enc28j60: Fix sporadic packet loss (corrected again)
Packet data read from the RX buffer the when the RSV is at the end of the RX buffer does not warp around. This causes packet loss, as the actual data is never read. Fix this by calculating the right packet data location. Thanks to Shachar Shemesh for suggesting the fix. Signed-off-by: Baruch Siach <baruch@tkos.co.il> Acked-by: Claudio Lanconelli <lanconelli.claudio@eptar.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/enc28j60.c')
-rw-r--r--drivers/net/enc28j60.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index e1b441effbbe..c414554ac321 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -568,6 +568,17 @@ static u16 erxrdpt_workaround(u16 next_packet_ptr, u16 start, u16 end)
return erxrdpt;
}
+/*
+ * Calculate wrap around when reading beyond the end of the RX buffer
+ */
+static u16 rx_packet_start(u16 ptr)
+{
+ if (ptr + RSV_SIZE > RXEND_INIT)
+ return (ptr + RSV_SIZE) - (RXEND_INIT - RXSTART_INIT + 1);
+ else
+ return ptr + RSV_SIZE;
+}
+
static void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
{
u16 erxrdpt;
@@ -938,8 +949,9 @@ static void enc28j60_hw_rx(struct net_device *ndev)
skb->dev = ndev;
skb_reserve(skb, NET_IP_ALIGN);
/* copy the packet from the receive buffer */
- enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv),
- len, skb_put(skb, len));
+ enc28j60_mem_read(priv,
+ rx_packet_start(priv->next_pk_ptr),
+ len, skb_put(skb, len));
if (netif_msg_pktdata(priv))
dump_packet(__func__, skb->len, skb->data);
skb->protocol = eth_type_trans(skb, ndev);