Exemple #1
0
/*
 * Bare-minimum autoneg protocol
 *
 * This code is only called when the link is up and we're receiving config
 * words, which implies that the link partner wants to autonegotiate
 * (otherwise, we wouldn't see configs and wouldn't reach this code).
 */
static void
bge_autoneg_serdes(bge_t *bgep)
{
	boolean_t ack;

	bgep->serdes_lpadv = bge_reg_get32(bgep, RX_1000BASEX_AUTONEG_REG);
	ack = BIS(bgep->serdes_lpadv, AUTONEG_CODE_ACKNOWLEDGE);

	if (!ack) {
		/*
		 * Phase 1: after SerDes reset, we send a few zero configs
		 * but then stop.  Here the partner is sending configs, but
		 * not ACKing ours; we assume that's 'cos we're not sending
		 * any.  So here we send ours, with ACK already set.
		 */
		bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG,
		    bgep->serdes_advert | AUTONEG_CODE_ACKNOWLEDGE);
		bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG,
		    ETHERNET_MODE_SEND_CFGS);
	} else {
		/*
		 * Phase 2: partner has ACKed our configs, so now we can
		 * stop sending; once our partner also stops sending, we
		 * can resolve the Tx/Rx configs.
		 */
		bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG,
		    ETHERNET_MODE_SEND_CFGS);
	}

	BGE_DEBUG(("bge_autoneg_serdes: Rx 0x%x %s Tx 0x%x",
	    bgep->serdes_lpadv,
	    ack ? "stop" : "send",
	    bgep->serdes_advert));
}
Exemple #2
0
/*
 * Here we have to determine which media we're using (copper or serdes).
 * Once that's done, we can initialise the physical layer appropriately.
 */
int
bge_phys_init(bge_t *bgep)
{
	BGE_TRACE(("bge_phys_init($%p)", (void *)bgep));

	mutex_enter(bgep->genlock);

	/*
	 * Probe for the (internal) PHY.  If it's not there, we'll assume
	 * that this is a 5703/4S, with a SerDes interface rather than
	 * a PHY. BCM5714S/BCM5715S are not supported.It are based on
	 * BCM800x PHY.
	 */
	bgep->phy_mii_addr = 1;
	if (DEVICE_5717_SERIES_CHIPSETS(bgep)) {
		int regval = bge_reg_get32(bgep, CPMU_STATUS_REG);
		if (regval & CPMU_STATUS_FUN_NUM)
			bgep->phy_mii_addr += 1;
		regval = bge_reg_get32(bgep, SGMII_STATUS_REG);
		if (regval & MEDIA_SELECTION_MODE)
			bgep->phy_mii_addr += 7;
	}

	if (bge_phy_probe(bgep)) {
		bgep->chipid.flags &= ~CHIP_FLAG_SERDES;
		bgep->physops = &copper_ops;
	} else {
		bgep->chipid.flags |= CHIP_FLAG_SERDES;
		bgep->physops = &serdes_ops;
	}

	if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS) {
		mutex_exit(bgep->genlock);
		return (EIO);
	}
	if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
		mutex_exit(bgep->genlock);
		return (EIO);
	}
	mutex_exit(bgep->genlock);
	return (0);
}
Exemple #3
0
/*
 * Reinitialise the SerDes interface.  Note that it normally powers
 * up in the disabled state, so we need to explicitly activate it.
 */
static int
bge_restart_serdes(bge_t *bgep, boolean_t powerdown)
{
	uint32_t macmode;

	BGE_TRACE(("bge_restart_serdes($%p, %d)", (void *)bgep, powerdown));

	ASSERT(mutex_owned(bgep->genlock));

	/*
	 * Ensure that the main Ethernet MAC mode register is programmed
	 * appropriately for the SerDes interface ...
	 */
	macmode = bge_reg_get32(bgep, ETHERNET_MAC_MODE_REG);
	if (DEVICE_5714_SERIES_CHIPSETS(bgep)) {
		macmode |= ETHERNET_MODE_LINK_POLARITY;
		macmode &= ~ETHERNET_MODE_PORTMODE_MASK;
		macmode |= ETHERNET_MODE_PORTMODE_GMII;
	} else {
		macmode &= ~ETHERNET_MODE_LINK_POLARITY;
		macmode &= ~ETHERNET_MODE_PORTMODE_MASK;
		macmode |= ETHERNET_MODE_PORTMODE_TBI;
	}
	bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, macmode);

	/*
	 * Ensure that loopback is OFF and comma detection is enabled.  Then
	 * disable the SerDes output (the first time through, it may/will
	 * already be disabled).  If we're shutting down, leave it disabled.
	 */
	bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TBI_LOOPBACK);
	bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_COMMA_DETECT);
	bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE);
	if (powerdown)
		return (DDI_SUCCESS);

	/*
	 * Otherwise, pause, (re-)enable the SerDes output, and send
	 * all-zero config words in order to force autoneg restart.
	 * Invalidate the saved "link partners received configs", as
	 * we're starting over ...
	 */
	drv_usecwait(10000);
	bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE);
	bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG, 0);
	bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS);
	drv_usecwait(10);
	bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS);
	bgep->serdes_lpadv = AUTONEG_CODE_FAULT_ANEG_ERR;
	bgep->serdes_status = ~0U;
	return (DDI_SUCCESS);
}
Exemple #4
0
/*
 * Basic low-level function to reset the PHY.
 * Doesn't incorporate any special-case workarounds.
 *
 * Returns TRUE on success, FALSE if the RESET bit doesn't clear
 */
