@@ -1015,6 +1015,31 @@ enum i40e_status_code i40e_init_shared_code(struct i40e_hw *hw)
hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE |
I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK;
+#ifdef I40E_NVMUPD_SUPPORT
+#ifndef EXTERNAL_RELEASE
+ /* At the moment there are only two OSes where this feature
+ * is required - FreeBSD and Linux. FreeBSD driver does
+ * not support transition to Flat NVM. Use preprocessor
+ * tag to ensure that this is exposed only for Linux.
+ */
+#endif
+ /* NVMUpdate features structure initialization */
+ hw->nvmupd_features.major = I40E_NVMUPD_FEATURES_API_VER_MAJOR;
+ hw->nvmupd_features.minor = I40E_NVMUPD_FEATURES_API_VER_MINOR;
+ hw->nvmupd_features.size = sizeof(hw->nvmupd_features);
+ i40e_memset(hw->nvmupd_features.features, 0x0,
+ I40E_NVMUPD_FEATURES_API_FEATURES_ARRAY_LEN *
+ sizeof(*hw->nvmupd_features.features),
+ I40E_NONDMA_MEM);
+
+#ifdef LINUX_SUPPORT
+ hw->nvmupd_features.features[0] = I40E_NVMUPD_FEATURE_FLAT_NVM_SUPPORT;
+#else
+ /* No features supported at the moment */
+ hw->nvmupd_features.features[0] = 0;
+#endif
+#endif /* I40E_NVMUPD_SUPPORT */
+
status = i40e_init_nvm(hw);
return status;
}
@@ -797,6 +797,7 @@ STATIC const char *i40e_nvm_update_state_str[] = {
"I40E_NVMUPD_EXEC_AQ",
"I40E_NVMUPD_GET_AQ_RESULT",
"I40E_NVMUPD_GET_AQ_EVENT",
+ "I40E_NVMUPD_GET_FEATURES",
};
/**
@@ -859,6 +860,31 @@ enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
return I40E_SUCCESS;
}
+ /*
+ * A supported features request returns immediately
+ * rather than going into state machine
+ */
+ if (upd_cmd == I40E_NVMUPD_FEATURES) {
+ if (cmd->data_size < hw->nvmupd_features.size) {
+ *perrno = -EFAULT;
+ return I40E_ERR_BUF_TOO_SHORT;
+ }
+
+ /*
+ * If buffer is bigger than i40e_nvmupd_features structure,
+ * make sure the trailing bytes are set to 0x0.
+ */
+ if (cmd->data_size > hw->nvmupd_features.size)
+ i40e_memset(bytes + hw->nvmupd_features.size, 0x0,
+ cmd->data_size - hw->nvmupd_features.size,
+ I40E_NONDMA_MEM);
+
+ i40e_memcpy(bytes, &hw->nvmupd_features,
+ hw->nvmupd_features.size, I40E_NONDMA_MEM);
+
+ return I40E_SUCCESS;
+ }
+
/* Clear status even it is not read and log */
if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) {
i40e_debug(hw, I40E_DEBUG_NVM,
@@ -1325,10 +1351,20 @@ STATIC enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
upd_cmd = I40E_NVMUPD_READ_SA;
break;
case I40E_NVM_EXEC:
- if (module == 0xf)
- upd_cmd = I40E_NVMUPD_STATUS;
- else if (module == 0)
+ switch (module) {
+ case I40E_NVM_EXEC_GET_AQ_RESULT:
upd_cmd = I40E_NVMUPD_GET_AQ_RESULT;
+ break;
+ case I40E_NVM_EXEC_FEATURES:
+ upd_cmd = I40E_NVMUPD_FEATURES;
+ break;
+ case I40E_NVM_EXEC_STATUS:
+ upd_cmd = I40E_NVMUPD_STATUS;
+ break;
+ default:
+ *perrno = -EFAULT;
+ return I40E_NVMUPD_INVALID;
+ }
break;
case I40E_NVM_AQE:
upd_cmd = I40E_NVMUPD_GET_AQ_EVENT;
@@ -478,6 +478,7 @@ enum i40e_nvmupd_cmd {
I40E_NVMUPD_EXEC_AQ,
I40E_NVMUPD_GET_AQ_RESULT,
I40E_NVMUPD_GET_AQ_EVENT,
+ I40E_NVMUPD_FEATURES,
};
enum i40e_nvmupd_state {
@@ -513,6 +514,10 @@ enum i40e_nvmupd_state {
#define I40E_NVM_AQE 0xe
#define I40E_NVM_EXEC 0xf
+#define I40E_NVM_EXEC_GET_AQ_RESULT 0x0
+#define I40E_NVM_EXEC_FEATURES 0xe
+#define I40E_NVM_EXEC_STATUS 0xf
+
#define I40E_NVM_ADAPT_SHIFT 16
#define I40E_NVM_ADAPT_MASK (0xffffULL << I40E_NVM_ADAPT_SHIFT)
@@ -527,6 +532,20 @@ struct i40e_nvm_access {
u8 data[1];
};
+/* NVMUpdate features API */
+#define I40E_NVMUPD_FEATURES_API_VER_MAJOR 0
+#define I40E_NVMUPD_FEATURES_API_VER_MINOR 14
+#define I40E_NVMUPD_FEATURES_API_FEATURES_ARRAY_LEN 12
+
+#define I40E_NVMUPD_FEATURE_FLAT_NVM_SUPPORT BIT(0)
+
+struct i40e_nvmupd_features {
+ u8 major;
+ u8 minor;
+ u16 size;
+ u8 features[I40E_NVMUPD_FEATURES_API_FEATURES_ARRAY_LEN];
+};
+
/* (Q)SFP module access definitions */
#define I40E_I2C_EEPROM_DEV_ADDR 0xA0
#define I40E_I2C_EEPROM_DEV_ADDR2 0xA2
@@ -730,6 +749,9 @@ struct i40e_hw {
u16 first_tag;
u16 second_tag;
+ /* NVMUpdate features */
+ struct i40e_nvmupd_features nvmupd_features;
+
/* debug mask */
u32 debug_mask;
char err_str[16];