diff options
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_adminq.c | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_adminq.h | 36 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_common.c | 88 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 61 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_nvm.c | 511 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_prototype.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_type.h | 58 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_adminq.h | 36 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_type.h | 58 |
10 files changed, 866 insertions, 16 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 0e551f281d59..1e21fbb1359c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c | |||
@@ -38,8 +38,8 @@ static void i40e_resume_aq(struct i40e_hw *hw); | |||
38 | **/ | 38 | **/ |
39 | static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) | 39 | static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) |
40 | { | 40 | { |
41 | return (desc->opcode == i40e_aqc_opc_nvm_erase) || | 41 | return (desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_erase)) || |
42 | (desc->opcode == i40e_aqc_opc_nvm_update); | 42 | (desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_update)); |
43 | } | 43 | } |
44 | 44 | ||
45 | /** | 45 | /** |
@@ -889,9 +889,6 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, | |||
889 | hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; | 889 | hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; |
890 | } | 890 | } |
891 | 891 | ||
892 | if (i40e_is_nvm_update_op(desc)) | ||
893 | hw->aq.nvm_busy = true; | ||
894 | |||
895 | if (le16_to_cpu(desc->datalen) == buff_size) { | 892 | if (le16_to_cpu(desc->datalen) == buff_size) { |
896 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | 893 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, |
897 | "AQTX: desc and buffer writeback:\n"); | 894 | "AQTX: desc and buffer writeback:\n"); |
@@ -907,6 +904,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, | |||
907 | status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; | 904 | status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; |
908 | } | 905 | } |
909 | 906 | ||
907 | if (!status && i40e_is_nvm_update_op(desc)) | ||
908 | hw->aq.nvm_busy = true; | ||
909 | |||
910 | asq_send_command_error: | 910 | asq_send_command_error: |
911 | mutex_unlock(&hw->aq.asq_mutex); | 911 | mutex_unlock(&hw->aq.asq_mutex); |
912 | asq_send_command_exit: | 912 | asq_send_command_exit: |
@@ -988,9 +988,6 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, | |||
988 | e->msg_size); | 988 | e->msg_size); |
989 | } | 989 | } |
990 | 990 | ||
991 | if (i40e_is_nvm_update_op(&e->desc)) | ||
992 | hw->aq.nvm_busy = false; | ||
993 | |||
994 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); | 991 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); |
995 | i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf); | 992 | i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf); |
996 | 993 | ||
@@ -1023,6 +1020,14 @@ clean_arq_element_out: | |||
1023 | *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); | 1020 | *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); |
1024 | mutex_unlock(&hw->aq.arq_mutex); | 1021 | mutex_unlock(&hw->aq.arq_mutex); |
1025 | 1022 | ||
1023 | if (i40e_is_nvm_update_op(&e->desc)) { | ||
1024 | hw->aq.nvm_busy = false; | ||
1025 | if (hw->aq.nvm_release_on_done) { | ||
1026 | i40e_release_nvm(hw); | ||
1027 | hw->aq.nvm_release_on_done = false; | ||
1028 | } | ||
1029 | } | ||
1030 | |||
1026 | return ret_code; | 1031 | return ret_code; |
1027 | } | 1032 | } |
1028 | 1033 | ||
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index bb76be1d38f7..ba38a89c79d6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h | |||
@@ -94,6 +94,7 @@ struct i40e_adminq_info { | |||
94 | u16 api_maj_ver; /* api major version */ | 94 | u16 api_maj_ver; /* api major version */ |
95 | u16 api_min_ver; /* api minor version */ | 95 | u16 api_min_ver; /* api minor version */ |
96 | bool nvm_busy; | 96 | bool nvm_busy; |
97 | bool nvm_release_on_done; | ||
97 | 98 | ||
98 | struct mutex asq_mutex; /* Send queue lock */ | 99 | struct mutex asq_mutex; /* Send queue lock */ |
99 | struct mutex arq_mutex; /* Receive queue lock */ | 100 | struct mutex arq_mutex; /* Receive queue lock */ |
@@ -103,6 +104,41 @@ struct i40e_adminq_info { | |||
103 | enum i40e_admin_queue_err arq_last_status; | 104 | enum i40e_admin_queue_err arq_last_status; |
104 | }; | 105 | }; |
105 | 106 | ||
107 | /** | ||
108 | * i40e_aq_rc_to_posix - convert errors to user-land codes | ||
109 | * aq_rc: AdminQ error code to convert | ||
110 | **/ | ||
111 | static inline int i40e_aq_rc_to_posix(u16 aq_rc) | ||
112 | { | ||
113 | int aq_to_posix[] = { | ||
114 | 0, /* I40E_AQ_RC_OK */ | ||
115 | -EPERM, /* I40E_AQ_RC_EPERM */ | ||
116 | -ENOENT, /* I40E_AQ_RC_ENOENT */ | ||
117 | -ESRCH, /* I40E_AQ_RC_ESRCH */ | ||
118 | -EINTR, /* I40E_AQ_RC_EINTR */ | ||
119 | -EIO, /* I40E_AQ_RC_EIO */ | ||
120 | -ENXIO, /* I40E_AQ_RC_ENXIO */ | ||
121 | -E2BIG, /* I40E_AQ_RC_E2BIG */ | ||
122 | -EAGAIN, /* I40E_AQ_RC_EAGAIN */ | ||
123 | -ENOMEM, /* I40E_AQ_RC_ENOMEM */ | ||
124 | -EACCES, /* I40E_AQ_RC_EACCES */ | ||
125 | -EFAULT, /* I40E_AQ_RC_EFAULT */ | ||
126 | -EBUSY, /* I40E_AQ_RC_EBUSY */ | ||
127 | -EEXIST, /* I40E_AQ_RC_EEXIST */ | ||
128 | -EINVAL, /* I40E_AQ_RC_EINVAL */ | ||
129 | -ENOTTY, /* I40E_AQ_RC_ENOTTY */ | ||
130 | -ENOSPC, /* I40E_AQ_RC_ENOSPC */ | ||
131 | -ENOSYS, /* I40E_AQ_RC_ENOSYS */ | ||
132 | -ERANGE, /* I40E_AQ_RC_ERANGE */ | ||
133 | -EPIPE, /* I40E_AQ_RC_EFLUSHED */ | ||
134 | -ESPIPE, /* I40E_AQ_RC_BAD_ADDR */ | ||
135 | -EROFS, /* I40E_AQ_RC_EMODE */ | ||
136 | -EFBIG, /* I40E_AQ_RC_EFBIG */ | ||
137 | }; | ||
138 | |||
139 | return aq_to_posix[aq_rc]; | ||
140 | } | ||
141 | |||
106 | /* general information */ | 142 | /* general information */ |
107 | #define I40E_AQ_LARGE_BUF 512 | 143 | #define I40E_AQ_LARGE_BUF 512 |
108 | #define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */ | 144 | #define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */ |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index c65f4e8e6cee..f4e502a305ff 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c | |||
@@ -2121,6 +2121,47 @@ i40e_aq_read_nvm_exit: | |||
2121 | return status; | 2121 | return status; |
2122 | } | 2122 | } |
2123 | 2123 | ||
2124 | /** | ||
2125 | * i40e_aq_erase_nvm | ||
2126 | * @hw: pointer to the hw struct | ||
2127 | * @module_pointer: module pointer location in words from the NVM beginning | ||
2128 | * @offset: offset in the module (expressed in 4 KB from module's beginning) | ||
2129 | * @length: length of the section to be erased (expressed in 4 KB) | ||
2130 | * @last_command: tells if this is the last command in a series | ||
2131 | * @cmd_details: pointer to command details structure or NULL | ||
2132 | * | ||
2133 | * Erase the NVM sector using the admin queue commands | ||
2134 | **/ | ||
2135 | i40e_status i40e_aq_erase_nvm(struct i40e_hw *hw, u8 module_pointer, | ||
2136 | u32 offset, u16 length, bool last_command, | ||
2137 | struct i40e_asq_cmd_details *cmd_details) | ||
2138 | { | ||
2139 | struct i40e_aq_desc desc; | ||
2140 | struct i40e_aqc_nvm_update *cmd = | ||
2141 | (struct i40e_aqc_nvm_update *)&desc.params.raw; | ||
2142 | i40e_status status; | ||
2143 | |||
2144 | /* In offset the highest byte must be zeroed. */ | ||
2145 | if (offset & 0xFF000000) { | ||
2146 | status = I40E_ERR_PARAM; | ||
2147 | goto i40e_aq_erase_nvm_exit; | ||
2148 | } | ||
2149 | |||
2150 | i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_erase); | ||
2151 | |||
2152 | /* If this is the last command in a series, set the proper flag. */ | ||
2153 | if (last_command) | ||
2154 | cmd->command_flags |= I40E_AQ_NVM_LAST_CMD; | ||
2155 | cmd->module_pointer = module_pointer; | ||
2156 | cmd->offset = cpu_to_le32(offset); | ||
2157 | cmd->length = cpu_to_le16(length); | ||
2158 | |||
2159 | status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); | ||
2160 | |||
2161 | i40e_aq_erase_nvm_exit: | ||
2162 | return status; | ||
2163 | } | ||
2164 | |||
2124 | #define I40E_DEV_FUNC_CAP_SWITCH_MODE 0x01 | 2165 | #define I40E_DEV_FUNC_CAP_SWITCH_MODE 0x01 |
2125 | #define I40E_DEV_FUNC_CAP_MGMT_MODE 0x02 | 2166 | #define I40E_DEV_FUNC_CAP_MGMT_MODE 0x02 |
2126 | #define I40E_DEV_FUNC_CAP_NPAR 0x03 | 2167 | #define I40E_DEV_FUNC_CAP_NPAR 0x03 |
@@ -2351,6 +2392,53 @@ exit: | |||
2351 | } | 2392 | } |
2352 | 2393 | ||
2353 | /** | 2394 | /** |
2395 | * i40e_aq_update_nvm | ||
2396 | * @hw: pointer to the hw struct | ||
2397 | * @module_pointer: module pointer location in words from the NVM beginning | ||
2398 | * @offset: byte offset from the module beginning | ||
2399 | * @length: length of the section to be written (in bytes from the offset) | ||
2400 | * @data: command buffer (size [bytes] = length) | ||
2401 | * @last_command: tells if this is the last command in a series | ||
2402 | * @cmd_details: pointer to command details structure or NULL | ||
2403 | * | ||
2404 | * Update the NVM using the admin queue commands | ||
2405 | **/ | ||
2406 | i40e_status i40e_aq_update_nvm(struct i40e_hw *hw, u8 module_pointer, | ||
2407 | u32 offset, u16 length, void *data, | ||
2408 | bool last_command, | ||
2409 | struct i40e_asq_cmd_details *cmd_details) | ||
2410 | { | ||
2411 | struct i40e_aq_desc desc; | ||
2412 | struct i40e_aqc_nvm_update *cmd = | ||
2413 | (struct i40e_aqc_nvm_update *)&desc.params.raw; | ||
2414 | i40e_status status; | ||
2415 | |||
2416 | /* In offset the highest byte must be zeroed. */ | ||
2417 | if (offset & 0xFF000000) { | ||
2418 | status = I40E_ERR_PARAM; | ||
2419 | goto i40e_aq_update_nvm_exit; | ||
2420 | } | ||
2421 | |||
2422 | i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_update); | ||
2423 | |||
2424 | /* If this is the last command in a series, set the proper flag. */ | ||
2425 | if (last_command) | ||
2426 | cmd->command_flags |= I40E_AQ_NVM_LAST_CMD; | ||
2427 | cmd->module_pointer = module_pointer; | ||
2428 | cmd->offset = cpu_to_le32(offset); | ||
2429 | cmd->length = cpu_to_le16(length); | ||
2430 | |||
2431 | desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD)); | ||
2432 | if (length > I40E_AQ_LARGE_BUF) | ||
2433 | desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); | ||
2434 | |||
2435 | status = i40e_asq_send_command(hw, &desc, data, length, cmd_details); | ||
2436 | |||
2437 | i40e_aq_update_nvm_exit: | ||
2438 | return status; | ||
2439 | } | ||
2440 | |||
2441 | /** | ||
2354 | * i40e_aq_get_lldp_mib | 2442 | * i40e_aq_get_lldp_mib |
2355 | * @hw: pointer to the hw struct | 2443 | * @hw: pointer to the hw struct |
2356 | * @bridge_type: type of bridge requested | 2444 | * @bridge_type: type of bridge requested |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 3abd3cbab75f..f1d241ec1fc3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c | |||
@@ -759,10 +759,33 @@ static int i40e_get_eeprom(struct net_device *netdev, | |||
759 | u8 *eeprom_buff; | 759 | u8 *eeprom_buff; |
760 | u16 i, sectors; | 760 | u16 i, sectors; |
761 | bool last; | 761 | bool last; |
762 | u32 magic; | ||
763 | |||
762 | #define I40E_NVM_SECTOR_SIZE 4096 | 764 | #define I40E_NVM_SECTOR_SIZE 4096 |
763 | if (eeprom->len == 0) | 765 | if (eeprom->len == 0) |
764 | return -EINVAL; | 766 | return -EINVAL; |
765 | 767 | ||
768 | /* check for NVMUpdate access method */ | ||
769 | magic = hw->vendor_id | (hw->device_id << 16); | ||
770 | if (eeprom->magic && eeprom->magic != magic) { | ||
771 | int errno; | ||
772 | |||
773 | /* make sure it is the right magic for NVMUpdate */ | ||
774 | if ((eeprom->magic >> 16) != hw->device_id) | ||
775 | return -EINVAL; | ||
776 | |||
777 | ret_val = i40e_nvmupd_command(hw, | ||
778 | (struct i40e_nvm_access *)eeprom, | ||
779 | bytes, &errno); | ||
780 | if (ret_val) | ||
781 | dev_info(&pf->pdev->dev, | ||
782 | "NVMUpdate read failed err=%d status=0x%x\n", | ||
783 | ret_val, hw->aq.asq_last_status); | ||
784 | |||
785 | return errno; | ||
786 | } | ||
787 | |||
788 | /* normal ethtool get_eeprom support */ | ||
766 | eeprom->magic = hw->vendor_id | (hw->device_id << 16); | 789 | eeprom->magic = hw->vendor_id | (hw->device_id << 16); |
767 | 790 | ||
768 | eeprom_buff = kzalloc(eeprom->len, GFP_KERNEL); | 791 | eeprom_buff = kzalloc(eeprom->len, GFP_KERNEL); |
@@ -789,7 +812,7 @@ static int i40e_get_eeprom(struct net_device *netdev, | |||
789 | ret_val = i40e_aq_read_nvm(hw, 0x0, | 812 | ret_val = i40e_aq_read_nvm(hw, 0x0, |
790 | eeprom->offset + (I40E_NVM_SECTOR_SIZE * i), | 813 | eeprom->offset + (I40E_NVM_SECTOR_SIZE * i), |
791 | len, | 814 | len, |
792 | eeprom_buff + (I40E_NVM_SECTOR_SIZE * i), | 815 | (u8 *)eeprom_buff + (I40E_NVM_SECTOR_SIZE * i), |
793 | last, NULL); | 816 | last, NULL); |
794 | if (ret_val) { | 817 | if (ret_val) { |
795 | dev_info(&pf->pdev->dev, | 818 | dev_info(&pf->pdev->dev, |
@@ -801,7 +824,7 @@ static int i40e_get_eeprom(struct net_device *netdev, | |||
801 | 824 | ||
802 | release_nvm: | 825 | release_nvm: |
803 | i40e_release_nvm(hw); | 826 | i40e_release_nvm(hw); |
804 | memcpy(bytes, eeprom_buff, eeprom->len); | 827 | memcpy(bytes, (u8 *)eeprom_buff, eeprom->len); |
805 | free_buff: | 828 | free_buff: |
806 | kfree(eeprom_buff); | 829 | kfree(eeprom_buff); |
807 | return ret_val; | 830 | return ret_val; |
@@ -821,6 +844,39 @@ static int i40e_get_eeprom_len(struct net_device *netdev) | |||
821 | return val; | 844 | return val; |
822 | } | 845 | } |
823 | 846 | ||
847 | static int i40e_set_eeprom(struct net_device *netdev, | ||
848 | struct ethtool_eeprom *eeprom, u8 *bytes) | ||
849 | { | ||
850 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
851 | struct i40e_hw *hw = &np->vsi->back->hw; | ||
852 | struct i40e_pf *pf = np->vsi->back; | ||
853 | int ret_val = 0; | ||
854 | int errno; | ||
855 | u32 magic; | ||
856 | |||
857 | /* normal ethtool set_eeprom is not supported */ | ||
858 | magic = hw->vendor_id | (hw->device_id << 16); | ||
859 | if (eeprom->magic == magic) | ||
860 | return -EOPNOTSUPP; | ||
861 | |||
862 | /* check for NVMUpdate access method */ | ||
863 | if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id) | ||
864 | return -EINVAL; | ||
865 | |||
866 | if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) || | ||
867 | test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state)) | ||
868 | return -EBUSY; | ||
869 | |||
870 | ret_val = i40e_nvmupd_command(hw, (struct i40e_nvm_access *)eeprom, | ||
871 | bytes, &errno); | ||
872 | if (ret_val) | ||
873 | dev_info(&pf->pdev->dev, | ||
874 | "NVMUpdate write failed err=%d status=0x%x\n", | ||
875 | ret_val, hw->aq.asq_last_status); | ||
876 | |||
877 | return errno; | ||
878 | } | ||
879 | |||
824 | static void i40e_get_drvinfo(struct net_device *netdev, | 880 | static void i40e_get_drvinfo(struct net_device *netdev, |
825 | struct ethtool_drvinfo *drvinfo) | 881 | struct ethtool_drvinfo *drvinfo) |
826 | { | 882 | { |
@@ -2094,6 +2150,7 @@ static const struct ethtool_ops i40e_ethtool_ops = { | |||
2094 | .get_link = ethtool_op_get_link, | 2150 | .get_link = ethtool_op_get_link, |
2095 | .get_wol = i40e_get_wol, | 2151 | .get_wol = i40e_get_wol, |
2096 | .set_wol = i40e_set_wol, | 2152 | .set_wol = i40e_set_wol, |
2153 | .set_eeprom = i40e_set_eeprom, | ||
2097 | .get_eeprom_len = i40e_get_eeprom_len, | 2154 | .get_eeprom_len = i40e_get_eeprom_len, |
2098 | .get_eeprom = i40e_get_eeprom, | 2155 | .get_eeprom = i40e_get_eeprom, |
2099 | .get_ringparam = i40e_get_ringparam, | 2156 | .get_ringparam = i40e_get_ringparam, |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 66bcb15422da..97bda3dffd49 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c | |||
@@ -241,6 +241,46 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, | |||
241 | } | 241 | } |
242 | 242 | ||
243 | /** | 243 | /** |
244 | * i40e_write_nvm_aq - Writes Shadow RAM. | ||
245 | * @hw: pointer to the HW structure. | ||
246 | * @module_pointer: module pointer location in words from the NVM beginning | ||
247 | * @offset: offset in words from module start | ||
248 | * @words: number of words to write | ||
249 | * @data: buffer with words to write to the Shadow RAM | ||
250 | * @last_command: tells the AdminQ that this is the last command | ||
251 | * | ||
252 | * Writes a 16 bit words buffer to the Shadow RAM using the admin command. | ||
253 | **/ | ||
254 | i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, | ||
255 | u32 offset, u16 words, void *data, | ||
256 | bool last_command) | ||
257 | { | ||
258 | i40e_status ret_code = I40E_ERR_NVM; | ||
259 | |||
260 | /* Here we are checking the SR limit only for the flat memory model. | ||
261 | * We cannot do it for the module-based model, as we did not acquire | ||
262 | * the NVM resource yet (we cannot get the module pointer value). | ||
263 | * Firmware will check the module-based model. | ||
264 | */ | ||
265 | if ((offset + words) > hw->nvm.sr_size) | ||
266 | hw_dbg(hw, "NVM write error: offset beyond Shadow RAM limit.\n"); | ||
267 | else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) | ||
268 | /* We can write only up to 4KB (one sector), in one AQ write */ | ||
269 | hw_dbg(hw, "NVM write fail error: cannot write more than 4KB in a single write.\n"); | ||
270 | else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) | ||
271 | != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) | ||
272 | /* A single write cannot spread over two sectors */ | ||
273 | hw_dbg(hw, "NVM write error: cannot spread over two sectors in a single write.\n"); | ||
274 | else | ||
275 | ret_code = i40e_aq_update_nvm(hw, module_pointer, | ||
276 | 2 * offset, /*bytes*/ | ||
277 | 2 * words, /*bytes*/ | ||
278 | data, last_command, NULL); | ||
279 | |||
280 | return ret_code; | ||
281 | } | ||
282 | |||
283 | /** | ||
244 | * i40e_calc_nvm_checksum - Calculates and returns the checksum | 284 | * i40e_calc_nvm_checksum - Calculates and returns the checksum |
245 | * @hw: pointer to hardware structure | 285 | * @hw: pointer to hardware structure |
246 | * @checksum: pointer to the checksum | 286 | * @checksum: pointer to the checksum |
@@ -310,6 +350,27 @@ i40e_calc_nvm_checksum_exit: | |||
310 | } | 350 | } |
311 | 351 | ||
312 | /** | 352 | /** |
353 | * i40e_update_nvm_checksum - Updates the NVM checksum | ||
354 | * @hw: pointer to hardware structure | ||
355 | * | ||
356 | * NVM ownership must be acquired before calling this function and released | ||
357 | * on ARQ completion event reception by caller. | ||
358 | * This function will commit SR to NVM. | ||
359 | **/ | ||
360 | i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw) | ||
361 | { | ||
362 | i40e_status ret_code = 0; | ||
363 | u16 checksum; | ||
364 | |||
365 | ret_code = i40e_calc_nvm_checksum(hw, &checksum); | ||
366 | if (!ret_code) | ||
367 | ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, | ||
368 | 1, &checksum, true); | ||
369 | |||
370 | return ret_code; | ||
371 | } | ||
372 | |||
373 | /** | ||
313 | * i40e_validate_nvm_checksum - Validate EEPROM checksum | 374 | * i40e_validate_nvm_checksum - Validate EEPROM checksum |
314 | * @hw: pointer to hardware structure | 375 | * @hw: pointer to hardware structure |
315 | * @checksum: calculated checksum | 376 | * @checksum: calculated checksum |
@@ -346,3 +407,453 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, | |||
346 | i40e_validate_nvm_checksum_exit: | 407 | i40e_validate_nvm_checksum_exit: |
347 | return ret_code; | 408 | return ret_code; |
348 | } | 409 | } |
410 | |||
411 | static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, | ||
412 | struct i40e_nvm_access *cmd, | ||
413 | u8 *bytes, int *errno); | ||
414 | static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, | ||
415 | struct i40e_nvm_access *cmd, | ||
416 | u8 *bytes, int *errno); | ||
417 | static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, | ||
418 | struct i40e_nvm_access *cmd, | ||
419 | u8 *bytes, int *errno); | ||
420 | static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, | ||
421 | struct i40e_nvm_access *cmd, | ||
422 | int *errno); | ||
423 | static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, | ||
424 | struct i40e_nvm_access *cmd, | ||
425 | int *errno); | ||
426 | static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, | ||
427 | struct i40e_nvm_access *cmd, | ||
428 | u8 *bytes, int *errno); | ||
429 | static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, | ||
430 | struct i40e_nvm_access *cmd, | ||
431 | u8 *bytes, int *errno); | ||
432 | static inline u8 i40e_nvmupd_get_module(u32 val) | ||
433 | { | ||
434 | return (u8)(val & I40E_NVM_MOD_PNT_MASK); | ||
435 | } | ||
436 | static inline u8 i40e_nvmupd_get_transaction(u32 val) | ||
437 | { | ||
438 | return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT); | ||
439 | } | ||
440 | |||
441 | /** | ||
442 | * i40e_nvmupd_command - Process an NVM update command | ||
443 | * @hw: pointer to hardware structure | ||
444 | * @cmd: pointer to nvm update command | ||
445 | * @bytes: pointer to the data buffer | ||
446 | * @errno: pointer to return error code | ||
447 | * | ||
448 | * Dispatches command depending on what update state is current | ||
449 | **/ | ||
450 | i40e_status i40e_nvmupd_command(struct i40e_hw *hw, | ||
451 | struct i40e_nvm_access *cmd, | ||
452 | u8 *bytes, int *errno) | ||
453 | { | ||
454 | i40e_status status; | ||
455 | |||
456 | /* assume success */ | ||
457 | *errno = 0; | ||
458 | |||
459 | switch (hw->nvmupd_state) { | ||
460 | case I40E_NVMUPD_STATE_INIT: | ||
461 | status = i40e_nvmupd_state_init(hw, cmd, bytes, errno); | ||
462 | break; | ||
463 | |||
464 | case I40E_NVMUPD_STATE_READING: | ||
465 | status = i40e_nvmupd_state_reading(hw, cmd, bytes, errno); | ||
466 | break; | ||
467 | |||
468 | case I40E_NVMUPD_STATE_WRITING: | ||
469 | status = i40e_nvmupd_state_writing(hw, cmd, bytes, errno); | ||
470 | break; | ||
471 | |||
472 | default: | ||
473 | /* invalid state, should never happen */ | ||
474 | status = I40E_NOT_SUPPORTED; | ||
475 | *errno = -ESRCH; | ||
476 | break; | ||
477 | } | ||
478 | return status; | ||
479 | } | ||
480 | |||
481 | /** | ||
482 | * i40e_nvmupd_state_init - Handle NVM update state Init | ||
483 | * @hw: pointer to hardware structure | ||
484 | * @cmd: pointer to nvm update command buffer | ||
485 | * @bytes: pointer to the data buffer | ||
486 | * @errno: pointer to return error code | ||
487 | * | ||
488 | * Process legitimate commands of the Init state and conditionally set next | ||
489 | * state. Reject all other commands. | ||
490 | **/ | ||
491 | static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, | ||
492 | struct i40e_nvm_access *cmd, | ||
493 | u8 *bytes, int *errno) | ||
494 | { | ||
495 | i40e_status status = 0; | ||
496 | enum i40e_nvmupd_cmd upd_cmd; | ||
497 | |||
498 | upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); | ||
499 | |||
500 | switch (upd_cmd) { | ||
501 | case I40E_NVMUPD_READ_SA: | ||
502 | status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); | ||
503 | if (status) { | ||
504 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
505 | } else { | ||
506 | status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); | ||
507 | i40e_release_nvm(hw); | ||
508 | } | ||
509 | break; | ||
510 | |||
511 | case I40E_NVMUPD_READ_SNT: | ||
512 | status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); | ||
513 | if (status) { | ||
514 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
515 | } else { | ||
516 | status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); | ||
517 | hw->nvmupd_state = I40E_NVMUPD_STATE_READING; | ||
518 | } | ||
519 | break; | ||
520 | |||
521 | case I40E_NVMUPD_WRITE_ERA: | ||
522 | status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); | ||
523 | if (status) { | ||
524 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
525 | } else { | ||
526 | status = i40e_nvmupd_nvm_erase(hw, cmd, errno); | ||
527 | if (status) | ||
528 | i40e_release_nvm(hw); | ||
529 | else | ||
530 | hw->aq.nvm_release_on_done = true; | ||
531 | } | ||
532 | break; | ||
533 | |||
534 | case I40E_NVMUPD_WRITE_SA: | ||
535 | status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); | ||
536 | if (status) { | ||
537 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
538 | } else { | ||
539 | status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); | ||
540 | if (status) | ||
541 | i40e_release_nvm(hw); | ||
542 | else | ||
543 | hw->aq.nvm_release_on_done = true; | ||
544 | } | ||
545 | break; | ||
546 | |||
547 | case I40E_NVMUPD_WRITE_SNT: | ||
548 | status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); | ||
549 | if (status) { | ||
550 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
551 | } else { | ||
552 | status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); | ||
553 | hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING; | ||
554 | } | ||
555 | break; | ||
556 | |||
557 | case I40E_NVMUPD_CSUM_SA: | ||
558 | status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); | ||
559 | if (status) { | ||
560 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
561 | } else { | ||
562 | status = i40e_update_nvm_checksum(hw); | ||
563 | if (status) { | ||
564 | *errno = hw->aq.asq_last_status ? | ||
565 | i40e_aq_rc_to_posix(hw->aq.asq_last_status) : | ||
566 | -EIO; | ||
567 | i40e_release_nvm(hw); | ||
568 | } else { | ||
569 | hw->aq.nvm_release_on_done = true; | ||
570 | } | ||
571 | } | ||
572 | break; | ||
573 | |||
574 | default: | ||
575 | status = I40E_ERR_NVM; | ||
576 | *errno = -ESRCH; | ||
577 | break; | ||
578 | } | ||
579 | return status; | ||
580 | } | ||
581 | |||
582 | /** | ||
583 | * i40e_nvmupd_state_reading - Handle NVM update state Reading | ||
584 | * @hw: pointer to hardware structure | ||
585 | * @cmd: pointer to nvm update command buffer | ||
586 | * @bytes: pointer to the data buffer | ||
587 | * @errno: pointer to return error code | ||
588 | * | ||
589 | * NVM ownership is already held. Process legitimate commands and set any | ||
590 | * change in state; reject all other commands. | ||
591 | **/ | ||
592 | static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, | ||
593 | struct i40e_nvm_access *cmd, | ||
594 | u8 *bytes, int *errno) | ||
595 | { | ||
596 | i40e_status status; | ||
597 | enum i40e_nvmupd_cmd upd_cmd; | ||
598 | |||
599 | upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); | ||
600 | |||
601 | switch (upd_cmd) { | ||
602 | case I40E_NVMUPD_READ_SA: | ||
603 | case I40E_NVMUPD_READ_CON: | ||
604 | status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); | ||
605 | break; | ||
606 | |||
607 | case I40E_NVMUPD_READ_LCB: | ||
608 | status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); | ||
609 | i40e_release_nvm(hw); | ||
610 | hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; | ||
611 | break; | ||
612 | |||
613 | default: | ||
614 | status = I40E_NOT_SUPPORTED; | ||
615 | *errno = -ESRCH; | ||
616 | break; | ||
617 | } | ||
618 | return status; | ||
619 | } | ||
620 | |||
621 | /** | ||
622 | * i40e_nvmupd_state_writing - Handle NVM update state Writing | ||
623 | * @hw: pointer to hardware structure | ||
624 | * @cmd: pointer to nvm update command buffer | ||
625 | * @bytes: pointer to the data buffer | ||
626 | * @errno: pointer to return error code | ||
627 | * | ||
628 | * NVM ownership is already held. Process legitimate commands and set any | ||
629 | * change in state; reject all other commands | ||
630 | **/ | ||
631 | static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, | ||
632 | struct i40e_nvm_access *cmd, | ||
633 | u8 *bytes, int *errno) | ||
634 | { | ||
635 | i40e_status status; | ||
636 | enum i40e_nvmupd_cmd upd_cmd; | ||
637 | |||
638 | upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); | ||
639 | |||
640 | switch (upd_cmd) { | ||
641 | case I40E_NVMUPD_WRITE_CON: | ||
642 | status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); | ||
643 | break; | ||
644 | |||
645 | case I40E_NVMUPD_WRITE_LCB: | ||
646 | status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); | ||
647 | if (!status) { | ||
648 | hw->aq.nvm_release_on_done = true; | ||
649 | hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; | ||
650 | } | ||
651 | break; | ||
652 | |||
653 | case I40E_NVMUPD_CSUM_CON: | ||
654 | status = i40e_update_nvm_checksum(hw); | ||
655 | if (status) | ||
656 | *errno = hw->aq.asq_last_status ? | ||
657 | i40e_aq_rc_to_posix(hw->aq.asq_last_status) : | ||
658 | -EIO; | ||
659 | break; | ||
660 | |||
661 | case I40E_NVMUPD_CSUM_LCB: | ||
662 | status = i40e_update_nvm_checksum(hw); | ||
663 | if (status) { | ||
664 | *errno = hw->aq.asq_last_status ? | ||
665 | i40e_aq_rc_to_posix(hw->aq.asq_last_status) : | ||
666 | -EIO; | ||
667 | } else { | ||
668 | hw->aq.nvm_release_on_done = true; | ||
669 | hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; | ||
670 | } | ||
671 | break; | ||
672 | |||
673 | default: | ||
674 | status = I40E_NOT_SUPPORTED; | ||
675 | *errno = -ESRCH; | ||
676 | break; | ||
677 | } | ||
678 | return status; | ||
679 | } | ||
680 | |||
681 | /** | ||
682 | * i40e_nvmupd_validate_command - Validate given command | ||
683 | * @hw: pointer to hardware structure | ||
684 | * @cmd: pointer to nvm update command buffer | ||
685 | * @errno: pointer to return error code | ||
686 | * | ||
687 | * Return one of the valid command types or I40E_NVMUPD_INVALID | ||
688 | **/ | ||
689 | static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, | ||
690 | struct i40e_nvm_access *cmd, | ||
691 | int *errno) | ||
692 | { | ||
693 | enum i40e_nvmupd_cmd upd_cmd; | ||
694 | u8 transaction, module; | ||
695 | |||
696 | /* anything that doesn't match a recognized case is an error */ | ||
697 | upd_cmd = I40E_NVMUPD_INVALID; | ||
698 | |||
699 | transaction = i40e_nvmupd_get_transaction(cmd->config); | ||
700 | module = i40e_nvmupd_get_module(cmd->config); | ||
701 | |||
702 | /* limits on data size */ | ||
703 | if ((cmd->data_size < 1) || | ||
704 | (cmd->data_size > I40E_NVMUPD_MAX_DATA)) { | ||
705 | hw_dbg(hw, "i40e_nvmupd_validate_command data_size %d\n", | ||
706 | cmd->data_size); | ||
707 | *errno = -EFAULT; | ||
708 | return I40E_NVMUPD_INVALID; | ||
709 | } | ||
710 | |||
711 | switch (cmd->command) { | ||
712 | case I40E_NVM_READ: | ||
713 | switch (transaction) { | ||
714 | case I40E_NVM_CON: | ||
715 | upd_cmd = I40E_NVMUPD_READ_CON; | ||
716 | break; | ||
717 | case I40E_NVM_SNT: | ||
718 | upd_cmd = I40E_NVMUPD_READ_SNT; | ||
719 | break; | ||
720 | case I40E_NVM_LCB: | ||
721 | upd_cmd = I40E_NVMUPD_READ_LCB; | ||
722 | break; | ||
723 | case I40E_NVM_SA: | ||
724 | upd_cmd = I40E_NVMUPD_READ_SA; | ||
725 | break; | ||
726 | } | ||
727 | break; | ||
728 | |||
729 | case I40E_NVM_WRITE: | ||
730 | switch (transaction) { | ||
731 | case I40E_NVM_CON: | ||
732 | upd_cmd = I40E_NVMUPD_WRITE_CON; | ||
733 | break; | ||
734 | case I40E_NVM_SNT: | ||
735 | upd_cmd = I40E_NVMUPD_WRITE_SNT; | ||
736 | break; | ||
737 | case I40E_NVM_LCB: | ||
738 | upd_cmd = I40E_NVMUPD_WRITE_LCB; | ||
739 | break; | ||
740 | case I40E_NVM_SA: | ||
741 | upd_cmd = I40E_NVMUPD_WRITE_SA; | ||
742 | break; | ||
743 | case I40E_NVM_ERA: | ||
744 | upd_cmd = I40E_NVMUPD_WRITE_ERA; | ||
745 | break; | ||
746 | case I40E_NVM_CSUM: | ||
747 | upd_cmd = I40E_NVMUPD_CSUM_CON; | ||
748 | break; | ||
749 | case (I40E_NVM_CSUM|I40E_NVM_SA): | ||
750 | upd_cmd = I40E_NVMUPD_CSUM_SA; | ||
751 | break; | ||
752 | case (I40E_NVM_CSUM|I40E_NVM_LCB): | ||
753 | upd_cmd = I40E_NVMUPD_CSUM_LCB; | ||
754 | break; | ||
755 | } | ||
756 | break; | ||
757 | } | ||
758 | |||
759 | if (upd_cmd == I40E_NVMUPD_INVALID) { | ||
760 | *errno = -EFAULT; | ||
761 | hw_dbg(hw, | ||
762 | "i40e_nvmupd_validate_command returns %d errno: %d\n", | ||
763 | upd_cmd, *errno); | ||
764 | } | ||
765 | return upd_cmd; | ||
766 | } | ||
767 | |||
768 | /** | ||
769 | * i40e_nvmupd_nvm_read - Read NVM | ||
770 | * @hw: pointer to hardware structure | ||
771 | * @cmd: pointer to nvm update command buffer | ||
772 | * @bytes: pointer to the data buffer | ||
773 | * @errno: pointer to return error code | ||
774 | * | ||
775 | * cmd structure contains identifiers and data buffer | ||
776 | **/ | ||
777 | static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, | ||
778 | struct i40e_nvm_access *cmd, | ||
779 | u8 *bytes, int *errno) | ||
780 | { | ||
781 | i40e_status status; | ||
782 | u8 module, transaction; | ||
783 | bool last; | ||
784 | |||
785 | transaction = i40e_nvmupd_get_transaction(cmd->config); | ||
786 | module = i40e_nvmupd_get_module(cmd->config); | ||
787 | last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA); | ||
788 | hw_dbg(hw, "i40e_nvmupd_nvm_read mod 0x%x off 0x%x len 0x%x\n", | ||
789 | module, cmd->offset, cmd->data_size); | ||
790 | |||
791 | status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size, | ||
792 | bytes, last, NULL); | ||
793 | hw_dbg(hw, "i40e_nvmupd_nvm_read status %d\n", status); | ||
794 | if (status) | ||
795 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
796 | |||
797 | return status; | ||
798 | } | ||
799 | |||
800 | /** | ||
801 | * i40e_nvmupd_nvm_erase - Erase an NVM module | ||
802 | * @hw: pointer to hardware structure | ||
803 | * @cmd: pointer to nvm update command buffer | ||
804 | * @errno: pointer to return error code | ||
805 | * | ||
806 | * module, offset, data_size and data are in cmd structure | ||
807 | **/ | ||
808 | static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, | ||
809 | struct i40e_nvm_access *cmd, | ||
810 | int *errno) | ||
811 | { | ||
812 | i40e_status status = 0; | ||
813 | u8 module, transaction; | ||
814 | bool last; | ||
815 | |||
816 | transaction = i40e_nvmupd_get_transaction(cmd->config); | ||
817 | module = i40e_nvmupd_get_module(cmd->config); | ||
818 | last = (transaction & I40E_NVM_LCB); | ||
819 | hw_dbg(hw, "i40e_nvmupd_nvm_erase mod 0x%x off 0x%x len 0x%x\n", | ||
820 | module, cmd->offset, cmd->data_size); | ||
821 | status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size, | ||
822 | last, NULL); | ||
823 | hw_dbg(hw, "i40e_nvmupd_nvm_erase status %d\n", status); | ||
824 | if (status) | ||
825 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
826 | |||
827 | return status; | ||
828 | } | ||
829 | |||
830 | /** | ||
831 | * i40e_nvmupd_nvm_write - Write NVM | ||
832 | * @hw: pointer to hardware structure | ||
833 | * @cmd: pointer to nvm update command buffer | ||
834 | * @bytes: pointer to the data buffer | ||
835 | * @errno: pointer to return error code | ||
836 | * | ||
837 | * module, offset, data_size and data are in cmd structure | ||
838 | **/ | ||
839 | static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, | ||
840 | struct i40e_nvm_access *cmd, | ||
841 | u8 *bytes, int *errno) | ||
842 | { | ||
843 | i40e_status status = 0; | ||
844 | u8 module, transaction; | ||
845 | bool last; | ||
846 | |||
847 | transaction = i40e_nvmupd_get_transaction(cmd->config); | ||
848 | module = i40e_nvmupd_get_module(cmd->config); | ||
849 | last = (transaction & I40E_NVM_LCB); | ||
850 | hw_dbg(hw, "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n", | ||
851 | module, cmd->offset, cmd->data_size); | ||
852 | status = i40e_aq_update_nvm(hw, module, cmd->offset, | ||
853 | (u16)cmd->data_size, bytes, last, NULL); | ||
854 | hw_dbg(hw, "i40e_nvmupd_nvm_write status %d\n", status); | ||
855 | if (status) | ||
856 | *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); | ||
857 | |||
858 | return status; | ||
859 | } | ||
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 9383f08ff4e3..a91d7e1a5b5b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h | |||
@@ -150,6 +150,9 @@ i40e_status i40e_aq_read_nvm(struct i40e_hw *hw, u8 module_pointer, | |||
150 | u32 offset, u16 length, void *data, | 150 | u32 offset, u16 length, void *data, |
151 | bool last_command, | 151 | bool last_command, |
152 | struct i40e_asq_cmd_details *cmd_details); | 152 | struct i40e_asq_cmd_details *cmd_details); |
153 | i40e_status i40e_aq_erase_nvm(struct i40e_hw *hw, u8 module_pointer, | ||
154 | u32 offset, u16 length, bool last_command, | ||
155 | struct i40e_asq_cmd_details *cmd_details); | ||
153 | i40e_status i40e_aq_discover_capabilities(struct i40e_hw *hw, | 156 | i40e_status i40e_aq_discover_capabilities(struct i40e_hw *hw, |
154 | void *buff, u16 buff_size, u16 *data_size, | 157 | void *buff, u16 buff_size, u16 *data_size, |
155 | enum i40e_admin_queue_opc list_type_opc, | 158 | enum i40e_admin_queue_opc list_type_opc, |
@@ -245,8 +248,12 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, | |||
245 | u16 *data); | 248 | u16 *data); |
246 | i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, | 249 | i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, |
247 | u16 *words, u16 *data); | 250 | u16 *words, u16 *data); |
251 | i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw); | ||
248 | i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, | 252 | i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, |
249 | u16 *checksum); | 253 | u16 *checksum); |
254 | i40e_status i40e_nvmupd_command(struct i40e_hw *hw, | ||
255 | struct i40e_nvm_access *cmd, | ||
256 | u8 *bytes, int *); | ||
250 | void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status); | 257 | void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status); |
251 | 258 | ||
252 | extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; | 259 | extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 1fcf2205ffe6..8bb9049191cb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h | |||
@@ -269,6 +269,61 @@ struct i40e_nvm_info { | |||
269 | u32 eetrack; /* NVM data version */ | 269 | u32 eetrack; /* NVM data version */ |
270 | }; | 270 | }; |
271 | 271 | ||
272 | /* definitions used in NVM update support */ | ||
273 | |||
274 | enum i40e_nvmupd_cmd { | ||
275 | I40E_NVMUPD_INVALID, | ||
276 | I40E_NVMUPD_READ_CON, | ||
277 | I40E_NVMUPD_READ_SNT, | ||
278 | I40E_NVMUPD_READ_LCB, | ||
279 | I40E_NVMUPD_READ_SA, | ||
280 | I40E_NVMUPD_WRITE_ERA, | ||
281 | I40E_NVMUPD_WRITE_CON, | ||
282 | I40E_NVMUPD_WRITE_SNT, | ||
283 | I40E_NVMUPD_WRITE_LCB, | ||
284 | I40E_NVMUPD_WRITE_SA, | ||
285 | I40E_NVMUPD_CSUM_CON, | ||
286 | I40E_NVMUPD_CSUM_SA, | ||
287 | I40E_NVMUPD_CSUM_LCB, | ||
288 | }; | ||
289 | |||
290 | enum i40e_nvmupd_state { | ||
291 | I40E_NVMUPD_STATE_INIT, | ||
292 | I40E_NVMUPD_STATE_READING, | ||
293 | I40E_NVMUPD_STATE_WRITING | ||
294 | }; | ||
295 | |||
296 | /* nvm_access definition and its masks/shifts need to be accessible to | ||
297 | * application, core driver, and shared code. Where is the right file? | ||
298 | */ | ||
299 | #define I40E_NVM_READ 0xB | ||
300 | #define I40E_NVM_WRITE 0xC | ||
301 | |||
302 | #define I40E_NVM_MOD_PNT_MASK 0xFF | ||
303 | |||
304 | #define I40E_NVM_TRANS_SHIFT 8 | ||
305 | #define I40E_NVM_TRANS_MASK (0xf << I40E_NVM_TRANS_SHIFT) | ||
306 | #define I40E_NVM_CON 0x0 | ||
307 | #define I40E_NVM_SNT 0x1 | ||
308 | #define I40E_NVM_LCB 0x2 | ||
309 | #define I40E_NVM_SA (I40E_NVM_SNT | I40E_NVM_LCB) | ||
310 | #define I40E_NVM_ERA 0x4 | ||
311 | #define I40E_NVM_CSUM 0x8 | ||
312 | |||
313 | #define I40E_NVM_ADAPT_SHIFT 16 | ||
314 | #define I40E_NVM_ADAPT_MASK (0xffff << I40E_NVM_ADAPT_SHIFT) | ||
315 | |||
316 | #define I40E_NVMUPD_MAX_DATA 4096 | ||
317 | #define I40E_NVMUPD_IFACE_TIMEOUT 2 /* seconds */ | ||
318 | |||
319 | struct i40e_nvm_access { | ||
320 | u32 command; | ||
321 | u32 config; | ||
322 | u32 offset; /* in bytes */ | ||
323 | u32 data_size; /* in bytes */ | ||
324 | u8 data[1]; | ||
325 | }; | ||
326 | |||
272 | /* PCI bus types */ | 327 | /* PCI bus types */ |
273 | enum i40e_bus_type { | 328 | enum i40e_bus_type { |
274 | i40e_bus_type_unknown = 0, | 329 | i40e_bus_type_unknown = 0, |
@@ -404,6 +459,9 @@ struct i40e_hw { | |||
404 | /* Admin Queue info */ | 459 | /* Admin Queue info */ |
405 | struct i40e_adminq_info aq; | 460 | struct i40e_adminq_info aq; |
406 | 461 | ||
462 | /* state of nvm update process */ | ||
463 | enum i40e_nvmupd_state nvmupd_state; | ||
464 | |||
407 | /* HMC info */ | 465 | /* HMC info */ |
408 | struct i40e_hmc_info hmc; /* HMC info struct */ | 466 | struct i40e_hmc_info hmc; /* HMC info struct */ |
409 | 467 | ||
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 8330744b02f1..ee3a934043bb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c | |||
@@ -708,12 +708,6 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, | |||
708 | goto asq_send_command_exit; | 708 | goto asq_send_command_exit; |
709 | } | 709 | } |
710 | 710 | ||
711 | if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) { | ||
712 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n"); | ||
713 | status = I40E_ERR_NVM; | ||
714 | goto asq_send_command_exit; | ||
715 | } | ||
716 | |||
717 | details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); | 711 | details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); |
718 | if (cmd_details) { | 712 | if (cmd_details) { |
719 | *details = *cmd_details; | 713 | *details = *cmd_details; |
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index 162845589bf7..91a5c5bd80f3 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h | |||
@@ -94,6 +94,7 @@ struct i40e_adminq_info { | |||
94 | u16 api_maj_ver; /* api major version */ | 94 | u16 api_maj_ver; /* api major version */ |
95 | u16 api_min_ver; /* api minor version */ | 95 | u16 api_min_ver; /* api minor version */ |
96 | bool nvm_busy; | 96 | bool nvm_busy; |
97 | bool nvm_release_on_done; | ||
97 | 98 | ||
98 | struct mutex asq_mutex; /* Send queue lock */ | 99 | struct mutex asq_mutex; /* Send queue lock */ |
99 | struct mutex arq_mutex; /* Receive queue lock */ | 100 | struct mutex arq_mutex; /* Receive queue lock */ |
@@ -103,6 +104,41 @@ struct i40e_adminq_info { | |||
103 | enum i40e_admin_queue_err arq_last_status; | 104 | enum i40e_admin_queue_err arq_last_status; |
104 | }; | 105 | }; |
105 | 106 | ||
107 | /** | ||
108 | * i40e_aq_rc_to_posix - convert errors to user-land codes | ||
109 | * aq_rc: AdminQ error code to convert | ||
110 | **/ | ||
111 | static inline int i40e_aq_rc_to_posix(u16 aq_rc) | ||
112 | { | ||
113 | int aq_to_posix[] = { | ||
114 | 0, /* I40E_AQ_RC_OK */ | ||
115 | -EPERM, /* I40E_AQ_RC_EPERM */ | ||
116 | -ENOENT, /* I40E_AQ_RC_ENOENT */ | ||
117 | -ESRCH, /* I40E_AQ_RC_ESRCH */ | ||
118 | -EINTR, /* I40E_AQ_RC_EINTR */ | ||
119 | -EIO, /* I40E_AQ_RC_EIO */ | ||
120 | -ENXIO, /* I40E_AQ_RC_ENXIO */ | ||
121 | -E2BIG, /* I40E_AQ_RC_E2BIG */ | ||
122 | -EAGAIN, /* I40E_AQ_RC_EAGAIN */ | ||
123 | -ENOMEM, /* I40E_AQ_RC_ENOMEM */ | ||
124 | -EACCES, /* I40E_AQ_RC_EACCES */ | ||
125 | -EFAULT, /* I40E_AQ_RC_EFAULT */ | ||
126 | -EBUSY, /* I40E_AQ_RC_EBUSY */ | ||
127 | -EEXIST, /* I40E_AQ_RC_EEXIST */ | ||
128 | -EINVAL, /* I40E_AQ_RC_EINVAL */ | ||
129 | -ENOTTY, /* I40E_AQ_RC_ENOTTY */ | ||
130 | -ENOSPC, /* I40E_AQ_RC_ENOSPC */ | ||
131 | -ENOSYS, /* I40E_AQ_RC_ENOSYS */ | ||
132 | -ERANGE, /* I40E_AQ_RC_ERANGE */ | ||
133 | -EPIPE, /* I40E_AQ_RC_EFLUSHED */ | ||
134 | -ESPIPE, /* I40E_AQ_RC_BAD_ADDR */ | ||
135 | -EROFS, /* I40E_AQ_RC_EMODE */ | ||
136 | -EFBIG, /* I40E_AQ_RC_EFBIG */ | ||
137 | }; | ||
138 | |||
139 | return aq_to_posix[aq_rc]; | ||
140 | } | ||
141 | |||
106 | /* general information */ | 142 | /* general information */ |
107 | #define I40E_AQ_LARGE_BUF 512 | 143 | #define I40E_AQ_LARGE_BUF 512 |
108 | #define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */ | 144 | #define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */ |
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 6dd72ad58e7d..15376436cead 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h | |||
@@ -268,6 +268,61 @@ struct i40e_nvm_info { | |||
268 | u32 eetrack; /* NVM data version */ | 268 | u32 eetrack; /* NVM data version */ |
269 | }; | 269 | }; |
270 | 270 | ||
271 | /* definitions used in NVM update support */ | ||
272 | |||
273 | enum i40e_nvmupd_cmd { | ||
274 | I40E_NVMUPD_INVALID, | ||
275 | I40E_NVMUPD_READ_CON, | ||
276 | I40E_NVMUPD_READ_SNT, | ||
277 | I40E_NVMUPD_READ_LCB, | ||
278 | I40E_NVMUPD_READ_SA, | ||
279 | I40E_NVMUPD_WRITE_ERA, | ||
280 | I40E_NVMUPD_WRITE_CON, | ||
281 | I40E_NVMUPD_WRITE_SNT, | ||
282 | I40E_NVMUPD_WRITE_LCB, | ||
283 | I40E_NVMUPD_WRITE_SA, | ||
284 | I40E_NVMUPD_CSUM_CON, | ||
285 | I40E_NVMUPD_CSUM_SA, | ||
286 | I40E_NVMUPD_CSUM_LCB, | ||
287 | }; | ||
288 | |||
289 | enum i40e_nvmupd_state { | ||
290 | I40E_NVMUPD_STATE_INIT, | ||
291 | I40E_NVMUPD_STATE_READING, | ||
292 | I40E_NVMUPD_STATE_WRITING | ||
293 | }; | ||
294 | |||
295 | /* nvm_access definition and its masks/shifts need to be accessible to | ||
296 | * application, core driver, and shared code. Where is the right file? | ||
297 | */ | ||
298 | #define I40E_NVM_READ 0xB | ||
299 | #define I40E_NVM_WRITE 0xC | ||
300 | |||
301 | #define I40E_NVM_MOD_PNT_MASK 0xFF | ||
302 | |||
303 | #define I40E_NVM_TRANS_SHIFT 8 | ||
304 | #define I40E_NVM_TRANS_MASK (0xf << I40E_NVM_TRANS_SHIFT) | ||
305 | #define I40E_NVM_CON 0x0 | ||
306 | #define I40E_NVM_SNT 0x1 | ||
307 | #define I40E_NVM_LCB 0x2 | ||
308 | #define I40E_NVM_SA (I40E_NVM_SNT | I40E_NVM_LCB) | ||
309 | #define I40E_NVM_ERA 0x4 | ||
310 | #define I40E_NVM_CSUM 0x8 | ||
311 | |||
312 | #define I40E_NVM_ADAPT_SHIFT 16 | ||
313 | #define I40E_NVM_ADAPT_MASK (0xffff << I40E_NVM_ADAPT_SHIFT) | ||
314 | |||
315 | #define I40E_NVMUPD_MAX_DATA 4096 | ||
316 | #define I40E_NVMUPD_IFACE_TIMEOUT 2 /* seconds */ | ||
317 | |||
318 | struct i40e_nvm_access { | ||
319 | u32 command; | ||
320 | u32 config; | ||
321 | u32 offset; /* in bytes */ | ||
322 | u32 data_size; /* in bytes */ | ||
323 | u8 data[1]; | ||
324 | }; | ||
325 | |||
271 | /* PCI bus types */ | 326 | /* PCI bus types */ |
272 | enum i40e_bus_type { | 327 | enum i40e_bus_type { |
273 | i40e_bus_type_unknown = 0, | 328 | i40e_bus_type_unknown = 0, |
@@ -403,6 +458,9 @@ struct i40e_hw { | |||
403 | /* Admin Queue info */ | 458 | /* Admin Queue info */ |
404 | struct i40e_adminq_info aq; | 459 | struct i40e_adminq_info aq; |
405 | 460 | ||
461 | /* state of nvm update process */ | ||
462 | enum i40e_nvmupd_state nvmupd_state; | ||
463 | |||
406 | /* HMC info */ | 464 | /* HMC info */ |
407 | struct i40e_hmc_info hmc; /* HMC info struct */ | 465 | struct i40e_hmc_info hmc; /* HMC info struct */ |
408 | 466 | ||