コード例 #1
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
/*
 * Basic low-level function to probe for a PHY
 *
 * Returns TRUE if the PHY responds with valid data, FALSE otherwise
 */
static boolean_t
bge_phy_probe(bge_t *bgep)
{
	uint16_t miicfg;
	uint32_t nicsig, niccfg;

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

	ASSERT(mutex_owned(bgep->genlock));

	nicsig = bge_nic_read32(bgep, BGE_NIC_DATA_SIG_ADDR);
	if (nicsig == BGE_NIC_DATA_SIG) {
		niccfg = bge_nic_read32(bgep, BGE_NIC_DATA_NIC_CFG_ADDR);
		switch (niccfg & BGE_NIC_CFG_PHY_TYPE_MASK) {
		default:
		case BGE_NIC_CFG_PHY_TYPE_COPPER:
			return (B_TRUE);
		case BGE_NIC_CFG_PHY_TYPE_FIBER:
			return (B_FALSE);
		}
	} else {
		/*
		 * Read the MII_STATUS register twice, in
		 * order to clear any sticky bits (but they should
		 * have been cleared by the RESET, I think).
		 */
		miicfg = bge_mii_get16(bgep, MII_STATUS);
		miicfg = bge_mii_get16(bgep, MII_STATUS);
		BGE_DEBUG(("bge_phy_probe: status 0x%x", miicfg));

		/*
		 * Now check the value read; it should have at least one bit set
		 * (for the device capabilities) and at least one clear (one of
		 * the error bits). So if we see all 0s or all 1s, there's a
		 * problem.  In particular, bge_mii_get16() returns all 1s if
		 * communications fails ...
		 */
		switch (miicfg) {
		case 0x0000:
		case 0xffff:
			return (B_FALSE);

		default :
			return (B_TRUE);
		}
	}
}
コード例 #2
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
static void
bge_phy_macro_wait(bge_t *bgep)
{
	uint_t count;

	for (count = 100; --count; )
		if ((bge_mii_get16(bgep, 0x16) & 0x1000) == 0)
			break;
}
コード例 #3
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
static void
bge_phydump(bge_t *bgep, uint16_t mii_status, uint16_t aux)
{
	uint16_t regs[32];
	int i;

	ASSERT(mutex_owned(bgep->genlock));

	for (i = 0; i < 32; ++i)
		switch (i) {
		default:
			regs[i] = bge_mii_get16(bgep, i);
			break;

		case MII_STATUS:
			regs[i] = mii_status;
			break;

		case MII_AUX_STATUS:
			regs[i] = aux;
			break;

		case 0x0b: case 0x0c: case 0x0d: case 0x0e:
		case 0x15: case 0x16: case 0x17:
		case 0x1c:
		case 0x1f:
			/* reserved registers -- don't read these */
			regs[i] = 0;
			break;
		}

	for (i = 0; i < 32; i += 8)
		BGE_DEBUG(("bge_phydump: "
		    "0x%04x %04x %04x %04x %04x %04x %04x %04x",
		    regs[i+0], regs[i+1], regs[i+2], regs[i+3],
		    regs[i+4], regs[i+5], regs[i+6], regs[i+7]));
}
コード例 #4
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
/*
 * 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);
}
コード例 #5
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
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);
}
コード例 #6
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
static int
bge_restart_copper(bge_t *bgep, boolean_t powerdown)
{
	uint16_t phy_status;
	boolean_t reset_ok;
	uint16_t extctrl, auxctrl;

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

	ASSERT(mutex_owned(bgep->genlock));

	switch (MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev)) {
	default:
		/*
		 * Shouldn't happen; it means we don't recognise this chip.
		 * It's probably a new one, so we'll try our best anyway ...
		 */
	case MHCR_CHIP_ASIC_REV_5703:
	case MHCR_CHIP_ASIC_REV_5704:
	case MHCR_CHIP_ASIC_REV_5705:
	case MHCR_CHIP_ASIC_REV_5752:
	case MHCR_CHIP_ASIC_REV_5714:
	case MHCR_CHIP_ASIC_REV_5715:
		reset_ok = bge_phy_reset_and_check(bgep);
		break;

	case MHCR_CHIP_ASIC_REV_5906:
	case MHCR_CHIP_ASIC_REV_5700:
	case MHCR_CHIP_ASIC_REV_5701:
	case MHCR_CHIP_ASIC_REV_5723:
	case MHCR_CHIP_ASIC_REV_5721_5751:
		/*
		 * Just a plain reset; the "check" code breaks these chips
		 */
		reset_ok = bge_phy_reset(bgep);
		if (!reset_ok)
			bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE);
		break;
	}
	if (!reset_ok) {
		BGE_REPORT((bgep, "PHY failed to reset correctly"));
		return (DDI_FAILURE);
	}

	/*
	 * Step 5: disable WOL (not required after RESET)
	 *
	 * Step 6: refer to errata
	 */
	switch (bgep->chipid.asic_rev) {
	default:
		break;

	case MHCR_CHIP_REV_5704_A0:
		bge_phy_tweak_gmii(bgep);
		break;
	}

	switch (MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev)) {
	case MHCR_CHIP_ASIC_REV_5705:
	case MHCR_CHIP_ASIC_REV_5721_5751:
		bge_phy_bit_err_fix(bgep);
		break;
	}

	if (!(bgep->chipid.flags & CHIP_FLAG_NO_JUMBO) &&
	    (bgep->chipid.default_mtu > BGE_DEFAULT_MTU)) {
		/* Set the GMII Fifo Elasticity to high latency */
		extctrl = bge_mii_get16(bgep, 0x10);
		bge_mii_put16(bgep, 0x10, extctrl | 0x1);

		/* Allow reception of extended length packets */
		bge_mii_put16(bgep, MII_AUX_CONTROL, 0x0007);
		auxctrl = bge_mii_get16(bgep, MII_AUX_CONTROL);
		auxctrl |= 0x4000;
		bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl);
	}

	/*
	 * Step 7: read the MII_INTR_STATUS register twice,
	 * in order to clear any sticky bits (but they should
	 * have been cleared by the RESET, I think), and we're
	 * not using PHY interrupts anyway.
	 *
	 * Step 8: enable the PHY to interrupt on link status
	 * change (not required)
	 *
	 * Step 9: configure PHY LED Mode - not applicable?
	 *
	 * Step 10: read the MII_STATUS register twice, in
	 * order to clear any sticky bits (but they should
	 * have been cleared by the RESET, I think).
	 */
	phy_status = bge_mii_get16(bgep, MII_STATUS);
	phy_status = bge_mii_get16(bgep, MII_STATUS);
	BGE_DEBUG(("bge_restart_copper: status 0x%x", phy_status));

	/*
	 * Finally, shut down the PHY, if required
	 */
	if (powerdown)
		bge_phy_powerdown(bgep);
	return (DDI_SUCCESS);
}
コード例 #7
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
/*
 * Special-case code to reset the PHY on the 5702/5703/5704C/5705/5782.
 * Tries up to 5 times to recover from failure to reset or PHY lockup.
 *
 * Returns TRUE on success, FALSE if there's an unrecoverable problem
 */
