Commit 07445f3c authored by Raju Rangoju's avatar Raju Rangoju Committed by Paolo Abeni
Browse files

amd-xgbe: Add support for 10 Mbps speed



Add the necessary changes to support 10 Mbps speed for BaseT and SFP
port modes. This is supported in MAC ver >= 30H.

Signed-off-by: default avatarRaju Rangoju <Raju.Rangoju@amd.com>
Link: https://lore.kernel.org/r/20230109101819.747572-1-Raju.Rangoju@amd.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent cbdbb58b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -807,6 +807,9 @@ static int xgbe_set_speed(struct xgbe_prv_data *pdata, int speed)
	unsigned int ss;

	switch (speed) {
	case SPEED_10:
		ss = 0x07;
		break;
	case SPEED_1000:
		ss = 0x03;
		break;
+24 −0
Original line number Diff line number Diff line
@@ -274,6 +274,15 @@ static void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
}

static void xgbe_sgmii_10_mode(struct xgbe_prv_data *pdata)
{
	/* Set MAC to 10M speed */
	pdata->hw_if.set_speed(pdata, SPEED_10);

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

static void xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
{
	/* Set MAC to 1G speed */
@@ -306,6 +315,9 @@ static void xgbe_change_mode(struct xgbe_prv_data *pdata,
	case XGBE_MODE_KR:
		xgbe_kr_mode(pdata);
		break;
	case XGBE_MODE_SGMII_10:
		xgbe_sgmii_10_mode(pdata);
		break;
	case XGBE_MODE_SGMII_100:
		xgbe_sgmii_100_mode(pdata);
		break;
@@ -1074,6 +1086,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_10:
		return "10Mbps";
	case SPEED_100:
		return "100Mbps";
	case SPEED_1000:
@@ -1161,6 +1175,7 @@ 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_10:
	case XGBE_MODE_SGMII_100:
	case XGBE_MODE_SGMII_1000:
	case XGBE_MODE_X:
@@ -1222,6 +1237,8 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
			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 if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_10)) {
			xgbe_set_mode(pdata, XGBE_MODE_SGMII_10);
		} else {
			enable_irq(pdata->an_irq);
			ret = -EINVAL;
@@ -1301,6 +1318,9 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
		mode = xgbe_phy_status_aneg(pdata);

	switch (mode) {
	case XGBE_MODE_SGMII_10:
		pdata->phy.speed = SPEED_10;
		break;
	case XGBE_MODE_SGMII_100:
		pdata->phy.speed = SPEED_100;
		break;
@@ -1443,6 +1463,8 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
		xgbe_sgmii_1000_mode(pdata);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
		xgbe_sgmii_100_mode(pdata);
	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_10)) {
		xgbe_sgmii_10_mode(pdata);
	} else {
		ret = -EINVAL;
		goto err_irq;
@@ -1540,6 +1562,8 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
		return SPEED_1000;
	else if (XGBE_ADV(lks, 100baseT_Full))
		return SPEED_100;
	else if (XGBE_ADV(lks, 10baseT_Full))
		return SPEED_10;

	return SPEED_UNKNOWN;
}
+97 −10
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@
#include "xgbe.h"
#include "xgbe-common.h"

#define XGBE_PHY_PORT_SPEED_10		BIT(0)
#define XGBE_PHY_PORT_SPEED_100		BIT(1)
#define XGBE_PHY_PORT_SPEED_1000	BIT(2)
#define XGBE_PHY_PORT_SPEED_2500	BIT(3)
@@ -759,6 +760,8 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
		XGBE_SET_SUP(lks, Pause);
		XGBE_SET_SUP(lks, Asym_Pause);
		if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) {
			if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)
				XGBE_SET_SUP(lks, 10baseT_Full);
			if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
				XGBE_SET_SUP(lks, 100baseT_Full);
			if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
@@ -1542,6 +1545,16 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
		xgbe_phy_phydev_flowctrl(pdata);

	switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) {
	case XGBE_SGMII_AN_LINK_SPEED_10:
		if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
			XGBE_SET_LP_ADV(lks, 10baseT_Full);
			mode = XGBE_MODE_SGMII_10;
		} else {
			/* Half-duplex not supported */
			XGBE_SET_LP_ADV(lks, 10baseT_Half);
			mode = XGBE_MODE_UNKNOWN;
		}
		break;
	case XGBE_SGMII_AN_LINK_SPEED_100:
		if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
			XGBE_SET_LP_ADV(lks, 100baseT_Full);
