diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
19 files changed, 512 insertions, 234 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index f98baaba0c2..56f41c9409d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -1189,6 +1189,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) | |||
1189 | 1189 | ||
1190 | memcpy(&rxon, &ctx->active, sizeof(rxon)); | 1190 | memcpy(&rxon, &ctx->active, sizeof(rxon)); |
1191 | 1191 | ||
1192 | priv->ucode_loaded = false; | ||
1192 | iwl_trans_stop_device(trans(priv)); | 1193 | iwl_trans_stop_device(trans(priv)); |
1193 | 1194 | ||
1194 | priv->wowlan = true; | 1195 | priv->wowlan = true; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index cc0227c1f35..44c6f712b77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c | |||
@@ -671,7 +671,7 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, | |||
671 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, | 671 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, |
672 | test_bit(STATUS_RF_KILL_HW, &priv->status)); | 672 | test_bit(STATUS_RF_KILL_HW, &priv->status)); |
673 | else | 673 | else |
674 | wake_up(&priv->shrd->wait_command_queue); | 674 | wake_up(&trans(priv)->wait_command_queue); |
675 | return 0; | 675 | return 0; |
676 | } | 676 | } |
677 | 677 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 36909077f99..2e1a31797a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |||
@@ -822,7 +822,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, | |||
822 | 822 | ||
823 | if (changes & BSS_CHANGED_ASSOC) { | 823 | if (changes & BSS_CHANGED_ASSOC) { |
824 | if (bss_conf->assoc) { | 824 | if (bss_conf->assoc) { |
825 | priv->timestamp = bss_conf->timestamp; | 825 | priv->timestamp = bss_conf->last_tsf; |
826 | ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; | 826 | ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; |
827 | } else { | 827 | } else { |
828 | /* | 828 | /* |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 28422c03d67..f1226dbf789 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -816,6 +816,7 @@ void iwl_down(struct iwl_priv *priv) | |||
816 | if (priv->mac80211_registered) | 816 | if (priv->mac80211_registered) |
817 | ieee80211_stop_queues(priv->hw); | 817 | ieee80211_stop_queues(priv->hw); |
818 | 818 | ||
819 | priv->ucode_loaded = false; | ||
819 | iwl_trans_stop_device(trans(priv)); | 820 | iwl_trans_stop_device(trans(priv)); |
820 | 821 | ||
821 | /* Clear out all status bits but a few that are stable across reset */ | 822 | /* Clear out all status bits but a few that are stable across reset */ |
@@ -962,8 +963,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
962 | { | 963 | { |
963 | priv->workqueue = create_singlethread_workqueue(DRV_NAME); | 964 | priv->workqueue = create_singlethread_workqueue(DRV_NAME); |
964 | 965 | ||
965 | init_waitqueue_head(&priv->shrd->wait_command_queue); | ||
966 | |||
967 | INIT_WORK(&priv->restart, iwl_bg_restart); | 966 | INIT_WORK(&priv->restart, iwl_bg_restart); |
968 | INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); | 967 | INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); |
969 | INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); | 968 | INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); |
@@ -1186,6 +1185,14 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1186 | u16 num_mac; | 1185 | u16 num_mac; |
1187 | u32 ucode_flags; | 1186 | u32 ucode_flags; |
1188 | struct iwl_trans_config trans_cfg; | 1187 | struct iwl_trans_config trans_cfg; |
1188 | static const u8 no_reclaim_cmds[] = { | ||
1189 | REPLY_RX_PHY_CMD, | ||
1190 | REPLY_RX, | ||
1191 | REPLY_RX_MPDU_CMD, | ||
1192 | REPLY_COMPRESSED_BA, | ||
1193 | STATISTICS_NOTIFICATION, | ||
1194 | REPLY_TX, | ||
1195 | }; | ||
1189 | 1196 | ||
1190 | /************************ | 1197 | /************************ |
1191 | * 1. Allocating HW data | 1198 | * 1. Allocating HW data |
@@ -1211,6 +1218,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1211 | * to know about. | 1218 | * to know about. |
1212 | */ | 1219 | */ |
1213 | trans_cfg.op_mode = op_mode; | 1220 | trans_cfg.op_mode = op_mode; |
1221 | trans_cfg.no_reclaim_cmds = no_reclaim_cmds; | ||
1222 | trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); | ||
1214 | 1223 | ||
1215 | ucode_flags = fw->ucode_capa.flags; | 1224 | ucode_flags = fw->ucode_capa.flags; |
1216 | 1225 | ||
@@ -1398,6 +1407,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) | |||
1398 | iwl_tt_exit(priv); | 1407 | iwl_tt_exit(priv); |
1399 | 1408 | ||
1400 | /*This will stop the queues, move the device to low power state */ | 1409 | /*This will stop the queues, move the device to low power state */ |
1410 | priv->ucode_loaded = false; | ||
1401 | iwl_trans_stop_device(trans(priv)); | 1411 | iwl_trans_stop_device(trans(priv)); |
1402 | 1412 | ||
1403 | iwl_eeprom_free(priv->shrd); | 1413 | iwl_eeprom_free(priv->shrd); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8b85940731f..46490d3b95b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -838,6 +838,9 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) | |||
838 | iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); | 838 | iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); |
839 | #endif | 839 | #endif |
840 | 840 | ||
841 | /* uCode is no longer loaded. */ | ||
842 | priv->ucode_loaded = false; | ||
843 | |||
841 | /* Set the FW error flag -- cleared on iwl_down */ | 844 | /* Set the FW error flag -- cleared on iwl_down */ |
842 | set_bit(STATUS_FW_ERROR, &priv->shrd->status); | 845 | set_bit(STATUS_FW_ERROR, &priv->shrd->status); |
843 | 846 | ||
@@ -850,7 +853,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) | |||
850 | * commands by clearing the ready bit */ | 853 | * commands by clearing the ready bit */ |
851 | clear_bit(STATUS_READY, &priv->status); | 854 | clear_bit(STATUS_READY, &priv->status); |
852 | 855 | ||
853 | wake_up(&priv->shrd->wait_command_queue); | 856 | wake_up(&trans(priv)->wait_command_queue); |
854 | 857 | ||
855 | if (!ondemand) { | 858 | if (!ondemand) { |
856 | /* | 859 | /* |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 9b71c87847c..b7b1c04f2fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
@@ -230,15 +230,18 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, | |||
230 | int pos = 0; | 230 | int pos = 0; |
231 | int sram; | 231 | int sram; |
232 | struct iwl_priv *priv = file->private_data; | 232 | struct iwl_priv *priv = file->private_data; |
233 | const struct fw_img *img; | ||
233 | size_t bufsz; | 234 | size_t bufsz; |
234 | 235 | ||
235 | /* default is to dump the entire data segment */ | 236 | /* default is to dump the entire data segment */ |
236 | if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { | 237 | if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { |
237 | priv->dbgfs_sram_offset = 0x800000; | 238 | priv->dbgfs_sram_offset = 0x800000; |
238 | if (priv->shrd->ucode_type == IWL_UCODE_INIT) | 239 | if (!priv->ucode_loaded) { |
239 | priv->dbgfs_sram_len = priv->fw->ucode_init.data.len; | 240 | IWL_ERR(priv, "No uCode has been loadded.\n"); |
240 | else | 241 | return -EINVAL; |
241 | priv->dbgfs_sram_len = priv->fw->ucode_rt.data.len; | 242 | } |
243 | img = &priv->fw->img[priv->shrd->ucode_type]; | ||
244 | priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
242 | } | 245 | } |
243 | len = priv->dbgfs_sram_len; | 246 | len = priv->dbgfs_sram_len; |
244 | 247 | ||
@@ -335,13 +338,14 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file, | |||
335 | size_t count, loff_t *ppos) | 338 | size_t count, loff_t *ppos) |
336 | { | 339 | { |
337 | struct iwl_priv *priv = file->private_data; | 340 | struct iwl_priv *priv = file->private_data; |
341 | const struct fw_img *img = &priv->fw->img[IWL_UCODE_WOWLAN]; | ||
338 | 342 | ||
339 | if (!priv->wowlan_sram) | 343 | if (!priv->wowlan_sram) |
340 | return -ENODATA; | 344 | return -ENODATA; |
341 | 345 | ||
342 | return simple_read_from_buffer(user_buf, count, ppos, | 346 | return simple_read_from_buffer(user_buf, count, ppos, |
343 | priv->wowlan_sram, | 347 | priv->wowlan_sram, |
344 | priv->fw->ucode_wowlan.data.len); | 348 | img->sec[IWL_UCODE_SECTION_DATA].len); |
345 | } | 349 | } |
346 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, | 350 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, |
347 | size_t count, loff_t *ppos) | 351 | size_t count, loff_t *ppos) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index aa4b3b122da..16956b777f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -769,6 +769,8 @@ struct iwl_priv { | |||
769 | /* firmware reload counter and timestamp */ | 769 | /* firmware reload counter and timestamp */ |
770 | unsigned long reload_jiffies; | 770 | unsigned long reload_jiffies; |
771 | int reload_count; | 771 | int reload_count; |
772 | bool ucode_loaded; | ||
773 | bool init_ucode_run; /* Don't run init uCode again */ | ||
772 | 774 | ||
773 | /* we allocate array of iwl_channel_info for NIC's valid channels. | 775 | /* we allocate array of iwl_channel_info for NIC's valid channels. |
774 | * Access via channel # using indirect index array */ | 776 | * Access via channel # using indirect index array */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 29a3ae48df6..6f312c77af5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -69,6 +69,7 @@ | |||
69 | #include "iwl-trans.h" | 69 | #include "iwl-trans.h" |
70 | #include "iwl-shared.h" | 70 | #include "iwl-shared.h" |
71 | #include "iwl-op-mode.h" | 71 | #include "iwl-op-mode.h" |
72 | #include "iwl-agn-hw.h" | ||
72 | 73 | ||
73 | /* private includes */ | 74 | /* private includes */ |
74 | #include "iwl-fw-file.h" | 75 | #include "iwl-fw-file.h" |
@@ -96,6 +97,16 @@ struct iwl_drv { | |||
96 | 97 | ||
97 | 98 | ||
98 | 99 | ||
100 | /* | ||
101 | * struct fw_sec: Just for the image parsing proccess. | ||
102 | * For the fw storage we are using struct fw_desc. | ||
103 | */ | ||
104 | struct fw_sec { | ||
105 | const void *data; /* the sec data */ | ||
106 | size_t size; /* section size */ | ||
107 | u32 offset; /* offset of writing in the device */ | ||
108 | }; | ||
109 | |||
99 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) | 110 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) |
100 | { | 111 | { |
101 | if (desc->v_addr) | 112 | if (desc->v_addr) |
@@ -107,32 +118,34 @@ static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) | |||
107 | 118 | ||
108 | static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img) | 119 | static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img) |
109 | { | 120 | { |
110 | iwl_free_fw_desc(drv, &img->code); | 121 | int i; |
111 | iwl_free_fw_desc(drv, &img->data); | 122 | for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) |
123 | iwl_free_fw_desc(drv, &img->sec[i]); | ||
112 | } | 124 | } |
113 | 125 | ||
114 | static void iwl_dealloc_ucode(struct iwl_drv *drv) | 126 | static void iwl_dealloc_ucode(struct iwl_drv *drv) |
115 | { | 127 | { |
116 | iwl_free_fw_img(drv, &drv->fw.ucode_rt); | 128 | int i; |
117 | iwl_free_fw_img(drv, &drv->fw.ucode_init); | 129 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
118 | iwl_free_fw_img(drv, &drv->fw.ucode_wowlan); | 130 | iwl_free_fw_img(drv, drv->fw.img + i); |
119 | } | 131 | } |
120 | 132 | ||
121 | static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, | 133 | static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, |
122 | const void *data, size_t len) | 134 | struct fw_sec *sec) |
123 | { | 135 | { |
124 | if (!len) { | 136 | if (!sec || !sec->size) { |
125 | desc->v_addr = NULL; | 137 | desc->v_addr = NULL; |
126 | return -EINVAL; | 138 | return -EINVAL; |
127 | } | 139 | } |
128 | 140 | ||
129 | desc->v_addr = dma_alloc_coherent(trans(drv)->dev, len, | 141 | desc->v_addr = dma_alloc_coherent(trans(drv)->dev, sec->size, |
130 | &desc->p_addr, GFP_KERNEL); | 142 | &desc->p_addr, GFP_KERNEL); |
131 | if (!desc->v_addr) | 143 | if (!desc->v_addr) |
132 | return -ENOMEM; | 144 | return -ENOMEM; |
133 | 145 | ||
134 | desc->len = len; | 146 | desc->len = sec->size; |
135 | memcpy(desc->v_addr, data, len); | 147 | desc->offset = sec->offset; |
148 | memcpy(desc->v_addr, sec->data, sec->size); | ||
136 | return 0; | 149 | return 0; |
137 | } | 150 | } |
138 | 151 | ||
@@ -177,18 +190,123 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
177 | GFP_KERNEL, drv, iwl_ucode_callback); | 190 | GFP_KERNEL, drv, iwl_ucode_callback); |
178 | } | 191 | } |
179 | 192 | ||
180 | struct iwlagn_firmware_pieces { | 193 | struct fw_img_parsing { |
181 | const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data; | 194 | struct fw_sec sec[IWL_UCODE_SECTION_MAX]; |
182 | size_t inst_size, data_size, init_size, init_data_size, | 195 | int sec_counter; |
183 | wowlan_inst_size, wowlan_data_size; | 196 | }; |
197 | |||
198 | /* | ||
199 | * struct fw_sec_parsing: to extract fw section and it's offset from tlv | ||
200 | */ | ||
201 | struct fw_sec_parsing { | ||
202 | __le32 offset; | ||
203 | const u8 data[]; | ||
204 | } __packed; | ||
205 | |||
206 | /** | ||
207 | * struct iwl_tlv_calib_data - parse the default calib data from TLV | ||
208 | * | ||
209 | * @ucode_type: the uCode to which the following default calib relates. | ||
210 | * @calib: default calibrations. | ||
211 | */ | ||
212 | struct iwl_tlv_calib_data { | ||
213 | __le32 ucode_type; | ||
214 | __le64 calib; | ||
215 | } __packed; | ||
216 | |||
217 | struct iwl_firmware_pieces { | ||
218 | struct fw_img_parsing img[IWL_UCODE_TYPE_MAX]; | ||
184 | 219 | ||
185 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 220 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
186 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 221 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
187 | }; | 222 | }; |
188 | 223 | ||
224 | /* | ||
225 | * These functions are just to extract uCode section data from the pieces | ||
226 | * structure. | ||
227 | */ | ||
228 | static struct fw_sec *get_sec(struct iwl_firmware_pieces *pieces, | ||
229 | enum iwl_ucode_type type, | ||
230 | int sec) | ||
231 | { | ||
232 | return &pieces->img[type].sec[sec]; | ||
233 | } | ||
234 | |||
235 | static void set_sec_data(struct iwl_firmware_pieces *pieces, | ||
236 | enum iwl_ucode_type type, | ||
237 | int sec, | ||
238 | const void *data) | ||
239 | { | ||
240 | pieces->img[type].sec[sec].data = data; | ||
241 | } | ||
242 | |||
243 | static void set_sec_size(struct iwl_firmware_pieces *pieces, | ||
244 | enum iwl_ucode_type type, | ||
245 | int sec, | ||
246 | size_t size) | ||
247 | { | ||
248 | pieces->img[type].sec[sec].size = size; | ||
249 | } | ||
250 | |||
251 | static size_t get_sec_size(struct iwl_firmware_pieces *pieces, | ||
252 | enum iwl_ucode_type type, | ||
253 | int sec) | ||
254 | { | ||
255 | return pieces->img[type].sec[sec].size; | ||
256 | } | ||
257 | |||
258 | static void set_sec_offset(struct iwl_firmware_pieces *pieces, | ||
259 | enum iwl_ucode_type type, | ||
260 | int sec, | ||
261 | u32 offset) | ||
262 | { | ||
263 | pieces->img[type].sec[sec].offset = offset; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * Gets uCode section from tlv. | ||
268 | */ | ||
269 | static int iwl_store_ucode_sec(struct iwl_firmware_pieces *pieces, | ||
270 | const void *data, enum iwl_ucode_type type, | ||
271 | int size) | ||
272 | { | ||
273 | struct fw_img_parsing *img; | ||
274 | struct fw_sec *sec; | ||
275 | struct fw_sec_parsing *sec_parse; | ||
276 | |||
277 | if (WARN_ON(!pieces || !data || type >= IWL_UCODE_TYPE_MAX)) | ||
278 | return -1; | ||
279 | |||
280 | sec_parse = (struct fw_sec_parsing *)data; | ||
281 | |||
282 | img = &pieces->img[type]; | ||
283 | sec = &img->sec[img->sec_counter]; | ||
284 | |||
285 | sec->offset = le32_to_cpu(sec_parse->offset); | ||
286 | sec->data = sec_parse->data; | ||
287 | |||
288 | ++img->sec_counter; | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data) | ||
294 | { | ||
295 | struct iwl_tlv_calib_data *def_calib = | ||
296 | (struct iwl_tlv_calib_data *)data; | ||
297 | u32 ucode_type = le32_to_cpu(def_calib->ucode_type); | ||
298 | if (ucode_type >= IWL_UCODE_TYPE_MAX) { | ||
299 | IWL_ERR(drv, "Wrong ucode_type %u for default calibration.\n", | ||
300 | ucode_type); | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | drv->fw.default_calib[ucode_type] = le64_to_cpu(def_calib->calib); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
189 | static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, | 307 | static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, |
190 | const struct firmware *ucode_raw, | 308 | const struct firmware *ucode_raw, |
191 | struct iwlagn_firmware_pieces *pieces) | 309 | struct iwl_firmware_pieces *pieces) |
192 | { | 310 | { |
193 | struct iwl_ucode_header *ucode = (void *)ucode_raw->data; | 311 | struct iwl_ucode_header *ucode = (void *)ucode_raw->data; |
194 | u32 api_ver, hdr_size, build; | 312 | u32 api_ver, hdr_size, build; |
@@ -206,11 +324,14 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, | |||
206 | return -EINVAL; | 324 | return -EINVAL; |
207 | } | 325 | } |
208 | build = le32_to_cpu(ucode->u.v2.build); | 326 | build = le32_to_cpu(ucode->u.v2.build); |
209 | pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); | 327 | set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST, |
210 | pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); | 328 | le32_to_cpu(ucode->u.v2.inst_size)); |
211 | pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); | 329 | set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA, |
212 | pieces->init_data_size = | 330 | le32_to_cpu(ucode->u.v2.data_size)); |
213 | le32_to_cpu(ucode->u.v2.init_data_size); | 331 | set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST, |
332 | le32_to_cpu(ucode->u.v2.init_size)); | ||
333 | set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA, | ||
334 | le32_to_cpu(ucode->u.v2.init_data_size)); | ||
214 | src = ucode->u.v2.data; | 335 | src = ucode->u.v2.data; |
215 | break; | 336 | break; |
216 | case 0: | 337 | case 0: |
@@ -222,11 +343,14 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, | |||
222 | return -EINVAL; | 343 | return -EINVAL; |
223 | } | 344 | } |
224 | build = 0; | 345 | build = 0; |
225 | pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size); | 346 | set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST, |
226 | pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); | 347 | le32_to_cpu(ucode->u.v1.inst_size)); |
227 | pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); | 348 | set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA, |
228 | pieces->init_data_size = | 349 | le32_to_cpu(ucode->u.v1.data_size)); |
229 | le32_to_cpu(ucode->u.v1.init_data_size); | 350 | set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST, |
351 | le32_to_cpu(ucode->u.v1.init_size)); | ||
352 | set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA, | ||
353 | le32_to_cpu(ucode->u.v1.init_data_size)); | ||
230 | src = ucode->u.v1.data; | 354 | src = ucode->u.v1.data; |
231 | break; | 355 | break; |
232 | } | 356 | } |
@@ -248,9 +372,12 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, | |||
248 | buildstr); | 372 | buildstr); |
249 | 373 | ||
250 | /* Verify size of file vs. image size info in file's header */ | 374 | /* Verify size of file vs. image size info in file's header */ |
251 | if (ucode_raw->size != hdr_size + pieces->inst_size + | 375 | |
252 | pieces->data_size + pieces->init_size + | 376 | if (ucode_raw->size != hdr_size + |
253 | pieces->init_data_size) { | 377 | get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) + |
378 | get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) + | ||
379 | get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) + | ||
380 | get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)) { | ||
254 | 381 | ||
255 | IWL_ERR(drv, | 382 | IWL_ERR(drv, |
256 | "uCode file size %d does not match expected size\n", | 383 | "uCode file size %d does not match expected size\n", |
@@ -258,21 +385,29 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, | |||
258 | return -EINVAL; | 385 | return -EINVAL; |
259 | } | 386 | } |
260 | 387 | ||
261 | pieces->inst = src; | ||
262 | src += pieces->inst_size; | ||
263 | pieces->data = src; | ||
264 | src += pieces->data_size; | ||
265 | pieces->init = src; | ||
266 | src += pieces->init_size; | ||
267 | pieces->init_data = src; | ||
268 | src += pieces->init_data_size; | ||
269 | 388 | ||
389 | set_sec_data(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST, src); | ||
390 | src += get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST); | ||
391 | set_sec_offset(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST, | ||
392 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
393 | set_sec_data(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA, src); | ||
394 | src += get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA); | ||
395 | set_sec_offset(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA, | ||
396 | IWLAGN_RTC_DATA_LOWER_BOUND); | ||
397 | set_sec_data(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST, src); | ||
398 | src += get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST); | ||
399 | set_sec_offset(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST, | ||
400 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
401 | set_sec_data(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA, src); | ||
402 | src += get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA); | ||
403 | set_sec_offset(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA, | ||
404 | IWLAGN_RTC_DATA_LOWER_BOUND); | ||
270 | return 0; | 405 | return 0; |
271 | } | 406 | } |
272 | 407 | ||
273 | static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | 408 | static int iwl_parse_tlv_firmware(struct iwl_drv *drv, |
274 | const struct firmware *ucode_raw, | 409 | const struct firmware *ucode_raw, |
275 | struct iwlagn_firmware_pieces *pieces, | 410 | struct iwl_firmware_pieces *pieces, |
276 | struct iwl_ucode_capabilities *capa) | 411 | struct iwl_ucode_capabilities *capa) |
277 | { | 412 | { |
278 | struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; | 413 | struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; |
@@ -368,20 +503,40 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
368 | 503 | ||
369 | switch (tlv_type) { | 504 | switch (tlv_type) { |
370 | case IWL_UCODE_TLV_INST: | 505 | case IWL_UCODE_TLV_INST: |
371 | pieces->inst = tlv_data; | 506 | set_sec_data(pieces, IWL_UCODE_REGULAR, |
372 | pieces->inst_size = tlv_len; | 507 | IWL_UCODE_SECTION_INST, tlv_data); |
508 | set_sec_size(pieces, IWL_UCODE_REGULAR, | ||
509 | IWL_UCODE_SECTION_INST, tlv_len); | ||
510 | set_sec_offset(pieces, IWL_UCODE_REGULAR, | ||
511 | IWL_UCODE_SECTION_INST, | ||
512 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
373 | break; | 513 | break; |
374 | case IWL_UCODE_TLV_DATA: | 514 | case IWL_UCODE_TLV_DATA: |
375 | pieces->data = tlv_data; | 515 | set_sec_data(pieces, IWL_UCODE_REGULAR, |
376 | pieces->data_size = tlv_len; | 516 | IWL_UCODE_SECTION_DATA, tlv_data); |
517 | set_sec_size(pieces, IWL_UCODE_REGULAR, | ||
518 | IWL_UCODE_SECTION_DATA, tlv_len); | ||
519 | set_sec_offset(pieces, IWL_UCODE_REGULAR, | ||
520 | IWL_UCODE_SECTION_DATA, | ||
521 | IWLAGN_RTC_DATA_LOWER_BOUND); | ||
377 | break; | 522 | break; |
378 | case IWL_UCODE_TLV_INIT: | 523 | case IWL_UCODE_TLV_INIT: |
379 | pieces->init = tlv_data; | 524 | set_sec_data(pieces, IWL_UCODE_INIT, |
380 | pieces->init_size = tlv_len; | 525 | IWL_UCODE_SECTION_INST, tlv_data); |
526 | set_sec_size(pieces, IWL_UCODE_INIT, | ||
527 | IWL_UCODE_SECTION_INST, tlv_len); | ||
528 | set_sec_offset(pieces, IWL_UCODE_INIT, | ||
529 | IWL_UCODE_SECTION_INST, | ||
530 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
381 | break; | 531 | break; |
382 | case IWL_UCODE_TLV_INIT_DATA: | 532 | case IWL_UCODE_TLV_INIT_DATA: |
383 | pieces->init_data = tlv_data; | 533 | set_sec_data(pieces, IWL_UCODE_INIT, |
384 | pieces->init_data_size = tlv_len; | 534 | IWL_UCODE_SECTION_DATA, tlv_data); |
535 | set_sec_size(pieces, IWL_UCODE_INIT, | ||
536 | IWL_UCODE_SECTION_DATA, tlv_len); | ||
537 | set_sec_offset(pieces, IWL_UCODE_INIT, | ||
538 | IWL_UCODE_SECTION_DATA, | ||
539 | IWLAGN_RTC_DATA_LOWER_BOUND); | ||
385 | break; | 540 | break; |
386 | case IWL_UCODE_TLV_BOOT: | 541 | case IWL_UCODE_TLV_BOOT: |
387 | IWL_ERR(drv, "Found unexpected BOOT ucode\n"); | 542 | IWL_ERR(drv, "Found unexpected BOOT ucode\n"); |
@@ -455,12 +610,22 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
455 | drv->fw.enhance_sensitivity_table = true; | 610 | drv->fw.enhance_sensitivity_table = true; |
456 | break; | 611 | break; |
457 | case IWL_UCODE_TLV_WOWLAN_INST: | 612 | case IWL_UCODE_TLV_WOWLAN_INST: |
458 | pieces->wowlan_inst = tlv_data; | 613 | set_sec_data(pieces, IWL_UCODE_WOWLAN, |
459 | pieces->wowlan_inst_size = tlv_len; | 614 | IWL_UCODE_SECTION_INST, tlv_data); |
615 | set_sec_size(pieces, IWL_UCODE_WOWLAN, | ||
616 | IWL_UCODE_SECTION_INST, tlv_len); | ||
617 | set_sec_offset(pieces, IWL_UCODE_WOWLAN, | ||
618 | IWL_UCODE_SECTION_INST, | ||
619 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
460 | break; | 620 | break; |
461 | case IWL_UCODE_TLV_WOWLAN_DATA: | 621 | case IWL_UCODE_TLV_WOWLAN_DATA: |
462 | pieces->wowlan_data = tlv_data; | 622 | set_sec_data(pieces, IWL_UCODE_WOWLAN, |
463 | pieces->wowlan_data_size = tlv_len; | 623 | IWL_UCODE_SECTION_DATA, tlv_data); |
624 | set_sec_size(pieces, IWL_UCODE_WOWLAN, | ||
625 | IWL_UCODE_SECTION_DATA, tlv_len); | ||
626 | set_sec_offset(pieces, IWL_UCODE_WOWLAN, | ||
627 | IWL_UCODE_SECTION_DATA, | ||
628 | IWLAGN_RTC_DATA_LOWER_BOUND); | ||
464 | break; | 629 | break; |
465 | case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: | 630 | case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: |
466 | if (tlv_len != sizeof(u32)) | 631 | if (tlv_len != sizeof(u32)) |
@@ -468,6 +633,32 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
468 | capa->standard_phy_calibration_size = | 633 | capa->standard_phy_calibration_size = |
469 | le32_to_cpup((__le32 *)tlv_data); | 634 | le32_to_cpup((__le32 *)tlv_data); |
470 | break; | 635 | break; |
636 | case IWL_UCODE_TLV_SEC_RT: | ||
637 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, | ||
638 | tlv_len); | ||
639 | drv->fw.mvm_fw = true; | ||
640 | break; | ||
641 | case IWL_UCODE_TLV_SEC_INIT: | ||
642 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT, | ||
643 | tlv_len); | ||
644 | drv->fw.mvm_fw = true; | ||
645 | break; | ||
646 | case IWL_UCODE_TLV_SEC_WOWLAN: | ||
647 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN, | ||
648 | tlv_len); | ||
649 | drv->fw.mvm_fw = true; | ||
650 | break; | ||
651 | case IWL_UCODE_TLV_DEF_CALIB: | ||
652 | if (tlv_len != sizeof(struct iwl_tlv_calib_data)) | ||
653 | goto invalid_tlv_len; | ||
654 | if (iwl_set_default_calib(drv, tlv_data)) | ||
655 | goto tlv_error; | ||
656 | break; | ||
657 | case IWL_UCODE_TLV_PHY_SKU: | ||
658 | if (tlv_len != sizeof(u32)) | ||
659 | goto invalid_tlv_len; | ||
660 | drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data); | ||
661 | break; | ||
471 | default: | 662 | default: |
472 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); | 663 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); |
473 | break; | 664 | break; |
@@ -484,11 +675,77 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
484 | 675 | ||
485 | invalid_tlv_len: | 676 | invalid_tlv_len: |
486 | IWL_ERR(drv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); | 677 | IWL_ERR(drv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); |
678 | tlv_error: | ||
487 | iwl_print_hex_dump(drv, IWL_DL_FW, tlv_data, tlv_len); | 679 | iwl_print_hex_dump(drv, IWL_DL_FW, tlv_data, tlv_len); |
488 | 680 | ||
489 | return -EINVAL; | 681 | return -EINVAL; |
490 | } | 682 | } |
491 | 683 | ||
684 | static int alloc_pci_desc(struct iwl_drv *drv, | ||
685 | struct iwl_firmware_pieces *pieces, | ||
686 | enum iwl_ucode_type type) | ||
687 | { | ||
688 | int i; | ||
689 | for (i = 0; | ||
690 | i < IWL_UCODE_SECTION_MAX && get_sec_size(pieces, type, i); | ||
691 | i++) | ||
692 | if (iwl_alloc_fw_desc(drv, &(drv->fw.img[type].sec[i]), | ||
693 | get_sec(pieces, type, i))) | ||
694 | return -1; | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int validate_sec_sizes(struct iwl_drv *drv, | ||
699 | struct iwl_firmware_pieces *pieces, | ||
700 | const struct iwl_cfg *cfg) | ||
701 | { | ||
702 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n", | ||
703 | get_sec_size(pieces, IWL_UCODE_REGULAR, | ||
704 | IWL_UCODE_SECTION_INST)); | ||
705 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n", | ||
706 | get_sec_size(pieces, IWL_UCODE_REGULAR, | ||
707 | IWL_UCODE_SECTION_DATA)); | ||
708 | IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n", | ||
709 | get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST)); | ||
710 | IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n", | ||
711 | get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)); | ||
712 | |||
713 | /* Verify that uCode images will fit in card's SRAM. */ | ||
714 | if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > | ||
715 | cfg->max_inst_size) { | ||
716 | IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", | ||
717 | get_sec_size(pieces, IWL_UCODE_REGULAR, | ||
718 | IWL_UCODE_SECTION_INST)); | ||
719 | return -1; | ||
720 | } | ||
721 | |||
722 | if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > | ||
723 | cfg->max_data_size) { | ||
724 | IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", | ||
725 | get_sec_size(pieces, IWL_UCODE_REGULAR, | ||
726 | IWL_UCODE_SECTION_DATA)); | ||
727 | return -1; | ||
728 | } | ||
729 | |||
730 | if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) > | ||
731 | cfg->max_inst_size) { | ||
732 | IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n", | ||
733 | get_sec_size(pieces, IWL_UCODE_INIT, | ||
734 | IWL_UCODE_SECTION_INST)); | ||
735 | return -1; | ||
736 | } | ||
737 | |||
738 | if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) > | ||
739 | cfg->max_data_size) { | ||
740 | IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n", | ||
741 | get_sec_size(pieces, IWL_UCODE_REGULAR, | ||
742 | IWL_UCODE_SECTION_DATA)); | ||
743 | return -1; | ||
744 | } | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | |||
492 | /** | 749 | /** |
493 | * iwl_ucode_callback - callback when firmware was loaded | 750 | * iwl_ucode_callback - callback when firmware was loaded |
494 | * | 751 | * |
@@ -502,11 +759,12 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
502 | struct iwl_fw *fw = &drv->fw; | 759 | struct iwl_fw *fw = &drv->fw; |
503 | struct iwl_ucode_header *ucode; | 760 | struct iwl_ucode_header *ucode; |
504 | int err; | 761 | int err; |
505 | struct iwlagn_firmware_pieces pieces; | 762 | struct iwl_firmware_pieces pieces; |
506 | const unsigned int api_max = cfg->ucode_api_max; | 763 | const unsigned int api_max = cfg->ucode_api_max; |
507 | unsigned int api_ok = cfg->ucode_api_ok; | 764 | unsigned int api_ok = cfg->ucode_api_ok; |
508 | const unsigned int api_min = cfg->ucode_api_min; | 765 | const unsigned int api_min = cfg->ucode_api_min; |
509 | u32 api_ver; | 766 | u32 api_ver; |
767 | int i; | ||
510 | 768 | ||
511 | fw->ucode_capa.max_probe_length = 200; | 769 | fw->ucode_capa.max_probe_length = 200; |
512 | fw->ucode_capa.standard_phy_calibration_size = | 770 | fw->ucode_capa.standard_phy_calibration_size = |
@@ -588,76 +846,48 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
588 | IWL_DEBUG_INFO(drv, "f/w package hdr ucode version raw = 0x%x\n", | 846 | IWL_DEBUG_INFO(drv, "f/w package hdr ucode version raw = 0x%x\n", |
589 | drv->fw.ucode_ver); | 847 | drv->fw.ucode_ver); |
590 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n", | 848 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n", |
591 | pieces.inst_size); | 849 | get_sec_size(&pieces, IWL_UCODE_REGULAR, |
850 | IWL_UCODE_SECTION_INST)); | ||
592 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n", | 851 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n", |
593 | pieces.data_size); | 852 | get_sec_size(&pieces, IWL_UCODE_REGULAR, |
853 | IWL_UCODE_SECTION_DATA)); | ||
594 | IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n", | 854 | IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n", |
595 | pieces.init_size); | 855 | get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST)); |
596 | IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n", | 856 | IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n", |
597 | pieces.init_data_size); | 857 | get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)); |
598 | 858 | ||
599 | /* Verify that uCode images will fit in card's SRAM */ | 859 | /* Verify that uCode images will fit in card's SRAM */ |
600 | if (pieces.inst_size > cfg->max_inst_size) { | 860 | if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > |
861 | cfg->max_inst_size) { | ||
601 | IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", | 862 | IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", |
602 | pieces.inst_size); | 863 | get_sec_size(&pieces, IWL_UCODE_REGULAR, |
864 | IWL_UCODE_SECTION_INST)); | ||
603 | goto try_again; | 865 | goto try_again; |
604 | } | 866 | } |
605 | 867 | ||
606 | if (pieces.data_size > cfg->max_data_size) { | 868 | if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > |
869 | cfg->max_data_size) { | ||
607 | IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", | 870 | IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", |
608 | pieces.data_size); | 871 | get_sec_size(&pieces, IWL_UCODE_REGULAR, |
872 | IWL_UCODE_SECTION_DATA)); | ||
609 | goto try_again; | 873 | goto try_again; |
610 | } | 874 | } |
611 | 875 | ||
612 | if (pieces.init_size > cfg->max_inst_size) { | 876 | /* |
613 | IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n", | 877 | * In mvm uCode there is no difference between data and instructions |
614 | pieces.init_size); | 878 | * sections. |
615 | goto try_again; | 879 | */ |
616 | } | 880 | if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, cfg)) |
617 | |||
618 | if (pieces.init_data_size > cfg->max_data_size) { | ||
619 | IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n", | ||
620 | pieces.init_data_size); | ||
621 | goto try_again; | 881 | goto try_again; |
622 | } | ||
623 | 882 | ||
624 | /* Allocate ucode buffers for card's bus-master loading ... */ | 883 | /* Allocate ucode buffers for card's bus-master loading ... */ |
625 | 884 | ||
626 | /* Runtime instructions and 2 copies of data: | 885 | /* Runtime instructions and 2 copies of data: |
627 | * 1) unmodified from disk | 886 | * 1) unmodified from disk |
628 | * 2) backup cache for save/restore during power-downs */ | 887 | * 2) backup cache for save/restore during power-downs */ |
629 | if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.code, | 888 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
630 | pieces.inst, pieces.inst_size)) | 889 | if (alloc_pci_desc(drv, &pieces, i)) |
631 | goto err_pci_alloc; | ||
632 | if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.data, | ||
633 | pieces.data, pieces.data_size)) | ||
634 | goto err_pci_alloc; | ||
635 | |||
636 | /* Initialization instructions and data */ | ||
637 | if (pieces.init_size && pieces.init_data_size) { | ||
638 | if (iwl_alloc_fw_desc(drv, | ||
639 | &drv->fw.ucode_init.code, | ||
640 | pieces.init, pieces.init_size)) | ||
641 | goto err_pci_alloc; | ||
642 | if (iwl_alloc_fw_desc(drv, | ||
643 | &drv->fw.ucode_init.data, | ||
644 | pieces.init_data, pieces.init_data_size)) | ||
645 | goto err_pci_alloc; | 890 | goto err_pci_alloc; |
646 | } | ||
647 | |||
648 | /* WoWLAN instructions and data */ | ||
649 | if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { | ||
650 | if (iwl_alloc_fw_desc(drv, | ||
651 | &drv->fw.ucode_wowlan.code, | ||
652 | pieces.wowlan_inst, | ||
653 | pieces.wowlan_inst_size)) | ||
654 | goto err_pci_alloc; | ||
655 | if (iwl_alloc_fw_desc(drv, | ||
656 | &drv->fw.ucode_wowlan.data, | ||
657 | pieces.wowlan_data, | ||
658 | pieces.wowlan_data_size)) | ||
659 | goto err_pci_alloc; | ||
660 | } | ||
661 | 891 | ||
662 | /* Now that we can no longer fail, copy information */ | 892 | /* Now that we can no longer fail, copy information */ |
663 | 893 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 7ca6c952635..c924ccb93c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -124,6 +124,11 @@ enum iwl_ucode_tlv_type { | |||
124 | IWL_UCODE_TLV_WOWLAN_INST = 16, | 124 | IWL_UCODE_TLV_WOWLAN_INST = 16, |
125 | IWL_UCODE_TLV_WOWLAN_DATA = 17, | 125 | IWL_UCODE_TLV_WOWLAN_DATA = 17, |
126 | IWL_UCODE_TLV_FLAGS = 18, | 126 | IWL_UCODE_TLV_FLAGS = 18, |
127 | IWL_UCODE_TLV_SEC_RT = 19, | ||
128 | IWL_UCODE_TLV_SEC_INIT = 20, | ||
129 | IWL_UCODE_TLV_SEC_WOWLAN = 21, | ||
130 | IWL_UCODE_TLV_DEF_CALIB = 22, | ||
131 | IWL_UCODE_TLV_PHY_SKU = 23, | ||
127 | }; | 132 | }; |
128 | 133 | ||
129 | struct iwl_ucode_tlv { | 134 | struct iwl_ucode_tlv { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 453812a2117..8e36bdc1e52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -85,22 +85,52 @@ enum iwl_ucode_tlv_flag { | |||
85 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 | 85 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 |
86 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 | 86 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 |
87 | 87 | ||
88 | /** | ||
89 | * enum iwl_ucode_type | ||
90 | * | ||
91 | * The type of ucode. | ||
92 | * | ||
93 | * @IWL_UCODE_REGULAR: Normal runtime ucode | ||
94 | * @IWL_UCODE_INIT: Initial ucode | ||
95 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode | ||
96 | */ | ||
97 | enum iwl_ucode_type { | ||
98 | IWL_UCODE_REGULAR, | ||
99 | IWL_UCODE_INIT, | ||
100 | IWL_UCODE_WOWLAN, | ||
101 | IWL_UCODE_TYPE_MAX, | ||
102 | }; | ||
103 | |||
104 | /* | ||
105 | * enumeration of ucode section. | ||
106 | * This enumeration is used for legacy tlv style (before 16.0 uCode). | ||
107 | */ | ||
108 | enum iwl_ucode_sec { | ||
109 | IWL_UCODE_SECTION_INST, | ||
110 | IWL_UCODE_SECTION_DATA, | ||
111 | }; | ||
112 | /* | ||
113 | * For 16.0 uCode and above, there is no differentiation between sections, | ||
114 | * just an offset to the HW address. | ||
115 | */ | ||
116 | #define IWL_UCODE_SECTION_MAX 4 | ||
117 | |||
88 | struct iwl_ucode_capabilities { | 118 | struct iwl_ucode_capabilities { |
89 | u32 max_probe_length; | 119 | u32 max_probe_length; |
90 | u32 standard_phy_calibration_size; | 120 | u32 standard_phy_calibration_size; |
91 | u32 flags; | 121 | u32 flags; |
92 | }; | 122 | }; |
93 | 123 | ||
94 | /* one for each uCode image (inst/data, boot/init/runtime) */ | 124 | /* one for each uCode image (inst/data, init/runtime/wowlan) */ |
95 | struct fw_desc { | 125 | struct fw_desc { |
96 | dma_addr_t p_addr; /* hardware address */ | 126 | dma_addr_t p_addr; /* hardware address */ |
97 | void *v_addr; /* software address */ | 127 | void *v_addr; /* software address */ |
98 | u32 len; /* size in bytes */ | 128 | u32 len; /* size in bytes */ |
129 | u32 offset; /* offset in the device */ | ||
99 | }; | 130 | }; |
100 | 131 | ||
101 | struct fw_img { | 132 | struct fw_img { |
102 | struct fw_desc code; /* firmware code image */ | 133 | struct fw_desc sec[IWL_UCODE_SECTION_MAX]; |
103 | struct fw_desc data; /* firmware data image */ | ||
104 | }; | 134 | }; |
105 | 135 | ||
106 | /* uCode version contains 4 values: Major/Minor/API/Serial */ | 136 | /* uCode version contains 4 values: Major/Minor/API/Serial */ |
@@ -114,9 +144,7 @@ struct fw_img { | |||
114 | * | 144 | * |
115 | * @ucode_ver: ucode version from the ucode file | 145 | * @ucode_ver: ucode version from the ucode file |
116 | * @fw_version: firmware version string | 146 | * @fw_version: firmware version string |
117 | * @ucode_rt: run time ucode image | 147 | * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan. |
118 | * @ucode_init: init ucode image | ||
119 | * @ucode_wowlan: wake on wireless ucode image (optional) | ||
120 | * @ucode_capa: capabilities parsed from the ucode file. | 148 | * @ucode_capa: capabilities parsed from the ucode file. |
121 | * @enhance_sensitivity_table: device can do enhanced sensitivity. | 149 | * @enhance_sensitivity_table: device can do enhanced sensitivity. |
122 | * @init_evtlog_ptr: event log offset for init ucode. | 150 | * @init_evtlog_ptr: event log offset for init ucode. |
@@ -132,15 +160,18 @@ struct iwl_fw { | |||
132 | char fw_version[ETHTOOL_BUSINFO_LEN]; | 160 | char fw_version[ETHTOOL_BUSINFO_LEN]; |
133 | 161 | ||
134 | /* ucode images */ | 162 | /* ucode images */ |
135 | struct fw_img ucode_rt; | 163 | struct fw_img img[IWL_UCODE_TYPE_MAX]; |
136 | struct fw_img ucode_init; | ||
137 | struct fw_img ucode_wowlan; | ||
138 | 164 | ||
139 | struct iwl_ucode_capabilities ucode_capa; | 165 | struct iwl_ucode_capabilities ucode_capa; |
140 | bool enhance_sensitivity_table; | 166 | bool enhance_sensitivity_table; |
141 | 167 | ||
142 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 168 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
143 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 169 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
170 | |||
171 | u64 default_calib[IWL_UCODE_TYPE_MAX]; | ||
172 | u32 phy_config; | ||
173 | |||
174 | bool mvm_fw; | ||
144 | }; | 175 | }; |
145 | 176 | ||
146 | #endif /* __iwl_fw_h__ */ | 177 | #endif /* __iwl_fw_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index 9212ee3bef9..b6805f8e9a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c | |||
@@ -196,7 +196,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, | |||
196 | WIPHY_FLAG_DISABLE_BEACON_HINTS | | 196 | WIPHY_FLAG_DISABLE_BEACON_HINTS | |
197 | WIPHY_FLAG_IBSS_RSN; | 197 | WIPHY_FLAG_IBSS_RSN; |
198 | 198 | ||
199 | if (priv->fw->ucode_wowlan.code.len && | 199 | if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && |
200 | trans(priv)->ops->wowlan_suspend && | 200 | trans(priv)->ops->wowlan_suspend && |
201 | device_can_wakeup(trans(priv)->dev)) { | 201 | device_can_wakeup(trans(priv)->dev)) { |
202 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | 202 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | |
@@ -437,6 +437,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
437 | unsigned long flags; | 437 | unsigned long flags; |
438 | u32 base, status = 0xffffffff; | 438 | u32 base, status = 0xffffffff; |
439 | int ret = -EIO; | 439 | int ret = -EIO; |
440 | const struct fw_img *img; | ||
440 | 441 | ||
441 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 442 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
442 | mutex_lock(&priv->mutex); | 443 | mutex_lock(&priv->mutex); |
@@ -457,16 +458,18 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
457 | 458 | ||
458 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 459 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
459 | if (ret == 0) { | 460 | if (ret == 0) { |
460 | if (!priv->wowlan_sram) | 461 | img = &(priv->fw->img[IWL_UCODE_WOWLAN]); |
462 | if (!priv->wowlan_sram) { | ||
461 | priv->wowlan_sram = | 463 | priv->wowlan_sram = |
462 | kzalloc(priv->fw->ucode_wowlan.data.len, | 464 | kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len, |
463 | GFP_KERNEL); | 465 | GFP_KERNEL); |
466 | } | ||
464 | 467 | ||
465 | if (priv->wowlan_sram) | 468 | if (priv->wowlan_sram) |
466 | _iwl_read_targ_mem_words( | 469 | _iwl_read_targ_mem_words( |
467 | trans(priv), 0x800000, | 470 | trans(priv), 0x800000, |
468 | priv->wowlan_sram, | 471 | priv->wowlan_sram, |
469 | priv->fw->ucode_wowlan.data.len / 4); | 472 | img->sec[IWL_UCODE_SECTION_DATA].len / 4); |
470 | } | 473 | } |
471 | #endif | 474 | #endif |
472 | } | 475 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index cf34087aa2f..b515d657a0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h | |||
@@ -192,23 +192,6 @@ struct iwl_hw_params { | |||
192 | const struct iwl_sensitivity_ranges *sens; | 192 | const struct iwl_sensitivity_ranges *sens; |
193 | }; | 193 | }; |
194 | 194 | ||
195 | /** | ||
196 | * enum iwl_ucode_type | ||
197 | * | ||
198 | * The type of ucode currently loaded on the hardware. | ||
199 | * | ||
200 | * @IWL_UCODE_NONE: No ucode loaded | ||
201 | * @IWL_UCODE_REGULAR: Normal runtime ucode | ||
202 | * @IWL_UCODE_INIT: Initial ucode | ||
203 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode | ||
204 | */ | ||
205 | enum iwl_ucode_type { | ||
206 | IWL_UCODE_NONE, | ||
207 | IWL_UCODE_REGULAR, | ||
208 | IWL_UCODE_INIT, | ||
209 | IWL_UCODE_WOWLAN, | ||
210 | }; | ||
211 | |||
212 | /* | 195 | /* |
213 | * LED mode | 196 | * LED mode |
214 | * IWL_LED_DEFAULT: use device default | 197 | * IWL_LED_DEFAULT: use device default |
@@ -376,7 +359,6 @@ struct iwl_cfg { | |||
376 | * @nic: pointer to the nic data | 359 | * @nic: pointer to the nic data |
377 | * @hw_params: see struct iwl_hw_params | 360 | * @hw_params: see struct iwl_hw_params |
378 | * @lock: protect general shared data | 361 | * @lock: protect general shared data |
379 | * @wait_command_queue: the wait_queue for SYNC host commands | ||
380 | * @eeprom: pointer to the eeprom/OTP image | 362 | * @eeprom: pointer to the eeprom/OTP image |
381 | * @ucode_type: indicator of loaded ucode image | 363 | * @ucode_type: indicator of loaded ucode image |
382 | * @device_pointers: pointers to ucode event tables | 364 | * @device_pointers: pointers to ucode event tables |
@@ -391,8 +373,6 @@ struct iwl_shared { | |||
391 | struct iwl_hw_params hw_params; | 373 | struct iwl_hw_params hw_params; |
392 | const struct iwl_fw *fw; | 374 | const struct iwl_fw *fw; |
393 | 375 | ||
394 | wait_queue_head_t wait_command_queue; | ||
395 | |||
396 | /* eeprom -- this is in the card's little endian byte order */ | 376 | /* eeprom -- this is in the card's little endian byte order */ |
397 | u8 *eeprom; | 377 | u8 *eeprom; |
398 | 378 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index b06c6763cb7..76f7f925143 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c | |||
@@ -466,6 +466,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) | |||
466 | unsigned char *rsp_data_ptr = NULL; | 466 | unsigned char *rsp_data_ptr = NULL; |
467 | int status = 0, rsp_data_len = 0; | 467 | int status = 0, rsp_data_len = 0; |
468 | u32 devid, inst_size = 0, data_size = 0; | 468 | u32 devid, inst_size = 0, data_size = 0; |
469 | const struct fw_img *img; | ||
469 | 470 | ||
470 | switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { | 471 | switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { |
471 | case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: | 472 | case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: |
@@ -494,6 +495,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) | |||
494 | 495 | ||
495 | case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: | 496 | case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: |
496 | iwl_testmode_cfg_init_calib(priv); | 497 | iwl_testmode_cfg_init_calib(priv); |
498 | priv->ucode_loaded = false; | ||
497 | iwl_trans_stop_device(trans); | 499 | iwl_trans_stop_device(trans); |
498 | break; | 500 | break; |
499 | 501 | ||
@@ -512,6 +514,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) | |||
512 | 514 | ||
513 | case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: | 515 | case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: |
514 | iwl_scan_cancel_timeout(priv, 200); | 516 | iwl_scan_cancel_timeout(priv, 200); |
517 | priv->ucode_loaded = false; | ||
515 | iwl_trans_stop_device(trans); | 518 | iwl_trans_stop_device(trans); |
516 | status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN); | 519 | status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN); |
517 | if (status) { | 520 | if (status) { |
@@ -591,25 +594,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) | |||
591 | IWL_ERR(priv, "Memory allocation fail\n"); | 594 | IWL_ERR(priv, "Memory allocation fail\n"); |
592 | return -ENOMEM; | 595 | return -ENOMEM; |
593 | } | 596 | } |
594 | switch (priv->shrd->ucode_type) { | 597 | if (!priv->ucode_loaded) { |
595 | case IWL_UCODE_REGULAR: | ||
596 | inst_size = priv->fw->ucode_rt.code.len; | ||
597 | data_size = priv->fw->ucode_rt.data.len; | ||
598 | break; | ||
599 | case IWL_UCODE_INIT: | ||
600 | inst_size = priv->fw->ucode_init.code.len; | ||
601 | data_size = priv->fw->ucode_init.data.len; | ||
602 | break; | ||
603 | case IWL_UCODE_WOWLAN: | ||
604 | inst_size = priv->fw->ucode_wowlan.code.len; | ||
605 | data_size = priv->fw->ucode_wowlan.data.len; | ||
606 | break; | ||
607 | case IWL_UCODE_NONE: | ||
608 | IWL_ERR(priv, "No uCode has not been loaded\n"); | 598 | IWL_ERR(priv, "No uCode has not been loaded\n"); |
609 | break; | 599 | return -EINVAL; |
610 | default: | 600 | } else { |
611 | IWL_ERR(priv, "Unsupported uCode type\n"); | 601 | img = &priv->fw->img[priv->shrd->ucode_type]; |
612 | break; | 602 | inst_size = img->sec[IWL_UCODE_SECTION_INST].len; |
603 | data_size = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
613 | } | 604 | } |
614 | NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type); | 605 | NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type); |
615 | NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size); | 606 | NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 67965599bb3..1c2fe87bd7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h | |||
@@ -291,6 +291,8 @@ struct iwl_trans_pcie { | |||
291 | wait_queue_head_t ucode_write_waitq; | 291 | wait_queue_head_t ucode_write_waitq; |
292 | unsigned long status; | 292 | unsigned long status; |
293 | u8 cmd_queue; | 293 | u8 cmd_queue; |
294 | u8 n_no_reclaim_cmds; | ||
295 | u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; | ||
294 | }; | 296 | }; |
295 | 297 | ||
296 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ | 298 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 9bc3c73af5e..8b1a7988e17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | |||
@@ -395,13 +395,17 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, | |||
395 | * there is no command buffer to reclaim. | 395 | * there is no command buffer to reclaim. |
396 | * Ucode should set SEQ_RX_FRAME bit if ucode-originated, | 396 | * Ucode should set SEQ_RX_FRAME bit if ucode-originated, |
397 | * but apparently a few don't get set; catch them here. */ | 397 | * but apparently a few don't get set; catch them here. */ |
398 | reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && | 398 | reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME); |
399 | (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && | 399 | if (reclaim) { |
400 | (pkt->hdr.cmd != REPLY_RX) && | 400 | int i; |
401 | (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && | 401 | |
402 | (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && | 402 | for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) { |
403 | (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && | 403 | if (trans_pcie->no_reclaim_cmds[i] == pkt->hdr.cmd) { |
404 | (pkt->hdr.cmd != REPLY_TX); | 404 | reclaim = false; |
405 | break; | ||
406 | } | ||
407 | } | ||
408 | } | ||
405 | 409 | ||
406 | sequence = le16_to_cpu(pkt->hdr.sequence); | 410 | sequence = le16_to_cpu(pkt->hdr.sequence); |
407 | index = SEQ_TO_INDEX(sequence); | 411 | index = SEQ_TO_INDEX(sequence); |
@@ -412,17 +416,6 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, | |||
412 | else | 416 | else |
413 | cmd = NULL; | 417 | cmd = NULL; |
414 | 418 | ||
415 | /* warn if this is cmd response / notification and the uCode | ||
416 | * didn't set the SEQ_RX_FRAME for a frame that is | ||
417 | * uCode-originated | ||
418 | * If you saw this code after the second half of 2012, then | ||
419 | * please remove it | ||
420 | */ | ||
421 | WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false && | ||
422 | (!(pkt->hdr.sequence & SEQ_RX_FRAME)), | ||
423 | "reclaim is false, SEQ_RX_FRAME unset: %s\n", | ||
424 | get_cmd_string(pkt->hdr.cmd)); | ||
425 | |||
426 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); | 419 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); |
427 | 420 | ||
428 | /* | 421 | /* |
@@ -691,7 +684,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans) | |||
691 | */ | 684 | */ |
692 | clear_bit(STATUS_READY, &trans->shrd->status); | 685 | clear_bit(STATUS_READY, &trans->shrd->status); |
693 | clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); | 686 | clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); |
694 | wake_up(&trans->shrd->wait_command_queue); | 687 | wake_up(&trans->wait_command_queue); |
695 | IWL_ERR(trans, "RF is used by WiMAX\n"); | 688 | IWL_ERR(trans, "RF is used by WiMAX\n"); |
696 | return; | 689 | return; |
697 | } | 690 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index eb430b6e1cd..e92972fd6ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | |||
@@ -928,7 +928,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, | |||
928 | clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); | 928 | clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); |
929 | IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", | 929 | IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", |
930 | get_cmd_string(cmd->hdr.cmd)); | 930 | get_cmd_string(cmd->hdr.cmd)); |
931 | wake_up(&trans->shrd->wait_command_queue); | 931 | wake_up(&trans->wait_command_queue); |
932 | } | 932 | } |
933 | 933 | ||
934 | meta->flags = 0; | 934 | meta->flags = 0; |
@@ -992,7 +992,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) | |||
992 | return ret; | 992 | return ret; |
993 | } | 993 | } |
994 | 994 | ||
995 | ret = wait_event_timeout(trans->shrd->wait_command_queue, | 995 | ret = wait_event_timeout(trans->wait_command_queue, |
996 | !test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status), | 996 | !test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status), |
997 | HOST_COMPLETE_TIMEOUT); | 997 | HOST_COMPLETE_TIMEOUT); |
998 | if (!ret) { | 998 | if (!ret) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 91628565409..b4f796c82e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | |||
@@ -951,12 +951,13 @@ static const u8 iwlagn_pan_ac_to_queue[] = { | |||
951 | /* | 951 | /* |
952 | * ucode | 952 | * ucode |
953 | */ | 953 | */ |
954 | static int iwl_load_section(struct iwl_trans *trans, const char *name, | 954 | static int iwl_load_section(struct iwl_trans *trans, u8 section_num, |
955 | const struct fw_desc *image, u32 dst_addr) | 955 | const struct fw_desc *section) |
956 | { | 956 | { |
957 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 957 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
958 | dma_addr_t phy_addr = image->p_addr; | 958 | dma_addr_t phy_addr = section->p_addr; |
959 | u32 byte_cnt = image->len; | 959 | u32 byte_cnt = section->len; |
960 | u32 dst_addr = section->offset; | ||
960 | int ret; | 961 | int ret; |
961 | 962 | ||
962 | trans_pcie->ucode_write_complete = false; | 963 | trans_pcie->ucode_write_complete = false; |
@@ -989,12 +990,13 @@ static int iwl_load_section(struct iwl_trans *trans, const char *name, | |||
989 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | | 990 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | |
990 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); | 991 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); |
991 | 992 | ||
992 | IWL_DEBUG_FW(trans, "%s uCode section being loaded...\n", name); | 993 | IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", |
994 | section_num); | ||
993 | ret = wait_event_timeout(trans_pcie->ucode_write_waitq, | 995 | ret = wait_event_timeout(trans_pcie->ucode_write_waitq, |
994 | trans_pcie->ucode_write_complete, 5 * HZ); | 996 | trans_pcie->ucode_write_complete, 5 * HZ); |
995 | if (!ret) { | 997 | if (!ret) { |
996 | IWL_ERR(trans, "Could not load the %s uCode section\n", | 998 | IWL_ERR(trans, "Could not load the [%d] uCode section\n", |
997 | name); | 999 | section_num); |
998 | return -ETIMEDOUT; | 1000 | return -ETIMEDOUT; |
999 | } | 1001 | } |
1000 | 1002 | ||
@@ -1005,16 +1007,16 @@ static int iwl_load_given_ucode(struct iwl_trans *trans, | |||
1005 | const struct fw_img *image) | 1007 | const struct fw_img *image) |
1006 | { | 1008 | { |
1007 | int ret = 0; | 1009 | int ret = 0; |
1010 | int i; | ||
1008 | 1011 | ||
1009 | ret = iwl_load_section(trans, "INST", &image->code, | 1012 | for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { |
1010 | IWLAGN_RTC_INST_LOWER_BOUND); | 1013 | if (!image->sec[i].p_addr) |
1011 | if (ret) | 1014 | break; |
1012 | return ret; | ||
1013 | 1015 | ||
1014 | ret = iwl_load_section(trans, "DATA", &image->data, | 1016 | ret = iwl_load_section(trans, i, &image->sec[i]); |
1015 | IWLAGN_RTC_DATA_LOWER_BOUND); | 1017 | if (ret) |
1016 | if (ret) | 1018 | return ret; |
1017 | return ret; | 1019 | } |
1018 | 1020 | ||
1019 | /* Remove all resets to allow NIC to operate */ | 1021 | /* Remove all resets to allow NIC to operate */ |
1020 | iwl_write32(trans, CSR_RESET, 0); | 1022 | iwl_write32(trans, CSR_RESET, 0); |
@@ -1466,8 +1468,6 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
1466 | IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n", | 1468 | IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n", |
1467 | le16_to_cpu(dev_cmd->hdr.sequence)); | 1469 | le16_to_cpu(dev_cmd->hdr.sequence)); |
1468 | IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | 1470 | IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); |
1469 | iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); | ||
1470 | iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); | ||
1471 | 1471 | ||
1472 | /* Set up entry for this TFD in Tx byte-count array */ | 1472 | /* Set up entry for this TFD in Tx byte-count array */ |
1473 | iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); | 1473 | iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); |
@@ -1628,6 +1628,13 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, | |||
1628 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1628 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
1629 | 1629 | ||
1630 | trans_pcie->cmd_queue = trans_cfg->cmd_queue; | 1630 | trans_pcie->cmd_queue = trans_cfg->cmd_queue; |
1631 | if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) | ||
1632 | trans_pcie->n_no_reclaim_cmds = 0; | ||
1633 | else | ||
1634 | trans_pcie->n_no_reclaim_cmds = trans_cfg->n_no_reclaim_cmds; | ||
1635 | if (trans_pcie->n_no_reclaim_cmds) | ||
1636 | memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds, | ||
1637 | trans_pcie->n_no_reclaim_cmds * sizeof(u8)); | ||
1631 | } | 1638 | } |
1632 | 1639 | ||
1633 | static void iwl_trans_pcie_free(struct iwl_trans *trans) | 1640 | static void iwl_trans_pcie_free(struct iwl_trans *trans) |
@@ -2322,6 +2329,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, | |||
2322 | pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); | 2329 | pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); |
2323 | } | 2330 | } |
2324 | 2331 | ||
2332 | /* Initialize the wait queue for commands */ | ||
2333 | init_waitqueue_head(&trans->wait_command_queue); | ||
2334 | |||
2325 | return trans; | 2335 | return trans; |
2326 | 2336 | ||
2327 | out_pci_release_regions: | 2337 | out_pci_release_regions: |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7d1990c7f65..0c81cbaa808 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -274,6 +274,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) | |||
274 | return p; | 274 | return p; |
275 | } | 275 | } |
276 | 276 | ||
277 | #define MAX_NO_RECLAIM_CMDS 6 | ||
278 | |||
277 | /** | 279 | /** |
278 | * struct iwl_trans_config - transport configuration | 280 | * struct iwl_trans_config - transport configuration |
279 | * | 281 | * |
@@ -281,10 +283,17 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) | |||
281 | * Must be set before any other call. | 283 | * Must be set before any other call. |
282 | * @cmd_queue: the index of the command queue. | 284 | * @cmd_queue: the index of the command queue. |
283 | * Must be set before start_fw. | 285 | * Must be set before start_fw. |
286 | * @no_reclaim_cmds: Some devices erroneously don't set the | ||
287 | * SEQ_RX_FRAME bit on some notifications, this is the | ||
288 | * list of such notifications to filter. Max length is | ||
289 | * %MAX_NO_RECLAIM_CMDS. | ||
290 | * @n_no_reclaim_cmds: # of commands in list | ||
284 | */ | 291 | */ |
285 | struct iwl_trans_config { | 292 | struct iwl_trans_config { |
286 | struct iwl_op_mode *op_mode; | 293 | struct iwl_op_mode *op_mode; |
287 | u8 cmd_queue; | 294 | u8 cmd_queue; |
295 | const u8 *no_reclaim_cmds; | ||
296 | int n_no_reclaim_cmds; | ||
288 | }; | 297 | }; |
289 | 298 | ||
290 | /** | 299 | /** |
@@ -404,6 +413,7 @@ enum iwl_trans_state { | |||
404 | * @hw_id_str: a string with info about HW ID. Set during transport allocation. | 413 | * @hw_id_str: a string with info about HW ID. Set during transport allocation. |
405 | * @nvm_device_type: indicates OTP or eeprom | 414 | * @nvm_device_type: indicates OTP or eeprom |
406 | * @pm_support: set to true in start_hw if link pm is supported | 415 | * @pm_support: set to true in start_hw if link pm is supported |
416 | * @wait_command_queue: the wait_queue for SYNC host commands | ||
407 | */ | 417 | */ |
408 | struct iwl_trans { | 418 | struct iwl_trans { |
409 | const struct iwl_trans_ops *ops; | 419 | const struct iwl_trans_ops *ops; |
@@ -420,6 +430,8 @@ struct iwl_trans { | |||
420 | int nvm_device_type; | 430 | int nvm_device_type; |
421 | bool pm_support; | 431 | bool pm_support; |
422 | 432 | ||
433 | wait_queue_head_t wait_command_queue; | ||
434 | |||
423 | /* pointer to trans specific struct */ | 435 | /* pointer to trans specific struct */ |
424 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 436 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
425 | char trans_specific[0] __aligned(sizeof(void *)); | 437 | char trans_specific[0] __aligned(sizeof(void *)); |
@@ -488,8 +500,8 @@ static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans) | |||
488 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 500 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
489 | struct iwl_host_cmd *cmd) | 501 | struct iwl_host_cmd *cmd) |
490 | { | 502 | { |
491 | if (trans->state != IWL_TRANS_FW_ALIVE) | 503 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
492 | IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); | 504 | "%s bad state = %d", __func__, trans->state); |
493 | 505 | ||
494 | return trans->ops->send_cmd(trans, cmd); | 506 | return trans->ops->send_cmd(trans, cmd); |
495 | } | 507 | } |
@@ -508,8 +520,8 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, | |||
508 | int tid, int txq_id, int ssn, | 520 | int tid, int txq_id, int ssn, |
509 | struct sk_buff_head *skbs) | 521 | struct sk_buff_head *skbs) |
510 | { | 522 | { |
511 | if (trans->state != IWL_TRANS_FW_ALIVE) | 523 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
512 | IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); | 524 | "%s bad state = %d", __func__, trans->state); |
513 | 525 | ||
514 | return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, skbs); | 526 | return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, skbs); |
515 | } | 527 | } |
@@ -517,8 +529,8 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, | |||
517 | static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, | 529 | static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, |
518 | int sta_id, int tid) | 530 | int sta_id, int tid) |
519 | { | 531 | { |
520 | if (trans->state != IWL_TRANS_FW_ALIVE) | 532 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
521 | IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); | 533 | "%s bad state = %d", __func__, trans->state); |
522 | 534 | ||
523 | return trans->ops->tx_agg_disable(trans, sta_id, tid); | 535 | return trans->ops->tx_agg_disable(trans, sta_id, tid); |
524 | } | 536 | } |
@@ -526,8 +538,8 @@ static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, | |||
526 | static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, | 538 | static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, |
527 | int sta_id, int tid) | 539 | int sta_id, int tid) |
528 | { | 540 | { |
529 | if (trans->state != IWL_TRANS_FW_ALIVE) | 541 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
530 | IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); | 542 | "%s bad state = %d", __func__, trans->state); |
531 | 543 | ||
532 | return trans->ops->tx_agg_alloc(trans, sta_id, tid); | 544 | return trans->ops->tx_agg_alloc(trans, sta_id, tid); |
533 | } | 545 | } |
@@ -540,8 +552,8 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, | |||
540 | { | 552 | { |
541 | might_sleep(); | 553 | might_sleep(); |
542 | 554 | ||
543 | if (trans->state != IWL_TRANS_FW_ALIVE) | 555 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
544 | IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); | 556 | "%s bad state = %d", __func__, trans->state); |
545 | 557 | ||
546 | trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); | 558 | trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); |
547 | } | 559 | } |
@@ -553,16 +565,16 @@ static inline void iwl_trans_free(struct iwl_trans *trans) | |||
553 | 565 | ||
554 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) | 566 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) |
555 | { | 567 | { |
556 | if (trans->state != IWL_TRANS_FW_ALIVE) | 568 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
557 | IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); | 569 | "%s bad state = %d", __func__, trans->state); |
558 | 570 | ||
559 | return trans->ops->wait_tx_queue_empty(trans); | 571 | return trans->ops->wait_tx_queue_empty(trans); |
560 | } | 572 | } |
561 | 573 | ||
562 | static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q) | 574 | static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q) |
563 | { | 575 | { |
564 | if (trans->state != IWL_TRANS_FW_ALIVE) | 576 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
565 | IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); | 577 | "%s bad state = %d", __func__, trans->state); |
566 | 578 | ||
567 | return trans->ops->check_stuck_queue(trans, q); | 579 | return trans->ops->check_stuck_queue(trans, q); |
568 | } | 580 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index d97cf44b75b..25282872883 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c | |||
@@ -80,17 +80,10 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { | |||
80 | static inline const struct fw_img * | 80 | static inline const struct fw_img * |
81 | iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type) | 81 | iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type) |
82 | { | 82 | { |
83 | switch (ucode_type) { | 83 | if (ucode_type >= IWL_UCODE_TYPE_MAX) |
84 | case IWL_UCODE_INIT: | 84 | return NULL; |
85 | return &priv->fw->ucode_init; | 85 | |
86 | case IWL_UCODE_WOWLAN: | 86 | return &priv->fw->img[ucode_type]; |
87 | return &priv->fw->ucode_wowlan; | ||
88 | case IWL_UCODE_REGULAR: | ||
89 | return &priv->fw->ucode_rt; | ||
90 | case IWL_UCODE_NONE: | ||
91 | break; | ||
92 | } | ||
93 | return NULL; | ||
94 | } | 87 | } |
95 | 88 | ||
96 | /* | 89 | /* |
@@ -342,7 +335,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) | |||
342 | * using sample data 100 bytes apart. If these sample points are good, | 335 | * using sample data 100 bytes apart. If these sample points are good, |
343 | * it's a pretty good bet that everything between them is good, too. | 336 | * it's a pretty good bet that everything between them is good, too. |
344 | */ | 337 | */ |
345 | static int iwl_verify_inst_sparse(struct iwl_priv *priv, | 338 | static int iwl_verify_sec_sparse(struct iwl_priv *priv, |
346 | const struct fw_desc *fw_desc) | 339 | const struct fw_desc *fw_desc) |
347 | { | 340 | { |
348 | __le32 *image = (__le32 *)fw_desc->v_addr; | 341 | __le32 *image = (__le32 *)fw_desc->v_addr; |
@@ -357,7 +350,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, | |||
357 | /* NOTE: Use the debugless read so we don't flood kernel log | 350 | /* NOTE: Use the debugless read so we don't flood kernel log |
358 | * if IWL_DL_IO is set */ | 351 | * if IWL_DL_IO is set */ |
359 | iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR, | 352 | iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR, |
360 | i + IWLAGN_RTC_INST_LOWER_BOUND); | 353 | i + fw_desc->offset); |
361 | val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); | 354 | val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); |
362 | if (val != le32_to_cpu(*image)) | 355 | if (val != le32_to_cpu(*image)) |
363 | return -EIO; | 356 | return -EIO; |
@@ -366,7 +359,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, | |||
366 | return 0; | 359 | return 0; |
367 | } | 360 | } |
368 | 361 | ||
369 | static void iwl_print_mismatch_inst(struct iwl_priv *priv, | 362 | static void iwl_print_mismatch_sec(struct iwl_priv *priv, |
370 | const struct fw_desc *fw_desc) | 363 | const struct fw_desc *fw_desc) |
371 | { | 364 | { |
372 | __le32 *image = (__le32 *)fw_desc->v_addr; | 365 | __le32 *image = (__le32 *)fw_desc->v_addr; |
@@ -378,7 +371,7 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, | |||
378 | IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); | 371 | IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); |
379 | 372 | ||
380 | iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR, | 373 | iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR, |
381 | IWLAGN_RTC_INST_LOWER_BOUND); | 374 | fw_desc->offset); |
382 | 375 | ||
383 | for (offs = 0; | 376 | for (offs = 0; |
384 | offs < len && errors < 20; | 377 | offs < len && errors < 20; |
@@ -408,14 +401,14 @@ static int iwl_verify_ucode(struct iwl_priv *priv, | |||
408 | return -EINVAL; | 401 | return -EINVAL; |
409 | } | 402 | } |
410 | 403 | ||
411 | if (!iwl_verify_inst_sparse(priv, &img->code)) { | 404 | if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) { |
412 | IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n"); | 405 | IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n"); |
413 | return 0; | 406 | return 0; |
414 | } | 407 | } |
415 | 408 | ||
416 | IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); | 409 | IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); |
417 | 410 | ||
418 | iwl_print_mismatch_inst(priv, &img->code); | 411 | iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]); |
419 | return -EIO; | 412 | return -EIO; |
420 | } | 413 | } |
421 | 414 | ||
@@ -465,6 +458,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, | |||
465 | priv->shrd->ucode_type = ucode_type; | 458 | priv->shrd->ucode_type = ucode_type; |
466 | fw = iwl_get_ucode_image(priv, ucode_type); | 459 | fw = iwl_get_ucode_image(priv, ucode_type); |
467 | 460 | ||
461 | priv->ucode_loaded = false; | ||
462 | |||
468 | if (!fw) | 463 | if (!fw) |
469 | return -EINVAL; | 464 | return -EINVAL; |
470 | 465 | ||
@@ -519,6 +514,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, | |||
519 | return ret; | 514 | return ret; |
520 | } | 515 | } |
521 | 516 | ||
517 | priv->ucode_loaded = true; | ||
518 | |||
522 | return 0; | 519 | return 0; |
523 | } | 520 | } |
524 | 521 | ||
@@ -530,10 +527,10 @@ int iwl_run_init_ucode(struct iwl_priv *priv) | |||
530 | lockdep_assert_held(&priv->mutex); | 527 | lockdep_assert_held(&priv->mutex); |
531 | 528 | ||
532 | /* No init ucode required? Curious, but maybe ok */ | 529 | /* No init ucode required? Curious, but maybe ok */ |
533 | if (!priv->fw->ucode_init.code.len) | 530 | if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len) |
534 | return 0; | 531 | return 0; |
535 | 532 | ||
536 | if (priv->shrd->ucode_type != IWL_UCODE_NONE) | 533 | if (priv->init_ucode_run) |
537 | return 0; | 534 | return 0; |
538 | 535 | ||
539 | iwl_init_notification_wait(&priv->notif_wait, &calib_wait, | 536 | iwl_init_notification_wait(&priv->notif_wait, &calib_wait, |
@@ -555,6 +552,8 @@ int iwl_run_init_ucode(struct iwl_priv *priv) | |||
555 | */ | 552 | */ |
556 | ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, | 553 | ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, |
557 | UCODE_CALIB_TIMEOUT); | 554 | UCODE_CALIB_TIMEOUT); |
555 | if (!ret) | ||
556 | priv->init_ucode_run = true; | ||
558 | 557 | ||
559 | goto out; | 558 | goto out; |
560 | 559 | ||
@@ -563,5 +562,7 @@ int iwl_run_init_ucode(struct iwl_priv *priv) | |||
563 | out: | 562 | out: |
564 | /* Whatever happened, stop the device */ | 563 | /* Whatever happened, stop the device */ |
565 | iwl_trans_stop_device(trans(priv)); | 564 | iwl_trans_stop_device(trans(priv)); |
565 | priv->ucode_loaded = false; | ||
566 | |||
566 | return ret; | 567 | return ret; |
567 | } | 568 | } |