/* * 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 char e100_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; }
void e100_force_speed_duplex_to_phy(struct e100_private *bdp) { u16 control; e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); control &= ~BMCR_ANENABLE; control &= ~BMCR_LOOPBACK; switch (bdp->params.e100_speed_duplex) { case E100_SPEED_10_HALF: control &= ~BMCR_SPEED100; control &= ~BMCR_FULLDPLX; break; case E100_SPEED_10_FULL: control &= ~BMCR_SPEED100; control |= BMCR_FULLDPLX; break; case E100_SPEED_100_HALF: control |= BMCR_SPEED100; control &= ~BMCR_FULLDPLX; break; case E100_SPEED_100_FULL: control |= BMCR_SPEED100; control |= BMCR_FULLDPLX; break; } /* Send speed/duplex command to PHY layer. */ e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); }
static unsigned char e100_phy_valid(struct e100_private *bdp, unsigned int phy_address) { u16 ctrl_reg, stat_reg; /* Read the MDI control register */ e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg); /* Read the status register twice, bacause of sticky bits */ e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0))) return false; return true; }
/* * 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 * */ void e100_force_speed_duplex(struct e100_private *bdp) { u16 control; unsigned long expires; bdp->flags |= DF_SPEED_FORCED; e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); control &= ~BMCR_ANENABLE; control &= ~BMCR_LOOPBACK; 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 { yield(); } } while (true); }
/* * 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 void e100_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; else /* If link partner is capable of autoneg, but */ /* not capable of flow control, Received PAUSE */ /* frames are still honored, i.e., */ /* transmitted frames would be paused */ /* by incoming PAUSE frames */ bdp->flags |= DF_LINK_FC_TX_ONLY; } else { bdp->flags &= ~DF_LINK_FC_CAP; } }
/* * 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 void e100_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); }
static void e100_phy_id_detect(struct e100_private *bdp) { u16 low_id_reg, high_id_reg; if (bdp->phy_addr == PHY_ADDRESS_503) { bdp->PhyId = PHY_503; return; } if (!(bdp->flags & IS_ICH)) { if (bdp->rev_id >= D102_REV_ID) { bdp->PhyId = PHY_82562ET; return; } } /* Read phy id from the MII register */ e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg); e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg); bdp->PhyId = ((unsigned int) low_id_reg | ((unsigned int) high_id_reg << 16)); }
static void e100_phy_isolate(struct e100_private *bdp) { unsigned int phy_address; u16 ctrl_reg; /* Go over all phy addresses. Deisolate the selected one, and isolate * all the rest */ for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) { if (phy_address != bdp->phy_addr) { e100_mdi_write(bdp, MII_BMCR, phy_address, BMCR_ISOLATE); } else { e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg); ctrl_reg &= ~BMCR_ISOLATE; e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); } udelay(100); } }
/* * 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 void e100_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)) { bdp->cur_line_speed = 0; bdp->cur_dplx_mode = 0; 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_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 e100_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; } }
static unsigned char e100_phy_specific_setup(struct e100_private *bdp) { u16 misc_reg; if (bdp->phy_addr == PHY_ADDRESS_503) { switch (bdp->params.e100_speed_duplex) { case E100_AUTONEG: /* The adapter can't autoneg. so set to 10/HALF */ printk(KERN_INFO "e100: 503 serial component detected which " "cannot autonegotiate\n"); printk(KERN_INFO "e100: speed/duplex forced to " "10Mbps / Half duplex\n"); bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; break; case E100_SPEED_100_HALF: case E100_SPEED_100_FULL: printk(KERN_ERR "e100: 503 serial component detected " "which does not support 100Mbps\n"); printk(KERN_ERR "e100: Change the forced speed/duplex " "to a supported setting\n"); return false; } return true; } if (IS_NC3133(bdp)) { u16 int_reg; /* enable 100BASE fiber interface */ e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr, MDI_NC3133_100FX_ENABLE); if ((bdp->params.e100_speed_duplex != E100_AUTONEG) && (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) { /* just inform user about 100 full */ printk(KERN_ERR "e100: NC3133 NIC can only run " "at 100Mbps full duplex\n"); } bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; /* enable interrupts */ e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG, bdp->phy_addr, &int_reg); int_reg |= MDI_NC3133_INT_ENABLE; e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG, bdp->phy_addr, int_reg); } /* Handle the National TX */ if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) { e100_mdi_read(bdp, NSC_CONG_CONTROL_REG, bdp->phy_addr, &misc_reg); misc_reg |= NSC_TX_CONG_TXREADY; /* disable the congestion control bit in the National Phy */ misc_reg &= ~NSC_TX_CONG_ENABLE; e100_mdi_write(bdp, NSC_CONG_CONTROL_REG, bdp->phy_addr, misc_reg); } return true; }
/**************************************************************************\ ** ** 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() ** \**************************************************************************/ void e100_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; } }
static int e100_cable_diag(struct e100_private *bdp) { int saved_open_circut = 0xffff; int saved_short_circut = 0xffff; int saved_distance = 0xffff; int saved_same = 0; int cable_status = E100_CABLE_UNKNOWN; int i; /* If we have link, */ if (e100_get_link_state(bdp)) return E100_CABLE_OK; if (bdp->rev_id < D102_REV_ID) return E100_CABLE_UNKNOWN; /* Disable MDI/MDI-X auto switching */ e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, MDI_MDIX_RESET_ALL_MASK); /* Set to 100 Full as required by cable test */ e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, BMCR_SPEED100 | BMCR_FULLDPLX); /* Test up to 100 times */ for (i = 0; i < 100; i++) { u16 ctrl_reg; int distance, open_circut, short_circut, near_end; /* Enable and execute cable test */ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); /* Wait for cable test finished */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/100 + 1); /* Read results */ e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); distance = ctrl_reg & HWI_TEST_DISTANCE; open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; if ((distance == saved_distance) && (open_circut == saved_open_circut) && (short_circut == saved_short_circut)) saved_same++; else { saved_same = 0; saved_distance = distance; saved_open_circut = open_circut; saved_short_circut = short_circut; } /* If results are the same 3 times */ if (saved_same == 3) { near_end = ((distance * HWI_REGISTER_GRANULARITY) < HWI_NEAR_END_BOUNDARY); if (open_circut) cable_status = (near_end) ? E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; if (short_circut) cable_status = (near_end) ? E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; break; } } /* Reset cable test */ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); return cable_status; }