mirror of https://gitee.com/openkylin/linux.git
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: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
372788f964
commit
abf0a1c2b2
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -530,6 +530,10 @@ enum xgbe_mode {
|
|||
XGBE_MODE_KX_1000 = 0,
|
||||
XGBE_MODE_KX_2500,
|
||||
XGBE_MODE_KR,
|
||||
XGBE_MODE_X,
|
||||
XGBE_MODE_SGMII_100,
|
||||
XGBE_MODE_SGMII_1000,
|
||||
XGBE_MODE_SFI,
|
||||
XGBE_MODE_UNKNOWN,
|
||||
};
|
||||
|
||||
|
@ -538,6 +542,12 @@ enum xgbe_speedset {
|
|||
XGBE_SPEEDSET_2500_10000,
|
||||
};
|
||||
|
||||
enum xgbe_mdio_mode {
|
||||
XGBE_MDIO_MODE_NONE = 0,
|
||||
XGBE_MDIO_MODE_CL22,
|
||||
XGBE_MDIO_MODE_CL45,
|
||||
};
|
||||
|
||||
struct xgbe_phy {
|
||||
u32 supported;
|
||||
u32 advertising;
|
||||
|
@ -764,7 +774,7 @@ struct xgbe_phy_impl_if {
|
|||
void (*stop)(struct xgbe_prv_data *);
|
||||
|
||||
/* 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 */
|
||||
bool (*valid_speed)(struct xgbe_prv_data *, int);
|
||||
|
@ -783,6 +793,9 @@ struct xgbe_phy_impl_if {
|
|||
/* Retrieve current auto-negotiation mode */
|
||||
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 */
|
||||
enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);
|
||||
|
||||
|
|
Loading…
Reference in New Issue