i40e: fix reading LLDP configuration
authorMariusz Stachura <mariusz.stachura@intel.com>
Fri, 20 Apr 2018 08:41:34 +0000 (01:41 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Mon, 30 Apr 2018 16:12:33 +0000 (09:12 -0700)
Previous method for reading LLDP config was based on hard-coded
offsets. It happened to work, because of structured architecture of
the NVM memory. In the new approach, known as FLAT, we need to
calculate the absolute address, instead of using relative values.
Needed defines for memory location were added.

Signed-off-by: Mariusz Stachura <mariusz.stachura@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e_dcb.c
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40evf/i40e_type.h

index 69e7d4967b1cd6f9ebd8256b5de9a32ec99c6df2..56bff8faf37185fa9c6f45910aad6eb146dc07c5 100644 (file)
@@ -920,6 +920,70 @@ i40e_status i40e_init_dcb(struct i40e_hw *hw)
        return ret;
 }
 
+/**
+ * _i40e_read_lldp_cfg - generic read of LLDP Configuration data from NVM
+ * @hw: pointer to the HW structure
+ * @lldp_cfg: pointer to hold lldp configuration variables
+ * @module: address of the module pointer
+ * @word_offset: offset of LLDP configuration
+ *
+ * Reads the LLDP configuration data from NVM using passed addresses
+ **/
+static i40e_status _i40e_read_lldp_cfg(struct i40e_hw *hw,
+                                      struct i40e_lldp_variables *lldp_cfg,
+                                      u8 module, u32 word_offset)
+{
+       u32 address, offset = (2 * word_offset);
+       i40e_status ret;
+       __le16 raw_mem;
+       u16 mem;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret)
+               return ret;
+
+       ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(raw_mem), &raw_mem,
+                              true, NULL);
+       i40e_release_nvm(hw);
+       if (ret)
+               return ret;
+
+       mem = le16_to_cpu(raw_mem);
+       /* Check if this pointer needs to be read in word size or 4K sector
+        * units.
+        */
+       if (mem & I40E_PTR_TYPE)
+               address = (0x7FFF & mem) * 4096;
+       else
+               address = (0x7FFF & mem) * 2;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret)
+               goto err_lldp_cfg;
+
+       ret = i40e_aq_read_nvm(hw, module, offset, sizeof(raw_mem), &raw_mem,
+                              true, NULL);
+       i40e_release_nvm(hw);
+       if (ret)
+               return ret;
+
+       mem = le16_to_cpu(raw_mem);
+       offset = mem + word_offset;
+       offset *= 2;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret)
+               goto err_lldp_cfg;
+
+       ret = i40e_aq_read_nvm(hw, 0, address + offset,
+                              sizeof(struct i40e_lldp_variables), lldp_cfg,
+                              true, NULL);
+       i40e_release_nvm(hw);
+
+err_lldp_cfg:
+       return ret;
+}
+
 /**
  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
  * @hw: pointer to the HW structure
@@ -931,21 +995,34 @@ i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
                               struct i40e_lldp_variables *lldp_cfg)
 {
        i40e_status ret = 0;
-       u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
+       u32 mem;
 
        if (!lldp_cfg)
                return I40E_ERR_PARAM;
 
        ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
        if (ret)
-               goto err_lldp_cfg;
+               return ret;
 
-       ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
-                              sizeof(struct i40e_lldp_variables),
-                              (u8 *)lldp_cfg,
-                              true, NULL);
+       ret = i40e_aq_read_nvm(hw, I40E_SR_NVM_CONTROL_WORD, 0, sizeof(mem),
+                              &mem, true, NULL);
        i40e_release_nvm(hw);
+       if (ret)
+               return ret;
+
+       /* Read a bit that holds information whether we are running flat or
+        * structured NVM image. Flat image has LLDP configuration in shadow
+        * ram, so there is a need to pass different addresses for both cases.
+        */
+       if (mem & I40E_SR_NVM_MAP_STRUCTURE_TYPE) {
+               /* Flat NVM case */
+               ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_SR_EMP_MODULE_PTR,
+                                         I40E_SR_LLDP_CFG_PTR);
+       } else {
+               /* Good old structured NVM image */
+               ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_EMP_MODULE_PTR,
+                                         I40E_NVM_LLDP_CFG_PTR);
+       }
 
