amd-xgbe: Only use the SFP supported transceiver signals

The SFP eeprom indicates the transceiver signals (Rx LOS, Tx Fault, etc.)
that it supports.  Update the driver to include checking the eeprom data
when deciding whether to use a transceiver signal.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Tom Lendacky 2018-04-23 11:43:34 -05:00 committed by David S. Miller
parent 96f4d430c5
commit 117df655f8
1 changed files with 54 additions and 17 deletions

View File

@ -253,6 +253,10 @@ enum xgbe_sfp_speed {
#define XGBE_SFP_BASE_VENDOR_SN 4
#define XGBE_SFP_BASE_VENDOR_SN_LEN 16
#define XGBE_SFP_EXTD_OPT1 1
#define XGBE_SFP_EXTD_OPT1_RX_LOS BIT(1)
#define XGBE_SFP_EXTD_OPT1_TX_FAULT BIT(3)
#define XGBE_SFP_EXTD_DIAG 28
#define XGBE_SFP_EXTD_DIAG_ADDR_CHANGE BIT(2)
@ -332,6 +336,7 @@ struct xgbe_phy_data {
unsigned int sfp_gpio_address;
unsigned int sfp_gpio_mask;
unsigned int sfp_gpio_inputs;
unsigned int sfp_gpio_rx_los;
unsigned int sfp_gpio_tx_fault;
unsigned int sfp_gpio_mod_absent;
@ -986,6 +991,49 @@ static void xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata)
phy_data->sfp_phy_avail = 1;
}
static bool xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data *phy_data)
{
u8 *sfp_extd = phy_data->sfp_eeprom.extd;
if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_RX_LOS))
return false;
if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS)
return false;
if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_rx_los))
return true;
return false;
}
static bool xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data *phy_data)
{
u8 *sfp_extd = phy_data->sfp_eeprom.extd;
if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_TX_FAULT))
return false;
if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT)
return false;
if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_tx_fault))
return true;
return false;
}
static bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data)
{
if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT)
return false;
if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_mod_absent))
return true;
return false;
}
static bool xgbe_phy_belfuse_parse_quirks(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
@ -1031,6 +1079,10 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
if (sfp_base[XGBE_SFP_BASE_EXT_ID] != XGBE_SFP_EXT_ID_SFP)
return;
/* Update transceiver signals (eeprom extd/options) */
phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
if (xgbe_phy_sfp_parse_quirks(pdata))
return;
@ -1196,7 +1248,6 @@ put:
static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
unsigned int gpio_input;
u8 gpio_reg, gpio_ports[2];
int ret;
@ -1211,23 +1262,9 @@ static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
return;
}
gpio_input = (gpio_ports[1] << 8) | gpio_ports[0];
phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0];
if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT) {
/* No GPIO, just assume the module is present for now */
phy_data->sfp_mod_absent = 0;
} else {
if (!(gpio_input & (1 << phy_data->sfp_gpio_mod_absent)))
phy_data->sfp_mod_absent = 0;
}
if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS) &&
(gpio_input & (1 << phy_data->sfp_gpio_rx_los)))
phy_data->sfp_rx_los = 1;
if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT) &&
(gpio_input & (1 << phy_data->sfp_gpio_tx_fault)))
phy_data->sfp_tx_fault = 1;
phy_data->sfp_mod_absent = xgbe_phy_check_sfp_mod_absent(phy_data);
}
static void xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata)