# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/09/13 13:26:10+09:00 tj@xxxxxxxxxxxxxxxx # via-velocity receive ring related bugs fixed. # # drivers/net/via-velocity.c # 2004/09/13 13:25:54+09:00 tj@xxxxxxxxxxxxxxxx +10 -7 # 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. # diff -Nru a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c --- a/drivers/net/via-velocity.c 2004-09-13 13:49:15 +09:00 +++ b/drivers/net/via-velocity.c 2004-09-13 13:49:15 +09:00 @@ -1018,8 +1018,8 @@ 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 @@ 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 @@ 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; }