xgmac.c

来自「linux 内核源代码」· C语言 代码 · 共 656 行 · 第 1/2 页

C
656
字号
	 */	mtu += 14;	if (mtu > MAX_FRAME_SIZE - 4)		return -EINVAL;	t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);	/*	 * Adjust the PAUSE frame watermarks.  We always set the LWM, and the	 * HWM only if flow-control is enabled.	 */	hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu, 		    MAC_RXFIFO_SIZE * 38 / 100);	hwm = min(hwm, MAC_RXFIFO_SIZE - 8192);	lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);	if (adap->params.rev >= T3_REV_B2 &&	    (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {		disable_exact_filters(mac);		v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);		t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,				 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);		reg = adap->params.rev == T3_REV_B2 ?			A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;		/* drain RX FIFO */		if (t3_wait_op_done(adap, reg + mac->offset,				    F_RXFIFO_EMPTY, 1, 20, 5)) {			t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);			enable_exact_filters(mac);			return -EIO;		}		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,				 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),				 V_RXMAXPKTSIZE(mtu));		t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);		enable_exact_filters(mac);	} else		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,				 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),				 V_RXMAXPKTSIZE(mtu));	/*	 * Adjust the PAUSE frame watermarks.  We always set the LWM, and the	 * HWM only if flow-control is enabled.	 */	hwm = rx_fifo_hwm(mtu);	lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);	v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);	v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);	v |= V_RXFIFOPAUSELWM(lwm / 8);	if (G_RXFIFOPAUSEHWM(v))		v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |		    V_RXFIFOPAUSEHWM(hwm / 8);	t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);	/* Adjust the TX FIFO threshold based on the MTU */	thres = (adap->params.vpd.cclk * 1000) / 15625;	thres = (thres * mtu) / 1000;	if (is_10G(adap))		thres /= 10;	thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;	thres = max(thres, 8U);	/* need at least 8 */	ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,			 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),			 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));	if (adap->params.rev > 0) {		divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;		t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,			     (hwm - lwm) * 4 / divisor);	}	t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,		     MAC_RXFIFO_SIZE * 4 * 8 / 512);	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)		val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(						t3_read_reg(adap,						A_XGM_RX_MAX_PKT_SIZE						+ oft)) / 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_enable(struct cmac *mac, int which){	int idx = macidx(mac);	struct adapter *adap = mac->adapter;	unsigned int oft = mac->offset;	struct mac_stats *s = &mac->stats;		if (which & MAC_DIRECTION_TX) {		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);		t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);		mac->tx_mcnt = s->tx_frames;		mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,							A_TP_PIO_DATA)));		mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,						A_XGM_TX_SPI4_SOP_EOP_CNT +						oft)));		mac->rx_mcnt = s->rx_frames;		mac->rx_pause = s->rx_pause;		mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,						A_XGM_RX_SPI4_SOP_EOP_CNT +						oft)));		mac->rx_ocnt = s->rx_fifo_ovfl;		mac->txen = F_TXEN;		mac->toggle_cnt = 0;	}	if (which & MAC_DIRECTION_RX)		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);	return 0;}int t3_mac_disable(struct cmac *mac, int which){	struct adapter *adap = mac->adapter;	if (which & MAC_DIRECTION_TX) {		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);		mac->txen = 0;	}	if (which & MAC_DIRECTION_RX) {		int val = F_MAC_RESET_;		t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,				 F_PCS_RESET_, 0);		msleep(100);		t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);		if (is_10G(adap))			val |= F_PCS_RESET_;		else if (uses_xaui(adap))			val |= F_PCS_RESET_ | F_XG2G_RESET_;		else			val |= F_RGMII_RESET_ | F_XG2G_RESET_;		t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);	}	return 0;}int t3b2_mac_watchdog_task(struct cmac *mac){	struct adapter *adap = mac->adapter;	struct mac_stats *s = &mac->stats;	unsigned int tx_tcnt, tx_xcnt;	unsigned int tx_mcnt = s->tx_frames;	unsigned int rx_mcnt = s->rx_frames;	unsigned int rx_xcnt;	int status;	status = 0;	tx_xcnt = 1;		/* By default tx_xcnt is making progress */	tx_tcnt = mac->tx_tcnt;	/* If tx_mcnt is progressing ignore tx_tcnt */	rx_xcnt = 1;		/* By default rx_xcnt is making progress */	if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {		tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,						A_XGM_TX_SPI4_SOP_EOP_CNT +					       	mac->offset)));		if (tx_xcnt == 0) {			t3_write_reg(adap, A_TP_PIO_ADDR,				     A_TP_TX_DROP_CNT_CH0 + macidx(mac));			tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,						      A_TP_PIO_DATA)));		} else {			goto rxcheck;		}	} else {		mac->toggle_cnt = 0;		goto rxcheck;	}	if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {		if (mac->toggle_cnt > 4) {			status = 2;			goto out;		} else {			status = 1;			goto out;		}	} else {		mac->toggle_cnt = 0;		goto rxcheck;	}rxcheck:	if (rx_mcnt != mac->rx_mcnt) {		rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,						A_XGM_RX_SPI4_SOP_EOP_CNT +						mac->offset))) +						(s->rx_fifo_ovfl -						 mac->rx_ocnt);		mac->rx_ocnt = s->rx_fifo_ovfl;	} else		goto out;	if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 &&	    mac->rx_xcnt == 0) {		status = 2;		goto out;	}out:	mac->tx_tcnt = tx_tcnt;	mac->tx_xcnt = tx_xcnt;	mac->tx_mcnt = s->tx_frames;	mac->rx_xcnt = rx_xcnt;	mac->rx_mcnt = s->rx_frames;	mac->rx_pause = s->rx_pause;	if (status == 1) {		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */		mac->toggle_cnt++;	} else if (status == 2) {		t3b2_mac_reset(mac);		mac->toggle_cnt = 0;	}	return status;}/* * This function is called periodically to accumulate the current values of the * RMON counters into the port statistics.  Since the packet counters are only * 32 bits they can overflow in ~286 secs at 10G, so the function should be * called more frequently than that.  The byte counters are 45-bit wide, they * would overflow in ~7.8 hours. */const struct mac_stats *t3_mac_update_stats(struct cmac *mac){#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)#define RMON_UPDATE(mac, name, reg) \	(mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \	(mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \			     ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)	u32 v, lo;	RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);	RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);	RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);	RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);	RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);	RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);	RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);	RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);	RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);	RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);	v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);	if (mac->adapter->params.rev == T3_REV_B2)		v &= 0x7fffffff;	mac->stats.rx_too_long += v;	RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);	RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);	RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);	RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);	RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);	RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);	RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);	RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);	RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);	RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);	RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);	RMON_UPDATE(mac, tx_pause, TX_PAUSE);	/* This counts error frames in general (bad FCS, underrun, etc). */	RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);	RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);	RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);	RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);	RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);	RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);	RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);	RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);	/* The next stat isn't clear-on-read. */	t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);	v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);	lo = (u32) mac->stats.rx_cong_drops;	mac->stats.rx_cong_drops += (u64) (v - lo);	return &mac->stats;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?