static boolean_t
bge_phy_reset_and_check(bge_t *bgep)
{
	boolean_t reset_success;
	boolean_t phy_locked;
	uint16_t extctrl;
	uint16_t gigctrl;
	uint_t retries;

	for (retries = 0; retries < 5; ++retries) {
		/* Issue a phy reset, and wait for reset to complete */
		/* Assuming reset is successful first */
		reset_success = bge_phy_reset(bgep);

		/*
		 * Now go check the DFE TAPs to see if locked up, but
		 * first, we need to set up PHY so we can read DFE
		 * TAPs.
		 */

		/*
		 * Disable Transmitter and Interrupt, while we play
		 * with the PHY registers, so the link partner won't
		 * see any strange data and the Driver won't see any
		 * interrupts.
		 */
		extctrl = bge_mii_get16(bgep, 0x10);
		bge_mii_put16(bgep, 0x10, extctrl | 0x3000);

		/* Setup Full-Duplex, 1000 mbps */
		bge_mii_put16(bgep, 0x0, 0x0140);

		/* Set to Master mode */
		gigctrl = bge_mii_get16(bgep, 0x9);
		bge_mii_put16(bgep, 0x9, 0x1800);

		/* Enable SM_DSP_CLOCK & 6dB */
		bge_mii_put16(bgep, 0x18, 0x0c00);	/* "the ADC fix" */

		/* Work-arounds */
		bge_mii_put16(bgep, 0x17, 0x201f);
		bge_mii_put16(bgep, 0x15, 0x2aaa);

		/* More workarounds */
		bge_mii_put16(bgep, 0x17, 0x000a);
		bge_mii_put16(bgep, 0x15, 0x0323);	/* "the Gamma fix" */

		/* Blocks the PHY control access */
		bge_mii_put16(bgep, 0x17, 0x8005);
		bge_mii_put16(bgep, 0x15, 0x0800);

		/* Test whether PHY locked up ;-( */
		phy_locked = bge_phy_locked_up(bgep);
		if (reset_success && !phy_locked)
			break;

		/*
		 * Some problem here ... log it & retry
		 */
		if (!reset_success)
			BGE_REPORT((bgep, "PHY didn't reset!"));
		if (phy_locked)
			BGE_REPORT((bgep, "PHY locked up!"));
	}

	/* Remove block phy control */
	bge_mii_put16(bgep, 0x17, 0x8005);
	bge_mii_put16(bgep, 0x15, 0x0000);

	/* Unfreeze DFE TAP filter for all channels */
	bge_mii_put16(bgep, 0x17, 0x8200);
	bge_mii_put16(bgep, 0x16, 0x0000);

	/* Restore PHY back to operating state */
	bge_mii_put16(bgep, 0x18, 0x0400);

	/* Restore 1000BASE-T Control Register */
	bge_mii_put16(bgep, 0x9, gigctrl);

	/* Enable transmitter and interrupt */
	extctrl = bge_mii_get16(bgep, 0x10);
	bge_mii_put16(bgep, 0x10, extctrl & ~0x3000);

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

	if (!reset_success)
		bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE);
	else if (phy_locked)
		bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE);
	return (reset_success && !phy_locked);
}
コード例 #8
0
ファイル: bge_mii.c プロジェクト: apprisi/illumos-gate
/*
 * Check whether the PHY has locked up after a RESET.
 *
 * Returns TRUE if it did, FALSE is it's OK ;-)
 */
