Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abf0a1c2 authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller
Browse files

amd-xgbe: Add support for SFP+ modules



Add support for recognizing and using SFP+ modules directly. This includes
using the I2C support to read and interpret the information returned from
an SFP+ module and configuring things properly.

Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 372788f9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -178,6 +178,7 @@ config AMD_XGBE
	select BITREVERSE
	select CRC32
	select PTP_1588_CLOCK
	select PHYLIB
	select AMD_XGBE_HAVE_ECC if X86
	---help---
	  This driver supports the AMD 10GbE Ethernet device found on an
+34 −0
Original line number Diff line number Diff line
@@ -929,6 +929,8 @@
#define XP_DRIVER_SCRATCH_0		0x0068
#define XP_DRIVER_SCRATCH_1		0x006c
#define XP_INT_EN			0x0078
#define XP_I2C_MUTEX			0x0080
#define XP_MDIO_MUTEX			0x0084

/* MAC Control register entry bit positions and sizes */
#define XP_DRIVER_INT_REQ_REQUEST_INDEX		0
@@ -975,6 +977,12 @@
#define XP_ECC_ISR_TX_DED_WIDTH			1
#define XP_ECC_ISR_TX_SEC_INDEX			5
#define XP_ECC_ISR_TX_SEC_WIDTH			1
#define XP_I2C_MUTEX_BUSY_INDEX			31
#define XP_I2C_MUTEX_BUSY_WIDTH			1
#define XP_I2C_MUTEX_ID_INDEX			29
#define XP_I2C_MUTEX_ID_WIDTH			2
#define XP_I2C_MUTEX_ACTIVE_INDEX		0
#define XP_I2C_MUTEX_ACTIVE_WIDTH		1
#define XP_MAC_ADDR_HI_VALID_INDEX		31
#define XP_MAC_ADDR_HI_VALID_WIDTH		1
#define XP_PROP_0_CONN_TYPE_INDEX		28
@@ -999,6 +1007,24 @@
#define XP_PROP_2_RX_FIFO_SIZE_WIDTH		16
#define XP_PROP_2_TX_FIFO_SIZE_INDEX		0
#define XP_PROP_2_TX_FIFO_SIZE_WIDTH		16
#define XP_PROP_3_GPIO_MASK_INDEX		28
#define XP_PROP_3_GPIO_MASK_WIDTH		4
#define XP_PROP_3_GPIO_MOD_ABS_INDEX		20
#define XP_PROP_3_GPIO_MOD_ABS_WIDTH		4
#define XP_PROP_3_GPIO_RATE_SELECT_INDEX	16
#define XP_PROP_3_GPIO_RATE_SELECT_WIDTH	4
#define XP_PROP_3_GPIO_RX_LOS_INDEX		24
#define XP_PROP_3_GPIO_RX_LOS_WIDTH		4
#define XP_PROP_3_GPIO_TX_FAULT_INDEX		12
#define XP_PROP_3_GPIO_TX_FAULT_WIDTH		4
#define XP_PROP_3_GPIO_ADDR_INDEX		8
#define XP_PROP_3_GPIO_ADDR_WIDTH		3
#define XP_PROP_4_MUX_ADDR_HI_INDEX		8
#define XP_PROP_4_MUX_ADDR_HI_WIDTH		5
#define XP_PROP_4_MUX_ADDR_LO_INDEX		0
#define XP_PROP_4_MUX_ADDR_LO_WIDTH		3
#define XP_PROP_4_MUX_CHAN_INDEX		4
#define XP_PROP_4_MUX_CHAN_WIDTH		3

/* I2C Control register offsets */
#define IC_CON					0x0000
@@ -1235,6 +1261,14 @@
#define MDIO_VEND2_CTRL1_AN_RESTART	BIT(9)
#endif

#ifndef MDIO_VEND2_CTRL1_SS6
#define MDIO_VEND2_CTRL1_SS6		BIT(6)
#endif

#ifndef MDIO_VEND2_CTRL1_SS13
#define MDIO_VEND2_CTRL1_SS13		BIT(13)
#endif

/* MDIO mask values */
#define XGBE_AN_CL73_INT_CMPLT		BIT(0)
#define XGBE_AN_CL73_INC_LINK		BIT(1)
+108 −1
Original line number Diff line number Diff line
@@ -252,6 +252,54 @@ static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
}

static void xgbe_sfi_mode(struct xgbe_prv_data *pdata)
{
	/* Disable KR training */
	xgbe_an73_disable_kr_training(pdata);

	/* Set MAC to 10G speed */
	pdata->hw_if.set_speed(pdata, SPEED_10000);

	/* Call PHY implementation support to complete rate change */
	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI);
}