-err_lldp_cfg:
        return ret;
 }
index 40968a4216a7c7d76c540ca24fb8e30f016f87ac..7df969c59855ceab0bbdd72653120817566a537e 100644 (file)
@@ -1294,7 +1294,8 @@ struct i40e_hw_port_stats {
 
 /* Checksum and Shadow RAM pointers */
 #define I40E_SR_NVM_CONTROL_WORD               0x00
-#define I40E_SR_EMP_MODULE_PTR                 0x0F
+#define I40E_EMP_MODULE_PTR                    0x0F
+#define I40E_SR_EMP_MODULE_PTR                 0x48
 #define I40E_SR_PBA_FLAGS                      0x15
 #define I40E_SR_PBA_BLOCK_PTR                  0x16
 #define I40E_SR_BOOT_CONFIG_PTR                        0x17
@@ -1313,6 +1314,8 @@ struct i40e_hw_port_stats {
 #define I40E_SR_PCIE_ALT_MODULE_MAX_SIZE       1024
 #define I40E_SR_CONTROL_WORD_1_SHIFT           0x06
 #define I40E_SR_CONTROL_WORD_1_MASK    (0x03 << I40E_SR_CONTROL_WORD_1_SHIFT)
+#define I40E_SR_CONTROL_WORD_1_NVM_BANK_VALID  BIT(5)
+#define I40E_SR_NVM_MAP_STRUCTURE_TYPE         BIT(12)
 #define I40E_PTR_TYPE                          BIT(15)
 #define I40E_SR_OCP_CFG_WORD0                  0x2B
 #define I40E_SR_OCP_ENABLED                    BIT(15)
@@ -1430,7 +1433,8 @@ enum i40e_reset_type {
 };
 
 /* IEEE 802.1AB LLDP Agent Variables from NVM */
-#define I40E_NVM_LLDP_CFG_PTR          0xD
+#define I40E_NVM_LLDP_CFG_PTR  0x06
+#define I40E_SR_LLDP_CFG_PTR   0x31
 struct i40e_lldp_variables {
        u16 length;
        u16 adminstatus;
index c77cb9f672d8809c987e2b45f6ffdf1f4b59317e..094387db3c110a707d21db6b525b984fc54c5165 100644 (file)
@@ -1233,7 +1233,8 @@ struct i40e_hw_port_stats {
 
 /* Checksum and Shadow RAM pointers */
 #define I40E_SR_NVM_CONTROL_WORD               0x00
-#define I40E_SR_EMP_MODULE_PTR                 0x0F
+#define I40E_EMP_MODULE_PTR                    0x0F
+#define I40E_SR_EMP_MODULE_PTR                 0x48
 #define I40E_NVM_OEM_VER_OFF                   0x83
 #define I40E_SR_NVM_DEV_STARTER_VERSION                0x18
 #define I40E_SR_NVM_WAKE_ON_LAN                        0x19
@@ -1249,6 +1250,9 @@ struct i40e_hw_port_stats {
 #define I40E_SR_PCIE_ALT_MODULE_MAX_SIZE       1024
 #define I40E_SR_CONTROL_WORD_1_SHIFT           0x06
 #define I40E_SR_CONTROL_WORD_1_MASK    (0x03 << I40E_SR_CONTROL_WORD_1_SHIFT)
+#define I40E_SR_CONTROL_WORD_1_NVM_BANK_VALID  BIT(5)
+#define I40E_SR_NVM_MAP_STRUCTURE_TYPE         BIT(12)
+#define I40E_PTR_TYPE                          BIT(15)
 
 /* Shadow RAM related */
 #define I40E_SR_SECTOR_SIZE_IN_WORDS   0x800
@@ -1362,6 +1366,10 @@ enum i40e_reset_type {
        I40E_RESET_EMPR         = 3,
 };
 
+/* IEEE 802.1AB LLDP Agent Variables from NVM */
+#define I40E_NVM_LLDP_CFG_PTR  0x06
+#define I40E_SR_LLDP_CFG_PTR   0x31
+
 /* RSS Hash Table Size */
 #define I40E_PFQF_CTL_0_HASHLUTSIZE_512        0x00010000