static boolean_t
bge_phy_locked_up(bge_t *bgep)
{
	uint16_t dataLo;
	uint16_t dataHi;
	uint_t chan;
	uint_t tap;

	/*
	 * Check TAPs for all 4 channels, as soon as we see a lockup
	 * we'll stop checking.
	 */
	for (chan = 0; chan < N_CHANNELS; ++chan) {
		/* Select channel and set TAP index to 0 */
		bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200);
		/* Freeze filter again just to be safe */
		bge_mii_put16(bgep, 0x16, 0x0002);

		/*
		 * Write fixed pattern to the RAM, 3 TAPs for
		 * each channel, each TAP have 2 WORDs (LO/HI)
		 */
		for (tap = 0; tap < N_TAPS; ++tap) {
			bge_mii_put16(bgep, 0x15, tap_data[chan][tap].lo);
			bge_mii_put16(bgep, 0x15, tap_data[chan][tap].hi);
		}

		/*
		 * Active PHY's Macro operation to write DFE
		 * TAP from RAM, and wait for Macro to complete.
		 */
		bge_mii_put16(bgep, 0x16, 0x0202);
		bge_phy_macro_wait(bgep);

		/*
		 * Done with write phase, now begin read phase.
		 */

		/* Select channel and set TAP index to 0 */
		bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200);

		/*
		 * Active PHY's Macro operation to load DFE
		 * TAP to RAM, and wait for Macro to complete
		 */
		bge_mii_put16(bgep, 0x16, 0x0082);
		bge_phy_macro_wait(bgep);

		/* Enable "pre-fetch" */
		bge_mii_put16(bgep, 0x16, 0x0802);
		bge_phy_macro_wait(bgep);

		/*
		 * Read back the TAP values.  3 TAPs for each
		 * channel, each TAP have 2 WORDs (LO/HI)
		 */
		for (tap = 0; tap < N_TAPS; ++tap) {
			/*
			 * Read Lo/Hi then wait for 'done' is faster.
			 * For DFE TAP, the HI word contains 6 bits,
			 * LO word contains 15 bits
			 */
			dataLo = bge_mii_get16(bgep, 0x15) & 0x7fff;
			dataHi = bge_mii_get16(bgep, 0x15) & 0x003f;
			bge_phy_macro_wait(bgep);

			/*
			 * Check if what we wrote is what we read back.
			 * If failed, then the PHY is locked up, we need
			 * to do PHY reset again
			 */
			if (dataLo != tap_data[chan][tap].lo)
				return (B_TRUE);	/* wedged!	*/

			if (dataHi != tap_data[chan][tap].hi)
				return (B_TRUE);	/* wedged!	*/
		}
	}

	/*
	 * The PHY isn't locked up ;-)
	 */
	return (B_FALSE);
}
コード例 #9
0
ファイル: bge_kstats.c プロジェクト: bahamas10/openzfs
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);
}
コード例 #10
0
ファイル: bge_kstats.c プロジェクト: bahamas10/openzfs
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);
}