net/i40e/base: fix reading LLDP configuration
authorQi Zhang <qi.z.zhang@intel.com>
Tue, 9 Jan 2018 20:30:19 +0000 (15:30 -0500)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 16 Jan 2018 17:47:49 +0000 (18:47 +0100)
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.

Fixes: 8db9e2a1b232 ("i40e: base driver")
CC: stable@dpdk.org
Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
Acked-by: Beilei Xing <beilei.xing@intel.com>
drivers/net/i40e/base/i40e_dcb.c
drivers/net/i40e/base/i40e_type.h

index 9b5405d..7600c92 100644 (file)
@@ -1276,6 +1276,67 @@ enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
 }
 
 
+/**
+ * _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 enum i40e_status_code _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);
+       enum i40e_status_code ret;
+       u16 mem;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret != I40E_SUCCESS)
+               return ret;
+
+       ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(mem), &mem, true,
+                              NULL);
+       i40e_release_nvm(hw);
+       if (ret != I40E_SUCCESS)
+               return ret;
+
+       /* 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 != I40E_SUCCESS)
+               goto err_lldp_cfg;
+
+       ret = i40e_aq_read_nvm(hw, module, offset, sizeof(mem), &mem, true,
+                              NULL);
+       i40e_release_nvm(hw);
+       if (ret != I40E_SUCCESS)
+               return ret;
+
+       offset = mem + word_offset;
+       offset *= 2;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret != I40E_SUCCESS)
+               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
@@ -1287,21 +1348,34 @@ enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
                                         struct i40e_lldp_variables *lldp_cfg)
 {
        enum i40e_status_code ret = I40E_SUCCESS;
-       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 != I40E_SUCCESS)
-               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 != I40E_SUCCESS)
+               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 a062816..006a11a 100644 (file)
@@ -1497,7 +1497,8 @@ struct i40e_hw_port_stats {
 #define I40E_SR_PE_IMAGE_PTR                   0x0C
 #define I40E_SR_CSR_PROTECTED_LIST_PTR         0x0D
 #define I40E_SR_MNG_CONFIG_PTR                 0x0E
-#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
@@ -1540,6 +1541,7 @@ struct i40e_hw_port_stats {
 #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
@@ -1857,7 +1859,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;