/* Poll PHY for interrupt */
static void tenxpress_phy_poll(struct efx_nic *efx)
{
	struct tenxpress_phy_data *phy_data = efx->phy_data;
	bool change = false;

	if (efx->phy_type == PHY_TYPE_SFX7101) {
		bool link_ok = sfx7101_link_ok(efx);
		if (link_ok != efx->link_up) {
			change = true;
		} else {
			unsigned int link_fc = mdio_clause45_get_pause(efx);
			if (link_fc != efx->link_fc)
				change = true;
		}
		sfx7101_check_bad_lp(efx, link_ok);
	} else if (efx->loopback_mode) {
		bool link_ok = sft9001_link_ok(efx, NULL);
		if (link_ok != efx->link_up)
			change = true;
	} else {
		u32 status = mdio_clause45_read(efx, efx->mii.phy_id,
						MDIO_MMD_PMAPMD,
						PMA_PMD_LASI_STATUS);
		if (status & (1 << PMA_PMD_LS_ALARM_LBN))
			change = true;
	}

	if (change)
		falcon_sim_phy_event(efx);

	if (phy_data->phy_mode != PHY_MODE_NORMAL)
		return;
}
Beispiel #2
0
/* Poll for link state changes */
static bool tenxpress_phy_poll(struct efx_nic *efx)
{
	struct efx_link_state old_state = efx->link_state;

	if (efx->phy_type == PHY_TYPE_SFX7101) {
		efx->link_state.up = sfx7101_link_ok(efx);
		efx->link_state.speed = 10000;
		efx->link_state.fd = true;
		efx->link_state.fc = efx_mdio_get_pause(efx);

		sfx7101_check_bad_lp(efx, efx->link_state.up);
	} else {
		struct ethtool_cmd ecmd;

		/* Check the LASI alarm first */
		if (efx->loopback_mode == LOOPBACK_NONE &&
		    !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) &
		      MDIO_PMA_LASI_LSALARM))
			return false;

		tenxpress_get_settings(efx, &ecmd);

		efx->link_state.up = sft9001_link_ok(efx, &ecmd);
		efx->link_state.speed = ecmd.speed;
		efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL);
		efx->link_state.fc = efx_mdio_get_pause(efx);
	}

	return !efx_link_state_equal(&efx->link_state, &old_state);
}
static void tenxpress_phy_reconfigure(struct efx_nic *efx)
{
	struct tenxpress_phy_data *phy_data = efx->phy_data;
	struct ethtool_cmd ecmd;
	bool phy_mode_change, loop_reset;

	if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
		phy_data->phy_mode = efx->phy_mode;
		return;
	}

	tenxpress_low_power(efx);

	phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
			   phy_data->phy_mode != PHY_MODE_NORMAL);
	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) ||
		      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));

	if (loop_reset || phy_mode_change) {
		int rc;

		efx->phy_op->get_settings(efx, &ecmd);

		if (loop_reset || phy_mode_change) {
			tenxpress_special_reset(efx);

			/* Reset XAUI if we were in 10G, and are staying
			 * in 10G. If we're moving into and out of 10G
			 * then xaui will be reset anyway */
			if (EFX_IS10G(efx))
				falcon_reset_xaui(efx);
		}

		rc = efx->phy_op->set_settings(efx, &ecmd);
		WARN_ON(rc);
	}

	mdio_clause45_transmit_disable(efx);
	mdio_clause45_phy_reconfigure(efx);
	tenxpress_ext_loopback(efx);

	phy_data->loopback_mode = efx->loopback_mode;
	phy_data->phy_mode = efx->phy_mode;

	if (efx->phy_type == PHY_TYPE_SFX7101) {
		efx->link_speed = 10000;
		efx->link_fd = true;
		efx->link_up = sfx7101_link_ok(efx);
	} else {
		efx->phy_op->get_settings(efx, &ecmd);
		efx->link_speed = ecmd.speed;
		efx->link_fd = ecmd.duplex == DUPLEX_FULL;
		efx->link_up = sft9001_link_ok(efx, &ecmd);
	}
	efx->link_fc = mdio_clause45_get_pause(efx);
}