Try to improve sky2 reliability a little bit. At least one oops has been seen when setting the link down with "ip li set eth0 down". The oops showed a NULL re->skb in sky2_receive(). Also backport some adjustments from 1.10. --- ./drivers/net/sky2.c.orig 2007-02-16 14:32:04 +0100 +++ ./drivers/net/sky2.c 2007-02-17 18:35:12 +0100 @@ -58,9 +58,9 @@ * a receive requires one (or two if using 64 bit dma). */ -#define RX_LE_SIZE 512 +#define RX_LE_SIZE 1024 #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) -#define RX_MAX_PENDING (RX_LE_SIZE/2 - 2) +#define RX_MAX_PENDING (RX_LE_SIZE/6 - 2) #define RX_DEF_PENDING RX_MAX_PENDING #define RX_SKB_ALIGN 8 #define RX_BUF_WRITE 16 @@ -88,7 +88,7 @@ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); -static int copybreak = 256; +static int copybreak = 128; module_param(copybreak, int, 0); MODULE_PARM_DESC(copybreak, "Receive copy threshold"); @@ -451,6 +451,7 @@ } gma_write16(hw, port, GM_GP_CTRL, reg); + gma_read16(hw, port, GM_GP_CTRL); if (hw->chip_id != CHIP_ID_YUKON_FE) gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); @@ -1086,6 +1087,7 @@ if (err) goto err_out; +just_ints: /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); imask |= portirq_msk[port]; @@ -1316,6 +1318,13 @@ struct tx_ring_info *re = sky2->tx_ring + put; struct sk_buff *skb = re->skb; + // FIXME: it seems possible that sky2_rx_clean() flushes the ring below us. + if (!skb) { + printk(KERN_WARNING "sky2: %s: NULL skb in %s\n", + dev->name, __FUNCTION__); + continue; + } + nxt = re->idx; BUG_ON(nxt >= TX_RING_SIZE); prefetch(sky2->tx_ring + nxt); @@ -1388,6 +1397,7 @@ ctrl = gma_read16(hw, port, GM_GP_CTRL); ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA); gma_write16(hw, port, GM_GP_CTRL, ctrl); + gma_read16(hw, port, GM_GP_CTRL); sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); @@ -1477,6 +1487,7 @@ reg = gma_read16(hw, port, GM_GP_CTRL); reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; gma_write16(hw, port, GM_GP_CTRL, reg); + gma_read16(hw, port, GM_GP_CTRL); gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); @@ -1529,6 +1540,7 @@ reg = gma_read16(hw, port, GM_GP_CTRL); reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, reg); + gma_read16(hw, port, GM_GP_CTRL); if (sky2->flow_status == FC_RX) { /* restore Asymmetric Pause bit */ @@ -1720,6 +1732,7 @@ ctl = gma_read16(hw, sky2->port, GM_GP_CTRL); gma_write16(hw, sky2->port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA); + gma_read16(hw, sky2->port, GM_GP_CTRL); sky2_rx_stop(sky2); sky2_rx_clean(sky2); @@ -1742,6 +1755,7 @@ dev_close(dev); else { gma_write16(hw, sky2->port, GM_GP_CTRL, ctl); + gma_read16(hw, sky2->port, GM_GP_CTRL); netif_wake_queue(dev); } @@ -1760,6 +1774,12 @@ struct ring_info *re = sky2->rx_ring + sky2->rx_next; struct sk_buff *skb = NULL; + // FIXME: it seems possible that sky2_rx_clean() flushes the ring below us. + if (!re->skb) { + printk(KERN_WARNING "sky2: NULL skb in %s\n", __FUNCTION__); + return NULL; + } + if (unlikely(netif_msg_rx_status(sky2))) printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n", sky2->netdev->name, sky2->rx_next, status, length);