static boolean_t
bge_phy_reset(bge_t *bgep)
{
	uint16_t control;
	uint_t count;

	BGE_TRACE(("bge_phy_reset($%p)", (void *)bgep));

	ASSERT(mutex_owned(bgep->genlock));

	if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
		drv_usecwait(40);
		/* put PHY into ready state */
		bge_reg_clr32(bgep, MISC_CONFIG_REG, MISC_CONFIG_EPHY_IDDQ);
		(void) bge_reg_get32(bgep, MISC_CONFIG_REG); /* flush */
		drv_usecwait(40);
	}

	/*
	 * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
	 */
	bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_RESET);
	for (count = 0; ++count < 1000; ) {
		drv_usecwait(5);
		control = bge_mii_get16(bgep, MII_CONTROL);
		if (BIC(control, MII_CONTROL_RESET))
			return (B_TRUE);
	}

	if (DEVICE_5906_SERIES_CHIPSETS(bgep))
		(void) bge_adj_volt_5906(bgep);

	BGE_DEBUG(("bge_phy_reset: FAILED, control now 0x%x", control));

	return (B_FALSE);
}
Exemple #5
0
static boolean_t
bge_check_copper(bge_t *bgep, boolean_t recheck)
{
	uint32_t emac_status;
	uint16_t mii_status;
	uint16_t aux;
	uint_t mode;
	boolean_t linkup;

	/*
	 * Step 10: read the status from the PHY (which is self-clearing
	 * on read!); also read & clear the main (Ethernet) MAC status
	 * (the relevant bits of this are write-one-to-clear).
	 */
	mii_status = bge_mii_get16(bgep, MII_STATUS);
	emac_status = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG);
	bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, emac_status);

	BGE_DEBUG(("bge_check_copper: link %d/%s, MII status 0x%x "
	    "(was 0x%x), Ethernet MAC status 0x%x",
	    bgep->link_state, UPORDOWN(bgep->param_link_up), mii_status,
	    bgep->phy_gen_status, emac_status));

	/*
	 * If the PHY status hasn't changed since last we looked, and
	 * we not forcing a recheck (i.e. the link state was already
	 * known), there's nothing to do.
	 */
	if (mii_status == bgep->phy_gen_status && !recheck)
		return (B_FALSE);

	do {
		/*
		 * Step 11: read AUX STATUS register to find speed/duplex
		 */
		aux = bge_mii_get16(bgep, MII_AUX_STATUS);
		BGE_CDB(bge_phydump, (bgep, mii_status, aux));

		/*
		 * We will only consider the link UP if all the readings
		 * are consistent and give meaningful results ...
		 */
		mode = aux & MII_AUX_STATUS_MODE_MASK;
		mode >>= MII_AUX_STATUS_MODE_SHIFT;
		if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
			linkup = BIS(aux, MII_AUX_STATUS_LINKUP);
			linkup &= BIS(mii_status, MII_STATUS_LINKUP);
		} else {
			linkup = bge_copper_link_speed[mode] > 0;
			linkup &= bge_copper_link_duplex[mode] !=
			    LINK_DUPLEX_UNKNOWN;
			linkup &= BIS(aux, MII_AUX_STATUS_LINKUP);
			linkup &= BIS(mii_status, MII_STATUS_LINKUP);
		}

		BGE_DEBUG(("bge_check_copper: MII status 0x%x aux 0x%x "
		    "=> mode %d (%s)",
		    mii_status, aux,
		    mode, UPORDOWN(linkup)));

		/*
		 * Record current register values, then reread status
		 * register & loop until it stabilises ...
		 */
		bgep->phy_aux_status = aux;
		bgep->phy_gen_status = mii_status;
		mii_status = bge_mii_get16(bgep, MII_STATUS);
	} while (mii_status != bgep->phy_gen_status);

	/*
	 * Assume very little ...
	 */
	bgep->param_lp_autoneg = B_FALSE;
	bgep->param_lp_1000fdx = B_FALSE;
	bgep->param_lp_1000hdx = B_FALSE;
	bgep->param_lp_100fdx = B_FALSE;
	bgep->param_lp_100hdx = B_FALSE;
	bgep->param_lp_10fdx = B_FALSE;
	bgep->param_lp_10hdx = B_FALSE;
	bgep->param_lp_pause = B_FALSE;
	bgep->param_lp_asym_pause = B_FALSE;
	bgep->param_link_autoneg = B_FALSE;
	bgep->param_link_tx_pause = B_FALSE;
	if (bgep->param_adv_autoneg)
		bgep->param_link_rx_pause = B_FALSE;
	else
		bgep->param_link_rx_pause = bgep->param_adv_pause;

	/*
	 * Discover all the link partner's abilities.
	 * These are scattered through various registers ...
	 */
	if (BIS(aux, MII_AUX_STATUS_LP_ANEG_ABLE)) {
		bgep->param_lp_autoneg = B_TRUE;
		bgep->param_link_autoneg = B_TRUE;
		bgep->param_link_tx_pause = BIS(aux, MII_AUX_STATUS_TX_PAUSE);
		bgep->param_link_rx_pause = BIS(aux, MII_AUX_STATUS_RX_PAUSE);

		aux = bge_mii_get16(bgep, MII_MSSTATUS);
		bgep->param_lp_1000fdx = BIS(aux, MII_MSSTATUS_LP1000T_FD);
		bgep->param_lp_1000hdx = BIS(aux, MII_MSSTATUS_LP1000T);

		aux = bge_mii_get16(bgep, MII_AN_LPABLE);
		bgep->param_lp_100fdx = BIS(aux, MII_ABILITY_100BASE_TX_FD);
		bgep->param_lp_100hdx = BIS(aux, MII_ABILITY_100BASE_TX);
		bgep->param_lp_10fdx = BIS(aux, MII_ABILITY_10BASE_T_FD);
		bgep->param_lp_10hdx = BIS(aux, MII_ABILITY_10BASE_T);
		bgep->param_lp_pause = BIS(aux, MII_ABILITY_PAUSE);
		bgep->param_lp_asym_pause = BIS(aux, MII_ABILITY_ASMPAUSE);
	}

	/*
	 * Step 12: update ndd-visible state parameters, BUT!
	 * we don't transfer the new state to <link_state> just yet;
	 * instead we mark the <link_state> as UNKNOWN, and our caller
	 * will resolve it once the status has stopped changing and
	 * been stable for several seconds.
	 */
	BGE_DEBUG(("bge_check_copper: link was %s speed %d duplex %d",
	    UPORDOWN(bgep->param_link_up),
	    bgep->param_link_speed,
	    bgep->param_link_duplex));

	if (!linkup)
		mode = MII_AUX_STATUS_MODE_NONE;
	bgep->param_link_up = linkup;
	bgep->link_state = LINK_STATE_UNKNOWN;
	if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
		if (bgep->phy_aux_status & MII_AUX_STATUS_NEG_ENABLED_5906) {
			bgep->param_link_speed =
			    bge_copper_link_speed_5906[mode];
			bgep->param_link_duplex =
			    bge_copper_link_duplex_5906[mode];
		} else {
			bgep->param_link_speed = (bgep->phy_aux_status &
			    MII_AUX_STATUS_SPEED_IND_5906) ?  100 : 10;
			bgep->param_link_duplex = (bgep->phy_aux_status &
			    MII_AUX_STATUS_DUPLEX_IND_5906) ? LINK_DUPLEX_FULL :
			    LINK_DUPLEX_HALF;
		}
	} else {
		bgep->param_link_speed = bge_copper_link_speed[mode];
		bgep->param_link_duplex = bge_copper_link_duplex[mode];
	}

	BGE_DEBUG(("bge_check_copper: link now %s speed %d duplex %d",
	    UPORDOWN(bgep->param_link_up),
	    bgep->param_link_speed,
	    bgep->param_link_duplex));

	return (B_TRUE);
}
Exemple #6
0
static boolean_t
bge_check_serdes(bge_t *bgep, boolean_t recheck)
{
	uint32_t emac_status;
	uint32_t tx_status;
	uint32_t lpadv;
	boolean_t linkup;
	boolean_t linkup_old = bgep->param_link_up;

	for (;;) {
		/*
		 * Step 10: BCM5714S, BCM5715S only
		 * Don't call function bge_autoneg_serdes() as
		 * RX_1000BASEX_AUTONEG_REG (0x0448) is not applicable
		 * to BCM5705, BCM5788, BCM5721, BCM5751, BCM5752,
		 * BCM5714, and BCM5715 devices.
		 */
		if (DEVICE_5714_SERIES_CHIPSETS(bgep)) {
			tx_status = bge_reg_get32(bgep,
			    TRANSMIT_MAC_STATUS_REG);
			linkup = BIS(tx_status, TRANSMIT_STATUS_LINK_UP);
			emac_status = bge_reg_get32(bgep,
			    ETHERNET_MAC_STATUS_REG);
			bgep->serdes_status = emac_status;
			if ((linkup && linkup_old) ||
			    (!linkup && !linkup_old)) {
				emac_status &= ~ETHERNET_STATUS_LINK_CHANGED;
				emac_status &= ~ETHERNET_STATUS_RECEIVING_CFG;
				break;
			}
			emac_status |= ETHERNET_STATUS_LINK_CHANGED;
			emac_status |= ETHERNET_STATUS_RECEIVING_CFG;
			if (linkup)
				linkup_old = B_TRUE;
			else
				linkup_old = B_FALSE;
			recheck = B_TRUE;
		} else {
			/*
			 * Step 10: others
			 * read & clear the main (Ethernet) MAC status
			 * (the relevant bits of this are write-one-to-clear).
			 */
			emac_status = bge_reg_get32(bgep,
			    ETHERNET_MAC_STATUS_REG);
			bge_reg_put32(bgep,
			    ETHERNET_MAC_STATUS_REG, emac_status);

			BGE_DEBUG(("bge_check_serdes: link %d/%s, "
			    "MAC status 0x%x (was 0x%x)",
			    bgep->link_state, UPORDOWN(bgep->param_link_up),
			    emac_status, bgep->serdes_status));

			/*
			 * We will only consider the link UP if all the readings
			 * are consistent and give meaningful results ...
			 */
			bgep->serdes_status = emac_status;
			linkup = BIS(emac_status,
			    ETHERNET_STATUS_SIGNAL_DETECT);
			linkup &= BIS(emac_status, ETHERNET_STATUS_PCS_SYNCHED);

			/*
			 * Now some fiddling with the interpretation:
			 *	if there's been an error at the PCS level, treat
			 *	it as a link change (the h/w doesn't do this)
			 *
			 *	if there's been a change, but it's only a PCS
			 *	sync change (not a config change), AND the link
			 *	already was & is still UP, then ignore the
			 *	change
			 */
			if (BIS(emac_status, ETHERNET_STATUS_PCS_ERROR))
				emac_status |= ETHERNET_STATUS_LINK_CHANGED;
			else if (BIC(emac_status, ETHERNET_STATUS_CFG_CHANGED))
				if (bgep->param_link_up && linkup)
					emac_status &=
					    ~ETHERNET_STATUS_LINK_CHANGED;

			BGE_DEBUG(("bge_check_serdes: status 0x%x => 0x%x %s",
			    bgep->serdes_status, emac_status,
			    UPORDOWN(linkup)));

			/*
			 * If we're receiving configs, run the autoneg protocol
			 */
			if (linkup && BIS(emac_status,
			    ETHERNET_STATUS_RECEIVING_CFG))
				bge_autoneg_serdes(bgep);

			/*
			 * If the SerDes status hasn't changed, we're done ...
			 */
			if (BIC(emac_status, ETHERNET_STATUS_LINK_CHANGED))
				break;

			/*
			 * Go round again until we no longer see a change ...
			 */
			recheck = B_TRUE;
		}
	}

	/*
	 * If we're not forcing a recheck (i.e. the link state was already
	 * known), and we didn't see the hardware flag a change, there's
	 * no more to do (and we tell the caller nothing happened).
	 */
	if (!recheck)
		return (B_FALSE);

	/*
	 * Don't resolve autoneg until we're no longer receiving configs
	 */
	if (linkup && BIS(emac_status, ETHERNET_STATUS_RECEIVING_CFG))
		return (B_FALSE);

	/*
	 * Assume very little ...
	 */
	bgep->param_lp_autoneg = B_FALSE;
	bgep->param_lp_1000fdx = B_FALSE;
	bgep->param_lp_1000hdx = B_FALSE;
	bgep->param_lp_100fdx = B_FALSE;
	bgep->param_lp_100hdx = B_FALSE;
	bgep->param_lp_10fdx = B_FALSE;
	bgep->param_lp_10hdx = B_FALSE;
	bgep->param_lp_pause = B_FALSE;
	bgep->param_lp_asym_pause = B_FALSE;
	bgep->param_link_autoneg = B_FALSE;
	bgep->param_link_tx_pause = B_FALSE;
	if (bgep->param_adv_autoneg)
		bgep->param_link_rx_pause = B_FALSE;
	else
		bgep->param_link_rx_pause = bgep->param_adv_pause;

	/*
	 * Discover all the link partner's abilities.
	 */
	lpadv = bgep->serdes_lpadv;
	if (lpadv != 0 && BIC(lpadv, AUTONEG_CODE_FAULT_MASK)) {
		/*
		 * No fault, so derive partner's capabilities
		 */
		bgep->param_lp_autoneg = B_TRUE;
		bgep->param_lp_1000fdx = BIS(lpadv, AUTONEG_CODE_FULL_DUPLEX);
		bgep->param_lp_1000hdx = BIS(lpadv, AUTONEG_CODE_HALF_DUPLEX);
		bgep->param_lp_pause = BIS(lpadv, AUTONEG_CODE_PAUSE);
		bgep->param_lp_asym_pause = BIS(lpadv, AUTONEG_CODE_ASYM_PAUSE);

		/*
		 * Pause direction resolution
		 */
		bgep->param_link_autoneg = B_TRUE;
		if (bgep->param_adv_pause &&
		    bgep->param_lp_pause) {
			bgep->param_link_tx_pause = B_TRUE;
			bgep->param_link_rx_pause = B_TRUE;
		}
		if (bgep->param_adv_asym_pause &&
		    bgep->param_lp_asym_pause) {
			if (bgep->param_adv_pause)
				bgep->param_link_rx_pause = B_TRUE;
			if (bgep->param_lp_pause)
				bgep->param_link_tx_pause = B_TRUE;
		}
	}

	/*
	 * Step 12: update ndd-visible state parameters, BUT!
	 * we don't transfer the new state to <link_state> just yet;
	 * instead we mark the <link_state> as UNKNOWN, and our caller
	 * will resolve it once the status has stopped changing and
	 * been stable for several seconds.
	 */
	BGE_DEBUG(("bge_check_serdes: link was %s speed %d duplex %d",
	    UPORDOWN(bgep->param_link_up),
	    bgep->param_link_speed,
	    bgep->param_link_duplex));

	if (linkup) {
		bgep->param_link_up = B_TRUE;
		bgep->param_link_speed = 1000;
		if (bgep->param_adv_1000fdx)
			bgep->param_link_duplex = LINK_DUPLEX_FULL;
		else
			bgep->param_link_duplex = LINK_DUPLEX_HALF;
		if (bgep->param_lp_autoneg && !bgep->param_lp_1000fdx)
			bgep->param_link_duplex = LINK_DUPLEX_HALF;
	} else {
		bgep->param_link_up = B_FALSE;
		bgep->param_link_speed = 0;
		bgep->param_link_duplex = LINK_DUPLEX_UNKNOWN;
	}
	bgep->link_state = LINK_STATE_UNKNOWN;

	BGE_DEBUG(("bge_check_serdes: link now %s speed %d duplex %d",
	    UPORDOWN(bgep->param_link_up),
	    bgep->param_link_speed,
	    bgep->param_link_duplex));

	return (B_TRUE);
}
Exemple #7
0
int
bge_m_stat(void *arg, uint_t stat, uint64_t *val)
{
	bge_t *bgep = arg;
	bge_statistics_t *bstp;
	bge_statistics_reg_t *pstats;

	if (bgep->bge_chip_state != BGE_CHIP_RUNNING) {
		return (EINVAL);
	}

	if (bgep->chipid.statistic_type == BGE_STAT_BLK)
		bstp = DMA_VPTR(bgep->statistics);
	else {
		pstats = bgep->pstats;
		pstats->ifHCOutOctets +=
		    bge_reg_get32(bgep, STAT_IFHCOUT_OCTETS_REG);
		pstats->etherStatsCollisions +=
		    bge_reg_get32(bgep, STAT_ETHER_COLLIS_REG);
		pstats->outXonSent +=
		    bge_reg_get32(bgep, STAT_OUTXON_SENT_REG);
		pstats->outXoffSent +=
		    bge_reg_get32(bgep, STAT_OUTXOFF_SENT_REG);
		pstats->dot3StatsInternalMacTransmitErrors +=
		    bge_reg_get32(bgep, STAT_DOT3_INTMACTX_ERR_REG);
		pstats->dot3StatsSingleCollisionFrames +=
		    bge_reg_get32(bgep, STAT_DOT3_SCOLLI_FRAME_REG);
		pstats->dot3StatsMultipleCollisionFrames +=
		    bge_reg_get32(bgep, STAT_DOT3_MCOLLI_FRAME_REG);
		pstats->dot3StatsDeferredTransmissions +=
		    bge_reg_get32(bgep, STAT_DOT3_DEFERED_TX_REG);
		pstats->dot3StatsExcessiveCollisions +=
		    bge_reg_get32(bgep, STAT_DOT3_EXCE_COLLI_REG);
		pstats->dot3StatsLateCollisions +=
		    bge_reg_get32(bgep, STAT_DOT3_LATE_COLLI_REG);
		pstats->ifHCOutUcastPkts +=
		    bge_reg_get32(bgep, STAT_IFHCOUT_UPKGS_REG);
		pstats->ifHCOutMulticastPkts +=
		    bge_reg_get32(bgep, STAT_IFHCOUT_MPKGS_REG);
		pstats->ifHCOutBroadcastPkts +=
		    bge_reg_get32(bgep, STAT_IFHCOUT_BPKGS_REG);
		pstats->ifHCInOctets +=
		    bge_reg_get32(bgep, STAT_IFHCIN_OCTETS_REG);
		pstats->etherStatsFragments +=
		    bge_reg_get32(bgep, STAT_ETHER_FRAGMENT_REG);
		pstats->ifHCInUcastPkts +=
		    bge_reg_get32(bgep, STAT_IFHCIN_UPKGS_REG);
		pstats->ifHCInMulticastPkts +=
		    bge_reg_get32(bgep, STAT_IFHCIN_MPKGS_REG);
		pstats->ifHCInBroadcastPkts +=
		    bge_reg_get32(bgep, STAT_IFHCIN_BPKGS_REG);
		pstats->dot3StatsFCSErrors +=
		    bge_reg_get32(bgep, STAT_DOT3_FCS_ERR_REG);
		pstats->dot3StatsAlignmentErrors +=
		    bge_reg_get32(bgep, STAT_DOT3_ALIGN_ERR_REG);
		pstats->xonPauseFramesReceived +=
		    bge_reg_get32(bgep, STAT_XON_PAUSE_RX_REG);
		pstats->xoffPauseFramesReceived +=
		    bge_reg_get32(bgep, STAT_XOFF_PAUSE_RX_REG);
		pstats->macControlFramesReceived +=
		    bge_reg_get32(bgep, STAT_MAC_CTRL_RX_REG);
		pstats->xoffStateEntered +=
		    bge_reg_get32(bgep, STAT_XOFF_STATE_ENTER_REG);
		pstats->dot3StatsFrameTooLongs +=
		    bge_reg_get32(bgep, STAT_DOT3_FRAME_TOOLONG_REG);
		pstats->etherStatsJabbers +=
		    bge_reg_get32(bgep, STAT_ETHER_JABBERS_REG);
		pstats->etherStatsUndersizePkts +=
		    bge_reg_get32(bgep, STAT_ETHER_UNDERSIZE_REG);
		mutex_enter(bgep->genlock);
		if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
			ddi_fm_service_impact(bgep->devinfo,
			    DDI_SERVICE_UNAFFECTED);
		}
		mutex_exit(bgep->genlock);
	}

	switch (stat) {
	case MAC_STAT_IFSPEED:
		*val = (bgep->link_state != LINK_STATE_UNKNOWN) ?
		           (bgep->param_link_speed * 1000000ull) : 0;
		break;

	case MAC_STAT_MULTIRCV:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCInMulticastPkts;
		else
			*val = pstats->ifHCInMulticastPkts;
		break;

	case MAC_STAT_BRDCSTRCV:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCInBroadcastPkts;
		else
			*val = pstats->ifHCInBroadcastPkts;
		break;

	case MAC_STAT_MULTIXMT:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCOutMulticastPkts;
		else
			*val = pstats->ifHCOutMulticastPkts;
		break;

	case MAC_STAT_BRDCSTXMT:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCOutBroadcastPkts;
		else
			*val = pstats->ifHCOutBroadcastPkts;
		break;

	case MAC_STAT_NORCVBUF:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifInDiscards;
		else
			*val = 0;
		break;

	case MAC_STAT_IERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK) {
			*val = bstp->s.dot3StatsFCSErrors +
			    bstp->s.dot3StatsAlignmentErrors +
			    bstp->s.dot3StatsFrameTooLongs +
			    bstp->s.etherStatsUndersizePkts +
			    bstp->s.etherStatsJabbers;
		} else {
			*val = pstats->dot3StatsFCSErrors +
			    pstats->dot3StatsAlignmentErrors +
			    pstats->dot3StatsFrameTooLongs +
			    pstats->etherStatsUndersizePkts +
			    pstats->etherStatsJabbers;
		}
		break;

	case MAC_STAT_NOXMTBUF:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifOutDiscards;
		else
			*val = 0;
		break;

	case MAC_STAT_OERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifOutDiscards;
		else
			*val = 0;
		break;

	case MAC_STAT_COLLISIONS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.etherStatsCollisions;
		else
			*val = pstats->etherStatsCollisions;
		break;

	case MAC_STAT_RBYTES:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCInOctets;
		else
			*val = pstats->ifHCInOctets;
		break;

	case MAC_STAT_IPACKETS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCInUcastPkts +
			    bstp->s.ifHCInMulticastPkts +
			    bstp->s.ifHCInBroadcastPkts;
		else
			*val = pstats->ifHCInUcastPkts +
			    pstats->ifHCInMulticastPkts +
			    pstats->ifHCInBroadcastPkts;
		break;

	case MAC_STAT_OBYTES:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCOutOctets;
		else
			*val = pstats->ifHCOutOctets;
		break;

	case MAC_STAT_OPACKETS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.ifHCOutUcastPkts +
			    bstp->s.ifHCOutMulticastPkts +
			    bstp->s.ifHCOutBroadcastPkts;
		else
			*val = pstats->ifHCOutUcastPkts +
			    pstats->ifHCOutMulticastPkts +
			    pstats->ifHCOutBroadcastPkts;
		break;

	case ETHER_STAT_ALIGN_ERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsAlignmentErrors;
		else
			*val = pstats->dot3StatsAlignmentErrors;
		break;

	case ETHER_STAT_FCS_ERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsFCSErrors;
		else
			*val = pstats->dot3StatsFCSErrors;
		break;

	case ETHER_STAT_FIRST_COLLISIONS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsSingleCollisionFrames;
		else
			*val = pstats->dot3StatsSingleCollisionFrames;
		break;

	case ETHER_STAT_MULTI_COLLISIONS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsMultipleCollisionFrames;
		else
			*val = pstats->dot3StatsMultipleCollisionFrames;
		break;

	case ETHER_STAT_DEFER_XMTS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsDeferredTransmissions;
		else
			*val = pstats->dot3StatsDeferredTransmissions;
		break;

	case ETHER_STAT_TX_LATE_COLLISIONS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsLateCollisions;
		else
			*val = pstats->dot3StatsLateCollisions;
		break;

	case ETHER_STAT_EX_COLLISIONS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsExcessiveCollisions;
		else
			*val = pstats->dot3StatsExcessiveCollisions;
		break;

	case ETHER_STAT_MACXMT_ERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsInternalMacTransmitErrors;
		else
			*val = bgep->pstats->dot3StatsInternalMacTransmitErrors;
		break;

	case ETHER_STAT_CARRIER_ERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsCarrierSenseErrors;
		else
			*val = 0;
		break;

	case ETHER_STAT_TOOLONG_ERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.dot3StatsFrameTooLongs;
		else
			*val = pstats->dot3StatsFrameTooLongs;
		break;

