FreeBSD/sys/dev/cxgb/common/cxgb_t3_hw.c
/**
 *	t3_link_changed - handle interface link changes
 *	@adapter: the adapter
 *	@port_id: the port index that changed link state
 *
 *	Called when a port's link settings change to propagate the new values
 *	to the associated PHY and MAC.  After performing the common tasks it
 *	invokes an OS-specific handler.
 */
handle interface link changes
@adapter: the adapter
@port_id: the port index that changed link state

Called when a port's link settings change to propagate the new values
to the associated PHY and MAC.  After performing the common tasks it
invokes an OS-specific handler.
handle interface link changes @adapter : the adapter @port_id : the port index that changed link state Called when a port ' s link settings change to propagate the new values to the associated PHY and MAC . After performing the common tasks it invokes an OS - specific handler .
void t3_link_changed(adapter_t *adapter, int port_id)
{
	int link_ok, speed, duplex, fc, link_fault, link_state;
	struct port_info *pi = adap2pinfo(adapter, port_id);
	struct cphy *phy = &pi->phy;
	struct cmac *mac = &pi->mac;
	struct link_config *lc = &pi->link_config;
	link_ok = lc->link_ok;
	speed = lc->speed;
	duplex = lc->duplex;
	fc = lc->fc;
	link_fault = 0;
	phy->ops->get_link_status(phy, &link_state, &speed, &duplex, &fc);
	link_ok = (link_state == PHY_LINK_UP);
	if (link_state != PHY_LINK_PARTIAL)
		phy->rst = 0;
	else if (++phy->rst == 3) {
		phy->ops->reset(phy, 0);
		phy->rst = 0;
	}
	if (link_ok == 0)
		pi->link_fault = LF_NO;
	if (lc->requested_fc & PAUSE_AUTONEG)
		fc &= lc->requested_fc;
	else
		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE &&
	    (speed != lc->speed || duplex != lc->duplex || fc != lc->fc))
		t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
	if (adapter->params.nports <= 2 &&
	    ((pi->link_fault && link_ok) || (!lc->link_ok && link_ok))) {
		link_fault = t3_detect_link_fault(adapter, port_id);
		if (link_fault) {
			if (pi->link_fault != LF_YES) {
				mac->stats.link_faults++;
				pi->link_fault = LF_YES;
			}
			if (uses_xaui(adapter)) {
				if (adapter->params.rev >= T3_REV_C)
					t3c_pcs_force_los(mac);
				else
					t3b_pcs_reset(mac);
			}
			link_ok = 0;
		} else {
			if (pi->link_fault == LF_MAYBE &&
			    link_ok && lc->link_ok)
				t3_clear_faults(adapter, port_id);
			pi->link_fault = LF_NO;
		}
	}
	if (link_ok == lc->link_ok && speed == lc->speed &&
	    duplex == lc->duplex && fc == lc->fc)
		return;                            
	lc->link_ok = (unsigned char)link_ok;
	lc->speed = speed < 0 ? SPEED_INVALID : speed;
	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
	lc->fc = fc;
	if (link_ok) {
		if (adapter->params.rev > 0 && uses_xaui(adapter)) {
			if (adapter->params.rev >= T3_REV_C)
				t3c_pcs_force_los(mac);
			else
				t3b_pcs_reset(mac);
			t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
				     F_TXACTENABLE | F_RXEN);
		}
		t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset,
				 F_ENDROPPKT, 0);
		t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
		t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset,
				 F_CLRSTATS, 1);
		t3_clear_faults(adapter, port_id);
	} else {
		if (adapter->params.rev > 0 && uses_xaui(adapter)) {
			t3_write_reg(adapter,
				     A_XGM_XAUI_ACT_CTRL + mac->offset, 0);
		}
		t3_xgm_intr_disable(adapter, pi->port_id);
		if (adapter->params.nports <= 2) {
			t3_set_reg_field(adapter,
					 A_XGM_INT_ENABLE + mac->offset,
					 F_XGM_INT, 0);
			t3_mac_disable(mac, MAC_DIRECTION_RX);
			t3_set_reg_field(adapter,
			    A_XGM_TXFIFO_CFG + mac->offset, 0, F_ENDROPPKT);
			t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
			t3_write_reg(adapter,
			    A_XGM_TX_CTRL + mac->offset, F_TXEN);
			t3_write_reg(adapter,
			    A_XGM_RX_CTRL + mac->offset, F_RXEN);
		}
	}
	t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc,
	    mac->was_reset);
	mac->was_reset = 0;
}
void t3_link_changed ( adapter_t * adapter , int port_id ) { int link_ok , speed , duplex , fc , link_fault , link_state ; struct port_info * pi = adap2pinfo ( adapter , port_id ) ; struct cphy * phy = & pi -> phy ; struct cmac * mac = & pi -> mac ; struct link_config * lc = & pi -> link_config ; link_ok = lc -> link_ok ; speed = lc -> speed ; duplex = lc -> duplex ; fc = lc -> fc ; link_fault = 0 ; phy -> ops -> get_link_status ( phy , & link_state , & speed , & duplex , & fc ) ; link_ok = ( link_state == PHY_LINK_UP ) ; if ( link_state != PHY_LINK_PARTIAL ) phy -> rst = 0 ; else if ( ++ phy -> rst == 3 ) { phy -> ops -> reset ( phy , 0 ) ; phy -> rst = 0 ; } if ( link_ok == 0 ) pi -> link_fault = LF_NO ; if ( lc -> requested_fc & PAUSE_AUTONEG ) fc &= lc -> requested_fc ; else fc = lc -> requested_fc & ( PAUSE_RX | PAUSE_TX ) ; if ( link_ok && speed >= 0 && lc -> autoneg == AUTONEG_ENABLE && ( speed != lc -> speed || duplex != lc -> duplex || fc != lc -> fc ) ) t3_mac_set_speed_duplex_fc ( mac , speed , duplex , fc ) ; if ( adapter -> params . nports <= 2 && ( ( pi -> link_fault && link_ok ) || ( ! lc -> link_ok && link_ok ) ) ) { link_fault = t3_detect_link_fault ( adapter , port_id ) ; if ( link_fault ) { if ( pi -> link_fault != LF_YES ) { mac -> stats . link_faults ++ ; pi -> link_fault = LF_YES ; } if ( uses_xaui ( adapter ) ) { if ( adapter -> params . rev >= T3_REV_C ) t3c_pcs_force_los ( mac ) ; else t3b_pcs_reset ( mac ) ; } link_ok = 0 ; } else { if ( pi -> link_fault == LF_MAYBE && link_ok && lc -> link_ok ) t3_clear_faults ( adapter , port_id ) ; pi -> link_fault = LF_NO ; } } if ( link_ok == lc -> link_ok && speed == lc -> speed && duplex == lc -> duplex && fc == lc -> fc ) return ; lc -> link_ok = ( unsigned char ) link_ok ; lc -> speed = speed < 0 ? SPEED_INVALID : speed ; lc -> duplex = duplex < 0 ? DUPLEX_INVALID : duplex ; lc -> fc = fc ; if ( link_ok ) { if ( adapter -> params . rev > 0 && uses_xaui ( adapter ) ) { if ( adapter -> params . rev >= T3_REV_C ) t3c_pcs_force_los ( mac ) ; else t3b_pcs_reset ( mac ) ; t3_write_reg ( adapter , A_XGM_XAUI_ACT_CTRL + mac -> offset , F_TXACTENABLE | F_RXEN ) ; } t3_set_reg_field ( adapter , A_XGM_TXFIFO_CFG + mac -> offset , F_ENDROPPKT , 0 ) ; t3_mac_enable ( mac , MAC_DIRECTION_TX | MAC_DIRECTION_RX ) ; t3_set_reg_field ( adapter , A_XGM_STAT_CTRL + mac -> offset , F_CLRSTATS , 1 ) ; t3_clear_faults ( adapter , port_id ) ; } else { if ( adapter -> params . rev > 0 && uses_xaui ( adapter ) ) { t3_write_reg ( adapter , A_XGM_XAUI_ACT_CTRL + mac -> offset , 0 ) ; } t3_xgm_intr_disable ( adapter , pi -> port_id ) ; if ( adapter -> params . nports <= 2 ) { t3_set_reg_field ( adapter , A_XGM_INT_ENABLE + mac -> offset , F_XGM_INT , 0 ) ; t3_mac_disable ( mac , MAC_DIRECTION_RX ) ; t3_set_reg_field ( adapter , A_XGM_TXFIFO_CFG + mac -> offset , 0 , F_ENDROPPKT ) ; t3_write_reg ( adapter , A_XGM_RX_CTRL + mac -> offset , 0 ) ; t3_write_reg ( adapter , A_XGM_TX_CTRL + mac -> offset , F_TXEN ) ; t3_write_reg ( adapter , A_XGM_RX_CTRL + mac -> offset , F_RXEN ) ; } } t3_os_link_changed ( adapter , port_id , link_ok , speed , duplex , fc , mac -> was_reset ) ; mac -> was_reset = 0 ; }
t3_link_changed - handle interface link changes
      @adapter: the adapter
      @port_id: the port index that changed link state
t3_link_changed - handle interface link changes @adapter : the adapter @port_id : the port index that changed link state
/* Update mac speed before checking for link fault. */ /*
	 * Check for link faults if any of these is true:
	 * a) A link fault is suspected, and PHY says link ok
	 * b) PHY link transitioned from down -> up
	 */ /* Don't report link up */ /* clear faults here if this was a false alarm. */ /* nothing changed */ /* down -> up, or up -> up with changed settings */ /* disable TX FIFO drain */ /* up -> down */ /*
			 * Make sure Tx FIFO continues to drain, even as rxen is
			 * left high to help detect and indicate remote faults.
			 */