@@ -1658,6 +1671,9 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
			switch (phy_data->sfp_base) {
			case XGBE_SFP_BASE_1000_T:
				if (phy_data->phydev &&
				    (phy_data->phydev->speed == SPEED_10))
					mode = XGBE_MODE_SGMII_10;
				else if (phy_data->phydev &&
					 (phy_data->phydev->speed == SPEED_100))
					mode = XGBE_MODE_SGMII_100;
				else
@@ -1673,6 +1689,9 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
			break;
		default:
			if (phy_data->phydev &&
			    (phy_data->phydev->speed == SPEED_10))
				mode = XGBE_MODE_SGMII_10;
			else if (phy_data->phydev &&
				 (phy_data->phydev->speed == SPEED_100))
				mode = XGBE_MODE_SGMII_100;
			else
@@ -2127,6 +2146,20 @@ static void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata)
	netif_dbg(pdata, link, pdata->netdev, "100MbE SGMII mode set\n");
}

static void xgbe_phy_sgmii_10_mode(struct xgbe_prv_data *pdata)
{
	struct xgbe_phy_data *phy_data = pdata->phy_data;

	xgbe_phy_set_redrv_mode(pdata);

	/* 10M/SGMII */
	xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_10MBITS);

	phy_data->cur_mode = XGBE_MODE_SGMII_10;

	netif_dbg(pdata, link, pdata->netdev, "10MbE SGMII mode set\n");
}

static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata)
{
	struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -2185,6 +2218,7 @@ static enum xgbe_mode xgbe_phy_switch_baset_mode(struct xgbe_prv_data *pdata)
		return xgbe_phy_cur_mode(pdata);

	switch (xgbe_phy_cur_mode(pdata)) {
	case XGBE_MODE_SGMII_10:
	case XGBE_MODE_SGMII_100:
	case XGBE_MODE_SGMII_1000:
		return XGBE_MODE_KR;
@@ -2252,6 +2286,8 @@ static enum xgbe_mode xgbe_phy_get_baset_mode(struct xgbe_phy_data *phy_data,
					      int speed)
{
	switch (speed) {
	case SPEED_10:
		return XGBE_MODE_SGMII_10;
	case SPEED_100:
		return XGBE_MODE_SGMII_100;
	case SPEED_1000:
@@ -2269,6 +2305,8 @@ static enum xgbe_mode xgbe_phy_get_sfp_mode(struct xgbe_phy_data *phy_data,
					    int speed)
{
	switch (speed) {
	case SPEED_10:
		return XGBE_MODE_SGMII_10;
	case SPEED_100:
		return XGBE_MODE_SGMII_100;
	case SPEED_1000:
@@ -2343,6 +2381,9 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
	case XGBE_MODE_KR:
		xgbe_phy_kr_mode(pdata);
		break;
	case XGBE_MODE_SGMII_10:
		xgbe_phy_sgmii_10_mode(pdata);
		break;
	case XGBE_MODE_SGMII_100:
		xgbe_phy_sgmii_100_mode(pdata);
		break;
@@ -2399,6 +2440,9 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata,
	struct ethtool_link_ksettings *lks = &pdata->phy.lks;

	switch (mode) {
	case XGBE_MODE_SGMII_10:
		return xgbe_phy_check_mode(pdata, mode,
					   XGBE_ADV(lks, 10baseT_Full));
	case XGBE_MODE_SGMII_100:
		return xgbe_phy_check_mode(pdata, mode,
					   XGBE_ADV(lks, 100baseT_Full));
@@ -2428,6 +2472,11 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
			return false;
		return xgbe_phy_check_mode(pdata, mode,
					   XGBE_ADV(lks, 1000baseX_Full));
	case XGBE_MODE_SGMII_10:
		if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
			return false;
		return xgbe_phy_check_mode(pdata, mode,
					   XGBE_ADV(lks, 10baseT_Full));
	case XGBE_MODE_SGMII_100:
		if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
			return false;
@@ -2520,10 +2569,17 @@ static bool xgbe_phy_valid_speed_basex_mode(struct xgbe_phy_data *phy_data,
	}
}

static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data,
static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_prv_data *pdata,
					    int speed)
{
	struct xgbe_phy_data *phy_data = pdata->phy_data;
	unsigned int ver;

	switch (speed) {
	case SPEED_10:
		/* Supported in ver >= 30H */
		ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
		return (ver >= 0x30) ? true : false;
	case SPEED_100:
	case SPEED_1000:
		return true;
@@ -2536,10 +2592,17 @@ static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data,
	}
}

static bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data *phy_data,
static bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_prv_data *pdata,
					  int speed)
{
	struct xgbe_phy_data *phy_data = pdata->phy_data;
	unsigned int ver;

	switch (speed) {
	case SPEED_10:
		/* Supported in ver >= 30H */
		ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
		return (ver >= 0x30) && (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000);
	case SPEED_100:
		return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000);
	case SPEED_1000:
@@ -2586,12 +2649,12 @@ static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
	case XGBE_PORT_MODE_1000BASE_T:
	case XGBE_PORT_MODE_NBASE_T:
	case XGBE_PORT_MODE_10GBASE_T:
		return xgbe_phy_valid_speed_baset_mode(phy_data, speed);
		return xgbe_phy_valid_speed_baset_mode(pdata, speed);
	case XGBE_PORT_MODE_1000BASE_X:
	case XGBE_PORT_MODE_10GBASE_R:
		return xgbe_phy_valid_speed_basex_mode(phy_data, speed);
	case XGBE_PORT_MODE_SFP:
		return xgbe_phy_valid_speed_sfp_mode(phy_data, speed);
		return xgbe_phy_valid_speed_sfp_mode(pdata, speed);
	default:
		return false;
	}
@@ -2862,6 +2925,12 @@ static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
{
	struct xgbe_phy_data *phy_data = pdata->phy_data;
	unsigned int ver;

	/* 10 Mbps speed is not supported in ver < 30H */
	ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
	if (ver < 0x30 && (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10))
		return true;

	switch (phy_data->port_mode) {
	case XGBE_PORT_MODE_BACKPLANE:
@@ -2875,7 +2944,8 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
			return false;
		break;
	case XGBE_PORT_MODE_1000BASE_T:
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000))
			return false;
		break;
@@ -2884,13 +2954,15 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
			return false;
		break;
	case XGBE_PORT_MODE_NBASE_T:
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500))
			return false;
		break;
	case XGBE_PORT_MODE_10GBASE_T:
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
			return false;
@@ -2900,7 +2972,8 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
			return false;
		break;
	case XGBE_PORT_MODE_SFP:
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
		    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
			return false;
@@ -3269,6 +3342,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
		XGBE_SET_SUP(lks, Pause);
		XGBE_SET_SUP(lks, Asym_Pause);
		XGBE_SET_SUP(lks, TP);
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) {
			XGBE_SET_SUP(lks, 10baseT_Full);
			phy_data->start_mode = XGBE_MODE_SGMII_10;
		}
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
			XGBE_SET_SUP(lks, 100baseT_Full);
			phy_data->start_mode = XGBE_MODE_SGMII_100;
@@ -3299,6 +3376,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
		XGBE_SET_SUP(lks, Pause);
		XGBE_SET_SUP(lks, Asym_Pause);
		XGBE_SET_SUP(lks, TP);
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) {
			XGBE_SET_SUP(lks, 10baseT_Full);
			phy_data->start_mode = XGBE_MODE_SGMII_10;
		}
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
			XGBE_SET_SUP(lks, 100baseT_Full);
			phy_data->start_mode = XGBE_MODE_SGMII_100;
