예제 #1
0
/**
 *	t3_mac_set_mtu - set the MAC MTU
 *	@mac: the MAC to configure
 *	@mtu: the MTU
 *
 *	Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
 */
int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
{
	int hwm, lwm, divisor;
	int ipg;
	unsigned int thres, v, reg;
	adapter_t *adap = mac->adapter;
	unsigned port_type = adap->params.vpd.port_type[macidx(mac)];
	unsigned int orig_mtu=mtu;

	/*
	 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
	 * packet size register includes header, but not FCS.
	 */
	mtu += 14;
	if (mac->multiport)
		mtu += 8;                             /* for preamble */
	if (mtu > MAX_FRAME_SIZE - 4)
		return -EINVAL;
	if (mac->multiport)
		return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);

	/* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */
	if (port_type == 2) {
		int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac));

		if (err)
			return err;
	}

	if (adap->params.rev >= T3_REV_B2 &&
	    (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
		t3_mac_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);
			t3_mac_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);
		t3_mac_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 = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0;
	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));

	/* Assuming a minimum drain rate of 2.5Gbps...
	 */
	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;
}
예제 #2
0
파일: xgmac.c 프로젝트: 020gzh/linux
int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
{
	int hwm, lwm, divisor;
	int ipg;
	unsigned int thres, v, reg;
	struct adapter *adap = mac->adapter;

	/*
	 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
	 * packet size register includes header, but not FCS.
	 */
	mtu += 14;
	if (mtu > 1536)
		mtu += 4;

	if (mtu > MAX_FRAME_SIZE - 4)
		return -EINVAL;
	t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);

	if (adap->params.rev >= T3_REV_B2 &&
	    (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
		t3_mac_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);
			t3_mac_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);
		t3_mac_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;
}
예제 #3
0
/**
 *	t3_mac_init - initialize a MAC
 *	@mac: the MAC to initialize
 *
 *	Initialize the given MAC.
 */
int t3_mac_init(struct cmac *mac)
{
	static struct addr_val_pair mac_reset_avp[] = {
		{ A_XGM_TX_CTRL, 0 },
		{ A_XGM_RX_CTRL, 0 },
		{ A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
		                F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
		{ A_XGM_RX_HASH_LOW, 0 },
		{ A_XGM_RX_HASH_HIGH, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
		{ A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
		{ A_XGM_STAT_CTRL, F_CLRSTATS }
	};
	u32 val;
	adapter_t *adap = mac->adapter;
	unsigned int oft = mac->offset;

	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */

	t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
	t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
			 F_RXSTRFRWRD | F_DISERRFRAMES,
			 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);

	if (uses_xaui(adap)) {
		if (adap->params.rev == 0) {
			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
					 F_RXENABLE | F_TXENABLE);
			if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
					    F_CMULOCK, 1, 5, 2)) {
				CH_ERR(adap,
				       "MAC %d XAUI SERDES CMU lock failed\n",
				       macidx(mac));
				return -1;
			}
			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
					 F_SERDESRESET_);
		} else
			xaui_serdes_reset(mac);
	}


	if (mac->multiport) {
		t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
			     V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4));
		t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
				 F_DISPREAMBLE);
		t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
				 F_ENNON802_3PREAMBLE);
		t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
				 V_TXFIFOTHRESH(M_TXFIFOTHRESH),
				 V_TXFIFOTHRESH(64));
		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
	}

	t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
			 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
			 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);

	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);
	}

	memset(&mac->stats, 0, sizeof(mac->stats));
	return 0;
}