--- drivers/net/sky2.c | 54 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 20 deletions(-) --- sky2.orig/drivers/net/sky2.c 2007-01-31 14:52:16.000000000 -0800 +++ sky2/drivers/net/sky2.c 2007-01-31 14:52:21.000000000 -0800 @@ -1840,15 +1840,18 @@ } -/* Transmit timeout is only called if we are running, carries is up +/* Transmit timeout is only called if we are running, carrier is up * and tx queue is full (stopped). + * netif_tx_lock is already held. */ static void sky2_tx_timeout(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - unsigned txq = txqaddr[sky2->port]; - u16 report, done; + unsigned port = sky2->port; + unsigned txq = txqaddr[port]; + u32 imask; + u16 report, done, ctrl; if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); @@ -1860,28 +1863,39 @@ dev->name, sky2->tx_cons, sky2->tx_prod, report, done); - if (report != done) { - printk(KERN_INFO PFX "status burst pending (irq moderation?)\n"); + imask = sky2_read32(hw, B0_IMSK); + sky2_write32(hw, B0_IMSK, 0); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); - } else if (report != sky2->tx_cons) { - printk(KERN_INFO PFX "status report lost?\n"); + /* don't reschedule when clean creates space */ + netif_start_queue(dev); - netif_tx_lock_bh(dev); - sky2_tx_complete(sky2, report); - netif_tx_unlock_bh(dev); - } else { - printk(KERN_INFO PFX "hardware hung? flushing\n"); + /* stop tx port */ + sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); + ctrl = gma_read16(hw, port, GM_GP_CTRL); + gma_write16(hw, port, GM_GP_CTRL, ctrl & ~GM_GPCR_TX_ENA); - sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); - sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); + sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST); + sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); + sky2_write32(hw, RB_ADDR(txq, RB_CTRL), RB_RST_SET); - sky2_tx_clean(dev); + sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); + sky2_read8(hw, SK_REG(port, TX_GMF_CTRL_T)); - sky2_qset(hw, txq); - sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); - } + sky2_tx_complete(sky2, sky2->tx_prod); + + sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); + sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); + + sky2_write8(hw, RB_ADDR(txq, RB_CTRL), RB_RST_CLR); + sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_CLR); + sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_CLR_RESET); + sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_OPER_INIT); + sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_FIFO_OP_ON); + + gma_write16(hw, port, GM_GP_CTRL, ctrl); + netif_poll_enable(hw->dev[0]); + sky2_write32(hw, B0_IMSK, imask); + sky2_read32(hw, B0_IMSK); } static int sky2_change_mtu(struct net_device *dev, int new_mtu)