static void xgbe_x_mode(struct xgbe_prv_data *pdata)
{
	/* Disable KR training */
	xgbe_an73_disable_kr_training(pdata);

	/* Set MAC to 1G speed */
	pdata->hw_if.set_speed(pdata, SPEED_1000);

	/* Call PHY implementation support to complete rate change */
	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X);
}

static void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
{
	/* Disable KR training */
	xgbe_an73_disable_kr_training(pdata);

	/* Set MAC to 1G speed */
	pdata->hw_if.set_speed(pdata, SPEED_1000);

	/* Call PHY implementation support to complete rate change */
	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
}

static void xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
{
	/* Disable KR training */
	xgbe_an73_disable_kr_training(pdata);

	/* Set MAC to 1G speed */
	pdata->hw_if.set_speed(pdata, SPEED_1000);

	/* Call PHY implementation support to complete rate change */
	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100);
}

static enum xgbe_mode xgbe_cur_mode(struct xgbe_prv_data *pdata)
{
	return pdata->phy_if.phy_impl.cur_mode(pdata);
@@ -275,6 +323,18 @@ static void xgbe_change_mode(struct xgbe_prv_data *pdata,
	case XGBE_MODE_KR:
		xgbe_kr_mode(pdata);
		break;
	case XGBE_MODE_SGMII_100:
		xgbe_sgmii_100_mode(pdata);
		break;
	case XGBE_MODE_SGMII_1000:
		xgbe_sgmii_1000_mode(pdata);
		break;
	case XGBE_MODE_X:
		xgbe_x_mode(pdata);
		break;
	case XGBE_MODE_SFI:
		xgbe_sfi_mode(pdata);
		break;
	case XGBE_MODE_UNKNOWN:
		break;
	default:
@@ -972,6 +1032,8 @@ static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
static const char *xgbe_phy_speed_string(int speed)
{
	switch (speed) {
	case SPEED_100:
		return "100Mbps";
	case SPEED_1000:
		return "1Gbps";
	case SPEED_2500:
@@ -1057,6 +1119,10 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
	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:
@@ -1074,9 +1140,15 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)

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)
		return xgbe_phy_config_fixed(pdata);

@@ -1092,6 +1164,14 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
		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;
@@ -1167,13 +1247,19 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
		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:
@@ -1189,6 +1275,7 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
static void xgbe_phy_status(struct xgbe_prv_data *pdata)
{
	unsigned int link_aneg;
	int an_restart;

	if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
		netif_carrier_off(pdata->netdev);
@@ -1199,7 +1286,13 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata)

	link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);

	pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata);
	pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata,
							     &an_restart);
	if (an_restart) {
		xgbe_phy_config_aneg(pdata);
		return;
	}

	if (pdata->phy.link) {
		if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
			xgbe_check_link_timeout(pdata);
@@ -1284,6 +1377,14 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
		xgbe_kx_2500_mode(pdata);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
		xgbe_kx_1000_mode(pdata);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
		xgbe_sfi_mode(pdata);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
		xgbe_x_mode(pdata);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
		xgbe_sgmii_1000_mode(pdata);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
		xgbe_sgmii_100_mode(pdata);
	} else {
		ret = -EINVAL;
		goto err_irq;
@@ -1367,10 +1468,16 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
{
	if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
		return SPEED_10000;
	else if (pdata->phy.advertising & ADVERTISED_10000baseT_Full)
		return SPEED_10000;
	else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
		return SPEED_2500;
	else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
		return SPEED_1000;
	else if (pdata->phy.advertising & ADVERTISED_1000baseT_Full)
		return SPEED_1000;
	else if (pdata->phy.advertising & ADVERTISED_100baseT_Full)
		return SPEED_100;

	return SPEED_UNKNOWN;
}
+11 −1
Original line number Diff line number Diff line
@@ -295,6 +295,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
	return mode;
}

static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
{
	/* Nothing uniquely required for an configuration */
	return 0;
}

static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata)
{
	return XGBE_AN_MODE_CL73;
@@ -607,10 +613,12 @@ static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
	}
}

static int xgbe_phy_link_status(struct xgbe_prv_data *pdata)
static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
{
	unsigned int reg;

	*an_restart = 0;

	/* Link status is latched low, so read once to clear
	 * and then read again to get current state
	 */
@@ -821,6 +829,8 @@ void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *phy_if)

	phy_impl->an_mode		= xgbe_phy_an_mode;

	phy_impl->an_config		= xgbe_phy_an_config;

	phy_impl->an_outcome		= xgbe_phy_an_outcome;

	phy_impl->kr_training_pre	= xgbe_phy_kr_training_pre;
+1484 −15

File changed.

Preview size limit exceeded, changes collapsed.

Loading