This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

smsc911 ethernet failure in kernel

Guru 20755 points
Other Parts Discussed in Thread: OMAP3530

Hello,

We recently replaced the ethernet chip in board from ks8851 to smsc911x, according to TI's recommendation, this is on order to support power save mode in ethernet.

But now we face another failure not seen before:

After startup, if there is no ethernet cable connected to board on booting to linux prompt, than reconnecting the cable and doing ping again, still ping fails !

Only if doing ifconfig eth0 down and than ifconfig eth0 up, will result in successful ping.

The same behaviour also happends on doing suspend-resume: only if doing link down and link up, will help.

I also see that other encounter this issue:

Is there any solution for this ?

Regards,

Ran

  • Hi Ran,
    What is your SDK and kernel version ?
    You didn't see this behavior with old PHY (ks8851) ?
    Disable the whole power management mode (run time and dynamic etc.,) and see the problem occurs or not.
  • Hi Titus,

    >What is your SDK and kernel version ?

    The SDK is  4.2.0.7 , linux 2.6.37

    >You didn't see this behavior with old PHY (ks8851) ?

    I think the old phy didn't behave like this, but I need to validate it, I'm not sure.

    >Disable the whole power management mode (run time and dynamic etc.,) and see the problem occurs or not.

    It seems I can't disable it becuase of menuconfig dependencies:

    │ Symbol: PM [=y] │
    │ Type : boolean │
    │ Prompt: Power Management support │
    │ Defined at kernel/power/Kconfig:1 │
    │ Depends on: !IA64_HP_SIM │
    │ Location: │
    │ -> Power management options │
    │ Selected by: ARCH_OMAP2PLUS_TYPICAL [=y] && ARCH_OMAP2PLUS [=y] || \ │
    │ MACH_TS78XX [=n] && ARCH_ORION5X [=n]

     

    │ Symbol: PM_RUNTIME [=y] │
    │ Type : boolean │
    │ Prompt: Run-time PM core functionality │
    │ Defined at kernel/power/Kconfig:230 │
    │ Depends on: PM [=y] │
    │ Location: │
    │ -> Power management options │
    │ Selected by: ARCH_OMAP2PLUS_TYPICAL [=y] && ARCH_OMAP2PLUS [=y]

    Thank you very muich for your assistance,

    Ran

  • Hi Titus,

    Did you check the previous message ?
    Do you have any tips what we can do ? It seems that there are others who encounter this with SMSC911
    e2e.ti.com/.../1469367

    Regards,
    Ran
  • Hi Ran,

    After startup, if there is no ethernet cable connected to board on booting to linux prompt, than reconnecting the cable and doing ping again, still ping fails !

    Only if doing ifconfig eth0 down and than ifconfig eth0 up, will result in successful ping.


    Have you followed the same steps in board when you use old PHY ?
    Did you modify the board file and kernel config appropriately for new PHY ?
    Check and compare one more time between old PHY kernel config with new PHY kernel config.

    Are you following the following procedure ?

    1) Booting Linux without ethernet cable connecting
    2) Now connecting the ethernet cable
    3) ifconfig eth0 up
    4) udhcpc -i eth0 (Titus : Getting IP through DHCP server)
    5) ping < IPv4 address > ( Titus : Failing here ?)
    6) ifconfig eth0 down
  • Hi Titus,

    Thank for the assistance.

    I've made more testing on this issue.

    I see that with previous phy (ks8851), there is no such problem , but only with smsc911x.

    I also see that the code is same as in GIT, except for changes made for our board:

    /board-omap3evm.c:

    #define OMAP3EVM_ETHR_START 0x2c000000
    #define OMAP3EVM_ETHR_SIZE 0x300 /*HH change 1024*/
    #define OMAP3EVM_ETHR_ID_REV 0x50
    #define OMAP3EVM_ETHR_GPIO_IRQ 164 /*HH changed orig value- 176*/
    #define OMAP3EVM_SMSC911X_CS 6 /*5*/


    static inline void __init omap3evm_init_smsc911x(void)/*HH tamaer- some changes here*/
    {
    int eth_cs, eth_rst;
    struct clk *l3ck;
    unsigned int rate;

    if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1)
    eth_rst = 64;
    else
    eth_rst = 128;/*HH replaced 7 with 128 */

    ..

    }

    and relevant pinmux changes 

    Though I'm not sure if any of the above changes can explaing why it fails in startup because of cable connection,

    The sequence I'm doing:

    1) Booting Linux without ethernet cable connecting
    2) Now connecting the ethernet cable
    3) doing ifconfig here will show the interface, and it seems OK (though it seems that the Ethernet HWaddr address is different when cable is not connected) :

    eth0 Link encap:Ethernet HWaddr 06:79:91:E9:CA:C0
    inet addr:150.42.40.221 Bcast:150.42.255.255 Mask:255.255.0.0
    UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
    RX packets:165 errors:0 dropped:164 overruns:0 frame:0
    TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
    collisions:0 txqueuelen:1000
    RX bytes:19701 (19.2 KiB) TX bytes:190 (190.0 B)
    Interrupt:68


    5) But ping to host (150.42.40.220) fails

    Do you catch any problem with these modifications ?

    Thanks,

    Ran

     

  • Hi ,

    I suspect that the driver might have failures.
    Did you encounter this in other OMAP3530 board ?

    Thank you,
    Ran
  • Hi,

    Seems I've solved the issue.
    Look like there are some bugs in this driver.

    These are patches I've made which solved the issues for me:


    1. power on when cable is disconnected - probably if cable is disconnected the driver does not finish initialization
    patch /drivers/net/smsc911x.c:

    #ifdef USE_PHY_WORK_AROUND
    static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
    {
    unsigned int tries;
    u32 wrsz;
    u32 rdsz;
    ulong bufp;

    for (tries = 0; tries < 10; tries++) {
    unsigned int txcmd_a;
    unsigned int txcmd_b;
    unsigned int status;
    unsigned int pktlength;
    unsigned int i;

    /* Zero-out rx packet memory */
    memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE);

    /* Write tx packet to 118 */
    txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16;
    txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
    txcmd_a |= MIN_PACKET_SIZE;

    txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE;

    smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a);
    smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b);

    bufp = (ulong)pdata->loopback_tx_pkt & (~0x3);
    wrsz = MIN_PACKET_SIZE + 3;
    wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3);
    wrsz >>= 2;

    smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);

    /* Wait till transmit is done */
    i = 60;
    do {
    udelay(5);
    status = smsc911x_tx_get_txstatus(pdata);
    } while ((i--) && (!status));

    if (!status) {
    SMSC_WARNING(HW, "Failed to transmit "
    "during loopback test");
    -- continue
    ++ //ranran continue;
    }

    2. original suspend/resume didn't work for me , I've used the following instead:

    int eth_suspend(void)
    {
    struct net_device *ndev = 0;
    struct smsc911x_data *pdata;
    unsigned int reg;


    ndev = dev_get_by_name(&init_net, "eth0");
    if (ndev == NULL)
    {
    printk("net is null");
    return -1;
    }

    pdata = netdev_priv(ndev);


    reg = smsc911x_mii_read(pdata->phy_dev->bus, pdata->phy_dev->addr, 17);
    reg = reg | 0x02000;
    smsc911x_mii_write(pdata->phy_dev->bus, pdata->phy_dev->addr, 17, reg);
    udelay(1000);

    smsc911x_reg_write(pdata, PMT_CTRL,
    PMT_CTRL_PM_MODE_D2_ | PMT_CTRL_WOL_EN_ |
    PMT_CTRL_ED_EN_ );
    return 0;
    }
    EXPORT_SYMBOL(eth_suspend);

    int eth_resume(void)
    {
    struct net_device *ndev = 0;
    struct smsc911x_data *pdata;
    unsigned int to = 100, reg;

    ndev = dev_get_by_name(&init_net, "eth0");

    if (ndev == NULL)
    {
    printk("net is null");
    return -1;
    }

    pdata = netdev_priv(ndev);


    /* Note 3.11 from the datasheet:
    * "When the LAN9220 is in a power saving state, a write of any
    * data to the BYTE_TEST register will wake-up the device."
    */
    smsc911x_reg_write(pdata, BYTE_TEST, 0);

    /* poll the READY bit in PMT_CTRL. Any other access to the device is
    * forbidden while this bit isn't set. Try for 100ms and return -EIO
    * if it failed. */
    while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to)
    udelay(1000);

    reg = smsc911x_mii_read(pdata->phy_dev->bus, pdata->phy_dev->addr, 17);
    reg = reg & ~0x02000;
    smsc911x_mii_write(pdata->phy_dev->bus, pdata->phy_dev->addr, 17, reg);

    if (to == 0)
    {
    printk("resume failed");
    return -1;
    }
    return 0;
    }
    EXPORT_SYMBOL(eth_resume);


    Hope it will help someone.

    Ran