#if (MAC_VERSION > 1)
	case ETHER_STAT_TOOSHORT_ERRORS:
		if (bgep->chipid.statistic_type == BGE_STAT_BLK)
			*val = bstp->s.etherStatsUndersizePkts;
		else
			*val = pstats->etherStatsUndersizePkts;
		break;
#endif

	case ETHER_STAT_XCVR_ADDR:
		*val = bgep->phy_mii_addr;
		break;

	case ETHER_STAT_XCVR_ID:
		mutex_enter(bgep->genlock);
		*val = bge_mii_get16(bgep, MII_PHYIDH);
		*val <<= 16;
		*val |= bge_mii_get16(bgep, MII_PHYIDL);
		if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
			ddi_fm_service_impact(bgep->devinfo,
			    DDI_SERVICE_UNAFFECTED);
		}
		mutex_exit(bgep->genlock);
		break;

	case ETHER_STAT_XCVR_INUSE:
		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
			*val = XCVR_1000X;
		else
			*val = XCVR_1000T;
		break;

	case ETHER_STAT_CAP_1000FDX:
		*val = 1;
		break;

	case ETHER_STAT_CAP_1000HDX:
		*val = 1;
		break;

	case ETHER_STAT_CAP_100FDX:
		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
			*val = 0;
		else
			*val = 1;
		break;

	case ETHER_STAT_CAP_100HDX:
		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
			*val = 0;
		else
			*val = 1;
		break;

	case ETHER_STAT_CAP_10FDX:
		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
			*val = 0;
		else
			*val = 1;
		break;

	case ETHER_STAT_CAP_10HDX:
		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
			*val = 0;
		else
			*val = 1;
		break;

	case ETHER_STAT_CAP_ASMPAUSE:
		*val = 1;
		break;

	case ETHER_STAT_CAP_PAUSE:
		*val = 1;
		break;

	case ETHER_STAT_CAP_AUTONEG:
		*val = 1;
		break;

