diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-ucode.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | 245 |
1 files changed, 173 insertions, 72 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 5c30f6b19a7f..c3ae2e44fcc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | |||
@@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, | |||
161 | } | 161 | } |
162 | 162 | ||
163 | static int iwlagn_load_given_ucode(struct iwl_priv *priv, | 163 | static int iwlagn_load_given_ucode(struct iwl_priv *priv, |
164 | struct fw_desc *inst_image, | 164 | struct fw_img *image) |
165 | struct fw_desc *data_image) | ||
166 | { | 165 | { |
167 | int ret = 0; | 166 | int ret = 0; |
168 | 167 | ||
169 | ret = iwlagn_load_section(priv, "INST", inst_image, | 168 | ret = iwlagn_load_section(priv, "INST", &image->code, |
170 | IWLAGN_RTC_INST_LOWER_BOUND); | 169 | IWLAGN_RTC_INST_LOWER_BOUND); |
171 | if (ret) | 170 | if (ret) |
172 | return ret; | 171 | return ret; |
173 | 172 | ||
174 | return iwlagn_load_section(priv, "DATA", data_image, | 173 | return iwlagn_load_section(priv, "DATA", &image->data, |
175 | IWLAGN_RTC_DATA_LOWER_BOUND); | 174 | IWLAGN_RTC_DATA_LOWER_BOUND); |
176 | } | 175 | } |
177 | 176 | ||
178 | int iwlagn_load_ucode(struct iwl_priv *priv) | ||
179 | { | ||
180 | int ret = 0; | ||
181 | |||
182 | /* check whether init ucode should be loaded, or rather runtime ucode */ | ||
183 | if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { | ||
184 | IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n"); | ||
185 | ret = iwlagn_load_given_ucode(priv, | ||
186 | &priv->ucode_init, &priv->ucode_init_data); | ||
187 | if (!ret) { | ||
188 | IWL_DEBUG_INFO(priv, "Init ucode load complete.\n"); | ||
189 | priv->ucode_type = UCODE_INIT; | ||
190 | } | ||
191 | } else { | ||
192 | IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. " | ||
193 | "Loading runtime ucode...\n"); | ||
194 | ret = iwlagn_load_given_ucode(priv, | ||
195 | &priv->ucode_code, &priv->ucode_data); | ||
196 | if (!ret) { | ||
197 | IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n"); | ||
198 | priv->ucode_type = UCODE_RT; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | /* | 177 | /* |
206 | * Calibration | 178 | * Calibration |
207 | */ | 179 | */ |
@@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, | |||
297 | iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); | 269 | iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); |
298 | } | 270 | } |
299 | 271 | ||
300 | void iwlagn_rx_calib_complete(struct iwl_priv *priv, | 272 | static int iwlagn_init_alive_start(struct iwl_priv *priv) |
301 | struct iwl_rx_mem_buffer *rxb) | ||
302 | { | 273 | { |
303 | IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n"); | 274 | int ret; |
304 | queue_work(priv->workqueue, &priv->restart); | ||
305 | } | ||
306 | |||
307 | void iwlagn_init_alive_start(struct iwl_priv *priv) | ||
308 | { | ||
309 | int ret = 0; | ||
310 | |||
311 | /* initialize uCode was loaded... verify inst image. | ||
312 | * This is a paranoid check, because we would not have gotten the | ||
313 | * "initialize" alive if code weren't properly loaded. */ | ||
314 | if (iwl_verify_ucode(priv, &priv->ucode_init)) { | ||
315 | /* Runtime instruction load was bad; | ||
316 | * take it all the way back down so we can try again */ | ||
317 | IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); | ||
318 | goto restart; | ||
319 | } | ||
320 | |||
321 | ret = iwlagn_alive_notify(priv); | ||
322 | if (ret) { | ||
323 | IWL_WARN(priv, | ||
324 | "Could not complete ALIVE transition: %d\n", ret); | ||
325 | goto restart; | ||
326 | } | ||
327 | 275 | ||
328 | if (priv->cfg->bt_params && | 276 | if (priv->cfg->bt_params && |
329 | priv->cfg->bt_params->advanced_bt_coexist) { | 277 | priv->cfg->bt_params->advanced_bt_coexist) { |
@@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) | |||
333 | * no need to close the envlope since we are going | 281 | * no need to close the envlope since we are going |
334 | * to load the runtime uCode later. | 282 | * to load the runtime uCode later. |
335 | */ | 283 | */ |
336 | iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, | 284 | ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, |
337 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | 285 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); |
286 | if (ret) | ||
287 | return ret; | ||
338 | 288 | ||
339 | } | 289 | } |
340 | iwlagn_send_calib_cfg(priv); | 290 | |
291 | ret = iwlagn_send_calib_cfg(priv); | ||
292 | if (ret) | ||
293 | return ret; | ||
341 | 294 | ||
342 | /** | 295 | /** |
343 | * temperature offset calibration is only needed for runtime ucode, | 296 | * temperature offset calibration is only needed for runtime ucode, |
344 | * so prepare the value now. | 297 | * so prepare the value now. |
345 | */ | 298 | */ |
346 | if (priv->cfg->need_temp_offset_calib) | 299 | if (priv->cfg->need_temp_offset_calib) |
347 | iwlagn_set_temperature_offset_calib(priv); | 300 | return iwlagn_set_temperature_offset_calib(priv); |
348 | |||
349 | return; | ||
350 | 301 | ||
351 | restart: | 302 | return 0; |
352 | /* real restart (first load init_ucode) */ | ||
353 | queue_work(priv->workqueue, &priv->restart); | ||
354 | } | 303 | } |
355 | 304 | ||
356 | static int iwlagn_send_wimax_coex(struct iwl_priv *priv) | 305 | static int iwlagn_send_wimax_coex(struct iwl_priv *priv) |
@@ -413,19 +362,22 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv) | |||
413 | IWL_ERR(priv, "failed to send BT prio tbl command\n"); | 362 | IWL_ERR(priv, "failed to send BT prio tbl command\n"); |
414 | } | 363 | } |
415 | 364 | ||
416 | void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) | 365 | int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) |
417 | { | 366 | { |
418 | struct iwl_bt_coex_prot_env_cmd env_cmd; | 367 | struct iwl_bt_coex_prot_env_cmd env_cmd; |
368 | int ret; | ||
419 | 369 | ||
420 | env_cmd.action = action; | 370 | env_cmd.action = action; |
421 | env_cmd.type = type; | 371 | env_cmd.type = type; |
422 | if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, | 372 | ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, |
423 | sizeof(env_cmd), &env_cmd)) | 373 | sizeof(env_cmd), &env_cmd); |
374 | if (ret) | ||
424 | IWL_ERR(priv, "failed to send BT env command\n"); | 375 | IWL_ERR(priv, "failed to send BT env command\n"); |
376 | return ret; | ||
425 | } | 377 | } |
426 | 378 | ||
427 | 379 | ||
428 | int iwlagn_alive_notify(struct iwl_priv *priv) | 380 | static int iwlagn_alive_notify(struct iwl_priv *priv) |
429 | { | 381 | { |
430 | const struct queue_to_fifo_ac *queue_to_fifo; | 382 | const struct queue_to_fifo_ac *queue_to_fifo; |
431 | struct iwl_rxon_context *ctx; | 383 | struct iwl_rxon_context *ctx; |
@@ -604,15 +556,164 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, | |||
604 | * iwl_verify_ucode - determine which instruction image is in SRAM, | 556 | * iwl_verify_ucode - determine which instruction image is in SRAM, |
605 | * and verify its contents | 557 | * and verify its contents |
606 | */ | 558 | */ |
607 | int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) | 559 | static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) |
608 | { | 560 | { |
609 | if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { | 561 | if (!iwlcore_verify_inst_sparse(priv, &img->code)) { |
610 | IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); | 562 | IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); |
611 | return 0; | 563 | return 0; |
612 | } | 564 | } |
613 | 565 | ||
614 | IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); | 566 | IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); |
615 | 567 | ||
616 | iwl_print_mismatch_inst(priv, fw_desc); | 568 | iwl_print_mismatch_inst(priv, &img->code); |
617 | return -EIO; | 569 | return -EIO; |
618 | } | 570 | } |
571 | |||
572 | struct iwlagn_alive_data { | ||
573 | bool valid; | ||
574 | u8 subtype; | ||
575 | }; | ||
576 | |||
577 | static void iwlagn_alive_fn(struct iwl_priv *priv, | ||
578 | struct iwl_rx_packet *pkt, | ||
579 | void *data) | ||
580 | { | ||
581 | struct iwlagn_alive_data *alive_data = data; | ||
582 | struct iwl_alive_resp *palive; | ||
583 | |||
584 | palive = &pkt->u.alive_frame; | ||
585 | |||
586 | IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " | ||
587 | "0x%01X 0x%01X\n", | ||
588 | palive->is_valid, palive->ver_type, | ||
589 | palive->ver_subtype); | ||
590 | |||
591 | priv->device_pointers.error_event_table = | ||
592 | le32_to_cpu(palive->error_event_table_ptr); | ||
593 | priv->device_pointers.log_event_table = | ||
594 | le32_to_cpu(palive->log_event_table_ptr); | ||
595 | |||
596 | alive_data->subtype = palive->ver_subtype; | ||
597 | alive_data->valid = palive->is_valid == UCODE_VALID_OK; | ||
598 | } | ||
599 | |||
600 | #define UCODE_ALIVE_TIMEOUT HZ | ||
601 | #define UCODE_CALIB_TIMEOUT (2*HZ) | ||
602 | |||
603 | int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, | ||
604 | struct fw_img *image, | ||
605 | int subtype, int alternate_subtype) | ||
606 | { | ||
607 | struct iwl_notification_wait alive_wait; | ||
608 | struct iwlagn_alive_data alive_data; | ||
609 | int ret; | ||
610 | enum iwlagn_ucode_subtype old_type; | ||
611 | |||
612 | ret = iwlagn_start_device(priv); | ||
613 | if (ret) | ||
614 | return ret; | ||
615 | |||
616 | iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE, | ||
617 | iwlagn_alive_fn, &alive_data); | ||
618 | |||
619 | old_type = priv->ucode_type; | ||
620 | priv->ucode_type = subtype; | ||
621 | |||
622 | ret = iwlagn_load_given_ucode(priv, image); | ||
623 | if (ret) { | ||
624 | priv->ucode_type = old_type; | ||
625 | iwlagn_remove_notification(priv, &alive_wait); | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | /* Remove all resets to allow NIC to operate */ | ||
630 | iwl_write32(priv, CSR_RESET, 0); | ||
631 | |||
632 | /* | ||
633 | * Some things may run in the background now, but we | ||
634 | * just wait for the ALIVE notification here. | ||
635 | */ | ||
636 | ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT); | ||
637 | if (ret) { | ||
638 | priv->ucode_type = old_type; | ||
639 | return ret; | ||
640 | } | ||
641 | |||
642 | if (!alive_data.valid) { | ||
643 | IWL_ERR(priv, "Loaded ucode is not valid!\n"); | ||
644 | priv->ucode_type = old_type; | ||
645 | return -EIO; | ||
646 | } | ||
647 | |||
648 | if (alive_data.subtype != subtype && | ||
649 | alive_data.subtype != alternate_subtype) { | ||
650 | IWL_ERR(priv, | ||
651 | "Loaded ucode is not expected type (got %d, expected %d)!\n", | ||
652 | alive_data.subtype, subtype); | ||
653 | priv->ucode_type = old_type; | ||
654 | return -EIO; | ||
655 | } | ||
656 | |||
657 | ret = iwl_verify_ucode(priv, image); | ||
658 | if (ret) { | ||
659 | priv->ucode_type = old_type; | ||
660 | return ret; | ||
661 | } | ||
662 | |||
663 | /* delay a bit to give rfkill time to run */ | ||
664 | msleep(5); | ||
665 | |||
666 | ret = iwlagn_alive_notify(priv); | ||
667 | if (ret) { | ||
668 | IWL_WARN(priv, | ||
669 | "Could not complete ALIVE transition: %d\n", ret); | ||
670 | priv->ucode_type = old_type; | ||
671 | return ret; | ||
672 | } | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | int iwlagn_run_init_ucode(struct iwl_priv *priv) | ||
678 | { | ||
679 | struct iwl_notification_wait calib_wait; | ||
680 | int ret; | ||
681 | |||
682 | lockdep_assert_held(&priv->mutex); | ||
683 | |||
684 | /* No init ucode required? Curious, but maybe ok */ | ||
685 | if (!priv->ucode_init.code.len) | ||
686 | return 0; | ||
687 | |||
688 | if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED) | ||
689 | return 0; | ||
690 | |||
691 | iwlagn_init_notification_wait(priv, &calib_wait, | ||
692 | CALIBRATION_COMPLETE_NOTIFICATION, | ||
693 | NULL, NULL); | ||
694 | |||
695 | /* Will also start the device */ | ||
696 | ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, | ||
697 | UCODE_SUBTYPE_INIT, -1); | ||
698 | if (ret) | ||
699 | goto error; | ||
700 | |||
701 | ret = iwlagn_init_alive_start(priv); | ||
702 | if (ret) | ||
703 | goto error; | ||
704 | |||
705 | /* | ||
706 | * Some things may run in the background now, but we | ||
707 | * just wait for the calibration complete notification. | ||
708 | */ | ||
709 | ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT); | ||
710 | |||
711 | goto out; | ||
712 | |||
713 | error: | ||
714 | iwlagn_remove_notification(priv, &calib_wait); | ||
715 | out: | ||
716 | /* Whatever happened, stop the device */ | ||
717 | iwlagn_stop_device(priv); | ||
718 | return ret; | ||
719 | } | ||