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 | } | ||
