• AVR Freaks

Hot!TCP/IP: Major bug within drv_extphy_smsc9303.c

Author
galjuergen
New Member
  • Total Posts : 1
  • Reward points : 0
  • Joined: 2019/03/20 05:36:14
  • Location: 0
  • Status: offline
2019/03/20 23:14:16 (permalink)
0

TCP/IP: Major bug within drv_extphy_smsc9303.c

I've found a serious bug within the Harmony TCP/IP stack, which I also reported to https://microchipsupport.force.com/ (Case 0395981). This problem is inherent at least within v2.06, but after reviewing the source within the Git repository of Harmony v3.x, I didn't find any fixes relating to this issue, so its highly likely that v3.x is also affected. Due to the fact, that this bug results in muting the stack completely I also want to share my findings here:
 
We use the Harmony TCP/IP Stack in one of our products in combination with the SMSC LAN9303 chip. After some time and mainly after repeatedly connecting/disconnecting a patch cable to one of the ethernet ports the stack gets "stuck", which results in not detecting link up/down events anymore. This makes the whole stack pretty useless - even reinitializing the stack does not solve the issue, only resetting the hardware does the trick.
I found out that the problem is within drv_extphy_smsc9303.c. There are two functions (DRV_ETHPHY_Smsc9303LinkStatusGet() and DRV_ETHPHY_Smsc9303NegotiationIsComplete()) where in some cases allocated ressources (DRV_MIIM_OPERATION_HANDLE objects) are not freed properly. I've applied a patch to these functions which improves the stability of the TCP/IP stack and eliminates the undesired hibernation of link up/down events.
 
Here is a patch solving this issue:
 
