]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
sky2: status ring race fix
authorStephen Hemminger <shemminger@linux-foundation.org>
Tue, 6 Nov 2007 22:12:34 +0000 (14:12 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 16 Nov 2007 17:25:36 +0000 (09:25 -0800)
patch ab5adecb2d02f3688719dfb5936a82833fcc3955 in mainline.

The D-Link PCI-X board (and maybe others) can lie about status
ring entries. It seems it will update the register for last status
index before completing the DMA for the ring entry. To avoid reading
stale data, zap the old entry and check.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/sky2.c

index ea117fc3d5e390c6da6b763a61f6d94a071c3c86..457de2654a5c467b28f3e8c8f446f299bc9321ce 100644 (file)
@@ -2246,20 +2246,26 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
        while (hw->st_idx != hwidx) {
                struct sky2_port *sky2;
                struct sky2_status_le *le  = hw->st_le + hw->st_idx;
-               unsigned port = le->css & CSS_LINK_BIT;
+               unsigned port;
                struct net_device *dev;
                struct sk_buff *skb;
                u32 status;
                u16 length;
+               u8 opcode = le->opcode;
+
+               if (!(opcode & HW_OWNER))
+                       break;
 
                hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
 
+               port = le->css & CSS_LINK_BIT;
                dev = hw->dev[port];
                sky2 = netdev_priv(dev);
                length = le16_to_cpu(le->length);
                status = le32_to_cpu(le->status);
 
-               switch (le->opcode & ~HW_OWNER) {
+               le->opcode = 0;
+               switch (opcode & ~HW_OWNER) {
                case OP_RXSTAT:
                        ++rx[port];
                        skb = sky2_receive(dev, length, status);
@@ -2352,7 +2358,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
                default:
                        if (net_ratelimit())
                                printk(KERN_WARNING PFX
-                                      "unknown status opcode 0x%x\n", le->opcode);
+                                      "unknown status opcode 0x%x\n", opcode);
                }
        }