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

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
...@@ -178,6 +178,7 @@ config AMD_XGBE ...@@ -178,6 +178,7 @@ config AMD_XGBE
select BITREVERSE select BITREVERSE
select CRC32 select CRC32
select PTP_1588_CLOCK select PTP_1588_CLOCK
select PHYLIB
select AMD_XGBE_HAVE_ECC if X86 select AMD_XGBE_HAVE_ECC if X86
---help--- ---help---
This driver supports the AMD 10GbE Ethernet device found on an This driver supports the AMD 10GbE Ethernet device found on an
......
...@@ -929,6 +929,8 @@ ...@@ -929,6 +929,8 @@
#define XP_DRIVER_SCRATCH_0 0x0068 #define XP_DRIVER_SCRATCH_0 0x0068
#define XP_DRIVER_SCRATCH_1 0x006c #define XP_DRIVER_SCRATCH_1 0x006c
#define XP_INT_EN 0x0078 #define XP_INT_EN 0x0078
#define XP_I2C_MUTEX 0x0080
#define XP_MDIO_MUTEX 0x0084
/* MAC Control register entry bit positions and sizes */ /* MAC Control register entry bit positions and sizes */
#define XP_DRIVER_INT_REQ_REQUEST_INDEX 0 #define XP_DRIVER_INT_REQ_REQUEST_INDEX 0
...@@ -975,6 +977,12 @@ ...@@ -975,6 +977,12 @@
#define XP_ECC_ISR_TX_DED_WIDTH 1 #define XP_ECC_ISR_TX_DED_WIDTH 1
#define XP_ECC_ISR_TX_SEC_INDEX 5 #define XP_ECC_ISR_TX_SEC_INDEX 5
#define XP_ECC_ISR_TX_SEC_WIDTH 1 #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_INDEX 31
#define XP_MAC_ADDR_HI_VALID_WIDTH 1 #define XP_MAC_ADDR_HI_VALID_WIDTH 1
#define XP_PROP_0_CONN_TYPE_INDEX 28 #define XP_PROP_0_CONN_TYPE_INDEX 28
...@@ -999,6 +1007,24 @@ ...@@ -999,6 +1007,24 @@
#define XP_PROP_2_RX_FIFO_SIZE_WIDTH 16 #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_INDEX 0
#define XP_PROP_2_TX_FIFO_SIZE_WIDTH 16 #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 */ /* I2C Control register offsets */
#define IC_CON 0x0000 #define IC_CON 0x0000
...@@ -1235,6 +1261,14 @@ ...@@ -1235,6 +1261,14 @@
#define MDIO_VEND2_CTRL1_AN_RESTART BIT(9) #define MDIO_VEND2_CTRL1_AN_RESTART BIT(9)
#endif #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 */ /* MDIO mask values */
#define XGBE_AN_CL73_INT_CMPLT BIT(0) #define XGBE_AN_CL73_INT_CMPLT BIT(0)
#define XGBE_AN_CL73_INC_LINK BIT(1) #define XGBE_AN_CL73_INC_LINK BIT(1)
......
...@@ -252,6 +252,54 @@ static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata) ...@@ -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); 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) static enum xgbe_mode xgbe_cur_mode(struct xgbe_prv_data *pdata)
{ {
return pdata->phy_if.phy_impl.cur_mode(pdata); return pdata->phy_if.phy_impl.cur_mode(pdata);
...@@ -275,6 +323,18 @@ static void xgbe_change_mode(struct xgbe_prv_data *pdata, ...@@ -275,6 +323,18 @@ static void xgbe_change_mode(struct xgbe_prv_data *pdata,
case XGBE_MODE_KR: case XGBE_MODE_KR:
xgbe_kr_mode(pdata); xgbe_kr_mode(pdata);
break; 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: case XGBE_MODE_UNKNOWN:
break; break;
default: default:
...@@ -972,6 +1032,8 @@ static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata) ...@@ -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) static const char *xgbe_phy_speed_string(int speed)
{ {
switch (speed) { switch (speed) {
case SPEED_100:
return "100Mbps";
case SPEED_1000: case SPEED_1000:
return "1Gbps"; return "1Gbps";
case SPEED_2500: case SPEED_2500:
...@@ -1057,6 +1119,10 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) ...@@ -1057,6 +1119,10 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
case XGBE_MODE_KX_1000: case XGBE_MODE_KX_1000:
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
case XGBE_MODE_KR: case XGBE_MODE_KR:
case XGBE_MODE_SGMII_100:
case XGBE_MODE_SGMII_1000:
case XGBE_MODE_X:
case XGBE_MODE_SFI:
break; break;
case XGBE_MODE_UNKNOWN: case XGBE_MODE_UNKNOWN:
default: default:
...@@ -1074,9 +1140,15 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) ...@@ -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) static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
{ {
int ret;
set_bit(XGBE_LINK_INIT, &pdata->dev_state); set_bit(XGBE_LINK_INIT, &pdata->dev_state);
pdata->link_check = jiffies; pdata->link_check = jiffies;
ret = pdata->phy_if.phy_impl.an_config(pdata);
if (ret)
return ret;
if (pdata->phy.autoneg != AUTONEG_ENABLE) if (pdata->phy.autoneg != AUTONEG_ENABLE)
return xgbe_phy_config_fixed(pdata); return xgbe_phy_config_fixed(pdata);
...@@ -1092,6 +1164,14 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) ...@@ -1092,6 +1164,14 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
xgbe_set_mode(pdata, XGBE_MODE_KX_2500); xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
xgbe_set_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 { } else {
enable_irq(pdata->an_irq); enable_irq(pdata->an_irq);
return -EINVAL; return -EINVAL;
...@@ -1167,13 +1247,19 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) ...@@ -1167,13 +1247,19 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
mode = xgbe_phy_status_aneg(pdata); mode = xgbe_phy_status_aneg(pdata);
switch (mode) { 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_KX_1000:
case XGBE_MODE_SGMII_1000:
pdata->phy.speed = SPEED_1000; pdata->phy.speed = SPEED_1000;
break; break;
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
pdata->phy.speed = SPEED_2500; pdata->phy.speed = SPEED_2500;
break; break;
case XGBE_MODE_KR: case XGBE_MODE_KR:
case XGBE_MODE_SFI:
pdata->phy.speed = SPEED_10000; pdata->phy.speed = SPEED_10000;
break; break;
case XGBE_MODE_UNKNOWN: case XGBE_MODE_UNKNOWN:
...@@ -1189,6 +1275,7 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) ...@@ -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) static void xgbe_phy_status(struct xgbe_prv_data *pdata)
{ {
unsigned int link_aneg; unsigned int link_aneg;
int an_restart;
if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) { if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
netif_carrier_off(pdata->netdev); netif_carrier_off(pdata->netdev);
...@@ -1199,7 +1286,13 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata) ...@@ -1199,7 +1286,13 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata)
link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE); 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 (pdata->phy.link) {
if (link_aneg && !xgbe_phy_aneg_done(pdata)) { if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
xgbe_check_link_timeout(pdata); xgbe_check_link_timeout(pdata);
...@@ -1284,6 +1377,14 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata) ...@@ -1284,6 +1377,14 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
xgbe_kx_2500_mode(pdata); xgbe_kx_2500_mode(pdata);
} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
xgbe_kx_1000_mode(pdata); 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 { } else {
ret = -EINVAL; ret = -EINVAL;
goto err_irq; goto err_irq;
...@@ -1367,10 +1468,16 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata) ...@@ -1367,10 +1468,16 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
{ {
if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
return SPEED_10000; return SPEED_10000;
else if (pdata->phy.advertising & ADVERTISED_10000baseT_Full)
return SPEED_10000;
else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full) else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
return SPEED_2500; return SPEED_2500;
else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full) else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
return SPEED_1000; 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; return SPEED_UNKNOWN;
} }
......
...@@ -295,6 +295,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -295,6 +295,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
return mode; 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) static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata)
{ {
return XGBE_AN_MODE_CL73; return XGBE_AN_MODE_CL73;
...@@ -607,10 +613,12 @@ static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) ...@@ -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; unsigned int reg;
*an_restart = 0;
/* Link status is latched low, so read once to clear /* Link status is latched low, so read once to clear
* and then read again to get current state * 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) ...@@ -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_mode = xgbe_phy_an_mode;
phy_impl->an_config = xgbe_phy_an_config;
phy_impl->an_outcome = xgbe_phy_an_outcome; phy_impl->an_outcome = xgbe_phy_an_outcome;
phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
......
This diff is collapsed.
...@@ -530,6 +530,10 @@ enum xgbe_mode { ...@@ -530,6 +530,10 @@ enum xgbe_mode {
XGBE_MODE_KX_1000 = 0, XGBE_MODE_KX_1000 = 0,
XGBE_MODE_KX_2500, XGBE_MODE_KX_2500,
XGBE_MODE_KR, XGBE_MODE_KR,
XGBE_MODE_X,
XGBE_MODE_SGMII_100,
XGBE_MODE_SGMII_1000,
XGBE_MODE_SFI,
XGBE_MODE_UNKNOWN, XGBE_MODE_UNKNOWN,
}; };
...@@ -538,6 +542,12 @@ enum xgbe_speedset { ...@@ -538,6 +542,12 @@ enum xgbe_speedset {
XGBE_SPEEDSET_2500_10000, XGBE_SPEEDSET_2500_10000,
}; };
enum xgbe_mdio_mode {
XGBE_MDIO_MODE_NONE = 0,
XGBE_MDIO_MODE_CL22,
XGBE_MDIO_MODE_CL45,
};
struct xgbe_phy { struct xgbe_phy {
u32 supported; u32 supported;
u32 advertising; u32 advertising;
...@@ -764,7 +774,7 @@ struct xgbe_phy_impl_if { ...@@ -764,7 +774,7 @@ struct xgbe_phy_impl_if {
void (*stop)(struct xgbe_prv_data *); void (*stop)(struct xgbe_prv_data *);
/* Return the link status */ /* Return the link status */
int (*link_status)(struct xgbe_prv_data *); int (*link_status)(struct xgbe_prv_data *, int *);
/* Indicate if a particular speed is valid */ /* Indicate if a particular speed is valid */
bool (*valid_speed)(struct xgbe_prv_data *, int); bool (*valid_speed)(struct xgbe_prv_data *, int);
...@@ -783,6 +793,9 @@ struct xgbe_phy_impl_if { ...@@ -783,6 +793,9 @@ struct xgbe_phy_impl_if {
/* Retrieve current auto-negotiation mode */ /* Retrieve current auto-negotiation mode */
enum xgbe_an_mode (*an_mode)(struct xgbe_prv_data *); enum xgbe_an_mode (*an_mode)(struct xgbe_prv_data *);
/* Configure auto-negotiation settings */
int (*an_config)(struct xgbe_prv_data *);
/* Process results of auto-negotiation */ /* Process results of auto-negotiation */
enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *); enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment