Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3115084
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-09-28 17:19:52

/**
 * mii_check_gmii_support - check if the MII supports Gb interfacesnetdev_info
 * @mii: the MII interface
 */
int mii_check_gmii_support(struct mii_if_info *mii)
{
 int reg;

 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
 if (reg & BMSR_ESTATEN) {
  reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
  if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
   return 1;
 }

 return 0;
}

/**
 * mii_link_ok - is link status up/ok
 * @mii: the MII interface
 *
 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
 */
int mii_link_ok (struct mii_if_info *mii)
{
 /* first, a dummy read, needed to latch some MII phys */
 mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
 if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
  return 1;
 return 0;
}

/**
 * mii_nway_restart - restart NWay (autonegotiation) for this interface
 * @mii: the MII interface
 *
 * Returns 0 on success, negative on error.
 */
int mii_nway_restart (struct mii_if_info *mii)
{
 int bmcr;
 int r = -EINVAL;

 /* if autoneg is off, it's an error */
 bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);

 if (bmcr & BMCR_ANENABLE) {
  bmcr |= BMCR_ANRESTART;
  mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
  r = 0;
 }

 return r;
}

/**
 * mii_check_link - check MII link status
 * @mii: MII interface
 *
 * If the link status changed (previous != current), call
 * netif_carrier_on() if current link status is Up or call
 * netif_carrier_off() if current link status is Down.
 */
void mii_check_link (struct mii_if_info *mii)
{
 int cur_link = mii_link_ok(mii);
 int prev_link = netif_carrier_ok(mii->dev);

 if (cur_link && !prev_link)
  netif_carrier_on(mii->dev);
 else if (prev_link && !cur_link)
  netif_carrier_off(mii->dev);
}

/**
 * mii_check_media - check the MII interface for a duplex change
 * @mii: the MII interface
 * @ok_to_print: OK to print link up/down messages
 * @init_media: OK to save duplex mode in @mii
 *
 * Returns 1 if the duplex mode changed, 0 if not.
 * If the media type is forced, always returns 0.
 */
unsigned int mii_check_media (struct mii_if_info *mii,
         unsigned int ok_to_print,
         unsigned int init_media)
{
 unsigned int old_carrier, new_carrier;
 int advertise, lpa, media, duplex;
 int lpa2 = 0;

 /* if forced media, go no further */
 if (mii->force_media)
  return 0; /* duplex did not change */

 /* check current and old link status */
 old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
 new_carrier = (unsigned int) mii_link_ok(mii);

 /* if carrier state did not change, this is a "bounce",
  * just exit as everything is already set correctly
  */
 if ((!init_media) && (old_carrier == new_carrier))
  return 0; /* duplex did not change */

 /* no carrier, nothing much to do */
 if (!new_carrier) {
  netif_carrier_off(mii->dev);
  if (ok_to_print)
   netdev_info(mii->dev, "link down\n");
  return 0; /* duplex did not change */
 }

 /*
  * we have carrier, see who's on the other end
  */
 netif_carrier_on(mii->dev);

 /* get MII advertise and LPA values */
 if ((!init_media) && (mii->advertising))
  advertise = mii->advertising;
 else {
  advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
  mii->advertising = advertise;
 }
 lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
 if (mii->supports_gmii)
  lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);

 /* figure out media and duplex from advertise and LPA values */
 media = mii_nway_result(lpa & advertise);
 duplex = (media & ADVERTISE_FULL) ? 1 : 0;
 if (lpa2 & LPA_1000FULL)
  duplex = 1;

 if (ok_to_print)
  netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
       lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
       media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
       100 : 10,
       duplex ? "full" : "half",
       lpa);

 if ((init_media) || (mii->full_duplex != duplex)) {
  mii->full_duplex = duplex;
  return 1; /* duplex changed */
 }

 return 0; /* duplex did not change */
}

/**
 * generic_mii_ioctl - main MII ioctl interface
 * @mii_if: the MII interface
 * @mii_data: MII ioctl data structure
 * @cmd: MII ioctl command
 * @duplex_chg_out: pointer to @duplex_changed status if there was no
 * ioctl error
 *
 * Returns 0 on success, negative on error.
 */
int generic_mii_ioctl(struct mii_if_info *mii_if,
        struct mii_ioctl_data *mii_data, int cmd,
        unsigned int *duplex_chg_out)
{
 int rc = 0;
 unsigned int duplex_changed = 0;

 if (duplex_chg_out)
  *duplex_chg_out = 0;

 mii_data->phy_id &= mii_if->phy_id_mask;
 mii_data->reg_num &= mii_if->reg_num_mask;

 switch(cmd) {
 case SIOCGMIIPHY:
  mii_data->phy_id = mii_if->phy_id;
  /* fall through */

 case SIOCGMIIREG:
  mii_data->val_out =
   mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
       mii_data->reg_num);
  break;

 case SIOCSMIIREG: {
  u16 val = mii_data->val_in;

  if (mii_data->phy_id == mii_if->phy_id) {
   switch(mii_data->reg_num) {
   case MII_BMCR: {
    unsigned int new_duplex = 0;
    if (val & (BMCR_RESET|BMCR_ANENABLE))
     mii_if->force_media = 0;
    else
     mii_if->force_media = 1;
    if (mii_if->force_media &&
        (val & BMCR_FULLDPLX))
     new_duplex = 1;
    if (mii_if->full_duplex != new_duplex) {
     duplex_changed = 1;
     mii_if->full_duplex = new_duplex;
    }
    break;
   }
   case MII_ADVERTISE:
    mii_if->advertising = val;
    break;
   default:
    /* do nothing */
    break;
   }
  }

  mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
       mii_data->reg_num, val);
  break;
 }

 default:
  rc = -EOPNOTSUPP;
  break;
 }

 if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
  *duplex_chg_out = 1;

 return rc;
}

MODULE_AUTHOR ("Jeff Garzik <>");
MODULE_DESCRIPTION ("MII hardware support library");
MODULE_LICENSE("GPL");

EXPORT_SYMBOL(mii_link_ok);
EXPORT_SYMBOL(mii_nway_restart);
EXPORT_SYMBOL(mii_ethtool_gset);
EXPORT_SYMBOL(mii_ethtool_sset);
EXPORT_SYMBOL(mii_check_link);
EXPORT_SYMBOL(mii_check_media);
EXPORT_SYMBOL(mii_check_gmii_support);
EXPORT_SYMBOL(generic_mii_ioctl);

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