ixgbe: implement SFF diagnostic monitoring via ethtool
authorAurélien Guillaume <footplus@gmail.com>
Thu, 17 Jan 2013 06:55:24 +0000 (06:55 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 16 Feb 2013 07:39:29 +0000 (23:39 -0800)
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>
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

index b91f9b6a83d52dd3983cc60e23efe19bb170b83b..196002ba031cf50fbff05310b086fb997b0a2659 100644 (file)
@@ -620,6 +620,7 @@ enum ixgbe_state_t {
        __IXGBE_DOWN,
        __IXGBE_SERVICE_SCHED,
        __IXGBE_IN_SFP_INIT,
+       __IXGBE_READ_I2C,
 };
 
 struct ixgbe_cb {
index 7349a8b4a534514e87c90a043039bb0fb48238e2..e6cebdc58def98729c8eb7bd8333c2ee48f6d5ea 100644 (file)
@@ -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)
index aea252ad730f53e002f6b48c7a39bfa15fbf81a5..b0b72fccb86bc68d7048b7fab5add1815fbcea17 100644 (file)
@@ -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;