Changeset 27035


Ignore:
Timestamp:
2011-05-31T01:08:01+02:00 (7 years ago)
Author:
nbd
Message:

ar71xx: only enable the rx engine after the link is up, fixes a race condition that got rx stuck when the interface is brought up during lots of inbound traffic (thx, matteo)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c

    r27034 r27035  
    345345} 
    346346 
     347static void ag71xx_dma_reset(struct ag71xx *ag) 
     348{ 
     349        u32 val; 
     350        int i; 
     351 
     352        ag71xx_dump_dma_regs(ag); 
     353 
     354        /* stop RX and TX */ 
     355        ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); 
     356        ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); 
     357 
     358        /* 
     359         * give the hardware some time to really stop all rx/tx activity 
     360         * clearing the descriptors too early causes random memory corruption 
     361         */ 
     362        mdelay(1); 
     363 
     364        /* clear descriptor addresses */ 
     365        ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0); 
     366        ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0); 
     367 
     368        /* clear pending RX/TX interrupts */ 
     369        for (i = 0; i < 256; i++) { 
     370                ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); 
     371                ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); 
     372        } 
     373 
     374        /* clear pending errors */ 
     375        ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF); 
     376        ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR); 
     377 
     378        val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); 
     379        if (val) 
     380                printk(KERN_ALERT "%s: unable to clear DMA Rx status: %08x\n", 
     381                        ag->dev->name, val); 
     382 
     383        val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS); 
     384 
     385        /* mask out reserved bits */ 
     386        val &= ~0xff000000; 
     387 
     388        if (val) 
     389                printk(KERN_ALERT "%s: unable to clear DMA Tx status: %08x\n", 
     390                        ag->dev->name, val); 
     391 
     392        ag71xx_dump_dma_regs(ag); 
     393} 
     394 
     395static void ag71xx_hw_start(struct ag71xx *ag) 
     396{ 
     397        /* start RX engine */ 
     398        ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); 
     399 
     400        /* enable interrupts */ 
     401        ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT); 
     402} 
     403 
     404static void ag71xx_hw_stop(struct ag71xx *ag) 
     405{ 
     406        /* disable all interrupts */ 
     407        ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0); 
     408 
     409        ag71xx_dma_reset(ag); 
     410} 
     411 
    347412void ag71xx_link_adjust(struct ag71xx *ag) 
    348413{ 
     
    354419 
    355420        if (!ag->link) { 
     421                ag71xx_hw_stop(ag); 
    356422                netif_carrier_off(ag->dev); 
    357423                if (netif_msg_link(ag)) 
     
    406472        ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); 
    407473 
     474        ag71xx_hw_start(ag); 
     475 
    408476        netif_carrier_on(ag->dev); 
    409477        if (netif_msg_link(ag)) 
     
    443511        t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16); 
    444512        ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t); 
    445 } 
    446  
    447 static void ag71xx_dma_reset(struct ag71xx *ag) 
    448 { 
    449         u32 val; 
    450         int i; 
    451  
    452         ag71xx_dump_dma_regs(ag); 
    453  
    454         /* stop RX and TX */ 
    455         ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); 
    456         ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); 
    457  
    458         /* 
    459          * give the hardware some time to really stop all rx/tx activity 
    460          * clearing the descriptors too early causes random memory corruption 
    461          */ 
    462         mdelay(1); 
    463  
    464         /* clear descriptor addresses */ 
    465         ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0); 
    466         ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0); 
    467  
    468         /* clear pending RX/TX interrupts */ 
    469         for (i = 0; i < 256; i++) { 
    470                 ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); 
    471                 ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); 
    472         } 
    473  
    474         /* clear pending errors */ 
    475         ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF); 
    476         ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR); 
    477  
    478         val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); 
    479         if (val) 
    480                 printk(KERN_ALERT "%s: unable to clear DMA Rx status: %08x\n", 
    481                         ag->dev->name, val); 
    482  
    483         val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS); 
    484  
    485         /* mask out reserved bits */ 
    486         val &= ~0xff000000; 
    487  
    488         if (val) 
    489                 printk(KERN_ALERT "%s: unable to clear DMA Tx status: %08x\n", 
    490                         ag->dev->name, val); 
    491  
    492         ag71xx_dump_dma_regs(ag); 
    493513} 
    494514 
     
    551571} 
    552572 
    553 static void ag71xx_hw_start(struct ag71xx *ag) 
    554 { 
    555         /* start RX engine */ 
    556         ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); 
    557  
    558         /* enable interrupts */ 
    559         ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT); 
    560 } 
    561  
    562 static void ag71xx_hw_stop(struct ag71xx *ag) 
    563 { 
    564         /* disable all interrupts */ 
    565         ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0); 
    566  
    567         ag71xx_dma_reset(ag); 
    568 } 
    569  
    570573static int ag71xx_open(struct net_device *dev) 
    571574{ 
     
    586589 
    587590        ag71xx_hw_set_macaddr(ag, dev->dev_addr); 
    588  
    589         ag71xx_hw_start(ag); 
    590591 
    591592        netif_start_queue(dev); 
Note: See TracChangeset for help on using the changeset viewer.