#if (MAC_VERSION > 1)
	case ETHER_STAT_CAP_REMFAULT:
		*val = 1;
		break;
#endif

	case ETHER_STAT_ADV_CAP_1000FDX:
		*val = bgep->param_adv_1000fdx;
		break;

	case ETHER_STAT_ADV_CAP_1000HDX:
		*val = bgep->param_adv_1000hdx;
		break;

	case ETHER_STAT_ADV_CAP_100FDX:
		*val = bgep->param_adv_100fdx;
		break;

	case ETHER_STAT_ADV_CAP_100HDX:
		*val = bgep->param_adv_100hdx;
		break;

	case ETHER_STAT_ADV_CAP_10FDX:
		*val = bgep->param_adv_10fdx;
		break;

	case ETHER_STAT_ADV_CAP_10HDX:
		*val = bgep->param_adv_10hdx;
		break;

	case ETHER_STAT_ADV_CAP_ASMPAUSE:
		*val = bgep->param_adv_asym_pause;
		break;

	case ETHER_STAT_ADV_CAP_PAUSE:
		*val = bgep->param_adv_pause;
		break;

	case ETHER_STAT_ADV_CAP_AUTONEG:
		*val = bgep->param_adv_autoneg;
		break;

#if (MAC_VERSION > 1)
	case ETHER_STAT_ADV_REMFAULT:
		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
			*val = 0;
		else {
			mutex_enter(bgep->genlock);
			*val = bge_mii_get16(bgep, MII_AN_ADVERT) &
			    MII_AN_ADVERT_REMFAULT ? 1 : 0;
			if (bge_check_acc_handle(bgep, bgep->io_handle) !=
			    DDI_FM_OK) {
				ddi_fm_service_impact(bgep->devinfo,
				    DDI_SERVICE_UNAFFECTED);
			}
			mutex_exit(bgep->genlock);
		}
		break;