@@ -3321,6 +3402,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
		XGBE_SET_SUP(lks, Pause);
		XGBE_SET_SUP(lks, Asym_Pause);
		XGBE_SET_SUP(lks, TP);
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) {
			XGBE_SET_SUP(lks, 10baseT_Full);
			phy_data->start_mode = XGBE_MODE_SGMII_10;
		}
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
			XGBE_SET_SUP(lks, 100baseT_Full);
			phy_data->start_mode = XGBE_MODE_SGMII_100;
@@ -3361,6 +3446,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
		XGBE_SET_SUP(lks, Asym_Pause);
		XGBE_SET_SUP(lks, TP);
		XGBE_SET_SUP(lks, FIBRE);
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)
			phy_data->start_mode = XGBE_MODE_SGMII_10;
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
			phy_data->start_mode = XGBE_MODE_SGMII_100;
		if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
+2 −0
Original line number Diff line number Diff line
@@ -293,6 +293,7 @@

#define XGBE_SGMII_AN_LINK_STATUS	BIT(1)
#define XGBE_SGMII_AN_LINK_SPEED	(BIT(2) | BIT(3))
#define XGBE_SGMII_AN_LINK_SPEED_10	0x00
#define XGBE_SGMII_AN_LINK_SPEED_100	0x04
#define XGBE_SGMII_AN_LINK_SPEED_1000	0x08
#define XGBE_SGMII_AN_LINK_DUPLEX	BIT(4)
@@ -594,6 +595,7 @@ enum xgbe_mode {
	XGBE_MODE_KX_2500,
	XGBE_MODE_KR,
	XGBE_MODE_X,
	XGBE_MODE_SGMII_10,
	XGBE_MODE_SGMII_100,
	XGBE_MODE_SGMII_1000,
	XGBE_MODE_SFI,