]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ixgbe: fix SFF data dumps of SFP+ modules
authorEmil Tantilov <emil.s.tantilov@intel.com>
Wed, 29 May 2013 06:23:10 +0000 (06:23 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 31 Jul 2013 00:56:04 +0000 (17:56 -0700)
This patch fixes several issues with the previous implementation of the
SFF data dump of SFP+ modules:

- removed the __IXGBE_READ_I2C flag - I2C access locking is handled in the
  HW specific routines

- fixed the read loop to read data from ee->offset to ee->len

- the reads fail if __IXGBE_IN_SFP_INIT is set in the process - this is
  needed because on some HW I2C operations can take long time and disrupt
  the SFP and link detection process

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Reported-by: Ben Hutchings <bhutchings@solarflare.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 7be725cdfea8d3b3c7f414a500dd83b965f24d99..d882278851d7a6e5dd484fb7a5e4e5f3409d7aa7 100644 (file)
@@ -754,7 +754,6 @@ enum ixgbe_state_t {
        __IXGBE_DOWN,
        __IXGBE_SERVICE_SCHED,
        __IXGBE_IN_SFP_INIT,
-       __IXGBE_READ_I2C,
 };
 
 struct ixgbe_cb {
index ae58a928d05c96dc08dae7151b1644b386889dd2..da1ea28b5d68bdc959b6604b6b510f7d6593c4be 100644 (file)
@@ -2910,33 +2910,21 @@ static int ixgbe_get_module_info(struct net_device *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;
-       }
+       if (status != 0)
+               return -EIO;
 
        /* 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 (status != 0)
+               return -EIO;
 
        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");
@@ -2953,9 +2941,7 @@ static int ixgbe_get_module_info(struct net_device *dev,
                modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
        }
 
-err_out:
-       clear_bit(__IXGBE_READ_I2C, &adapter->state);
-       return ret_val;
+       return 0;
 }
 
 static int ixgbe_get_module_eeprom(struct net_device *dev,
@@ -2969,48 +2955,25 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
        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.
-        */
+       if (ee->len == 0)
+               return -EINVAL;
 
-       while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
-               msleep(100);
-       set_bit(__IXGBE_READ_I2C, &adapter->state);
+       for (i = ee->offset; i < ee->len; i++) {
+               /* I2C reads can take long time */
+               if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+                       return -EBUSY;
 
-       /* 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 */
+               if (i < ETH_MODULE_SFF_8079_LEN)
+                       status  = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
+               else
+                       status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte);
+
+               if (status != 0)
                        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;
-               }
+               data[i - ee->offset] = databyte;
        }
 
-err_out:
-       clear_bit(__IXGBE_READ_I2C, &adapter->state);
-
        return ret_val;
 }
 
index 61fa0c3fb1d1b9e370ce332148032d8091208376..2d0e8465a68b308449d2657e492e8ef5c9320110 100644 (file)
@@ -5832,10 +5832,6 @@ 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;