/** * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control * @mac: the MAC to configure * @speed: the desired speed (10/100/1000/10000) * @duplex: the desired duplex * @fc: desired Tx/Rx PAUSE configuration * * Set the MAC speed, duplex (actually only full-duplex is supported), and * flow control. If a parameter value is negative the corresponding * MAC setting is left at its current value. */ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) { u32 val; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; if (duplex >= 0 && duplex != DUPLEX_FULL) return -EINVAL; if (mac->multiport) { u32 rx_max_pkt_size = G_RXMAXPKTSIZE(t3_read_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft)); val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, F_TXPAUSEEN); return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); } if (speed >= 0) { if (speed == SPEED_10) val = V_PORTSPEED(0); else if (speed == SPEED_100) val = V_PORTSPEED(1); else if (speed == SPEED_1000) val = V_PORTSPEED(2); else if (speed == SPEED_10000) val = V_PORTSPEED(3); else return -EINVAL; if (!uses_xaui(adap)) /* T302 */ t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED), val); else { u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft); if ((old & V_PORTSPEED(M_PORTSPEED)) != val) { t3_mac_reset(mac, val); mac->was_reset = 1; } } } val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); if (fc & PAUSE_TX) { u32 rx_max_pkt_size = G_RXMAXPKTSIZE(t3_read_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft)); val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); } t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); return 0; }
int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) { u32 val; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; if (duplex >= 0 && duplex != DUPLEX_FULL) return -EINVAL; if (speed >= 0) { if (speed == SPEED_10) val = V_PORTSPEED(0); else if (speed == SPEED_100) val = V_PORTSPEED(1); else if (speed == SPEED_1000) val = V_PORTSPEED(2); else if (speed == SPEED_10000) val = V_PORTSPEED(3); else return -EINVAL; t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED), val); } val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); if (fc & PAUSE_TX) { u32 rx_max_pkt_size = G_RXMAXPKTSIZE(t3_read_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft)); val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); } t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); return 0; }
static int t3_mac_reset(struct cmac *mac, int portspeed) { u32 val, store_mps; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; int idx = macidx(mac); unsigned int store; /* Stop egress traffic to xgm*/ store_mps = t3_read_reg(adap, A_MPS_CFG); if (!idx) t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); else t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); /* This will reduce the number of TXTOGGLES */ /* Clear: to stop the NIC traffic */ t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); /* Ensure TX drains */ t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); /* PCS in reset */ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ /* Store A_TP_TX_DROP_CFG_CH0 */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); store = t3_read_reg(adap, A_TP_PIO_DATA); msleep(10); /* Change DROP_CFG to 0xc0000011 */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); /* Check for xgm Rx fifo empty */ /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 0x80000000, 1, 1000, 2) && portspeed < 0) { CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx); return -1; } if (portspeed >= 0) { u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft); /* * safespeedchange: wipes out pretty much all XGMAC registers. */ t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE, portspeed | F_SAFESPEEDCHANGE); (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, F_SAFESPEEDCHANGE, 0); (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); t3_mac_init(mac); t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr); } else { t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ val = xgm_reset_ctrl(mac); t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { msleep(1); t3b_pcs_reset(mac); } t3_write_reg(adap, A_XGM_RX_CFG + oft, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); } /* Restore the DROP_CFG */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, store); /* Resume egress traffic to xgm */ t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, store_mps); /* Set: re-enable NIC traffic */ t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT); return 0; }