#endif

	case ETHER_STAT_LP_CAP_1000FDX:
		*val = bgep->param_lp_1000fdx;
		break;

	case ETHER_STAT_LP_CAP_1000HDX:
		*val = bgep->param_lp_1000hdx;
		break;

	case ETHER_STAT_LP_CAP_100FDX:
		*val = bgep->param_lp_100fdx;
		break;

	case ETHER_STAT_LP_CAP_100HDX:
		*val = bgep->param_lp_100hdx;
		break;

	case ETHER_STAT_LP_CAP_10FDX:
		*val = bgep->param_lp_10fdx;
		break;

	case ETHER_STAT_LP_CAP_10HDX:
		*val = bgep->param_lp_10hdx;
		break;

	case ETHER_STAT_LP_CAP_ASMPAUSE:
		*val = bgep->param_lp_asym_pause;
		break;

	case ETHER_STAT_LP_CAP_PAUSE:
		*val = bgep->param_lp_pause;
		break;

	case ETHER_STAT_LP_CAP_AUTONEG:
		*val = bgep->param_lp_autoneg;
		break;

#if (MAC_VERSION > 1)
	case ETHER_STAT_LP_REMFAULT:
		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
			*val = 0;
		else {
			mutex_enter(bgep->genlock);
			*val = bge_mii_get16(bgep, MII_AN_LPABLE) &
			    MII_AN_ADVERT_REMFAULT ? 1 : 0;
			if (bge_check_acc_handle(bgep, bgep->io_handle) !=
			    DDI_FM_OK) {
				ddi_fm_service_impact(bgep->devinfo,
				    DDI_SERVICE_UNAFFECTED);
			}
			mutex_exit(bgep->genlock);
		}
		break;
