全部博文(685)
分类: 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);