Пример #1
0
static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
{
	netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n");

	/* Disable auto-negotiation */
	xgbe_disable_an(pdata);

	/* Validate/Set specified speed */
	switch (pdata->phy.speed) {
	case SPEED_10000:
		xgbe_set_mode(pdata, XGBE_MODE_KR);
		break;

	case SPEED_2500:
	case SPEED_1000:
		xgbe_set_mode(pdata, XGBE_MODE_KX);
		break;

	default:
		return -EINVAL;
	}

	/* Validate duplex mode */
	if (pdata->phy.duplex != DUPLEX_FULL)
		return -EINVAL;

	return 0;
}
Пример #2
0
static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
{
	enum xgbe_mode mode;

	netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n");

	/* Disable auto-negotiation */
	xgbe_an_disable(pdata);

	/* Set specified mode for specified speed */
	mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed);
	switch (mode) {
	case XGBE_MODE_KX_1000:
	case XGBE_MODE_KX_2500:
	case XGBE_MODE_KR:
	case XGBE_MODE_SGMII_100:
	case XGBE_MODE_SGMII_1000:
	case XGBE_MODE_X:
	case XGBE_MODE_SFI:
		break;
	case XGBE_MODE_UNKNOWN:
	default:
		return -EINVAL;
	}

	/* Validate duplex mode */
	if (pdata->phy.duplex != DUPLEX_FULL)
		return -EINVAL;

	xgbe_set_mode(pdata, mode);

	return 0;
}
Пример #3
0
static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
{
	set_bit(XGBE_LINK_INIT, &pdata->dev_state);
	pdata->link_check = jiffies;

	if (pdata->phy.autoneg != AUTONEG_ENABLE)
		return xgbe_phy_config_fixed(pdata);

	netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n");

	/* Disable auto-negotiation interrupt */
	disable_irq(pdata->an_irq);

	/* Start auto-negotiation in a supported mode */
	if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) {
		xgbe_set_mode(pdata, XGBE_MODE_KR);
	} else if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) ||
		   (pdata->phy.advertising & ADVERTISED_2500baseX_Full)) {
		xgbe_set_mode(pdata, XGBE_MODE_KX);
	} else {
		enable_irq(pdata->an_irq);
		return -EINVAL;
	}

	/* Disable and stop any in progress auto-negotiation */
	xgbe_disable_an(pdata);

	/* Clear any auto-negotitation interrupts */
	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);

	pdata->an_result = XGBE_AN_READY;
	pdata->an_state = XGBE_AN_READY;
	pdata->kr_state = XGBE_RX_BPA;
	pdata->kx_state = XGBE_RX_BPA;

	/* Re-enable auto-negotiation interrupt */
	enable_irq(pdata->an_irq);

	/* Set up advertisement registers based on current settings */
	xgbe_an_init(pdata);

	/* Enable and start auto-negotiation */
	xgbe_restart_an(pdata);

	return 0;
}
Пример #4
0
static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
{
	enum xgbe_mode mode;

	pdata->phy.lp_advertising = 0;

	if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
		mode = xgbe_cur_mode(pdata);
	else
		mode = xgbe_phy_status_aneg(pdata);

	switch (mode) {
	case XGBE_MODE_SGMII_100:
		pdata->phy.speed = SPEED_100;
		break;
	case XGBE_MODE_X:
	case XGBE_MODE_KX_1000:
	case XGBE_MODE_SGMII_1000:
		pdata->phy.speed = SPEED_1000;
		break;
	case XGBE_MODE_KX_2500:
		pdata->phy.speed = SPEED_2500;
		break;
	case XGBE_MODE_KR:
	case XGBE_MODE_SFI:
		pdata->phy.speed = SPEED_10000;
		break;
	case XGBE_MODE_UNKNOWN:
	default:
		pdata->phy.speed = SPEED_UNKNOWN;
	}

	pdata->phy.duplex = DUPLEX_FULL;

	xgbe_set_mode(pdata, mode);
}
Пример #5
0
static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
{
	int ret;

	set_bit(XGBE_LINK_INIT, &pdata->dev_state);
	pdata->link_check = jiffies;

	ret = pdata->phy_if.phy_impl.an_config(pdata);
	if (ret)
		return ret;

	if (pdata->phy.autoneg != AUTONEG_ENABLE) {
		ret = xgbe_phy_config_fixed(pdata);
		if (ret || !pdata->kr_redrv)
			return ret;

		netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");
	} else {
		netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n");
	}

	/* Disable auto-negotiation interrupt */
	disable_irq(pdata->an_irq);

	/* Start auto-negotiation in a supported mode */
	if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
		xgbe_set_mode(pdata, XGBE_MODE_KR);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
		xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
		xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
		xgbe_set_mode(pdata, XGBE_MODE_SFI);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
		xgbe_set_mode(pdata, XGBE_MODE_X);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
		xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
		xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
	} else {
		enable_irq(pdata->an_irq);
		return -EINVAL;
	}

	/* Disable and stop any in progress auto-negotiation */
	xgbe_an_disable_all(pdata);

	/* Clear any auto-negotitation interrupts */
	xgbe_an_clear_interrupts_all(pdata);

	pdata->an_result = XGBE_AN_READY;
	pdata->an_state = XGBE_AN_READY;
	pdata->kr_state = XGBE_RX_BPA;
	pdata->kx_state = XGBE_RX_BPA;

	/* Re-enable auto-negotiation interrupt */
	enable_irq(pdata->an_irq);

	xgbe_an_init(pdata);
	xgbe_an_restart(pdata);

	return 0;
}
Пример #6
0
static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
{
	unsigned int ad_reg, lp_reg;

	pdata->phy.lp_advertising = 0;

	if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
		return xgbe_phy_status_force(pdata);

	pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
	pdata->phy.lp_advertising |= ADVERTISED_Backplane;

	/* Compare Advertisement and Link Partner register 1 */
	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
	if (lp_reg & 0x400)
		pdata->phy.lp_advertising |= ADVERTISED_Pause;
	if (lp_reg & 0x800)
		pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;

	if (pdata->phy.pause_autoneg) {
		/* Set flow control based on auto-negotiation result */
		pdata->phy.tx_pause = 0;
		pdata->phy.rx_pause = 0;

		if (ad_reg & lp_reg & 0x400) {
			pdata->phy.tx_pause = 1;
			pdata->phy.rx_pause = 1;
		} else if (ad_reg & lp_reg & 0x800) {
			if (ad_reg & 0x400)
				pdata->phy.rx_pause = 1;
			else if (lp_reg & 0x400)
				pdata->phy.tx_pause = 1;
		}
	}

	/* Compare Advertisement and Link Partner register 2 */
	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
	if (lp_reg & 0x80)
		pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
	if (lp_reg & 0x20) {
		switch (pdata->speed_set) {
		case XGBE_SPEEDSET_1000_10000:
			pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
			break;
		case XGBE_SPEEDSET_2500_10000:
			pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full;
			break;
		}
	}

	ad_reg &= lp_reg;
	if (ad_reg & 0x80) {
		pdata->phy.speed = SPEED_10000;
		xgbe_set_mode(pdata, XGBE_MODE_KR);
	} else if (ad_reg & 0x20) {
		switch (pdata->speed_set) {
		case XGBE_SPEEDSET_1000_10000:
			pdata->phy.speed = SPEED_1000;
			break;

		case XGBE_SPEEDSET_2500_10000:
			pdata->phy.speed = SPEED_2500;
			break;
		}

		xgbe_set_mode(pdata, XGBE_MODE_KX);
	} else {
		pdata->phy.speed = SPEED_UNKNOWN;
	}

	/* Compare Advertisement and Link Partner register 3 */
	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
	if (lp_reg & 0xc000)
		pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC;

	pdata->phy.duplex = DUPLEX_FULL;
}