net/sonic: Improve receive descriptor status flag check
After sonic_tx_timeout() calls sonic_init(), it can happen that
sonic_rx() will subsequently encounter a receive descriptor with no
flags set. Remove the comment that says that this can't happen.
When giving a receive descriptor to the SONIC, clear the descriptor
status field. That way, any rx descriptor with flags set can only be
a newly received packet.
Don't process a descriptor without the LPKT bit set. The buffer is
still in use by the SONIC.
Fixes: 1da177e4c3
("Linux-2.6.12-rc2")
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
eaabfd19b2
commit
94b1663495
@ -434,7 +434,6 @@ static int index_from_addr(struct sonic_local *lp, dma_addr_t addr,
|
|||||||
static void sonic_rx(struct net_device *dev)
|
static void sonic_rx(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct sonic_local *lp = netdev_priv(dev);
|
struct sonic_local *lp = netdev_priv(dev);
|
||||||
int status;
|
|
||||||
int entry = lp->cur_rx;
|
int entry = lp->cur_rx;
|
||||||
int prev_entry = lp->eol_rx;
|
int prev_entry = lp->eol_rx;
|
||||||
|
|
||||||
@ -445,9 +444,10 @@ static void sonic_rx(struct net_device *dev)
|
|||||||
u16 bufadr_l;
|
u16 bufadr_l;
|
||||||
u16 bufadr_h;
|
u16 bufadr_h;
|
||||||
int pkt_len;
|
int pkt_len;
|
||||||
|
u16 status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
|
||||||
|
|
||||||
status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
|
/* If the RD has LPKT set, the chip has finished with the RB */
|
||||||
if (status & SONIC_RCR_PRX) {
|
if ((status & SONIC_RCR_PRX) && (status & SONIC_RCR_LPKT)) {
|
||||||
u32 addr = (sonic_rda_get(dev, entry,
|
u32 addr = (sonic_rda_get(dev, entry,
|
||||||
SONIC_RD_PKTPTR_H) << 16) |
|
SONIC_RD_PKTPTR_H) << 16) |
|
||||||
sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L);
|
sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L);
|
||||||
@ -495,10 +495,6 @@ static void sonic_rx(struct net_device *dev)
|
|||||||
bufadr_h = (unsigned long)new_laddr >> 16;
|
bufadr_h = (unsigned long)new_laddr >> 16;
|
||||||
sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
|
sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
|
||||||
sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
|
sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
|
||||||
} else {
|
|
||||||
/* This should only happen, if we enable accepting broken packets. */
|
|
||||||
}
|
|
||||||
if (status & SONIC_RCR_LPKT) {
|
|
||||||
/*
|
/*
|
||||||
* this was the last packet out of the current receive buffer
|
* this was the last packet out of the current receive buffer
|
||||||
* give the buffer back to the SONIC
|
* give the buffer back to the SONIC
|
||||||
@ -511,12 +507,11 @@ static void sonic_rx(struct net_device *dev)
|
|||||||
__func__);
|
__func__);
|
||||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
|
SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
|
|
||||||
dev->name);
|
|
||||||
/*
|
/*
|
||||||
* give back the descriptor
|
* give back the descriptor
|
||||||
*/
|
*/
|
||||||
|
sonic_rda_put(dev, entry, SONIC_RD_STATUS, 0);
|
||||||
sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
|
sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
|
||||||
|
|
||||||
prev_entry = entry;
|
prev_entry = entry;
|
||||||
|
Loading…
Reference in New Issue
Block a user