diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/fw.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw.c | 160 |
1 files changed, 143 insertions, 17 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index ca38e9817374..bc5eac4960e1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -112,25 +112,27 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, | |||
112 | struct iwl_mvm *mvm = | 112 | struct iwl_mvm *mvm = |
113 | container_of(notif_wait, struct iwl_mvm, notif_wait); | 113 | container_of(notif_wait, struct iwl_mvm, notif_wait); |
114 | struct iwl_mvm_alive_data *alive_data = data; | 114 | struct iwl_mvm_alive_data *alive_data = data; |
115 | struct mvm_alive_resp *palive; | 115 | struct mvm_alive_resp_ver1 *palive1; |
116 | struct mvm_alive_resp_ver2 *palive2; | 116 | struct mvm_alive_resp_ver2 *palive2; |
117 | struct mvm_alive_resp *palive; | ||
117 | 118 | ||
118 | if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) { | 119 | if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive1)) { |
119 | palive = (void *)pkt->data; | 120 | palive1 = (void *)pkt->data; |
120 | 121 | ||
121 | mvm->support_umac_log = false; | 122 | mvm->support_umac_log = false; |
122 | mvm->error_event_table = | 123 | mvm->error_event_table = |
123 | le32_to_cpu(palive->error_event_table_ptr); | 124 | le32_to_cpu(palive1->error_event_table_ptr); |
124 | mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); | 125 | mvm->log_event_table = |
125 | alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); | 126 | le32_to_cpu(palive1->log_event_table_ptr); |
127 | alive_data->scd_base_addr = le32_to_cpu(palive1->scd_base_ptr); | ||
126 | 128 | ||
127 | alive_data->valid = le16_to_cpu(palive->status) == | 129 | alive_data->valid = le16_to_cpu(palive1->status) == |
128 | IWL_ALIVE_STATUS_OK; | 130 | IWL_ALIVE_STATUS_OK; |
129 | IWL_DEBUG_FW(mvm, | 131 | IWL_DEBUG_FW(mvm, |
130 | "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", | 132 | "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", |
131 | le16_to_cpu(palive->status), palive->ver_type, | 133 | le16_to_cpu(palive1->status), palive1->ver_type, |
132 | palive->ver_subtype, palive->flags); | 134 | palive1->ver_subtype, palive1->flags); |
133 | } else { | 135 | } else if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive2)) { |
134 | palive2 = (void *)pkt->data; | 136 | palive2 = (void *)pkt->data; |
135 | 137 | ||
136 | mvm->error_event_table = | 138 | mvm->error_event_table = |
@@ -156,6 +158,33 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, | |||
156 | IWL_DEBUG_FW(mvm, | 158 | IWL_DEBUG_FW(mvm, |
157 | "UMAC version: Major - 0x%x, Minor - 0x%x\n", | 159 | "UMAC version: Major - 0x%x, Minor - 0x%x\n", |
158 | palive2->umac_major, palive2->umac_minor); | 160 | palive2->umac_major, palive2->umac_minor); |
161 | } else if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) { | ||
162 | palive = (void *)pkt->data; | ||
163 | |||
164 | mvm->error_event_table = | ||
165 | le32_to_cpu(palive->error_event_table_ptr); | ||
166 | mvm->log_event_table = | ||
167 | le32_to_cpu(palive->log_event_table_ptr); | ||
168 | alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); | ||
169 | mvm->umac_error_event_table = | ||
170 | le32_to_cpu(palive->error_info_addr); | ||
171 | mvm->sf_space.addr = le32_to_cpu(palive->st_fwrd_addr); | ||
172 | mvm->sf_space.size = le32_to_cpu(palive->st_fwrd_size); | ||
173 | |||
174 | alive_data->valid = le16_to_cpu(palive->status) == | ||
175 | IWL_ALIVE_STATUS_OK; | ||
176 | if (mvm->umac_error_event_table) | ||
177 | mvm->support_umac_log = true; | ||
178 | |||
179 | IWL_DEBUG_FW(mvm, | ||
180 | "Alive VER3 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", | ||
181 | le16_to_cpu(palive->status), palive->ver_type, | ||
182 | palive->ver_subtype, palive->flags); | ||
183 | |||
184 | IWL_DEBUG_FW(mvm, | ||
185 | "UMAC version: Major - 0x%x, Minor - 0x%x\n", | ||
186 | le32_to_cpu(palive->umac_major), | ||
187 | le32_to_cpu(palive->umac_minor)); | ||
159 | } | 188 | } |
160 | 189 | ||
161 | return true; | 190 | return true; |
@@ -188,8 +217,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
188 | struct iwl_sf_region st_fwrd_space; | 217 | struct iwl_sf_region st_fwrd_space; |
189 | 218 | ||
190 | if (ucode_type == IWL_UCODE_REGULAR && | 219 | if (ucode_type == IWL_UCODE_REGULAR && |
191 | iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_CUSTOM) && | 220 | iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE)) |
192 | iwl_fw_dbg_conf_enabled(mvm->fw, FW_DBG_CUSTOM)) | ||
193 | fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER); | 221 | fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER); |
194 | else | 222 | else |
195 | fw = iwl_get_ucode_image(mvm, ucode_type); | 223 | fw = iwl_get_ucode_image(mvm, ucode_type); |
@@ -451,20 +479,97 @@ exit: | |||
451 | iwl_free_resp(&cmd); | 479 | iwl_free_resp(&cmd); |
452 | } | 480 | } |
453 | 481 | ||
454 | void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm) | 482 | int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, |
483 | struct iwl_mvm_dump_desc *desc, | ||
484 | unsigned int delay) | ||
455 | { | 485 | { |
486 | if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status)) | ||
487 | return -EBUSY; | ||
488 | |||
489 | if (WARN_ON(mvm->fw_dump_desc)) | ||
490 | iwl_mvm_free_fw_dump_desc(mvm); | ||
491 | |||
492 | IWL_WARN(mvm, "Collecting data: trigger %d fired.\n", | ||
493 | le32_to_cpu(desc->trig_desc.type)); | ||
494 | |||
495 | mvm->fw_dump_desc = desc; | ||
496 | |||
456 | /* stop recording */ | 497 | /* stop recording */ |
457 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | 498 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { |
458 | iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); | 499 | iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); |
459 | } else { | 500 | } else { |
460 | iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); | 501 | iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); |
461 | iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0); | 502 | /* wait before we collect the data till the DBGC stop */ |
503 | udelay(100); | ||
504 | } | ||
505 | |||
506 | queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, | ||
512 | const char *str, size_t len, unsigned int delay) | ||
513 | { | ||
514 | struct iwl_mvm_dump_desc *desc; | ||
515 | |||
516 | desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC); | ||
517 | if (!desc) | ||
518 | return -ENOMEM; | ||
519 | |||
520 | desc->len = len; | ||
521 | desc->trig_desc.type = cpu_to_le32(trig); | ||
522 | memcpy(desc->trig_desc.data, str, len); | ||
523 | |||
524 | return iwl_mvm_fw_dbg_collect_desc(mvm, desc, delay); | ||
525 | } | ||
526 | |||
527 | int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, | ||
528 | struct iwl_fw_dbg_trigger_tlv *trigger, | ||
529 | const char *fmt, ...) | ||
530 | { | ||
531 | unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); | ||
532 | u16 occurrences = le16_to_cpu(trigger->occurrences); | ||
533 | int ret, len = 0; | ||
534 | char buf[64]; | ||
535 | |||
536 | if (!occurrences) | ||
537 | return 0; | ||
538 | |||
539 | if (fmt) { | ||
540 | va_list ap; | ||
541 | |||
542 | buf[sizeof(buf) - 1] = '\0'; | ||
543 | |||
544 | va_start(ap, fmt); | ||
545 | vsnprintf(buf, sizeof(buf), fmt, ap); | ||
546 | va_end(ap); | ||
547 | |||
548 | /* check for truncation */ | ||
549 | if (WARN_ON_ONCE(buf[sizeof(buf) - 1])) | ||
550 | buf[sizeof(buf) - 1] = '\0'; | ||
551 | |||
552 | len = strlen(buf) + 1; | ||
462 | } | 553 | } |
463 | 554 | ||
464 | schedule_work(&mvm->fw_error_dump_wk); | 555 | ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, |
556 | len, delay); | ||
557 | if (ret) | ||
558 | return ret; | ||
559 | |||
560 | trigger->occurrences = cpu_to_le16(occurrences - 1); | ||
561 | return 0; | ||
465 | } | 562 | } |
466 | 563 | ||
467 | int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) | 564 | static inline void iwl_mvm_restart_early_start(struct iwl_mvm *mvm) |
565 | { | ||
566 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) | ||
567 | iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); | ||
568 | else | ||
569 | iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 1); | ||
570 | } | ||
571 | |||
572 | int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id) | ||
468 | { | 573 | { |
469 | u8 *ptr; | 574 | u8 *ptr; |
470 | int ret; | 575 | int ret; |
@@ -474,6 +579,14 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) | |||
474 | "Invalid configuration %d\n", conf_id)) | 579 | "Invalid configuration %d\n", conf_id)) |
475 | return -EINVAL; | 580 | return -EINVAL; |
476 | 581 | ||
582 | /* EARLY START - firmware's configuration is hard coded */ | ||
583 | if ((!mvm->fw->dbg_conf_tlv[conf_id] || | ||
584 | !mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) && | ||
585 | conf_id == FW_DBG_START_FROM_ALIVE) { | ||
586 | iwl_mvm_restart_early_start(mvm); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
477 | if (!mvm->fw->dbg_conf_tlv[conf_id]) | 590 | if (!mvm->fw->dbg_conf_tlv[conf_id]) |
478 | return -EINVAL; | 591 | return -EINVAL; |
479 | 592 | ||
@@ -583,7 +696,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
583 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); | 696 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); |
584 | 697 | ||
585 | mvm->fw_dbg_conf = FW_DBG_INVALID; | 698 | mvm->fw_dbg_conf = FW_DBG_INVALID; |
586 | iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM); | 699 | /* if we have a destination, assume EARLY START */ |
700 | if (mvm->fw->dbg_dest_tlv) | ||
701 | mvm->fw_dbg_conf = FW_DBG_START_FROM_ALIVE; | ||
702 | iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_START_FROM_ALIVE); | ||
587 | 703 | ||
588 | ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); | 704 | ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); |
589 | if (ret) | 705 | if (ret) |
@@ -640,6 +756,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
640 | if (ret) | 756 | if (ret) |
641 | goto error; | 757 | goto error; |
642 | 758 | ||
759 | /* | ||
760 | * RTNL is not taken during Ct-kill, but we don't need to scan/Tx | ||
761 | * anyway, so don't init MCC. | ||
762 | */ | ||
763 | if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) { | ||
764 | ret = iwl_mvm_init_mcc(mvm); | ||
765 | if (ret) | ||
766 | goto error; | ||
767 | } | ||
768 | |||
643 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | 769 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { |
644 | ret = iwl_mvm_config_scan(mvm); | 770 | ret = iwl_mvm_config_scan(mvm); |
645 | if (ret) | 771 | if (ret) |