Commit 2f652923 authored by François Romieu's avatar François Romieu Committed by Jeff Garzik

[PATCH] via-velocity: received ring wrong index and missing barriers

There were several receive ring related bugs.

In velocity_give_many_rx_descs(), index calculation was incorrect.
This and bugs in velocity_rx_srv() described in the following paragraph
caused packet loss, truncation and infinite error interrupt generation.

In velocity_rx_srv(), velocity_rx_refill() could be called without any
dirty slot.  With proper timing, This can result in refilling yet
unreceived packets and pushing dirty pointer ahead of the current pointer.
And vptr->rd_curr which is used by velocity_rx_refill() was updated after
calling velocity_rx_refill() thus screwing receive descriptor ring.
Also, between checking owner and reading the packet, rmb() is missing.
Signed-off-by: default avatarTejun Heo <tj@home-tj.org>
parent 9030eb03
......@@ -1018,8 +1018,8 @@ static inline void velocity_give_many_rx_descs(struct velocity_info *vptr)
wmb();
unusable = vptr->rd_filled | 0x0003;
dirty = vptr->rd_dirty - unusable + 1;
unusable = vptr->rd_filled & 0x0003;
dirty = vptr->rd_dirty - unusable;
for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
......@@ -1232,15 +1232,17 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
int rd_curr = vptr->rd_curr;
int works = 0;
while (1) {
do {
struct rx_desc *rd = vptr->rd_ring + rd_curr;
if (!vptr->rd_info[rd_curr].skb || (works++ > 15))
if (!vptr->rd_info[rd_curr].skb)
break;
if (rd->rdesc0.owner == OWNED_BY_NIC)
break;
rmb();
/*
* Don't drop CE or RL error frame although RXOK is off
*/
......@@ -1263,14 +1265,15 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
rd_curr++;
if (rd_curr >= vptr->options.numrx)
rd_curr = 0;
}
} while (++works <= 15);
if (velocity_rx_refill(vptr) < 0) {
vptr->rd_curr = rd_curr;
if (works > 0 && velocity_rx_refill(vptr) < 0) {
VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
"%s: rx buf allocation failure\n", vptr->dev->name);
}
vptr->rd_curr = rd_curr;
VAR_USED(stats);
return works;
}
......
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