Ejemplo n.º 1
0
/* 
 * 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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
/* 
 * 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);
}
Ejemplo n.º 5
0
/* 
 * 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;
	}
}
Ejemplo n.º 6
0
/* 
 * 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);
}
Ejemplo n.º 7
0
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));
}
Ejemplo n.º 8
0
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);
	}
}
Ejemplo n.º 9
0
/* 
 * 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;
	}
}
Ejemplo n.º 10
0
/* 
 * 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;
	}
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
/**************************************************************************\
 **
 ** 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;
	}
}
Ejemplo n.º 13
0
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;
}