📄 e100_phy.c
字号:
* */unsigned chare100_phy_check(struct e100_private *bdp){ unsigned char old_link; unsigned char changed = false; old_link = netif_carrier_ok(bdp->device) ? 1 : 0; e100_find_speed_duplex(bdp); if (!old_link && netif_carrier_ok(bdp->device)) { e100_set_fc(bdp); changed = true; } if (old_link && !netif_carrier_ok(bdp->device)) { /* reset the zero lock state */ bdp->zlock_state = ZLOCK_INITIAL; // set auto lock for phy auto-negotiation on link up if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX) e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, bdp->phy_addr, 0); changed = true; } e100_phy_fix_squelch(bdp); e100_handle_zlock(bdp); return changed;}/* * Procedure: e100_auto_neg * * Description: This routine will start autonegotiation and wait * for it to complete * * Arguments: * bdp - pointer to this card's e100_bdconfig structure * force_restart - defines if autoneg should be restarted even if it * has been completed before * Returns: * NOTHING */static voide100_auto_neg(struct e100_private *bdp, unsigned char force_restart){ u16 stat_reg; unsigned long expires; bdp->flags &= ~DF_SPEED_FORCED; e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); /* if we are capable of performing autoneg then we restart if needed */ if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) { if ((!force_restart) && (stat_reg & BMSR_ANEGCOMPLETE)) { goto exit; } e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, BMCR_ANENABLE | BMCR_ANRESTART); /* wait for autoneg to complete (up to 3 seconds) */ expires = jiffies + HZ * 3; do { /* now re-read the value. Sticky so read twice */ e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); if ((stat_reg & BMSR_ANEGCOMPLETE) || time_after(jiffies, expires) ) { goto exit; } else { yield(); } } while (true); }exit: e100_find_speed_duplex(bdp);}voide100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart){ if (bdp->params.e100_speed_duplex == E100_AUTONEG) { if (bdp->rev_id >= D102_REV_ID) /* Enable MDI/MDI-X auto switching */ e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, MDI_MDIX_AUTO_SWITCH_ENABLE); e100_auto_neg(bdp, force_restart); } else { if (bdp->rev_id >= D102_REV_ID) /* Disable MDI/MDI-X auto switching */ e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, MDI_MDIX_RESET_ALL_MASK); e100_force_speed_duplex(bdp); } e100_set_fc(bdp);}voide100_phy_autoneg(struct e100_private *bdp){ u16 ctrl_reg; ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET; e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); udelay(100);}voide100_phy_set_loopback(struct e100_private *bdp){ u16 ctrl_reg; ctrl_reg = BMCR_LOOPBACK; e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); udelay(100);} voide100_phy_reset(struct e100_private *bdp){ u16 ctrl_reg; ctrl_reg = BMCR_RESET; e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); /* ieee 802.3 : The reset process shall be completed */ /* within 0.5 seconds from the settting of PHY reset bit. */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 2);}unsigned chare100_phy_init(struct e100_private *bdp){ e100_phy_reset(bdp); e100_phy_address_detect(bdp); e100_phy_isolate(bdp); e100_phy_id_detect(bdp); if (!e100_phy_specific_setup(bdp)) return false; bdp->PhyState = 0; bdp->PhyDelay = 0; bdp->zlock_state = ZLOCK_INITIAL; e100_phy_set_speed_duplex(bdp, false); e100_fix_polarity(bdp); return true;}/* * Procedure: e100_get_link_state * * Description: This routine checks the link status of the adapter * * Arguments: bdp - Pointer to the e100_private structure for the board * * * Returns: true - If a link is found * false - If there is no link * */unsigned chare100_get_link_state(struct e100_private *bdp){ unsigned char link = false; u16 status; /* Check link status */ /* If the controller is a 82559 or later one, link status is available * from the CSR. This avoids the mdi_read. */ if (bdp->rev_id >= D101MA_REV_ID) { if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) { link = true; } else { link = false; } } else { /* Read the status register twice because of sticky bits */ e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); if (status & BMSR_LSTATUS) { link = true; } else { link = false; } } return link;}/* * Procedure: e100_update_link_state * * Description: This routine updates the link status of the adapter, * also considering netif_running * * Arguments: bdp - Pointer to the e100_private structure for the board * * * Returns: true - If a link is found * false - If there is no link * */unsigned chare100_update_link_state(struct e100_private *bdp){ unsigned char link; /* Logical AND PHY link & netif_running */ link = e100_get_link_state(bdp) && netif_running(bdp->device); if (link) { if (!netif_carrier_ok(bdp->device)) netif_carrier_on(bdp->device); } else { if (netif_carrier_ok(bdp->device)) netif_carrier_off(bdp->device); } return link;}/**************************************************************************\ ** ** PROC NAME: e100_handle_zlock ** This function manages a state machine that controls ** the driver's zero locking algorithm. ** This function is called by e100_watchdog() every ~2 second. ** States: ** The current link handling state is stored in ** bdp->zlock_state, and is one of: ** ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING ** Detailed description of the states and the transitions ** between states is found below. ** Note that any time the link is down / there is a reset ** state will be changed outside this function to ZLOCK_INITIAL ** Algorithm: ** 1. If link is up & 100 Mbps continue else stay in #1: ** 2. Set 'auto lock' ** 3. Read & Store 100 times 'Zero' locked in 1 sec interval ** 4. If max zero read >= 0xB continue else goto 1 ** 5. Set most popular 'Zero' read in #3 ** 6. Sleep 5 minutes ** 7. Read number of errors, if it is > 300 goto 2 else goto 6 ** Data Structures (in DRIVER_DATA): ** zlock_state - current state of the algorithm ** zlock_read_cnt - counts number of reads (up to 100) ** zlock_read_data[i] - counts number of times 'Zero' read was i, 0 <= i <= 15 ** zlock_sleep_cnt - keeps track of "sleep" time (up to 300 secs = 5 minutes) ** ** Parameters: DRIVER_DATA *bdp ** ** bdp - Pointer to HSM's adapter data space ** ** Return Value: NONE ** ** See Also: e100_watchdog() ** \**************************************************************************/voide100_handle_zlock(struct e100_private *bdp){ u16 pos; u16 eq_reg; u16 err_cnt; u8 mpz; /* Most Popular Zero */ switch (bdp->zlock_state) { case ZLOCK_INITIAL: if (((u8) bdp->rev_id <= D102_REV_ID) || !(bdp->cur_line_speed == 100) || !netif_carrier_ok(bdp->device)) { break; } /* initialize hw and sw and start reading */ e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, bdp->phy_addr, 0); /* reset read counters: */ bdp->zlock_read_cnt = 0; for (pos = 0; pos < 16; pos++) bdp->zlock_read_data[pos] = 0; /* start reading in the next call back: */ bdp->zlock_state = ZLOCK_READING; /* FALL THROUGH !! */ case ZLOCK_READING: /* state: reading (100 times) zero locked in 1 sec interval * prev states: ZLOCK_INITIAL * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */ e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR, bdp->phy_addr, &eq_reg); pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4; bdp->zlock_read_data[pos]++; bdp->zlock_read_cnt++; if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) { /* check if we read a 'Zero' value of 0xB or greater */ if ((bdp->zlock_read_data[0xB]) || (bdp->zlock_read_data[0xC]) || (bdp->zlock_read_data[0xD]) || (bdp->zlock_read_data[0xE]) || (bdp->zlock_read_data[0xF])) { /* we've read 'Zero' value of 0xB or greater, * find most popular 'Zero' value and lock it */ mpz = 0; /* this loop finds the most popular 'Zero': */ for (pos = 1; pos < 16; pos++) { if (bdp->zlock_read_data[pos] > bdp->zlock_read_data[mpz]) mpz = pos; } /* now lock the most popular 'Zero': */ eq_reg = (ZLOCK_SET_ZERO | mpz); e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, bdp->phy_addr, eq_reg); /* sleep for 5 minutes: */ bdp->zlock_sleep_cnt = jiffies; bdp->zlock_state = ZLOCK_SLEEPING; /* we will be reading the # of errors after 5 * minutes, so we need to reset the error * counters - these registers are self clearing * on read, so read them */ e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, bdp->phy_addr, &err_cnt); } else { /* we did not read a 'Zero' value of 0xB or * above. go back to the start */ bdp->zlock_state = ZLOCK_INITIAL; } } break; case ZLOCK_SLEEPING: /* state: sleeping for 5 minutes * prev states: ZLOCK_READING * next states: ZLOCK_READING, ZLOCK_SLEEPING */ /* if 5 minutes have passed: */ if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) { /* read and sum up the number of errors: */ e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, bdp->phy_addr, &err_cnt); /* if we've more than 300 errors (this number was * calculated according to the spec max allowed errors * (80 errors per 1 million frames) for 5 minutes in * 100 Mbps (or the user specified max BER number) */ if (err_cnt > bdp->params.ber) { /* start again in the next callback: */ bdp->zlock_state = ZLOCK_INITIAL; } else { /* we don't have more errors than allowed, * sleep for 5 minutes */ bdp->zlock_sleep_cnt = jiffies; } } break; default: break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -