Chinaunix首页 | 论坛 | 博客
  • 博客访问: 434489
  • 博文数量: 99
  • 博客积分: 65
  • 博客等级: 民兵
  • 技术积分: 1012
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-20 16:30
个人简介

linux kernel 工程师

文章分类

全部博文(99)

文章存档

2018年(5)

2017年(12)

2016年(27)

2015年(10)

2014年(43)

2012年(2)

我的朋友

分类: LINUX

2017-07-26 15:55:33

mii-tool是net-tools package里面的一个小工具。
在Denverton SOC 上,针对光口使用mii-tool工具时打印出
SIOCGMIIREG on eth0 failed: Invalid argument


经过定位发现,drivers/net/mdio.c中
mdio_mii_ioctl函数对于寄存器的地址进行了限制, 导致读取0x4-0xa寄存器时,返回-EINVAL
mii-tool连续读取0---0xa这些寄存器, 读0x4->0xa 这些寄存器时都返回 -EINVAL, 导致mii-tool打印Invalid argument



/**
 * mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs
 * @mdio: MDIO interface
 * @mii_data: MII ioctl data structure
 * @cmd: MII ioctl command
 *
 * Returns 0 on success, negative on error.
 */
int mdio_mii_ioctl(const struct mdio_if_info *mdio,
           struct mii_ioctl_data *mii_data, int cmd)
{
    int prtad, devad;
    u16 addr = mii_data->reg_num;

    /* Validate/convert cmd to one of SIOC{G,S}MIIREG */
    switch (cmd) {
    case SIOCGMIIPHY:
/* prtad:0x1f */
        if (mdio->prtad == MDIO_PRTAD_NONE)
            return -EOPNOTSUPP;
        mii_data->phy_id = mdio->prtad;
        cmd = SIOCGMIIREG;
        break;
    case SIOCGMIIREG:
    case SIOCSMIIREG:
        break;
    default:
        return -EOPNOTSUPP;
    }

/* 在ixgbe_main.c中,ixgbe_probe函数中
hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
*/

    /* Validate/convert phy_id */
    if ((mdio->mode_support & MDIO_SUPPORTS_C45) &&
        mdio_phy_id_is_c45(mii_data->phy_id)) {
        prtad = mdio_phy_id_prtad(mii_data->phy_id);
        devad = mdio_phy_id_devad(mii_data->phy_id);
    } else if ((mdio->mode_support & MDIO_SUPPORTS_C22) &&
           mii_data->phy_id < 0x20) {
        prtad = mii_data->phy_id;
        devad = MDIO_DEVAD_NONE;
        addr &= 0x1f;
    } else if ((mdio->mode_support & MDIO_EMULATE_C22) &&
           mdio->prtad != MDIO_PRTAD_NONE &&
           mii_data->phy_id == mdio->prtad) {

/* Denverton 走这个分支,并mmds=0, 所以只有寄存器0,1,2,3可以读出来 */
/*  mii-tool连续读取0---0xa这些寄存器, 读0x4->0xa 这些寄存器时都返回 -EINVAL, 导致mii-tool打印Invalid argument */

        /* Remap commonly-used MII registers. */
        prtad = mdio->prtad;
        switch (addr) {
        case MII_BMCR:
        case MII_BMSR:
        case MII_PHYSID1:
        case MII_PHYSID2:
        /* mmds=0, devad=0 */
            devad = __ffs(mdio->mmds);
            break;
        case MII_ADVERTISE:
        case MII_LPA:
            if (!(mdio->mmds & MDIO_DEVS_AN))
                return -EINVAL;
            devad = MDIO_MMD_AN;
            if (addr == MII_ADVERTISE)
                addr = MDIO_AN_ADVERTISE;
            else
                addr = MDIO_AN_LPA;
            break;
        default:
            return -EINVAL;
        }
    } else {
        return -EINVAL;
    }

    if (cmd == SIOCGMIIREG) {
        int rc = mdio->mdio_read(mdio->dev, prtad, devad, addr);
        if (rc < 0)
            return rc;
        mii_data->val_out = rc;
        return 0;
    } else {
        return mdio->mdio_write(mdio->dev, prtad, devad, addr,
                    mii_data->val_in);
    }
}

在ixgbe_main.c中,ixgbe_probe函数中对phy初始设置:

    /* PHY */
    hw->phy.ops = *ii->phy_ops;
    hw->phy.sfp_type = ixgbe_sfp_type_unknown;
    /* ixgbe_identify_phy_generic will set prtad and mmds properly */
    hw->phy.mdio.prtad = MDIO_PRTAD_NONE;
    hw->phy.mdio.mmds = 0;
    hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
    hw->phy.mdio.dev = netdev;
    hw->phy.mdio.mdio_read = ixgbe_mdio_read;
    hw->phy.mdio.mdio_write = ixgbe_mdio_write;

ixgbe_read_mng_if_sel_x550em函数里面,
hw->phy.mdio.prtad 会被重新设置
/**
 * ixgbe_read_mng_if_sel_x550em - Read NW_MNG_IF_SEL register
 * @hw: pointer to hardware structure
 *
 * Read NW_MNG_IF_SEL register and save field values.
 */
static void ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw)
{
    /* Save NW management interface connected on board. This is used
     * to determine internal PHY mode.
     */
/* hw->phy.nw_mng_if_sel = 0x186820fb */
    hw->phy.nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);

    /* If X552 (X550EM_a) and MDIO is connected to external PHY, then set
     * PHY address. This register field was has only been used for X552.
     */
    if (!hw->phy.nw_mng_if_sel) {
        if (hw->mac.type == ixgbe_mac_x550em_a) {
            struct ixgbe_adapter *adapter = hw->back;

            e_warn(drv, "nw_mng_if_sel not set\n");
        }
        return;
    }

    hw->phy.mdio.prtad = (hw->phy.nw_mng_if_sel &
                  IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
                 IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
}

阅读(1475) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~