#endif

	case ETHER_STAT_LINK_ASMPAUSE:
		*val = bgep->param_adv_asym_pause &&
		    bgep->param_lp_asym_pause &&
		    bgep->param_adv_pause != bgep->param_lp_pause;
		break;

	case ETHER_STAT_LINK_PAUSE:
		*val = bgep->param_link_rx_pause;
		break;

	case ETHER_STAT_LINK_AUTONEG:
		*val = bgep->param_link_autoneg;
		break;

	case ETHER_STAT_LINK_DUPLEX:
		*val = (bgep->link_state != LINK_STATE_UNKNOWN) ?
		           bgep->param_link_duplex : LINK_DUPLEX_UNKNOWN;
		break;

	default:
		return (ENOTSUP);
	}

	return (0);
}
Exemple #8
0
static int
bge_phydata_update(kstat_t *ksp, int flag)
{
	bge_t *bgep;
	kstat_named_t *knp;
	const bge_ksindex_t *ksip;

	if (flag != KSTAT_READ)
		return (EACCES);

	bgep = ksp->ks_private;
	if (bgep->bge_chip_state == BGE_CHIP_FAULT)
		return (EIO);

	knp = ksp->ks_data;

	/*
	 * Read the PHY registers & update the kstats ...
	 *
	 * We need to hold the mutex while performing MII reads, but
	 * we don't want to hold it across the entire sequence of reads.
	 * So we grab and release it on each iteration, 'cos it doesn't
	 * really matter if the kstats are less than 100% consistent ...
	 */
	for (ksip = bge_phydata; ksip->name != NULL; ++knp, ++ksip) {
		mutex_enter(bgep->genlock);
		switch (ksip->index) {
		case MII_STATUS:
			knp->value.ui64 = bgep->phy_gen_status;
			break;

		case MII_PHYIDH:
			knp->value.ui64 = bge_mii_get16(bgep, MII_PHYIDH);
			knp->value.ui64 <<= 16;
			knp->value.ui64 |= bge_mii_get16(bgep, MII_PHYIDL);
			break;

		case EEE_MODE_REG:
			knp->value.ui64 = 0;
			if (bgep->link_state == LINK_STATE_UP)
			{
				knp->value.ui64 =
				    (bge_reg_get32(bgep, EEE_MODE_REG) & 0x80) ?
				        1 : 0;
			}
			break;

		default:
			knp->value.ui64 = bge_mii_get16(bgep, ksip->index);
			break;
		}
		if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
			ddi_fm_service_impact(bgep->devinfo,
			    DDI_SERVICE_DEGRADED);
			mutex_exit(bgep->genlock);
			return (EIO);
		}
		mutex_exit(bgep->genlock);
	}

	return (0);
}
Exemple #9
0
static int
bge_driverinfo_update(kstat_t *ksp, int flag)
{
	bge_t *bgep;
	kstat_named_t *knp;
	ddi_acc_handle_t handle;

	if (flag != KSTAT_READ)
		return (EACCES);

	bgep = ksp->ks_private;
	if (bgep->bge_chip_state == BGE_CHIP_FAULT)
		return (EIO);

	knp = ksp->ks_data;

	(knp++)->value.ui64 = bgep->rx_buff[0].cookie.dmac_laddress;
	(knp++)->value.ui64 = bgep->tx_buff[0].cookie.dmac_laddress;
	(knp++)->value.ui64 = bgep->rx_desc[0].cookie.dmac_laddress;
	(knp++)->value.ui64 = bgep->tx_desc.cookie.dmac_laddress;

	(knp++)->value.ui64 = bgep->send[0].tx_free;
	(knp++)->value.ui64 = bgep->send[0].tx_array;
	(knp++)->value.ui64 = bgep->send[0].tc_next;
	(knp++)->value.ui64 = bgep->send[0].tx_next;
	(knp++)->value.ui64 = bgep->send[0].txfill_next;
	(knp++)->value.ui64 = bgep->send[0].txpkt_next;
	(knp++)->value.ui64 = bgep->send[0].txbuf_pop_queue->count +
	    bgep->send[0].txbuf_push_queue->count;
	(knp++)->value.ui64 = bgep->send[0].tx_flow;
	(knp++)->value.ui64 = bgep->tx_resched_needed;
	(knp++)->value.ui64 = bgep->tx_resched;
	(knp++)->value.ui64 = bgep->send[0].tx_nobuf;
	(knp++)->value.ui64 = bgep->send[0].tx_nobd;
	(knp++)->value.ui64 = bgep->send[0].tx_block;
	(knp++)->value.ui64 = bgep->send[0].tx_alloc_fail;

	(knp++)->value.ui64 = bgep->watchdog;
	(knp++)->value.ui64 = bgep->chip_resets;
	(knp++)->value.ui64 = bgep->missed_dmas;
	(knp++)->value.ui64 = bgep->missed_updates;

	/*
	 * Hold the mutex while accessing the chip registers
	 * just in case the factotum is trying to reset it!
	 */
	handle = bgep->cfg_handle;
	mutex_enter(bgep->genlock);
	(knp++)->value.ui64 = pci_config_get32(handle, PCI_CONF_BGE_MHCR);
	(knp++)->value.ui64 = pci_config_get32(handle, PCI_CONF_BGE_PDRWCR);
	(knp++)->value.ui64 = pci_config_get32(handle, PCI_CONF_BGE_PCISTATE);
	if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
		ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
		mutex_exit(bgep->genlock);
		return (EIO);
	}

	(knp++)->value.ui64 = bge_reg_get32(bgep, BUFFER_MANAGER_STATUS_REG);
	(knp++)->value.ui64 = bge_reg_get32(bgep, RCV_INITIATOR_STATUS_REG);
	if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
		ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
		mutex_exit(bgep->genlock);
		return (EIO);
	}
	mutex_exit(bgep->genlock);

	return (0);
}