e100_phy.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,130 行 · 第 1/3 页
C
1,130 行
case 2: e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, bdp->phy_addr, 0x3000); bdp->PhyState = 0; break; } e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, BMCR_ANENABLE | BMCR_ANRESTART); bdp->PhyDelay = 3; }}/* * Procedure: e100_fix_polarity * * Description: * Fix for 82555 auto-polarity toggle problem. With a short cable * connecting an 82555 with an 840A link partner, if the medium is noisy, * the 82555 sometime thinks that the polarity might be wrong and so * toggles polarity. This happens repeatedly and results in a high bit * error rate. * NOTE: This happens only at 10 Mbps * * Arguments: * bdp - Ptr to this card's e100_bdconfig structure * * Returns: * NOTHING */static void __devinite100_fix_polarity(struct e100_private *bdp){ u16 status; u16 errors; u16 misc_reg; int speed; if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) && (bdp->PhyId != PHY_82562EM)) return; /* If the user wants auto-polarity disabled, do only that and nothing * * else. * e100_autopolarity == 0 means disable --- we do just the * disabling * e100_autopolarity == 1 means enable --- we do nothing at * all * e100_autopolarity >= 2 means we do the workaround code. */ /* Change for 82558 enhancement */ switch (E100_AUTOPOLARITY) { case 0: e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, &misc_reg); e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, (u16) (misc_reg | DISABLE_AUTO_POLARITY)); break; case 1: e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, &misc_reg); e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, (u16) (misc_reg & ~DISABLE_AUTO_POLARITY)); break; case 2: /* we do this only if link is up */ if (!netif_carrier_ok(bdp->device)) { break; } e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status); speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10; /* we need to do this only if speed is 10 */ if (speed != 10) { break; } /* see if we have any end of frame errors */ e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, bdp->phy_addr, &errors); /* if non-zero, wait for 100 ms before reading again */ if (errors) { udelay(200); e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, bdp->phy_addr, &errors); /* if non-zero again, we disable polarity */ if (errors) { e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, &misc_reg); e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, (u16) (misc_reg | DISABLE_AUTO_POLARITY)); } } if (!errors) { /* it is safe to read the polarity now */ e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status); /* if polarity is normal, disable polarity */ if (!(status & PHY_82555_POLARITY_BIT)) { e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, &misc_reg); e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, (u16) (misc_reg | DISABLE_AUTO_POLARITY)); } } break; default: break; }}/* * Procedure: e100_find_speed_duplex * * Description: This routine will figure out what line speed and duplex mode * the PHY is currently using. * * Arguments: * bdp - Ptr to this card's e100_bdconfig structure * * Returns: * NOTHING */static voide100_find_speed_duplex(struct e100_private *bdp){ unsigned int PhyId; u16 stat_reg, misc_reg; u16 ad_reg, lp_ad_reg; PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK; /* First we should check to see if we have link */ /* If we don't have a link no reason to print a speed and duplex */ if (!e100_update_link_state(bdp)) { return; } if (bdp->flags & DF_SPEED_FORCED) { return; } /* On the 82559 and later controllers, speed/duplex is part of the * * SCB. So, we save an mdi_read and get these from the SCB. * */ if (bdp->rev_id >= D101MA_REV_ID) { /* Read speed */ if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1) bdp->cur_line_speed = 100; else bdp->cur_line_speed = 10; /* Read duplex */ if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2) bdp->cur_dplx_mode = FULL_DUPLEX; else bdp->cur_dplx_mode = HALF_DUPLEX; return; } /* If this is a Phy 100, then read bits 1 and 0 of extended register 0, * to get the current speed and duplex settings. */ if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_82555_TX)) { /* Read Phy 100 extended register 0 */ e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg); /* Get current speed setting */ if (misc_reg & PHY_100_ER0_SPEED_INDIC) bdp->cur_line_speed = 100; else bdp->cur_line_speed = 10; /* Get current duplex setting -- FDX enabled if bit is set */ if (misc_reg & PHY_100_ER0_FDX_INDIC) bdp->cur_dplx_mode = FULL_DUPLEX; else bdp->cur_dplx_mode = HALF_DUPLEX; return; } /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg); /* See if Auto-Negotiation was complete (bit 5, reg 1) */ e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); /* If a True NWAY connection was made, then we can detect speed/dplx * by ANDing our adapter's advertised abilities with our link partner's * advertised ablilities, and then assuming that the highest common * denominator was chosed by NWAY. */ if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) { /* Read our advertisement register */ e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); /* Read our link partner's advertisement register */ e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); /* AND the two advertisement registers together, and get rid * of any extraneous bits. */ ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY); /* Get speed setting */ if (ad_reg & (ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_100BASE4)) bdp->cur_line_speed = 100; else bdp->cur_line_speed = 10; /* Get duplex setting -- use priority resolution algorithm */ if (ad_reg & ADVERTISE_100BASE4) { bdp->cur_dplx_mode = HALF_DUPLEX; } else if (ad_reg & ADVERTISE_100FULL) { bdp->cur_dplx_mode = FULL_DUPLEX; } else if (ad_reg & ADVERTISE_100HALF) { bdp->cur_dplx_mode = HALF_DUPLEX; } else if (ad_reg & ADVERTISE_10FULL) { bdp->cur_dplx_mode = FULL_DUPLEX; } else { bdp->cur_dplx_mode = HALF_DUPLEX; } return; } /* If we are connected to a dumb (non-NWAY) repeater or hub, and the * line speed was determined automatically by parallel detection, then * we have no way of knowing exactly what speed the PHY is set to * unless that PHY has a propietary register which indicates speed in * this situation. The NSC TX PHY does have such a register. Also, * since NWAY didn't establish the connection, the duplex setting * should HALF duplex. */ bdp->cur_dplx_mode = HALF_DUPLEX; if (PhyId == PHY_NSC_TX) { /* Read register 25 to get the SPEED_10 bit */ e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg); /* If bit 6 was set then we're at 10Mbps */ if (misc_reg & NSC_TX_SPD_INDC_SPEED) bdp->cur_line_speed = 10; else bdp->cur_line_speed = 100; } else { /* If we don't know the line speed, default to 10Mbps */ bdp->cur_line_speed = 10; }}/* * Procedure: e100_force_speed_duplex * * Description: This routine forces line speed and duplex mode of the * adapter based on the values the user has set in e100.c. * * Arguments: bdp - Pointer to the e100_private structure for the board * * Returns: void * */static voide100_force_speed_duplex(struct e100_private *bdp){ u16 control; unsigned long expires; bdp->flags |= DF_SPEED_FORCED; spin_lock_bh(&(bdp->mdi_access_lock)); e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); control &= ~BMCR_ANENABLE; /* Check e100.c values */ switch (bdp->params.e100_speed_duplex) { case E100_SPEED_10_HALF: control &= ~BMCR_SPEED100; control &= ~BMCR_FULLDPLX; bdp->cur_line_speed = 10; bdp->cur_dplx_mode = HALF_DUPLEX; break; case E100_SPEED_10_FULL: control &= ~BMCR_SPEED100; control |= BMCR_FULLDPLX; bdp->cur_line_speed = 10; bdp->cur_dplx_mode = FULL_DUPLEX; break; case E100_SPEED_100_HALF: control |= BMCR_SPEED100; control &= ~BMCR_FULLDPLX; bdp->cur_line_speed = 100; bdp->cur_dplx_mode = HALF_DUPLEX; break; case E100_SPEED_100_FULL: control |= BMCR_SPEED100; control |= BMCR_FULLDPLX; bdp->cur_line_speed = 100; bdp->cur_dplx_mode = FULL_DUPLEX; break; } e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); /* loop must run at least once */ expires = jiffies + 2 * HZ; do { if (e100_update_link_state(bdp) || time_after(jiffies, expires)) { break; } else { spin_unlock_bh(&(bdp->mdi_access_lock)); yield(); spin_lock_bh(&(bdp->mdi_access_lock)); } } while (true); spin_unlock_bh(&(bdp->mdi_access_lock));}/* * Procedure: e100_set_fc * * Description: Checks the link's capability for flow control. * * Arguments: bdp - Pointer to the e100_private structure for the board * * Returns: void * */static voide100_set_fc(struct e100_private *bdp){ u16 ad_reg; u16 lp_ad_reg; u16 exp_reg; /* no flow control for 82557, forced links or half duplex */ if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) || (bdp->cur_dplx_mode == HALF_DUPLEX) || !(bdp->flags & IS_BACHELOR)) { bdp->flags &= ~DF_LINK_FC_CAP; return; } /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg); if (exp_reg & EXPANSION_NWAY) { /* Read our advertisement register */ e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); /* Read our link partner's advertisement register */ e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); ad_reg &= lp_ad_reg; /* AND the 2 ad registers */ if (ad_reg & NWAY_AD_FC_SUPPORTED) bdp->flags |= DF_LINK_FC_CAP;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?