ice: Reimplement module reads used by ethtool
authorScott W Taylor <scott.w.taylor@intel.com>
Wed, 31 Mar 2021 21:17:00 +0000 (14:17 -0700)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Thu, 15 Apr 2021 00:00:06 +0000 (17:00 -0700)
There was an excessive increment of the QSFP page, which is
now fixed. Additionally, this new update now reads 8 bytes
at a time and will retry each request if the module/bus is
busy.

Also, prevent reading from upper pages if module does not
support those pages.

Signed-off-by: Scott W Taylor <scott.w.taylor@intel.com>
Tested-by: Tony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_ethtool.c

index 68c8ad8..d9ddd0b 100644 (file)
@@ -3914,30 +3914,33 @@ ice_get_module_eeprom(struct net_device *netdev,
                      struct ethtool_eeprom *ee, u8 *data)
 {
        struct ice_netdev_priv *np = netdev_priv(netdev);
+#define SFF_READ_BLOCK_SIZE 8
+       u8 value[SFF_READ_BLOCK_SIZE] = { 0 };
        u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
        struct ice_vsi *vsi = np->vsi;
        struct ice_pf *pf = vsi->back;
        struct ice_hw *hw = &pf->hw;
        enum ice_status status;
        bool is_sfp = false;
-       unsigned int i;
+       unsigned int i, j;
        u16 offset = 0;
-       u8 value = 0;
        u8 page = 0;
 
        if (!ee || !ee->len || !data)
                return -EINVAL;
 
-       status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, &value, 1, 0,
+       status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, value, 1, 0,
                                   NULL);
        if (status)
                return -EIO;
 
-       if (value == ICE_MODULE_TYPE_SFP)
+       if (value[0] == ICE_MODULE_TYPE_SFP)
                is_sfp = true;
 
-       for (i = 0; i < ee->len; i++) {
+       memset(data, 0, ee->len);
+       for (i = 0; i < ee->len; i += SFF_READ_BLOCK_SIZE) {
                offset = i + ee->offset;
+               page = 0;
 
                /* Check if we need to access the other memory page */
                if (is_sfp) {
@@ -3953,11 +3956,37 @@ ice_get_module_eeprom(struct net_device *netdev,
                        }
                }
 
-               status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, !is_sfp,
-                                          &value, 1, 0, NULL);
-               if (status)
-                       value = 0;
-               data[i] = value;
+               /* Bit 2 of EEPROM address 0x02 declares upper
+                * pages are disabled on QSFP modules.
+                * SFP modules only ever use page 0.
+                */
+               if (page == 0 || !(data[0x2] & 0x4)) {
+                       /* If i2c bus is busy due to slow page change or
+                        * link management access, call can fail. This is normal.
+                        * So we retry this a few times.
+                        */
+                       for (j = 0; j < 4; j++) {
+                               status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
+                                                          !is_sfp, value,
+                                                          SFF_READ_BLOCK_SIZE,
+                                                          0, NULL);
+                               netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
+                                          addr, offset, page, is_sfp,
+                                          value[0], value[1], value[2], value[3],
+                                          value[4], value[5], value[6], value[7],
+                                          status);
+                               if (status) {
+                                       usleep_range(1500, 2500);
+                                       memset(value, 0, SFF_READ_BLOCK_SIZE);
+                                       continue;
+                               }
+                               break;
+                       }
+
+                       /* Make sure we have enough room for the new block */
+                       if ((i + SFF_READ_BLOCK_SIZE) < ee->len)
+                               memcpy(data + i, value, SFF_READ_BLOCK_SIZE);
+               }
        }
        return 0;
 }