ixgbe: implement SFF diagnostic monitoring via ethtool
This patch adds support for reading data from SFP+ modules over i2c. Signed-off-by: Aurélien Guillaume <footplus@gmail.com> Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com> Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
51d0420b0a
commit
71858acbe5
@ -620,6 +620,7 @@ enum ixgbe_state_t {
|
||||
__IXGBE_DOWN,
|
||||
__IXGBE_SERVICE_SCHED,
|
||||
__IXGBE_IN_SFP_INIT,
|
||||
__IXGBE_READ_I2C,
|
||||
};
|
||||
|
||||
struct ixgbe_cb {
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "ixgbe.h"
|
||||
#include "ixgbe_phy.h"
|
||||
|
||||
|
||||
#define IXGBE_ALL_RAR_ENTRIES 16
|
||||
@ -2839,6 +2840,117 @@ static int ixgbe_set_channels(struct net_device *dev,
|
||||
return ixgbe_setup_tc(dev, netdev_get_num_tc(dev));
|
||||
}
|
||||
|
||||
static int ixgbe_get_module_info(struct net_device *dev,
|
||||
struct ethtool_modinfo *modinfo)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = netdev_priv(dev);
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 status;
|
||||
u8 sff8472_rev, addr_mode;
|
||||
int ret_val = 0;
|
||||
bool page_swap = false;
|
||||
|
||||
/* avoid concurent i2c reads */
|
||||
while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
|
||||
msleep(100);
|
||||
|
||||
/* used by the service task */
|
||||
set_bit(__IXGBE_READ_I2C, &adapter->state);
|
||||
|
||||
/* Check whether we support SFF-8472 or not */
|
||||
status = hw->phy.ops.read_i2c_eeprom(hw,
|
||||
IXGBE_SFF_SFF_8472_COMP,
|
||||
&sff8472_rev);
|
||||
if (status != 0) {
|
||||
ret_val = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* addressing mode is not supported */
|
||||
status = hw->phy.ops.read_i2c_eeprom(hw,
|
||||
IXGBE_SFF_SFF_8472_SWAP,
|
||||
&addr_mode);
|
||||
if (status != 0) {
|
||||
ret_val = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
|
||||
e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
|
||||
page_swap = true;
|
||||
}
|
||||
|
||||
if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap) {
|
||||
/* We have a SFP, but it does not support SFF-8472 */
|
||||
modinfo->type = ETH_MODULE_SFF_8079;
|
||||
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
|
||||
} else {
|
||||
/* We have a SFP which supports a revision of SFF-8472. */
|
||||
modinfo->type = ETH_MODULE_SFF_8472;
|
||||
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
|
||||
}
|
||||
|
||||
err_out:
|
||||
clear_bit(__IXGBE_READ_I2C, &adapter->state);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int ixgbe_get_module_eeprom(struct net_device *dev,
|
||||
struct ethtool_eeprom *ee,
|
||||
u8 *data)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = netdev_priv(dev);
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 status = IXGBE_ERR_PHY_ADDR_INVALID;
|
||||
u8 databyte = 0xFF;
|
||||
int i = 0;
|
||||
int ret_val = 0;
|
||||
|
||||
/* ixgbe_get_module_info is called before this function in all
|
||||
* cases, so we do not need any checks we already do above,
|
||||
* and can trust ee->len to be a known value.
|
||||
*/
|
||||
|
||||
while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
|
||||
msleep(100);
|
||||
set_bit(__IXGBE_READ_I2C, &adapter->state);
|
||||
|
||||
/* Read the first block, SFF-8079 */
|
||||
for (i = 0; i < ETH_MODULE_SFF_8079_LEN; i++) {
|
||||
status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
|
||||
if (status != 0) {
|
||||
/* Error occured while reading module */
|
||||
ret_val = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
data[i] = databyte;
|
||||
}
|
||||
|
||||
/* If the second block is requested, check if SFF-8472 is supported. */
|
||||
if (ee->len == ETH_MODULE_SFF_8472_LEN) {
|
||||
if (data[IXGBE_SFF_SFF_8472_COMP] == IXGBE_SFF_SFF_8472_UNSUP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Read the second block, SFF-8472 */
|
||||
for (i = ETH_MODULE_SFF_8079_LEN;
|
||||
i < ETH_MODULE_SFF_8472_LEN; i++) {
|
||||
status = hw->phy.ops.read_i2c_sff8472(hw,
|
||||
i - ETH_MODULE_SFF_8079_LEN, &databyte);
|
||||
if (status != 0) {
|
||||
/* Error occured while reading module */
|
||||
ret_val = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
data[i] = databyte;
|
||||
}
|
||||
}
|
||||
|
||||
err_out:
|
||||
clear_bit(__IXGBE_READ_I2C, &adapter->state);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops ixgbe_ethtool_ops = {
|
||||
.get_settings = ixgbe_get_settings,
|
||||
.set_settings = ixgbe_set_settings,
|
||||
@ -2870,6 +2982,8 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
|
||||
.get_channels = ixgbe_get_channels,
|
||||
.set_channels = ixgbe_set_channels,
|
||||
.get_ts_info = ixgbe_get_ts_info,
|
||||
.get_module_info = ixgbe_get_module_info,
|
||||
.get_module_eeprom = ixgbe_get_module_eeprom,
|
||||
};
|
||||
|
||||
void ixgbe_set_ethtool_ops(struct net_device *netdev)
|
||||
|
@ -5709,6 +5709,10 @@ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
|
||||
!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
|
||||
return;
|
||||
|
||||
/* concurent i2c reads are not supported */
|
||||
if (test_bit(__IXGBE_READ_I2C, &adapter->state))
|
||||
return;
|
||||
|
||||
/* someone else is in init, wait until next service event */
|
||||
if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user