DRV_ETHPHY_RESULT DRV_ETHPHY_Smsc9303LinkStatusGet( DRV_HANDLE handle, DRV_ETHPHY_INTERFACE_INDEX portIndex, DRV_ETHPHY_LINK_STATUS* pLinkStat, bool refresh )
{
    DRV_ETHPHY_CLIENT_OBJ * hClientObj = (DRV_ETHPHY_CLIENT_OBJ *) handle;

    if (portIndex > DRV_ETHPHY_INF_IDX_PORT_2)
    {
        return DRV_ETHPHY_RES_HANDLE_ERR;
    }
    
    /* Check for the Client validity */
    if(hClientObj == 0)
    {
        return DRV_ETHPHY_RES_HANDLE_ERR;
    }
    
    int x = 0;
    for (x = 0; x < 3; x++)
    {
        if (lan9303OperationsHandles[x] != 0)
        {
            uint16_t opResults;
            DRV_MIIM_RESULT mmiRes = DRV_MIIM_OperationResult(hClientObj->miimHandle, lan9303OperationsHandles[x], &opResults);
            if (mmiRes == DRV_MIIM_RES_OK)
            {
                lan9303OperationResults[x] = opResults;
                lan9303OperationsHandles[x] = 0;
            }
            else if (mmiRes != DRV_MIIM_RES_PENDING)
            {
                DRV_MIIM_OperationAbort(hClientObj->miimHandle, lan9303OperationsHandles[x]);
                lan9303OperationsHandles[x] = 0;
            }
        }
    }
 
    DRV_MIIM_RESULT res;
    if (portIndex == DRV_ETHPHY_INF_IDX_ALL_EXTERNAL)
    {
        DRV_MIIM_RESULT res;
        if (lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_1 - 1] == 0)
        {
            lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_1 - 1] = DRV_MIIM_Read(hClientObj->miimHandle, PHY_REG_BMSTAT, hClientObj->smiPhyAddress + DRV_ETHPHY_INF_IDX_PORT_1 - 1, DRV_MIIM_OPERATION_FLAG_NONE, &res);
        }
        if (lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_2 - 1] == 0)
        {
            lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_2 - 1] = DRV_MIIM_Read(hClientObj->miimHandle, PHY_REG_BMSTAT, hClientObj->smiPhyAddress + DRV_ETHPHY_INF_IDX_PORT_2 - 1, DRV_MIIM_OPERATION_FLAG_NONE, &res);
        }
        __BMSTATbits_t b1, b2;
        b1.w = (lan9303OperationResults[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_1 - 1]);
        b2.w = (lan9303OperationResults[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_2 - 1]);
        if (b1.LINK_STAT || b2.LINK_STAT)
        {
            *pLinkStat = DRV_ETHPHY_LINK_ST_UP;
        }
        else
        {
            *pLinkStat = DRV_ETHPHY_LINK_ST_DOWN;
        }
        if (b1.REM_FAULT || b2.REM_FAULT)
        {
            *pLinkStat |= DRV_ETHPHY_LINK_ST_REMOTE_FAULT;
        }
        return DRV_ETHPHY_RES_PENDING;
    }
    if (lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + portIndex - 1] == 0)
    {
        lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + portIndex - 1] = DRV_MIIM_Read(hClientObj->miimHandle, PHY_REG_BMSTAT, hClientObj->smiPhyAddress + portIndex - 1, DRV_MIIM_OPERATION_FLAG_NONE, &res);
    }
    __BMSTATbits_t b1;
    b1.w = lan9303OperationResults[LAND9303_LINK_STATUS_INDEX + portIndex - 1];
    if (b1.LINK_STAT)
    {
        *pLinkStat = DRV_ETHPHY_LINK_ST_UP;
    }
    else
    {
        *pLinkStat = DRV_ETHPHY_LINK_ST_DOWN;
    }
    if (b1.REM_FAULT)
    {
        *pLinkStat |= DRV_ETHPHY_LINK_ST_REMOTE_FAULT;
    }
    return DRV_ETHPHY_RES_PENDING;
}

 
DRV_ETHPHY_RESULT DRV_ETHPHY_Smsc9303NegotiationIsComplete( DRV_HANDLE handle, DRV_ETHPHY_INTERFACE_INDEX portIndex, bool waitComplete )
{
    DRV_ETHPHY_CLIENT_OBJ * hClientObj = (DRV_ETHPHY_CLIENT_OBJ *) handle;

    if (portIndex > DRV_ETHPHY_INF_IDX_PORT_2)
    {
        return DRV_ETHPHY_RES_HANDLE_ERR;
    }
    
    /* Check for the Client validity */
    if(hClientObj == 0)
    {
        return DRV_ETHPHY_RES_HANDLE_ERR;
    }
    
    int x = 0;
    for (x = 0; x < 3; x++)
    {
        if (lan9303OperationsHandles[x] != 0)
        {
            uint16_t opResults;
            DRV_MIIM_RESULT mmiRes = DRV_MIIM_OperationResult(hClientObj->miimHandle, lan9303OperationsHandles[x], &opResults);
            if (mmiRes == DRV_MIIM_RES_OK)
            {
                lan9303OperationResults[x] = opResults;
                lan9303OperationsHandles[x] = 0;
            }
            else if (mmiRes != DRV_MIIM_RES_PENDING)
            {
                DRV_MIIM_OperationAbort(hClientObj->miimHandle, lan9303OperationsHandles[x]);
                lan9303OperationsHandles[x] = 0;
            }
        }
    }
    if (portIndex == DRV_ETHPHY_INF_IDX_ALL_EXTERNAL)
    {
        DRV_MIIM_RESULT res;
        if (lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_1 - 1] == 0)
        {
            lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_1 - 1] = DRV_MIIM_Read(hClientObj->miimHandle, PHY_REG_BMSTAT, hClientObj->smiPhyAddress + DRV_ETHPHY_INF_IDX_PORT_1 - 1, DRV_MIIM_OPERATION_FLAG_NONE, &res);
        }
        if (lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_2 - 1] == 0)
        {
            lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_2 - 1] = DRV_MIIM_Read(hClientObj->miimHandle, PHY_REG_BMSTAT, hClientObj->smiPhyAddress + DRV_ETHPHY_INF_IDX_PORT_2 - 1, DRV_MIIM_OPERATION_FLAG_NONE, &res);
        }
        __BMSTATbits_t b1, b2;
        b1.w = (lan9303OperationResults[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_1 - 1]);
        b2.w = (lan9303OperationResults[LAND9303_LINK_STATUS_INDEX + DRV_ETHPHY_INF_IDX_PORT_2 - 1]);
        if (b1.LINK_STAT)
        {
            if (b1.AN_COMPLETE == 0)
            {
                return DRV_ETHPHY_RES_PENDING;
            }
        }
        if (b2.LINK_STAT)
        {
            if (b2.AN_COMPLETE == 0)
            {
                return DRV_ETHPHY_RES_PENDING;
            }
        }
        return DRV_ETHPHY_RES_OK;
    }
    DRV_MIIM_RESULT res;
    if (lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + portIndex - 1] == 0)
    {
        lan9303OperationsHandles[LAND9303_LINK_STATUS_INDEX + portIndex - 1] = DRV_MIIM_Read(hClientObj->miimHandle, PHY_REG_BMSTAT, hClientObj->smiPhyAddress + portIndex - 1, DRV_MIIM_OPERATION_FLAG_NONE, &res);
    }
    __BMSTATbits_t b1;
    b1.w = lan9303OperationResults[LAND9303_LINK_STATUS_INDEX + portIndex - 1];
    if (b1.LINK_STAT)
    {
        if (b1.AN_COMPLETE == 0)
        {
            return DRV_ETHPHY_RES_PENDING;
        }
        return DRV_ETHPHY_RES_OK;
    }
    return DRV_ETHPHY_RES_PENDING;
}

#1

0 Replies Related Threads

    Jump to:
    © 2019 APG vNext Commercial Version 4.5