diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2015-10-21 04:07:55 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-10-21 04:07:55 -0400 |
commit | 81c1f74de3b6a9be0006a734d3584150f9c2e295 (patch) | |
tree | 49828ae4f2f6a06cecb0687de7013e0c7681109d | |
parent | f8273bafcbc1bc04d1b139144f78f25c559f10c3 (diff) | |
parent | bc6f9ae6043a219b5afadf0391ce77db401a966f (diff) |
Merge ath-next from ath.git
Major changes:
ath10k
* add board 2 API support for automatically choosing correct board file
* data path optimisations
* disable PCI power save for qca988x and QCA99x0 due to interop reasons
wil6210
* BlockAckReq support
* firmware crashdump using devcoredump
* capture all frames with sniffer
39 files changed, 1855 insertions, 548 deletions
diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index df7c7616533b..7d3231acfb24 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h | |||
@@ -82,6 +82,16 @@ enum bmi_cmd_id { | |||
82 | 82 | ||
83 | #define BMI_NVRAM_SEG_NAME_SZ 16 | 83 | #define BMI_NVRAM_SEG_NAME_SZ 16 |
84 | 84 | ||
85 | #define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10 | ||
86 | |||
87 | #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00 | ||
88 | #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10 | ||
89 | |||
90 | #define ATH10K_BMI_CHIP_ID_FROM_OTP_MASK 0x18000 | ||
91 | #define ATH10K_BMI_CHIP_ID_FROM_OTP_LSB 15 | ||
92 | |||
93 | #define ATH10K_BMI_BOARD_ID_STATUS_MASK 0xff | ||
94 | |||
85 | struct bmi_cmd { | 95 | struct bmi_cmd { |
86 | __le32 id; /* enum bmi_cmd_id */ | 96 | __le32 id; /* enum bmi_cmd_id */ |
87 | union { | 97 | union { |
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index cf28fbebaedc..84220c376308 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c | |||
@@ -413,7 +413,7 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) | |||
413 | lockdep_assert_held(&ar_pci->ce_lock); | 413 | lockdep_assert_held(&ar_pci->ce_lock); |
414 | 414 | ||
415 | if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) | 415 | if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) |
416 | return -EIO; | 416 | return -ENOSPC; |
417 | 417 | ||
418 | desc->addr = __cpu_to_le32(paddr); | 418 | desc->addr = __cpu_to_le32(paddr); |
419 | desc->nbytes = 0; | 419 | desc->nbytes = 0; |
@@ -1076,9 +1076,7 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) | |||
1076 | } | 1076 | } |
1077 | 1077 | ||
1078 | int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, | 1078 | int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, |
1079 | const struct ce_attr *attr, | 1079 | const struct ce_attr *attr) |
1080 | void (*send_cb)(struct ath10k_ce_pipe *), | ||
1081 | void (*recv_cb)(struct ath10k_ce_pipe *)) | ||
1082 | { | 1080 | { |
1083 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 1081 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
1084 | struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; | 1082 | struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; |
@@ -1104,10 +1102,10 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, | |||
1104 | ce_state->src_sz_max = attr->src_sz_max; | 1102 | ce_state->src_sz_max = attr->src_sz_max; |
1105 | 1103 | ||
1106 | if (attr->src_nentries) | 1104 | if (attr->src_nentries) |
1107 | ce_state->send_cb = send_cb; | 1105 | ce_state->send_cb = attr->send_cb; |
1108 | 1106 | ||
1109 | if (attr->dest_nentries) | 1107 | if (attr->dest_nentries) |
1110 | ce_state->recv_cb = recv_cb; | 1108 | ce_state->recv_cb = attr->recv_cb; |
1111 | 1109 | ||
1112 | if (attr->src_nentries) { | 1110 | if (attr->src_nentries) { |
1113 | ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); | 1111 | ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); |
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 5c903e15dd65..dbb94fdb274b 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h | |||
@@ -209,9 +209,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, | |||
209 | const struct ce_attr *attr); | 209 | const struct ce_attr *attr); |
210 | void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); | 210 | void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); |
211 | int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, | 211 | int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, |
212 | const struct ce_attr *attr, | 212 | const struct ce_attr *attr); |
213 | void (*send_cb)(struct ath10k_ce_pipe *), | ||
214 | void (*recv_cb)(struct ath10k_ce_pipe *)); | ||
215 | void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id); | 213 | void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id); |
216 | 214 | ||
217 | /*==================CE Engine Shutdown=======================*/ | 215 | /*==================CE Engine Shutdown=======================*/ |
@@ -277,6 +275,9 @@ struct ce_attr { | |||
277 | 275 | ||
278 | /* #entries in destination ring - Must be a power of 2 */ | 276 | /* #entries in destination ring - Must be a power of 2 */ |
279 | unsigned int dest_nentries; | 277 | unsigned int dest_nentries; |
278 | |||
279 | void (*send_cb)(struct ath10k_ce_pipe *); | ||
280 | void (*recv_cb)(struct ath10k_ce_pipe *); | ||
280 | }; | 281 | }; |
281 | 282 | ||
282 | #define SR_BA_ADDRESS 0x0000 | 283 | #define SR_BA_ADDRESS 0x0000 |
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 879625adc63a..13de3617d5ab 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c | |||
@@ -448,6 +448,56 @@ out: | |||
448 | return ret; | 448 | return ret; |
449 | } | 449 | } |
450 | 450 | ||
451 | static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) | ||
452 | { | ||
453 | u32 result, address; | ||
454 | u8 board_id, chip_id; | ||
455 | int ret; | ||
456 | |||
457 | address = ar->hw_params.patch_load_addr; | ||
458 | |||
459 | if (!ar->otp_data || !ar->otp_len) { | ||
460 | ath10k_warn(ar, | ||
461 | "failed to retrieve board id because of invalid otp\n"); | ||
462 | return -ENODATA; | ||
463 | } | ||
464 | |||
465 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | ||
466 | "boot upload otp to 0x%x len %zd for board id\n", | ||
467 | address, ar->otp_len); | ||
468 | |||
469 | ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); | ||
470 | if (ret) { | ||
471 | ath10k_err(ar, "could not write otp for board id check: %d\n", | ||
472 | ret); | ||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID, | ||
477 | &result); | ||
478 | if (ret) { | ||
479 | ath10k_err(ar, "could not execute otp for board id check: %d\n", | ||
480 | ret); | ||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP); | ||
485 | chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP); | ||
486 | |||
487 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | ||
488 | "boot get otp board id result 0x%08x board_id %d chip_id %d\n", | ||
489 | result, board_id, chip_id); | ||
490 | |||
491 | if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0) | ||
492 | return -EOPNOTSUPP; | ||
493 | |||
494 | ar->id.bmi_ids_valid = true; | ||
495 | ar->id.bmi_board_id = board_id; | ||
496 | ar->id.bmi_chip_id = chip_id; | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
451 | static int ath10k_download_and_run_otp(struct ath10k *ar) | 501 | static int ath10k_download_and_run_otp(struct ath10k *ar) |
452 | { | 502 | { |
453 | u32 result, address = ar->hw_params.patch_load_addr; | 503 | u32 result, address = ar->hw_params.patch_load_addr; |
@@ -486,8 +536,8 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) | |||
486 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); | 536 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); |
487 | 537 | ||
488 | if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, | 538 | if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, |
489 | ar->fw_features)) | 539 | ar->fw_features)) && |
490 | && result != 0) { | 540 | result != 0) { |
491 | ath10k_err(ar, "otp calibration failed: %d", result); | 541 | ath10k_err(ar, "otp calibration failed: %d", result); |
492 | return -EINVAL; | 542 | return -EINVAL; |
493 | } | 543 | } |
@@ -510,7 +560,7 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) | |||
510 | data_len = ar->firmware_len; | 560 | data_len = ar->firmware_len; |
511 | mode_name = "normal"; | 561 | mode_name = "normal"; |
512 | ret = ath10k_swap_code_seg_configure(ar, | 562 | ret = ath10k_swap_code_seg_configure(ar, |
513 | ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); | 563 | ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); |
514 | if (ret) { | 564 | if (ret) { |
515 | ath10k_err(ar, "failed to configure fw code swap: %d\n", | 565 | ath10k_err(ar, "failed to configure fw code swap: %d\n", |
516 | ret); | 566 | ret); |
@@ -541,11 +591,18 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) | |||
541 | return ret; | 591 | return ret; |
542 | } | 592 | } |
543 | 593 | ||
544 | static void ath10k_core_free_firmware_files(struct ath10k *ar) | 594 | static void ath10k_core_free_board_files(struct ath10k *ar) |
545 | { | 595 | { |
546 | if (!IS_ERR(ar->board)) | 596 | if (!IS_ERR(ar->board)) |
547 | release_firmware(ar->board); | 597 | release_firmware(ar->board); |
548 | 598 | ||
599 | ar->board = NULL; | ||
600 | ar->board_data = NULL; | ||
601 | ar->board_len = 0; | ||
602 | } | ||
603 | |||
604 | static void ath10k_core_free_firmware_files(struct ath10k *ar) | ||
605 | { | ||
549 | if (!IS_ERR(ar->otp)) | 606 | if (!IS_ERR(ar->otp)) |
550 | release_firmware(ar->otp); | 607 | release_firmware(ar->otp); |
551 | 608 | ||
@@ -557,10 +614,6 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) | |||
557 | 614 | ||
558 | ath10k_swap_code_seg_release(ar); | 615 | ath10k_swap_code_seg_release(ar); |
559 | 616 | ||
560 | ar->board = NULL; | ||
561 | ar->board_data = NULL; | ||
562 | ar->board_len = 0; | ||
563 | |||
564 | ar->otp = NULL; | 617 | ar->otp = NULL; |
565 | ar->otp_data = NULL; | 618 | ar->otp_data = NULL; |
566 | ar->otp_len = 0; | 619 | ar->otp_len = 0; |
@@ -570,7 +623,6 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) | |||
570 | ar->firmware_len = 0; | 623 | ar->firmware_len = 0; |
571 | 624 | ||
572 | ar->cal_file = NULL; | 625 | ar->cal_file = NULL; |
573 | |||
574 | } | 626 | } |
575 | 627 | ||
576 | static int ath10k_fetch_cal_file(struct ath10k *ar) | 628 | static int ath10k_fetch_cal_file(struct ath10k *ar) |
@@ -592,68 +644,251 @@ static int ath10k_fetch_cal_file(struct ath10k *ar) | |||
592 | return 0; | 644 | return 0; |
593 | } | 645 | } |
594 | 646 | ||
595 | static int ath10k_core_fetch_spec_board_file(struct ath10k *ar) | 647 | static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar) |
596 | { | 648 | { |
597 | char filename[100]; | 649 | if (!ar->hw_params.fw.board) { |
598 | 650 | ath10k_err(ar, "failed to find board file fw entry\n"); | |
599 | scnprintf(filename, sizeof(filename), "board-%s-%s.bin", | 651 | return -EINVAL; |
600 | ath10k_bus_str(ar->hif.bus), ar->spec_board_id); | 652 | } |
601 | 653 | ||
602 | ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename); | 654 | ar->board = ath10k_fetch_fw_file(ar, |
655 | ar->hw_params.fw.dir, | ||
656 | ar->hw_params.fw.board); | ||
603 | if (IS_ERR(ar->board)) | 657 | if (IS_ERR(ar->board)) |
604 | return PTR_ERR(ar->board); | 658 | return PTR_ERR(ar->board); |
605 | 659 | ||
606 | ar->board_data = ar->board->data; | 660 | ar->board_data = ar->board->data; |
607 | ar->board_len = ar->board->size; | 661 | ar->board_len = ar->board->size; |
608 | ar->spec_board_loaded = true; | ||
609 | 662 | ||
610 | return 0; | 663 | return 0; |
611 | } | 664 | } |
612 | 665 | ||
613 | static int ath10k_core_fetch_generic_board_file(struct ath10k *ar) | 666 | static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, |
667 | const void *buf, size_t buf_len, | ||
668 | const char *boardname) | ||
614 | { | 669 | { |
615 | if (!ar->hw_params.fw.board) { | 670 | const struct ath10k_fw_ie *hdr; |
616 | ath10k_err(ar, "failed to find board file fw entry\n"); | 671 | bool name_match_found; |
617 | return -EINVAL; | 672 | int ret, board_ie_id; |
673 | size_t board_ie_len; | ||
674 | const void *board_ie_data; | ||
675 | |||
676 | name_match_found = false; | ||
677 | |||
678 | /* go through ATH10K_BD_IE_BOARD_ elements */ | ||
679 | while (buf_len > sizeof(struct ath10k_fw_ie)) { | ||
680 | hdr = buf; | ||
681 | board_ie_id = le32_to_cpu(hdr->id); | ||
682 | board_ie_len = le32_to_cpu(hdr->len); | ||
683 | board_ie_data = hdr->data; | ||
684 | |||
685 | buf_len -= sizeof(*hdr); | ||
686 | buf += sizeof(*hdr); | ||
687 | |||
688 | if (buf_len < ALIGN(board_ie_len, 4)) { | ||
689 | ath10k_err(ar, "invalid ATH10K_BD_IE_BOARD length: %zu < %zu\n", | ||
690 | buf_len, ALIGN(board_ie_len, 4)); | ||
691 | ret = -EINVAL; | ||
692 | goto out; | ||
693 | } | ||
694 | |||
695 | switch (board_ie_id) { | ||
696 | case ATH10K_BD_IE_BOARD_NAME: | ||
697 | ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "board name", "", | ||
698 | board_ie_data, board_ie_len); | ||
699 | |||
700 | if (board_ie_len != strlen(boardname)) | ||
701 | break; | ||
702 | |||
703 | ret = memcmp(board_ie_data, boardname, strlen(boardname)); | ||
704 | if (ret) | ||
705 | break; | ||
706 | |||
707 | name_match_found = true; | ||
708 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | ||
709 | "boot found match for name '%s'", | ||
710 | boardname); | ||
711 | break; | ||
712 | case ATH10K_BD_IE_BOARD_DATA: | ||
713 | if (!name_match_found) | ||
714 | /* no match found */ | ||
715 | break; | ||
716 | |||
717 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | ||
718 | "boot found board data for '%s'", | ||
719 | boardname); | ||
720 | |||
721 | ar->board_data = board_ie_data; | ||
722 | ar->board_len = board_ie_len; | ||
723 | |||
724 | ret = 0; | ||
725 | goto out; | ||
726 | default: | ||
727 | ath10k_warn(ar, "unknown ATH10K_BD_IE_BOARD found: %d\n", | ||
728 | board_ie_id); | ||
729 | break; | ||
730 | } | ||
731 | |||
732 | /* jump over the padding */ | ||
733 | board_ie_len = ALIGN(board_ie_len, 4); | ||
734 | |||
735 | buf_len -= board_ie_len; | ||
736 | buf += board_ie_len; | ||
618 | } | 737 | } |
619 | 738 | ||
620 | ar->board = ath10k_fetch_fw_file(ar, | 739 | /* no match found */ |
621 | ar->hw_params.fw.dir, | 740 | ret = -ENOENT; |
622 | ar->hw_params.fw.board); | 741 | |
742 | out: | ||
743 | return ret; | ||
744 | } | ||
745 | |||
746 | static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, | ||
747 | const char *boardname, | ||
748 | const char *filename) | ||
749 | { | ||
750 | size_t len, magic_len, ie_len; | ||
751 | struct ath10k_fw_ie *hdr; | ||
752 | const u8 *data; | ||
753 | int ret, ie_id; | ||
754 | |||
755 | ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename); | ||
623 | if (IS_ERR(ar->board)) | 756 | if (IS_ERR(ar->board)) |
624 | return PTR_ERR(ar->board); | 757 | return PTR_ERR(ar->board); |
625 | 758 | ||
626 | ar->board_data = ar->board->data; | 759 | data = ar->board->data; |
627 | ar->board_len = ar->board->size; | 760 | len = ar->board->size; |
628 | ar->spec_board_loaded = false; | 761 | |
762 | /* magic has extra null byte padded */ | ||
763 | magic_len = strlen(ATH10K_BOARD_MAGIC) + 1; | ||
764 | if (len < magic_len) { | ||
765 | ath10k_err(ar, "failed to find magic value in %s/%s, file too short: %zu\n", | ||
766 | ar->hw_params.fw.dir, filename, len); | ||
767 | ret = -EINVAL; | ||
768 | goto err; | ||
769 | } | ||
770 | |||
771 | if (memcmp(data, ATH10K_BOARD_MAGIC, magic_len)) { | ||
772 | ath10k_err(ar, "found invalid board magic\n"); | ||
773 | ret = -EINVAL; | ||
774 | goto err; | ||
775 | } | ||
776 | |||
777 | /* magic is padded to 4 bytes */ | ||
778 | magic_len = ALIGN(magic_len, 4); | ||
779 | if (len < magic_len) { | ||
780 | ath10k_err(ar, "failed: %s/%s too small to contain board data, len: %zu\n", | ||
781 | ar->hw_params.fw.dir, filename, len); | ||
782 | ret = -EINVAL; | ||
783 | goto err; | ||
784 | } | ||
785 | |||
786 | data += magic_len; | ||
787 | len -= magic_len; | ||
788 | |||
789 | while (len > sizeof(struct ath10k_fw_ie)) { | ||
790 | hdr = (struct ath10k_fw_ie *)data; | ||
791 | ie_id = le32_to_cpu(hdr->id); | ||
792 | ie_len = le32_to_cpu(hdr->len); | ||
793 | |||
794 | len -= sizeof(*hdr); | ||
795 | data = hdr->data; | ||
796 | |||
797 | if (len < ALIGN(ie_len, 4)) { | ||
798 | ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", | ||
799 | ie_id, ie_len, len); | ||
800 | ret = -EINVAL; | ||
801 | goto err; | ||
802 | } | ||
803 | |||
804 | switch (ie_id) { | ||
805 | case ATH10K_BD_IE_BOARD: | ||
806 | ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, | ||
807 | boardname); | ||
808 | if (ret == -ENOENT) | ||
809 | /* no match found, continue */ | ||
810 | break; | ||
811 | else if (ret) | ||
812 | /* there was an error, bail out */ | ||
813 | goto err; | ||
814 | |||
815 | /* board data found */ | ||
816 | goto out; | ||
817 | } | ||
818 | |||
819 | /* jump over the padding */ | ||
820 | ie_len = ALIGN(ie_len, 4); | ||
821 | |||
822 | len -= ie_len; | ||
823 | data += ie_len; | ||
824 | } | ||
825 | |||
826 | out: | ||
827 | if (!ar->board_data || !ar->board_len) { | ||
828 | ath10k_err(ar, | ||
829 | "failed to fetch board data for %s from %s/%s\n", | ||
830 | ar->hw_params.fw.dir, boardname, filename); | ||
831 | ret = -ENODATA; | ||
832 | goto err; | ||
833 | } | ||
834 | |||
835 | return 0; | ||
836 | |||
837 | err: | ||
838 | ath10k_core_free_board_files(ar); | ||
839 | return ret; | ||
840 | } | ||
841 | |||
842 | static int ath10k_core_create_board_name(struct ath10k *ar, char *name, | ||
843 | size_t name_len) | ||
844 | { | ||
845 | if (ar->id.bmi_ids_valid) { | ||
846 | scnprintf(name, name_len, | ||
847 | "bus=%s,bmi-chip-id=%d,bmi-board-id=%d", | ||
848 | ath10k_bus_str(ar->hif.bus), | ||
849 | ar->id.bmi_chip_id, | ||
850 | ar->id.bmi_board_id); | ||
851 | goto out; | ||
852 | } | ||
853 | |||
854 | scnprintf(name, name_len, | ||
855 | "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x", | ||
856 | ath10k_bus_str(ar->hif.bus), | ||
857 | ar->id.vendor, ar->id.device, | ||
858 | ar->id.subsystem_vendor, ar->id.subsystem_device); | ||
859 | |||
860 | out: | ||
861 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name); | ||
629 | 862 | ||
630 | return 0; | 863 | return 0; |
631 | } | 864 | } |
632 | 865 | ||
633 | static int ath10k_core_fetch_board_file(struct ath10k *ar) | 866 | static int ath10k_core_fetch_board_file(struct ath10k *ar) |
634 | { | 867 | { |
868 | char boardname[100]; | ||
635 | int ret; | 869 | int ret; |
636 | 870 | ||
637 | if (strlen(ar->spec_board_id) > 0) { | 871 | ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname)); |
638 | ret = ath10k_core_fetch_spec_board_file(ar); | 872 | if (ret) { |
639 | if (ret) { | 873 | ath10k_err(ar, "failed to create board name: %d", ret); |
640 | ath10k_info(ar, "failed to load spec board file, falling back to generic: %d\n", | 874 | return ret; |
641 | ret); | ||
642 | goto generic; | ||
643 | } | ||
644 | |||
645 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "found specific board file for %s\n", | ||
646 | ar->spec_board_id); | ||
647 | return 0; | ||
648 | } | 875 | } |
649 | 876 | ||
650 | generic: | 877 | ar->bd_api = 2; |
651 | ret = ath10k_core_fetch_generic_board_file(ar); | 878 | ret = ath10k_core_fetch_board_data_api_n(ar, boardname, |
879 | ATH10K_BOARD_API2_FILE); | ||
880 | if (!ret) | ||
881 | goto success; | ||
882 | |||
883 | ar->bd_api = 1; | ||
884 | ret = ath10k_core_fetch_board_data_api_1(ar); | ||
652 | if (ret) { | 885 | if (ret) { |
653 | ath10k_err(ar, "failed to fetch generic board data: %d\n", ret); | 886 | ath10k_err(ar, "failed to fetch board data\n"); |
654 | return ret; | 887 | return ret; |
655 | } | 888 | } |
656 | 889 | ||
890 | success: | ||
891 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api); | ||
657 | return 0; | 892 | return 0; |
658 | } | 893 | } |
659 | 894 | ||
@@ -885,12 +1120,6 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) | |||
885 | /* calibration file is optional, don't check for any errors */ | 1120 | /* calibration file is optional, don't check for any errors */ |
886 | ath10k_fetch_cal_file(ar); | 1121 | ath10k_fetch_cal_file(ar); |
887 | 1122 | ||
888 | ret = ath10k_core_fetch_board_file(ar); | ||
889 | if (ret) { | ||
890 | ath10k_err(ar, "failed to fetch board file: %d\n", ret); | ||
891 | return ret; | ||
892 | } | ||
893 | |||
894 | ar->fw_api = 5; | 1123 | ar->fw_api = 5; |
895 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); | 1124 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); |
896 | 1125 | ||
@@ -1263,10 +1492,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) | |||
1263 | goto err; | 1492 | goto err; |
1264 | 1493 | ||
1265 | /* Some of of qca988x solutions are having global reset issue | 1494 | /* Some of of qca988x solutions are having global reset issue |
1266 | * during target initialization. Bypassing PLL setting before | 1495 | * during target initialization. Bypassing PLL setting before |
1267 | * downloading firmware and letting the SoC run on REF_CLK is | 1496 | * downloading firmware and letting the SoC run on REF_CLK is |
1268 | * fixing the problem. Corresponding firmware change is also needed | 1497 | * fixing the problem. Corresponding firmware change is also needed |
1269 | * to set the clock source once the target is initialized. | 1498 | * to set the clock source once the target is initialized. |
1270 | */ | 1499 | */ |
1271 | if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, | 1500 | if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, |
1272 | ar->fw_features)) { | 1501 | ar->fw_features)) { |
@@ -1500,6 +1729,19 @@ static int ath10k_core_probe_fw(struct ath10k *ar) | |||
1500 | goto err_power_down; | 1729 | goto err_power_down; |
1501 | } | 1730 | } |
1502 | 1731 | ||
1732 | ret = ath10k_core_get_board_id_from_otp(ar); | ||
1733 | if (ret && ret != -EOPNOTSUPP) { | ||
1734 | ath10k_err(ar, "failed to get board id from otp for qca99x0: %d\n", | ||
1735 | ret); | ||
1736 | return ret; | ||
1737 | } | ||
1738 | |||
1739 | ret = ath10k_core_fetch_board_file(ar); | ||
1740 | if (ret) { | ||
1741 | ath10k_err(ar, "failed to fetch board file: %d\n", ret); | ||
1742 | goto err_free_firmware_files; | ||
1743 | } | ||
1744 | |||
1503 | ret = ath10k_core_init_firmware_features(ar); | 1745 | ret = ath10k_core_init_firmware_features(ar); |
1504 | if (ret) { | 1746 | if (ret) { |
1505 | ath10k_err(ar, "fatal problem with firmware features: %d\n", | 1747 | ath10k_err(ar, "fatal problem with firmware features: %d\n", |
@@ -1627,6 +1869,7 @@ void ath10k_core_unregister(struct ath10k *ar) | |||
1627 | ath10k_testmode_destroy(ar); | 1869 | ath10k_testmode_destroy(ar); |
1628 | 1870 | ||
1629 | ath10k_core_free_firmware_files(ar); | 1871 | ath10k_core_free_firmware_files(ar); |
1872 | ath10k_core_free_board_files(ar); | ||
1630 | 1873 | ||
1631 | ath10k_debug_unregister(ar); | 1874 | ath10k_debug_unregister(ar); |
1632 | } | 1875 | } |
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 04e040a06cb1..7cc7cdd56c95 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -250,6 +250,30 @@ struct ath10k_fw_stats { | |||
250 | struct list_head peers; | 250 | struct list_head peers; |
251 | }; | 251 | }; |
252 | 252 | ||
253 | #define ATH10K_TPC_TABLE_TYPE_FLAG 1 | ||
254 | #define ATH10K_TPC_PREAM_TABLE_END 0xFFFF | ||
255 | |||
256 | struct ath10k_tpc_table { | ||
257 | u32 pream_idx[WMI_TPC_RATE_MAX]; | ||
258 | u8 rate_code[WMI_TPC_RATE_MAX]; | ||
259 | char tpc_value[WMI_TPC_RATE_MAX][WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE]; | ||
260 | }; | ||
261 | |||
262 | struct ath10k_tpc_stats { | ||
263 | u32 reg_domain; | ||
264 | u32 chan_freq; | ||
265 | u32 phy_mode; | ||
266 | u32 twice_antenna_reduction; | ||
267 | u32 twice_max_rd_power; | ||
268 | s32 twice_antenna_gain; | ||
269 | u32 power_limit; | ||
270 | u32 num_tx_chain; | ||
271 | u32 ctl; | ||
272 | u32 rate_max; | ||
273 | u8 flag[WMI_TPC_FLAG]; | ||
274 | struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG]; | ||
275 | }; | ||
276 | |||
253 | struct ath10k_dfs_stats { | 277 | struct ath10k_dfs_stats { |
254 | u32 phy_errors; | 278 | u32 phy_errors; |
255 | u32 pulses_total; | 279 | u32 pulses_total; |
@@ -378,6 +402,11 @@ struct ath10k_debug { | |||
378 | struct ath10k_dfs_stats dfs_stats; | 402 | struct ath10k_dfs_stats dfs_stats; |
379 | struct ath_dfs_pool_stats dfs_pool_stats; | 403 | struct ath_dfs_pool_stats dfs_pool_stats; |
380 | 404 | ||
405 | /* used for tpc-dump storage, protected by data-lock */ | ||
406 | struct ath10k_tpc_stats *tpc_stats; | ||
407 | |||
408 | struct completion tpc_complete; | ||
409 | |||
381 | /* protected by conf_mutex */ | 410 | /* protected by conf_mutex */ |
382 | u32 fw_dbglog_mask; | 411 | u32 fw_dbglog_mask; |
383 | u32 fw_dbglog_level; | 412 | u32 fw_dbglog_level; |
@@ -647,10 +676,19 @@ struct ath10k { | |||
647 | struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info; | 676 | struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info; |
648 | } swap; | 677 | } swap; |
649 | 678 | ||
650 | char spec_board_id[100]; | 679 | struct { |
651 | bool spec_board_loaded; | 680 | u32 vendor; |
681 | u32 device; | ||
682 | u32 subsystem_vendor; | ||
683 | u32 subsystem_device; | ||
684 | |||
685 | bool bmi_ids_valid; | ||
686 | u8 bmi_board_id; | ||
687 | u8 bmi_chip_id; | ||
688 | } id; | ||
652 | 689 | ||
653 | int fw_api; | 690 | int fw_api; |
691 | int bd_api; | ||
654 | enum ath10k_cal_mode cal_mode; | 692 | enum ath10k_cal_mode cal_mode; |
655 | 693 | ||
656 | struct { | 694 | struct { |
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index bf033f46f8aa..6cc1aa3449c8 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c | |||
@@ -125,19 +125,25 @@ EXPORT_SYMBOL(ath10k_info); | |||
125 | void ath10k_print_driver_info(struct ath10k *ar) | 125 | void ath10k_print_driver_info(struct ath10k *ar) |
126 | { | 126 | { |
127 | char fw_features[128] = {}; | 127 | char fw_features[128] = {}; |
128 | char boardinfo[100]; | ||
128 | 129 | ||
129 | ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); | 130 | ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); |
130 | 131 | ||
131 | ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n", | 132 | if (ar->id.bmi_ids_valid) |
133 | scnprintf(boardinfo, sizeof(boardinfo), "bmi %d:%d", | ||
134 | ar->id.bmi_chip_id, ar->id.bmi_board_id); | ||
135 | else | ||
136 | scnprintf(boardinfo, sizeof(boardinfo), "sub %04x:%04x", | ||
137 | ar->id.subsystem_vendor, ar->id.subsystem_device); | ||
138 | |||
139 | ath10k_info(ar, "%s (0x%08x, 0x%08x %s) fw %s fwapi %d bdapi %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n", | ||
132 | ar->hw_params.name, | 140 | ar->hw_params.name, |
133 | ar->target_version, | 141 | ar->target_version, |
134 | ar->chip_id, | 142 | ar->chip_id, |
135 | (strlen(ar->spec_board_id) > 0 ? ", " : ""), | 143 | boardinfo, |
136 | ar->spec_board_id, | ||
137 | (strlen(ar->spec_board_id) > 0 && !ar->spec_board_loaded | ||
138 | ? " fallback" : ""), | ||
139 | ar->hw->wiphy->fw_version, | 144 | ar->hw->wiphy->fw_version, |
140 | ar->fw_api, | 145 | ar->fw_api, |
146 | ar->bd_api, | ||
141 | ar->htt.target_version_major, | 147 | ar->htt.target_version_major, |
142 | ar->htt.target_version_minor, | 148 | ar->htt.target_version_minor, |
143 | ar->wmi.op_version, | 149 | ar->wmi.op_version, |
@@ -285,28 +291,6 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar) | |||
285 | spin_unlock_bh(&ar->data_lock); | 291 | spin_unlock_bh(&ar->data_lock); |
286 | } | 292 | } |
287 | 293 | ||
288 | static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head) | ||
289 | { | ||
290 | struct ath10k_fw_stats_peer *i; | ||
291 | size_t num = 0; | ||
292 | |||
293 | list_for_each_entry(i, head, list) | ||
294 | ++num; | ||
295 | |||
296 | return num; | ||
297 | } | ||
298 | |||
299 | static size_t ath10k_debug_fw_stats_num_vdevs(struct list_head *head) | ||
300 | { | ||
301 | struct ath10k_fw_stats_vdev *i; | ||
302 | size_t num = 0; | ||
303 | |||
304 | list_for_each_entry(i, head, list) | ||
305 | ++num; | ||
306 | |||
307 | return num; | ||
308 | } | ||
309 | |||
310 | void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) | 294 | void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) |
311 | { | 295 | { |
312 | struct ath10k_fw_stats stats = {}; | 296 | struct ath10k_fw_stats stats = {}; |
@@ -343,8 +327,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) | |||
343 | goto free; | 327 | goto free; |
344 | } | 328 | } |
345 | 329 | ||
346 | num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers); | 330 | num_peers = ath10k_wmi_fw_stats_num_peers(&ar->debug.fw_stats.peers); |
347 | num_vdevs = ath10k_debug_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs); | 331 | num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs); |
348 | is_start = (list_empty(&ar->debug.fw_stats.pdevs) && | 332 | is_start = (list_empty(&ar->debug.fw_stats.pdevs) && |
349 | !list_empty(&stats.pdevs)); | 333 | !list_empty(&stats.pdevs)); |
350 | is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && | 334 | is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && |
@@ -429,240 +413,6 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar) | |||
429 | return 0; | 413 | return 0; |
430 | } | 414 | } |
431 | 415 | ||
432 | /* FIXME: How to calculate the buffer size sanely? */ | ||
433 | #define ATH10K_FW_STATS_BUF_SIZE (1024*1024) | ||
434 | |||
435 | static void ath10k_fw_stats_fill(struct ath10k *ar, | ||
436 | struct ath10k_fw_stats *fw_stats, | ||
437 | char *buf) | ||
438 | { | ||
439 | unsigned int len = 0; | ||
440 | unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
441 | const struct ath10k_fw_stats_pdev *pdev; | ||
442 | const struct ath10k_fw_stats_vdev *vdev; | ||
443 | const struct ath10k_fw_stats_peer *peer; | ||
444 | size_t num_peers; | ||
445 | size_t num_vdevs; | ||
446 | int i; | ||
447 | |||
448 | spin_lock_bh(&ar->data_lock); | ||
449 | |||
450 | pdev = list_first_entry_or_null(&fw_stats->pdevs, | ||
451 | struct ath10k_fw_stats_pdev, list); | ||
452 | if (!pdev) { | ||
453 | ath10k_warn(ar, "failed to get pdev stats\n"); | ||
454 | goto unlock; | ||
455 | } | ||
456 | |||
457 | num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers); | ||
458 | num_vdevs = ath10k_debug_fw_stats_num_vdevs(&fw_stats->vdevs); | ||
459 | |||
460 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
461 | len += scnprintf(buf + len, buf_len - len, "%30s\n", | ||
462 | "ath10k PDEV stats"); | ||
463 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
464 | "================="); | ||
465 | |||
466 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
467 | "Channel noise floor", pdev->ch_noise_floor); | ||
468 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
469 | "Channel TX power", pdev->chan_tx_power); | ||
470 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
471 | "TX frame count", pdev->tx_frame_count); | ||
472 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
473 | "RX frame count", pdev->rx_frame_count); | ||
474 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
475 | "RX clear count", pdev->rx_clear_count); | ||
476 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
477 | "Cycle count", pdev->cycle_count); | ||
478 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
479 | "PHY error count", pdev->phy_err_count); | ||
480 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
481 | "RTS bad count", pdev->rts_bad); | ||
482 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
483 | "RTS good count", pdev->rts_good); | ||
484 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
485 | "FCS bad count", pdev->fcs_bad); | ||
486 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
487 | "No beacon count", pdev->no_beacons); | ||
488 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
489 | "MIB int count", pdev->mib_int_count); | ||
490 | |||
491 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
492 | len += scnprintf(buf + len, buf_len - len, "%30s\n", | ||
493 | "ath10k PDEV TX stats"); | ||
494 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
495 | "================="); | ||
496 | |||
497 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
498 | "HTT cookies queued", pdev->comp_queued); | ||
499 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
500 | "HTT cookies disp.", pdev->comp_delivered); | ||
501 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
502 | "MSDU queued", pdev->msdu_enqued); | ||
503 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
504 | "MPDU queued", pdev->mpdu_enqued); | ||
505 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
506 | "MSDUs dropped", pdev->wmm_drop); | ||
507 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
508 | "Local enqued", pdev->local_enqued); | ||
509 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
510 | "Local freed", pdev->local_freed); | ||
511 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
512 | "HW queued", pdev->hw_queued); | ||
513 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
514 | "PPDUs reaped", pdev->hw_reaped); | ||
515 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
516 | "Num underruns", pdev->underrun); | ||
517 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
518 | "PPDUs cleaned", pdev->tx_abort); | ||
519 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
520 | "MPDUs requed", pdev->mpdus_requed); | ||
521 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
522 | "Excessive retries", pdev->tx_ko); | ||
523 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
524 | "HW rate", pdev->data_rc); | ||
525 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
526 | "Sched self tiggers", pdev->self_triggers); | ||
527 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
528 | "Dropped due to SW retries", | ||
529 | pdev->sw_retry_failure); | ||
530 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
531 | "Illegal rate phy errors", | ||
532 | pdev->illgl_rate_phy_err); | ||
533 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
534 | "Pdev continous xretry", pdev->pdev_cont_xretry); | ||
535 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
536 | "TX timeout", pdev->pdev_tx_timeout); | ||
537 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
538 | "PDEV resets", pdev->pdev_resets); | ||
539 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
540 | "PHY underrun", pdev->phy_underrun); | ||
541 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
542 | "MPDU is more than txop limit", pdev->txop_ovf); | ||
543 | |||
544 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
545 | len += scnprintf(buf + len, buf_len - len, "%30s\n", | ||
546 | "ath10k PDEV RX stats"); | ||
547 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
548 | "================="); | ||
549 | |||
550 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
551 | "Mid PPDU route change", | ||
552 | pdev->mid_ppdu_route_change); | ||
553 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
554 | "Tot. number of statuses", pdev->status_rcvd); | ||
555 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
556 | "Extra frags on rings 0", pdev->r0_frags); | ||
557 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
558 | "Extra frags on rings 1", pdev->r1_frags); | ||
559 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
560 | "Extra frags on rings 2", pdev->r2_frags); | ||
561 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
562 | "Extra frags on rings 3", pdev->r3_frags); | ||
563 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
564 | "MSDUs delivered to HTT", pdev->htt_msdus); | ||
565 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
566 | "MPDUs delivered to HTT", pdev->htt_mpdus); | ||
567 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
568 | "MSDUs delivered to stack", pdev->loc_msdus); | ||
569 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
570 | "MPDUs delivered to stack", pdev->loc_mpdus); | ||
571 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
572 | "Oversized AMSUs", pdev->oversize_amsdu); | ||
573 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
574 | "PHY errors", pdev->phy_errs); | ||
575 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
576 | "PHY errors drops", pdev->phy_err_drop); | ||
577 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
578 | "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); | ||
579 | |||
580 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
581 | len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", | ||
582 | "ath10k VDEV stats", num_vdevs); | ||
583 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
584 | "================="); | ||
585 | |||
586 | list_for_each_entry(vdev, &fw_stats->vdevs, list) { | ||
587 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
588 | "vdev id", vdev->vdev_id); | ||
589 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
590 | "beacon snr", vdev->beacon_snr); | ||
591 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
592 | "data snr", vdev->data_snr); | ||
593 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
594 | "num rx frames", vdev->num_rx_frames); | ||
595 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
596 | "num rts fail", vdev->num_rts_fail); | ||
597 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
598 | "num rts success", vdev->num_rts_success); | ||
599 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
600 | "num rx err", vdev->num_rx_err); | ||
601 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
602 | "num rx discard", vdev->num_rx_discard); | ||
603 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
604 | "num tx not acked", vdev->num_tx_not_acked); | ||
605 | |||
606 | for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++) | ||
607 | len += scnprintf(buf + len, buf_len - len, | ||
608 | "%25s [%02d] %u\n", | ||
609 | "num tx frames", i, | ||
610 | vdev->num_tx_frames[i]); | ||
611 | |||
612 | for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++) | ||
613 | len += scnprintf(buf + len, buf_len - len, | ||
614 | "%25s [%02d] %u\n", | ||
615 | "num tx frames retries", i, | ||
616 | vdev->num_tx_frames_retries[i]); | ||
617 | |||
618 | for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++) | ||
619 | len += scnprintf(buf + len, buf_len - len, | ||
620 | "%25s [%02d] %u\n", | ||
621 | "num tx frames failures", i, | ||
622 | vdev->num_tx_frames_failures[i]); | ||
623 | |||
624 | for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++) | ||
625 | len += scnprintf(buf + len, buf_len - len, | ||
626 | "%25s [%02d] 0x%08x\n", | ||
627 | "tx rate history", i, | ||
628 | vdev->tx_rate_history[i]); | ||
629 | |||
630 | for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++) | ||
631 | len += scnprintf(buf + len, buf_len - len, | ||
632 | "%25s [%02d] %u\n", | ||
633 | "beacon rssi history", i, | ||
634 | vdev->beacon_rssi_history[i]); | ||
635 | |||
636 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
637 | } | ||
638 | |||
639 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
640 | len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", | ||
641 | "ath10k PEER stats", num_peers); | ||
642 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
643 | "================="); | ||
644 | |||
645 | list_for_each_entry(peer, &fw_stats->peers, list) { | ||
646 | len += scnprintf(buf + len, buf_len - len, "%30s %pM\n", | ||
647 | "Peer MAC address", peer->peer_macaddr); | ||
648 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
649 | "Peer RSSI", peer->peer_rssi); | ||
650 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
651 | "Peer TX rate", peer->peer_tx_rate); | ||
652 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
653 | "Peer RX rate", peer->peer_rx_rate); | ||
654 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
655 | } | ||
656 | |||
657 | unlock: | ||
658 | spin_unlock_bh(&ar->data_lock); | ||
659 | |||
660 | if (len >= buf_len) | ||
661 | buf[len - 1] = 0; | ||
662 | else | ||
663 | buf[len] = 0; | ||
664 | } | ||
665 | |||
666 | static int ath10k_fw_stats_open(struct inode *inode, struct file *file) | 416 | static int ath10k_fw_stats_open(struct inode *inode, struct file *file) |
667 | { | 417 | { |
668 | struct ath10k *ar = inode->i_private; | 418 | struct ath10k *ar = inode->i_private; |
@@ -688,7 +438,12 @@ static int ath10k_fw_stats_open(struct inode *inode, struct file *file) | |||
688 | goto err_free; | 438 | goto err_free; |
689 | } | 439 | } |
690 | 440 | ||
691 | ath10k_fw_stats_fill(ar, &ar->debug.fw_stats, buf); | 441 | ret = ath10k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, buf); |
442 | if (ret) { | ||
443 | ath10k_warn(ar, "failed to fill fw stats: %d\n", ret); | ||
444 | goto err_free; | ||
445 | } | ||
446 | |||
692 | file->private_data = buf; | 447 | file->private_data = buf; |
693 | 448 | ||
694 | mutex_unlock(&ar->conf_mutex); | 449 | mutex_unlock(&ar->conf_mutex); |
@@ -1843,6 +1598,233 @@ static const struct file_operations fops_nf_cal_period = { | |||
1843 | .llseek = default_llseek, | 1598 | .llseek = default_llseek, |
1844 | }; | 1599 | }; |
1845 | 1600 | ||
1601 | #define ATH10K_TPC_CONFIG_BUF_SIZE (1024 * 1024) | ||
1602 | |||
1603 | static int ath10k_debug_tpc_stats_request(struct ath10k *ar) | ||
1604 | { | ||
1605 | int ret; | ||
1606 | unsigned long time_left; | ||
1607 | |||
1608 | lockdep_assert_held(&ar->conf_mutex); | ||
1609 | |||
1610 | reinit_completion(&ar->debug.tpc_complete); | ||
1611 | |||
1612 | ret = ath10k_wmi_pdev_get_tpc_config(ar, WMI_TPC_CONFIG_PARAM); | ||
1613 | if (ret) { | ||
1614 | ath10k_warn(ar, "failed to request tpc config: %d\n", ret); | ||
1615 | return ret; | ||
1616 | } | ||
1617 | |||
1618 | time_left = wait_for_completion_timeout(&ar->debug.tpc_complete, | ||
1619 | 1 * HZ); | ||
1620 | if (time_left == 0) | ||
1621 | return -ETIMEDOUT; | ||
1622 | |||
1623 | return 0; | ||
1624 | } | ||
1625 | |||
1626 | void ath10k_debug_tpc_stats_process(struct ath10k *ar, | ||
1627 | struct ath10k_tpc_stats *tpc_stats) | ||
1628 | { | ||
1629 | spin_lock_bh(&ar->data_lock); | ||
1630 | |||
1631 | kfree(ar->debug.tpc_stats); | ||
1632 | ar->debug.tpc_stats = tpc_stats; | ||
1633 | complete(&ar->debug.tpc_complete); | ||
1634 | |||
1635 | spin_unlock_bh(&ar->data_lock); | ||
1636 | } | ||
1637 | |||
1638 | static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, | ||
1639 | unsigned int j, char *buf, unsigned int *len) | ||
1640 | { | ||
1641 | unsigned int i, buf_len; | ||
1642 | static const char table_str[][5] = { "CDD", | ||
1643 | "STBC", | ||
1644 | "TXBF" }; | ||
1645 | static const char pream_str[][6] = { "CCK", | ||
1646 | "OFDM", | ||
1647 | "HT20", | ||
1648 | "HT40", | ||
1649 | "VHT20", | ||
1650 | "VHT40", | ||
1651 | "VHT80", | ||
1652 | "HTCUP" }; | ||
1653 | |||
1654 | buf_len = ATH10K_TPC_CONFIG_BUF_SIZE; | ||
1655 | *len += scnprintf(buf + *len, buf_len - *len, | ||
1656 | "********************************\n"); | ||
1657 | *len += scnprintf(buf + *len, buf_len - *len, | ||
1658 | "******************* %s POWER TABLE ****************\n", | ||
1659 | table_str[j]); | ||
1660 | *len += scnprintf(buf + *len, buf_len - *len, | ||
1661 | "********************************\n"); | ||
1662 | *len += scnprintf(buf + *len, buf_len - *len, | ||
1663 | "No. Preamble Rate_code tpc_value1 tpc_value2 tpc_value3\n"); | ||
1664 | |||
1665 | for (i = 0; i < tpc_stats->rate_max; i++) { | ||
1666 | *len += scnprintf(buf + *len, buf_len - *len, | ||
1667 | "%8d %s 0x%2x %s\n", i, | ||
1668 | pream_str[tpc_stats->tpc_table[j].pream_idx[i]], | ||
1669 | tpc_stats->tpc_table[j].rate_code[i], | ||
1670 | tpc_stats->tpc_table[j].tpc_value[i]); | ||
1671 | } | ||
1672 | |||
1673 | *len += scnprintf(buf + *len, buf_len - *len, | ||
1674 | "***********************************\n"); | ||
1675 | } | ||
1676 | |||
1677 | static void ath10k_tpc_stats_fill(struct ath10k *ar, | ||
1678 | struct ath10k_tpc_stats *tpc_stats, | ||
1679 | char *buf) | ||
1680 | { | ||
1681 | unsigned int len, j, buf_len; | ||
1682 | |||
1683 | len = 0; | ||
1684 | buf_len = ATH10K_TPC_CONFIG_BUF_SIZE; | ||
1685 | |||
1686 | spin_lock_bh(&ar->data_lock); | ||
1687 | |||
1688 | if (!tpc_stats) { | ||
1689 | ath10k_warn(ar, "failed to get tpc stats\n"); | ||
1690 | goto unlock; | ||
1691 | } | ||
1692 | |||
1693 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
1694 | len += scnprintf(buf + len, buf_len - len, | ||
1695 | "*************************************\n"); | ||
1696 | len += scnprintf(buf + len, buf_len - len, | ||
1697 | "TPC config for channel %4d mode %d\n", | ||
1698 | tpc_stats->chan_freq, | ||
1699 | tpc_stats->phy_mode); | ||
1700 | len += scnprintf(buf + len, buf_len - len, | ||
1701 | "*************************************\n"); | ||
1702 | len += scnprintf(buf + len, buf_len - len, | ||
1703 | "CTL = 0x%2x Reg. Domain = %2d\n", | ||
1704 | tpc_stats->ctl, | ||
1705 | tpc_stats->reg_domain); | ||
1706 | len += scnprintf(buf + len, buf_len - len, | ||
1707 | "Antenna Gain = %2d Reg. Max Antenna Gain = %2d\n", | ||
1708 | tpc_stats->twice_antenna_gain, | ||
1709 | tpc_stats->twice_antenna_reduction); | ||
1710 | len += scnprintf(buf + len, buf_len - len, | ||
1711 | "Power Limit = %2d Reg. Max Power = %2d\n", | ||
1712 | tpc_stats->power_limit, | ||
1713 | tpc_stats->twice_max_rd_power / 2); | ||
1714 | len += scnprintf(buf + len, buf_len - len, | ||
1715 | "Num tx chains = %2d Num supported rates = %2d\n", | ||
1716 | tpc_stats->num_tx_chain, | ||
1717 | tpc_stats->rate_max); | ||
1718 | |||
1719 | for (j = 0; j < tpc_stats->num_tx_chain ; j++) { | ||
1720 | switch (j) { | ||
1721 | case WMI_TPC_TABLE_TYPE_CDD: | ||
1722 | if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { | ||
1723 | len += scnprintf(buf + len, buf_len - len, | ||
1724 | "CDD not supported\n"); | ||
1725 | break; | ||
1726 | } | ||
1727 | |||
1728 | ath10k_tpc_stats_print(tpc_stats, j, buf, &len); | ||
1729 | break; | ||
1730 | case WMI_TPC_TABLE_TYPE_STBC: | ||
1731 | if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { | ||
1732 | len += scnprintf(buf + len, buf_len - len, | ||
1733 | "STBC not supported\n"); | ||
1734 | break; | ||
1735 | } | ||
1736 | |||
1737 | ath10k_tpc_stats_print(tpc_stats, j, buf, &len); | ||
1738 | break; | ||
1739 | case WMI_TPC_TABLE_TYPE_TXBF: | ||
1740 | if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { | ||
1741 | len += scnprintf(buf + len, buf_len - len, | ||
1742 | "TXBF not supported\n***************************\n"); | ||
1743 | break; | ||
1744 | } | ||
1745 | |||
1746 | ath10k_tpc_stats_print(tpc_stats, j, buf, &len); | ||
1747 | break; | ||
1748 | default: | ||
1749 | len += scnprintf(buf + len, buf_len - len, | ||
1750 | "Invalid Type\n"); | ||
1751 | break; | ||
1752 | } | ||
1753 | } | ||
1754 | |||
1755 | unlock: | ||
1756 | spin_unlock_bh(&ar->data_lock); | ||
1757 | |||
1758 | if (len >= buf_len) | ||
1759 | buf[len - 1] = 0; | ||
1760 | else | ||
1761 | buf[len] = 0; | ||
1762 | } | ||
1763 | |||
1764 | static int ath10k_tpc_stats_open(struct inode *inode, struct file *file) | ||
1765 | { | ||
1766 | struct ath10k *ar = inode->i_private; | ||
1767 | void *buf = NULL; | ||
1768 | int ret; | ||
1769 | |||
1770 | mutex_lock(&ar->conf_mutex); | ||
1771 | |||
1772 | if (ar->state != ATH10K_STATE_ON) { | ||
1773 | ret = -ENETDOWN; | ||
1774 | goto err_unlock; | ||
1775 | } | ||
1776 | |||
1777 | buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE); | ||
1778 | if (!buf) { | ||
1779 | ret = -ENOMEM; | ||
1780 | goto err_unlock; | ||
1781 | } | ||
1782 | |||
1783 | ret = ath10k_debug_tpc_stats_request(ar); | ||
1784 | if (ret) { | ||
1785 | ath10k_warn(ar, "failed to request tpc config stats: %d\n", | ||
1786 | ret); | ||
1787 | goto err_free; | ||
1788 | } | ||
1789 | |||
1790 | ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf); | ||
1791 | file->private_data = buf; | ||
1792 | |||
1793 | mutex_unlock(&ar->conf_mutex); | ||
1794 | return 0; | ||
1795 | |||
1796 | err_free: | ||
1797 | vfree(buf); | ||
1798 | |||
1799 | err_unlock: | ||
1800 | mutex_unlock(&ar->conf_mutex); | ||
1801 | return ret; | ||
1802 | } | ||
1803 | |||
1804 | static int ath10k_tpc_stats_release(struct inode *inode, struct file *file) | ||
1805 | { | ||
1806 | vfree(file->private_data); | ||
1807 | |||
1808 | return 0; | ||
1809 | } | ||
1810 | |||
1811 | static ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf, | ||
1812 | size_t count, loff_t *ppos) | ||
1813 | { | ||
1814 | const char *buf = file->private_data; | ||
1815 | unsigned int len = strlen(buf); | ||
1816 | |||
1817 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1818 | } | ||
1819 | |||
1820 | static const struct file_operations fops_tpc_stats = { | ||
1821 | .open = ath10k_tpc_stats_open, | ||
1822 | .release = ath10k_tpc_stats_release, | ||
1823 | .read = ath10k_tpc_stats_read, | ||
1824 | .owner = THIS_MODULE, | ||
1825 | .llseek = default_llseek, | ||
1826 | }; | ||
1827 | |||
1846 | int ath10k_debug_start(struct ath10k *ar) | 1828 | int ath10k_debug_start(struct ath10k *ar) |
1847 | { | 1829 | { |
1848 | int ret; | 1830 | int ret; |
@@ -2111,6 +2093,8 @@ void ath10k_debug_destroy(struct ath10k *ar) | |||
2111 | ar->debug.fw_crash_data = NULL; | 2093 | ar->debug.fw_crash_data = NULL; |
2112 | 2094 | ||
2113 | ath10k_debug_fw_stats_reset(ar); | 2095 | ath10k_debug_fw_stats_reset(ar); |
2096 | |||
2097 | kfree(ar->debug.tpc_stats); | ||
2114 | } | 2098 | } |
2115 | 2099 | ||
2116 | int ath10k_debug_register(struct ath10k *ar) | 2100 | int ath10k_debug_register(struct ath10k *ar) |
@@ -2127,6 +2111,7 @@ int ath10k_debug_register(struct ath10k *ar) | |||
2127 | INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, | 2111 | INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, |
2128 | ath10k_debug_htt_stats_dwork); | 2112 | ath10k_debug_htt_stats_dwork); |
2129 | 2113 | ||
2114 | init_completion(&ar->debug.tpc_complete); | ||
2130 | init_completion(&ar->debug.fw_stats_complete); | 2115 | init_completion(&ar->debug.fw_stats_complete); |
2131 | 2116 | ||
2132 | debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar, | 2117 | debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar, |
@@ -2195,6 +2180,9 @@ int ath10k_debug_register(struct ath10k *ar) | |||
2195 | debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR, | 2180 | debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR, |
2196 | ar->debug.debugfs_phy, ar, &fops_quiet_period); | 2181 | ar->debug.debugfs_phy, ar, &fops_quiet_period); |
2197 | 2182 | ||
2183 | debugfs_create_file("tpc_stats", S_IRUSR, | ||
2184 | ar->debug.debugfs_phy, ar, &fops_tpc_stats); | ||
2185 | |||
2198 | return 0; | 2186 | return 0; |
2199 | } | 2187 | } |
2200 | 2188 | ||
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 53bd6a19eab6..7de780c4ec8d 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h | |||
@@ -55,6 +55,9 @@ enum ath10k_dbg_aggr_mode { | |||
55 | ATH10K_DBG_AGGR_MODE_MAX, | 55 | ATH10K_DBG_AGGR_MODE_MAX, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* FIXME: How to calculate the buffer size sanely? */ | ||
59 | #define ATH10K_FW_STATS_BUF_SIZE (1024*1024) | ||
60 | |||
58 | extern unsigned int ath10k_debug_mask; | 61 | extern unsigned int ath10k_debug_mask; |
59 | 62 | ||
60 | __printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...); | 63 | __printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...); |
@@ -70,6 +73,8 @@ void ath10k_debug_destroy(struct ath10k *ar); | |||
70 | int ath10k_debug_register(struct ath10k *ar); | 73 | int ath10k_debug_register(struct ath10k *ar); |
71 | void ath10k_debug_unregister(struct ath10k *ar); | 74 | void ath10k_debug_unregister(struct ath10k *ar); |
72 | void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); | 75 | void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); |
76 | void ath10k_debug_tpc_stats_process(struct ath10k *ar, | ||
77 | struct ath10k_tpc_stats *tpc_stats); | ||
73 | struct ath10k_fw_crash_data * | 78 | struct ath10k_fw_crash_data * |
74 | ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); | 79 | ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); |
75 | 80 | ||
@@ -117,6 +122,12 @@ static inline void ath10k_debug_fw_stats_process(struct ath10k *ar, | |||
117 | { | 122 | { |
118 | } | 123 | } |
119 | 124 | ||
125 | static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar, | ||
126 | struct ath10k_tpc_stats *tpc_stats) | ||
127 | { | ||
128 | kfree(tpc_stats); | ||
129 | } | ||
130 | |||
120 | static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, | 131 | static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, |
121 | int len) | 132 | int len) |
122 | { | 133 | { |
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 0c92e0251e84..89e7076c919f 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h | |||
@@ -30,13 +30,6 @@ struct ath10k_hif_sg_item { | |||
30 | u16 len; | 30 | u16 len; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | struct ath10k_hif_cb { | ||
34 | int (*tx_completion)(struct ath10k *ar, | ||
35 | struct sk_buff *wbuf); | ||
36 | int (*rx_completion)(struct ath10k *ar, | ||
37 | struct sk_buff *wbuf); | ||
38 | }; | ||
39 | |||
40 | struct ath10k_hif_ops { | 33 | struct ath10k_hif_ops { |
41 | /* send a scatter-gather list to the target */ | 34 | /* send a scatter-gather list to the target */ |
42 | int (*tx_sg)(struct ath10k *ar, u8 pipe_id, | 35 | int (*tx_sg)(struct ath10k *ar, u8 pipe_id, |
@@ -65,8 +58,7 @@ struct ath10k_hif_ops { | |||
65 | void (*stop)(struct ath10k *ar); | 58 | void (*stop)(struct ath10k *ar); |
66 | 59 | ||
67 | int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, | 60 | int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, |
68 | u8 *ul_pipe, u8 *dl_pipe, | 61 | u8 *ul_pipe, u8 *dl_pipe); |
69 | int *ul_is_polled, int *dl_is_polled); | ||
70 | 62 | ||
71 | void (*get_default_pipe)(struct ath10k *ar, u8 *ul_pipe, u8 *dl_pipe); | 63 | void (*get_default_pipe)(struct ath10k *ar, u8 *ul_pipe, u8 *dl_pipe); |
72 | 64 | ||
@@ -80,9 +72,6 @@ struct ath10k_hif_ops { | |||
80 | */ | 72 | */ |
81 | void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force); | 73 | void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force); |
82 | 74 | ||
83 | void (*set_callbacks)(struct ath10k *ar, | ||
84 | struct ath10k_hif_cb *callbacks); | ||
85 | |||
86 | u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); | 75 | u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); |
87 | 76 | ||
88 | u32 (*read32)(struct ath10k *ar, u32 address); | 77 | u32 (*read32)(struct ath10k *ar, u32 address); |
@@ -142,13 +131,10 @@ static inline void ath10k_hif_stop(struct ath10k *ar) | |||
142 | 131 | ||
143 | static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar, | 132 | static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar, |
144 | u16 service_id, | 133 | u16 service_id, |
145 | u8 *ul_pipe, u8 *dl_pipe, | 134 | u8 *ul_pipe, u8 *dl_pipe) |
146 | int *ul_is_polled, | ||
147 | int *dl_is_polled) | ||
148 | { | 135 | { |
149 | return ar->hif.ops->map_service_to_pipe(ar, service_id, | 136 | return ar->hif.ops->map_service_to_pipe(ar, service_id, |
150 | ul_pipe, dl_pipe, | 137 | ul_pipe, dl_pipe); |
151 | ul_is_polled, dl_is_polled); | ||
152 | } | 138 | } |
153 | 139 | ||
154 | static inline void ath10k_hif_get_default_pipe(struct ath10k *ar, | 140 | static inline void ath10k_hif_get_default_pipe(struct ath10k *ar, |
@@ -163,12 +149,6 @@ static inline void ath10k_hif_send_complete_check(struct ath10k *ar, | |||
163 | ar->hif.ops->send_complete_check(ar, pipe_id, force); | 149 | ar->hif.ops->send_complete_check(ar, pipe_id, force); |
164 | } | 150 | } |
165 | 151 | ||
166 | static inline void ath10k_hif_set_callbacks(struct ath10k *ar, | ||
167 | struct ath10k_hif_cb *callbacks) | ||
168 | { | ||
169 | ar->hif.ops->set_callbacks(ar, callbacks); | ||
170 | } | ||
171 | |||
172 | static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, | 152 | static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, |
173 | u8 pipe_id) | 153 | u8 pipe_id) |
174 | { | 154 | { |
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 32d9ff1b19dc..5b3c6bcf9598 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c | |||
@@ -23,16 +23,6 @@ | |||
23 | /* Send */ | 23 | /* Send */ |
24 | /********/ | 24 | /********/ |
25 | 25 | ||
26 | static inline void ath10k_htc_send_complete_check(struct ath10k_htc_ep *ep, | ||
27 | int force) | ||
28 | { | ||
29 | /* | ||
30 | * Check whether HIF has any prior sends that have finished, | ||
31 | * have not had the post-processing done. | ||
32 | */ | ||
33 | ath10k_hif_send_complete_check(ep->htc->ar, ep->ul_pipe_id, force); | ||
34 | } | ||
35 | |||
36 | static void ath10k_htc_control_tx_complete(struct ath10k *ar, | 26 | static void ath10k_htc_control_tx_complete(struct ath10k *ar, |
37 | struct sk_buff *skb) | 27 | struct sk_buff *skb) |
38 | { | 28 | { |
@@ -181,24 +171,22 @@ err_pull: | |||
181 | return ret; | 171 | return ret; |
182 | } | 172 | } |
183 | 173 | ||
184 | static int ath10k_htc_tx_completion_handler(struct ath10k *ar, | 174 | void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb) |
185 | struct sk_buff *skb) | ||
186 | { | 175 | { |
187 | struct ath10k_htc *htc = &ar->htc; | 176 | struct ath10k_htc *htc = &ar->htc; |
188 | struct ath10k_skb_cb *skb_cb; | 177 | struct ath10k_skb_cb *skb_cb; |
189 | struct ath10k_htc_ep *ep; | 178 | struct ath10k_htc_ep *ep; |
190 | 179 | ||
191 | if (WARN_ON_ONCE(!skb)) | 180 | if (WARN_ON_ONCE(!skb)) |
192 | return 0; | 181 | return; |
193 | 182 | ||
194 | skb_cb = ATH10K_SKB_CB(skb); | 183 | skb_cb = ATH10K_SKB_CB(skb); |
195 | ep = &htc->endpoint[skb_cb->eid]; | 184 | ep = &htc->endpoint[skb_cb->eid]; |
196 | 185 | ||
197 | ath10k_htc_notify_tx_completion(ep, skb); | 186 | ath10k_htc_notify_tx_completion(ep, skb); |
198 | /* the skb now belongs to the completion handler */ | 187 | /* the skb now belongs to the completion handler */ |
199 | |||
200 | return 0; | ||
201 | } | 188 | } |
189 | EXPORT_SYMBOL(ath10k_htc_tx_completion_handler); | ||
202 | 190 | ||
203 | /***********/ | 191 | /***********/ |
204 | /* Receive */ | 192 | /* Receive */ |
@@ -304,8 +292,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, | |||
304 | return status; | 292 | return status; |
305 | } | 293 | } |
306 | 294 | ||
307 | static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | 295 | void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) |
308 | struct sk_buff *skb) | ||
309 | { | 296 | { |
310 | int status = 0; | 297 | int status = 0; |
311 | struct ath10k_htc *htc = &ar->htc; | 298 | struct ath10k_htc *htc = &ar->htc; |
@@ -326,21 +313,11 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | |||
326 | ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid); | 313 | ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid); |
327 | ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "", | 314 | ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "", |
328 | hdr, sizeof(*hdr)); | 315 | hdr, sizeof(*hdr)); |
329 | status = -EINVAL; | ||
330 | goto out; | 316 | goto out; |
331 | } | 317 | } |
332 | 318 | ||
333 | ep = &htc->endpoint[eid]; | 319 | ep = &htc->endpoint[eid]; |
334 | 320 | ||
335 | /* | ||
336 | * If this endpoint that received a message from the target has | ||
337 | * a to-target HIF pipe whose send completions are polled rather | ||
338 | * than interrupt-driven, this is a good point to ask HIF to check | ||
339 | * whether it has any completed sends to handle. | ||
340 | */ | ||
341 | if (ep->ul_is_polled) | ||
342 | ath10k_htc_send_complete_check(ep, 1); | ||
343 | |||
344 | payload_len = __le16_to_cpu(hdr->len); | 321 | payload_len = __le16_to_cpu(hdr->len); |
345 | 322 | ||
346 | if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) { | 323 | if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) { |
@@ -348,7 +325,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | |||
348 | payload_len + sizeof(*hdr)); | 325 | payload_len + sizeof(*hdr)); |
349 | ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", | 326 | ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", |
350 | hdr, sizeof(*hdr)); | 327 | hdr, sizeof(*hdr)); |
351 | status = -EINVAL; | ||
352 | goto out; | 328 | goto out; |
353 | } | 329 | } |
354 | 330 | ||
@@ -358,7 +334,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | |||
358 | skb->len, payload_len); | 334 | skb->len, payload_len); |
359 | ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", | 335 | ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", |
360 | "", hdr, sizeof(*hdr)); | 336 | "", hdr, sizeof(*hdr)); |
361 | status = -EINVAL; | ||
362 | goto out; | 337 | goto out; |
363 | } | 338 | } |
364 | 339 | ||
@@ -374,7 +349,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | |||
374 | (trailer_len > payload_len)) { | 349 | (trailer_len > payload_len)) { |
375 | ath10k_warn(ar, "Invalid trailer length: %d\n", | 350 | ath10k_warn(ar, "Invalid trailer length: %d\n", |
376 | trailer_len); | 351 | trailer_len); |
377 | status = -EPROTO; | ||
378 | goto out; | 352 | goto out; |
379 | } | 353 | } |
380 | 354 | ||
@@ -407,7 +381,6 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | |||
407 | * sending unsolicited messages on the ep 0 | 381 | * sending unsolicited messages on the ep 0 |
408 | */ | 382 | */ |
409 | ath10k_warn(ar, "HTC rx ctrl still processing\n"); | 383 | ath10k_warn(ar, "HTC rx ctrl still processing\n"); |
410 | status = -EINVAL; | ||
411 | complete(&htc->ctl_resp); | 384 | complete(&htc->ctl_resp); |
412 | goto out; | 385 | goto out; |
413 | } | 386 | } |
@@ -439,9 +412,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, | |||
439 | skb = NULL; | 412 | skb = NULL; |
440 | out: | 413 | out: |
441 | kfree_skb(skb); | 414 | kfree_skb(skb); |
442 | |||
443 | return status; | ||
444 | } | 415 | } |
416 | EXPORT_SYMBOL(ath10k_htc_rx_completion_handler); | ||
445 | 417 | ||
446 | static void ath10k_htc_control_rx_complete(struct ath10k *ar, | 418 | static void ath10k_htc_control_rx_complete(struct ath10k *ar, |
447 | struct sk_buff *skb) | 419 | struct sk_buff *skb) |
@@ -767,9 +739,7 @@ setup: | |||
767 | status = ath10k_hif_map_service_to_pipe(htc->ar, | 739 | status = ath10k_hif_map_service_to_pipe(htc->ar, |
768 | ep->service_id, | 740 | ep->service_id, |
769 | &ep->ul_pipe_id, | 741 | &ep->ul_pipe_id, |
770 | &ep->dl_pipe_id, | 742 | &ep->dl_pipe_id); |
771 | &ep->ul_is_polled, | ||
772 | &ep->dl_is_polled); | ||
773 | if (status) | 743 | if (status) |
774 | return status; | 744 | return status; |
775 | 745 | ||
@@ -778,10 +748,6 @@ setup: | |||
778 | htc_service_name(ep->service_id), ep->ul_pipe_id, | 748 | htc_service_name(ep->service_id), ep->ul_pipe_id, |
779 | ep->dl_pipe_id, ep->eid); | 749 | ep->dl_pipe_id, ep->eid); |
780 | 750 | ||
781 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | ||
782 | "boot htc ep %d ul polled %d dl polled %d\n", | ||
783 | ep->eid, ep->ul_is_polled, ep->dl_is_polled); | ||
784 | |||
785 | if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { | 751 | if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { |
786 | ep->tx_credit_flow_enabled = false; | 752 | ep->tx_credit_flow_enabled = false; |
787 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | 753 | ath10k_dbg(ar, ATH10K_DBG_BOOT, |
@@ -841,7 +807,6 @@ int ath10k_htc_start(struct ath10k_htc *htc) | |||
841 | /* registered target arrival callback from the HIF layer */ | 807 | /* registered target arrival callback from the HIF layer */ |
842 | int ath10k_htc_init(struct ath10k *ar) | 808 | int ath10k_htc_init(struct ath10k *ar) |
843 | { | 809 | { |
844 | struct ath10k_hif_cb htc_callbacks; | ||
845 | struct ath10k_htc_ep *ep = NULL; | 810 | struct ath10k_htc_ep *ep = NULL; |
846 | struct ath10k_htc *htc = &ar->htc; | 811 | struct ath10k_htc *htc = &ar->htc; |
847 | 812 | ||
@@ -849,15 +814,11 @@ int ath10k_htc_init(struct ath10k *ar) | |||
849 | 814 | ||
850 | ath10k_htc_reset_endpoint_states(htc); | 815 | ath10k_htc_reset_endpoint_states(htc); |
851 | 816 | ||
852 | /* setup HIF layer callbacks */ | ||
853 | htc_callbacks.rx_completion = ath10k_htc_rx_completion_handler; | ||
854 | htc_callbacks.tx_completion = ath10k_htc_tx_completion_handler; | ||
855 | htc->ar = ar; | 817 | htc->ar = ar; |
856 | 818 | ||
857 | /* Get HIF default pipe for HTC message exchange */ | 819 | /* Get HIF default pipe for HTC message exchange */ |
858 | ep = &htc->endpoint[ATH10K_HTC_EP_0]; | 820 | ep = &htc->endpoint[ATH10K_HTC_EP_0]; |
859 | 821 | ||
860 | ath10k_hif_set_callbacks(ar, &htc_callbacks); | ||
861 | ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id); | 822 | ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id); |
862 | 823 | ||
863 | init_completion(&htc->ctl_resp); | 824 | init_completion(&htc->ctl_resp); |
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 527179c0edce..e70aa38e6e05 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h | |||
@@ -312,8 +312,6 @@ struct ath10k_htc_ep { | |||
312 | int max_ep_message_len; | 312 | int max_ep_message_len; |
313 | u8 ul_pipe_id; | 313 | u8 ul_pipe_id; |
314 | u8 dl_pipe_id; | 314 | u8 dl_pipe_id; |
315 | int ul_is_polled; /* call HIF to get tx completions */ | ||
316 | int dl_is_polled; /* call HIF to fetch rx (not implemented) */ | ||
317 | 315 | ||
318 | u8 seq_no; /* for debugging */ | 316 | u8 seq_no; /* for debugging */ |
319 | int tx_credits; | 317 | int tx_credits; |
@@ -355,5 +353,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, | |||
355 | int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, | 353 | int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, |
356 | struct sk_buff *packet); | 354 | struct sk_buff *packet); |
357 | struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size); | 355 | struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size); |
356 | void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb); | ||
357 | void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb); | ||
358 | 358 | ||
359 | #endif | 359 | #endif |
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 5a8e4eae7a9c..2bad50e520b5 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h | |||
@@ -1488,7 +1488,6 @@ struct ath10k_htt { | |||
1488 | int num_pending_mgmt_tx; | 1488 | int num_pending_mgmt_tx; |
1489 | struct idr pending_tx; | 1489 | struct idr pending_tx; |
1490 | wait_queue_head_t empty_tx_wq; | 1490 | wait_queue_head_t empty_tx_wq; |
1491 | struct dma_pool *tx_pool; | ||
1492 | 1491 | ||
1493 | /* set if host-fw communication goes haywire | 1492 | /* set if host-fw communication goes haywire |
1494 | * used to avoid further failures */ | 1493 | * used to avoid further failures */ |
@@ -1509,6 +1508,11 @@ struct ath10k_htt { | |||
1509 | dma_addr_t paddr; | 1508 | dma_addr_t paddr; |
1510 | struct htt_msdu_ext_desc *vaddr; | 1509 | struct htt_msdu_ext_desc *vaddr; |
1511 | } frag_desc; | 1510 | } frag_desc; |
1511 | |||
1512 | struct { | ||
1513 | dma_addr_t paddr; | ||
1514 | struct ath10k_htt_txbuf *vaddr; | ||
1515 | } txbuf; | ||
1512 | }; | 1516 | }; |
1513 | 1517 | ||
1514 | #define RX_HTT_HDR_STATUS_LEN 64 | 1518 | #define RX_HTT_HDR_STATUS_LEN 64 |
@@ -1587,6 +1591,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); | |||
1587 | int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, | 1591 | int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, |
1588 | u8 max_subfrms_ampdu, | 1592 | u8 max_subfrms_ampdu, |
1589 | u8 max_subfrms_amsdu); | 1593 | u8 max_subfrms_amsdu); |
1594 | void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb); | ||
1590 | 1595 | ||
1591 | void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc); | 1596 | void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc); |
1592 | int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb); | 1597 | int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb); |
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 606c1a34f004..6060dda4e910 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c | |||
@@ -2125,6 +2125,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) | |||
2125 | /* Free the indication buffer */ | 2125 | /* Free the indication buffer */ |
2126 | dev_kfree_skb_any(skb); | 2126 | dev_kfree_skb_any(skb); |
2127 | } | 2127 | } |
2128 | EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler); | ||
2128 | 2129 | ||
2129 | static void ath10k_htt_txrx_compl_task(unsigned long ptr) | 2130 | static void ath10k_htt_txrx_compl_task(unsigned long ptr) |
2130 | { | 2131 | { |
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index eb5ba9bb8b4d..16823970dbfd 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c | |||
@@ -108,9 +108,12 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) | |||
108 | spin_lock_init(&htt->tx_lock); | 108 | spin_lock_init(&htt->tx_lock); |
109 | idr_init(&htt->pending_tx); | 109 | idr_init(&htt->pending_tx); |
110 | 110 | ||
111 | htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, | 111 | size = htt->max_num_pending_tx * sizeof(struct ath10k_htt_txbuf); |
112 | sizeof(struct ath10k_htt_txbuf), 4, 0); | 112 | htt->txbuf.vaddr = dma_alloc_coherent(ar->dev, size, |
113 | if (!htt->tx_pool) { | 113 | &htt->txbuf.paddr, |
114 | GFP_DMA); | ||
115 | if (!htt->txbuf.vaddr) { | ||
116 | ath10k_err(ar, "failed to alloc tx buffer\n"); | ||
114 | ret = -ENOMEM; | 117 | ret = -ENOMEM; |
115 | goto free_idr_pending_tx; | 118 | goto free_idr_pending_tx; |
116 | } | 119 | } |
@@ -125,14 +128,17 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) | |||
125 | if (!htt->frag_desc.vaddr) { | 128 | if (!htt->frag_desc.vaddr) { |
126 | ath10k_warn(ar, "failed to alloc fragment desc memory\n"); | 129 | ath10k_warn(ar, "failed to alloc fragment desc memory\n"); |
127 | ret = -ENOMEM; | 130 | ret = -ENOMEM; |
128 | goto free_tx_pool; | 131 | goto free_txbuf; |
129 | } | 132 | } |
130 | 133 | ||
131 | skip_frag_desc_alloc: | 134 | skip_frag_desc_alloc: |
132 | return 0; | 135 | return 0; |
133 | 136 | ||
134 | free_tx_pool: | 137 | free_txbuf: |
135 | dma_pool_destroy(htt->tx_pool); | 138 | size = htt->max_num_pending_tx * |
139 | sizeof(struct ath10k_htt_txbuf); | ||
140 | dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr, | ||
141 | htt->txbuf.paddr); | ||
136 | free_idr_pending_tx: | 142 | free_idr_pending_tx: |
137 | idr_destroy(&htt->pending_tx); | 143 | idr_destroy(&htt->pending_tx); |
138 | return ret; | 144 | return ret; |
@@ -160,7 +166,13 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt) | |||
160 | 166 | ||
161 | idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); | 167 | idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); |
162 | idr_destroy(&htt->pending_tx); | 168 | idr_destroy(&htt->pending_tx); |
163 | dma_pool_destroy(htt->tx_pool); | 169 | |
170 | if (htt->txbuf.vaddr) { | ||
171 | size = htt->max_num_pending_tx * | ||
172 | sizeof(struct ath10k_htt_txbuf); | ||
173 | dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr, | ||
174 | htt->txbuf.paddr); | ||
175 | } | ||
164 | 176 | ||
165 | if (htt->frag_desc.vaddr) { | 177 | if (htt->frag_desc.vaddr) { |
166 | size = htt->max_num_pending_tx * | 178 | size = htt->max_num_pending_tx * |
@@ -175,6 +187,12 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) | |||
175 | dev_kfree_skb_any(skb); | 187 | dev_kfree_skb_any(skb); |
176 | } | 188 | } |
177 | 189 | ||
190 | void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb) | ||
191 | { | ||
192 | dev_kfree_skb_any(skb); | ||
193 | } | ||
194 | EXPORT_SYMBOL(ath10k_htt_hif_tx_complete); | ||
195 | |||
178 | int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) | 196 | int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) |
179 | { | 197 | { |
180 | struct ath10k *ar = htt->ar; | 198 | struct ath10k *ar = htt->ar; |
@@ -454,9 +472,9 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
454 | spin_lock_bh(&htt->tx_lock); | 472 | spin_lock_bh(&htt->tx_lock); |
455 | res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); | 473 | res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); |
456 | spin_unlock_bh(&htt->tx_lock); | 474 | spin_unlock_bh(&htt->tx_lock); |
457 | if (res < 0) { | 475 | if (res < 0) |
458 | goto err_tx_dec; | 476 | goto err_tx_dec; |
459 | } | 477 | |
460 | msdu_id = res; | 478 | msdu_id = res; |
461 | 479 | ||
462 | txdesc = ath10k_htc_alloc_skb(ar, len); | 480 | txdesc = ath10k_htc_alloc_skb(ar, len); |
@@ -521,7 +539,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
521 | int res; | 539 | int res; |
522 | u8 flags0 = 0; | 540 | u8 flags0 = 0; |
523 | u16 msdu_id, flags1 = 0; | 541 | u16 msdu_id, flags1 = 0; |
524 | dma_addr_t paddr = 0; | ||
525 | u32 frags_paddr = 0; | 542 | u32 frags_paddr = 0; |
526 | struct htt_msdu_ext_desc *ext_desc = NULL; | 543 | struct htt_msdu_ext_desc *ext_desc = NULL; |
527 | bool limit_mgmt_desc = false; | 544 | bool limit_mgmt_desc = false; |
@@ -542,21 +559,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
542 | spin_lock_bh(&htt->tx_lock); | 559 | spin_lock_bh(&htt->tx_lock); |
543 | res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); | 560 | res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); |
544 | spin_unlock_bh(&htt->tx_lock); | 561 | spin_unlock_bh(&htt->tx_lock); |
545 | if (res < 0) { | 562 | if (res < 0) |
546 | goto err_tx_dec; | 563 | goto err_tx_dec; |
547 | } | 564 | |
548 | msdu_id = res; | 565 | msdu_id = res; |
549 | 566 | ||
550 | prefetch_len = min(htt->prefetch_len, msdu->len); | 567 | prefetch_len = min(htt->prefetch_len, msdu->len); |
551 | prefetch_len = roundup(prefetch_len, 4); | 568 | prefetch_len = roundup(prefetch_len, 4); |
552 | 569 | ||
553 | skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, | 570 | skb_cb->htt.txbuf = &htt->txbuf.vaddr[msdu_id]; |
554 | &paddr); | 571 | skb_cb->htt.txbuf_paddr = htt->txbuf.paddr + |
555 | if (!skb_cb->htt.txbuf) { | 572 | (sizeof(struct ath10k_htt_txbuf) * msdu_id); |
556 | res = -ENOMEM; | ||
557 | goto err_free_msdu_id; | ||
558 | } | ||
559 | skb_cb->htt.txbuf_paddr = paddr; | ||
560 | 573 | ||
561 | if ((ieee80211_is_action(hdr->frame_control) || | 574 | if ((ieee80211_is_action(hdr->frame_control) || |
562 | ieee80211_is_deauth(hdr->frame_control) || | 575 | ieee80211_is_deauth(hdr->frame_control) || |
@@ -574,7 +587,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
574 | res = dma_mapping_error(dev, skb_cb->paddr); | 587 | res = dma_mapping_error(dev, skb_cb->paddr); |
575 | if (res) { | 588 | if (res) { |
576 | res = -EIO; | 589 | res = -EIO; |
577 | goto err_free_txbuf; | 590 | goto err_free_msdu_id; |
578 | } | 591 | } |
579 | 592 | ||
580 | switch (skb_cb->txmode) { | 593 | switch (skb_cb->txmode) { |
@@ -706,10 +719,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
706 | 719 | ||
707 | err_unmap_msdu: | 720 | err_unmap_msdu: |
708 | dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); | 721 | dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
709 | err_free_txbuf: | ||
710 | dma_pool_free(htt->tx_pool, | ||
711 | skb_cb->htt.txbuf, | ||
712 | skb_cb->htt.txbuf_paddr); | ||
713 | err_free_msdu_id: | 722 | err_free_msdu_id: |
714 | spin_lock_bh(&htt->tx_lock); | 723 | spin_lock_bh(&htt->tx_lock); |
715 | ath10k_htt_tx_free_msdu_id(htt, msdu_id); | 724 | ath10k_htt_tx_free_msdu_id(htt, msdu_id); |
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index bc421a5c5356..291df3d6d484 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h | |||
@@ -97,6 +97,9 @@ enum qca6174_chip_id_rev { | |||
97 | 97 | ||
98 | /* includes also the null byte */ | 98 | /* includes also the null byte */ |
99 | #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" | 99 | #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" |
100 | #define ATH10K_BOARD_MAGIC "QCA-ATH10K-BOARD" | ||
101 | |||
102 | #define ATH10K_BOARD_API2_FILE "board-2.bin" | ||
100 | 103 | ||
101 | #define REG_DUMP_COUNT_QCA988X 60 | 104 | #define REG_DUMP_COUNT_QCA988X 60 |
102 | 105 | ||
@@ -159,6 +162,16 @@ enum ath10k_fw_htt_op_version { | |||
159 | ATH10K_FW_HTT_OP_VERSION_MAX, | 162 | ATH10K_FW_HTT_OP_VERSION_MAX, |
160 | }; | 163 | }; |
161 | 164 | ||
165 | enum ath10k_bd_ie_type { | ||
166 | /* contains sub IEs of enum ath10k_bd_ie_board_type */ | ||
167 | ATH10K_BD_IE_BOARD = 0, | ||
168 | }; | ||
169 | |||
170 | enum ath10k_bd_ie_board_type { | ||
171 | ATH10K_BD_IE_BOARD_NAME = 0, | ||
172 | ATH10K_BD_IE_BOARD_DATA = 1, | ||
173 | }; | ||
174 | |||
162 | enum ath10k_hw_rev { | 175 | enum ath10k_hw_rev { |
163 | ATH10K_HW_QCA988X, | 176 | ATH10K_HW_QCA988X, |
164 | ATH10K_HW_QCA6174, | 177 | ATH10K_HW_QCA6174, |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 79490ad41ac5..484c1a10372f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -197,9 +197,8 @@ static int ath10k_send_key(struct ath10k_vif *arvif, | |||
197 | return -EOPNOTSUPP; | 197 | return -EOPNOTSUPP; |
198 | } | 198 | } |
199 | 199 | ||
200 | if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { | 200 | if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) |
201 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 201 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
202 | } | ||
203 | 202 | ||
204 | if (cmd == DISABLE_KEY) { | 203 | if (cmd == DISABLE_KEY) { |
205 | arg.key_cipher = WMI_CIPHER_NONE; | 204 | arg.key_cipher = WMI_CIPHER_NONE; |
@@ -1111,7 +1110,8 @@ static int ath10k_monitor_recalc(struct ath10k *ar) | |||
1111 | 1110 | ||
1112 | ret = ath10k_monitor_stop(ar); | 1111 | ret = ath10k_monitor_stop(ar); |
1113 | if (ret) | 1112 | if (ret) |
1114 | ath10k_warn(ar, "failed to stop disallowed monitor: %d\n", ret); | 1113 | ath10k_warn(ar, "failed to stop disallowed monitor: %d\n", |
1114 | ret); | ||
1115 | /* not serious */ | 1115 | /* not serious */ |
1116 | } | 1116 | } |
1117 | 1117 | ||
@@ -2084,7 +2084,8 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, | |||
2084 | enum ieee80211_band band; | 2084 | enum ieee80211_band band; |
2085 | const u8 *ht_mcs_mask; | 2085 | const u8 *ht_mcs_mask; |
2086 | const u16 *vht_mcs_mask; | 2086 | const u16 *vht_mcs_mask; |
2087 | int i, n, max_nss; | 2087 | int i, n; |
2088 | u8 max_nss; | ||
2088 | u32 stbc; | 2089 | u32 stbc; |
2089 | 2090 | ||
2090 | lockdep_assert_held(&ar->conf_mutex); | 2091 | lockdep_assert_held(&ar->conf_mutex); |
@@ -2169,7 +2170,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, | |||
2169 | arg->peer_ht_rates.rates[i] = i; | 2170 | arg->peer_ht_rates.rates[i] = i; |
2170 | } else { | 2171 | } else { |
2171 | arg->peer_ht_rates.num_rates = n; | 2172 | arg->peer_ht_rates.num_rates = n; |
2172 | arg->peer_num_spatial_streams = max_nss; | 2173 | arg->peer_num_spatial_streams = min(sta->rx_nss, max_nss); |
2173 | } | 2174 | } |
2174 | 2175 | ||
2175 | ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", | 2176 | ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", |
@@ -4065,6 +4066,7 @@ static u32 get_nss_from_chainmask(u16 chain_mask) | |||
4065 | static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar) | 4066 | static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar) |
4066 | { | 4067 | { |
4067 | int nsts = ar->vht_cap_info; | 4068 | int nsts = ar->vht_cap_info; |
4069 | |||
4068 | nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; | 4070 | nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; |
4069 | nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; | 4071 | nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; |
4070 | 4072 | ||
@@ -4081,8 +4083,9 @@ static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar) | |||
4081 | static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar) | 4083 | static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar) |
4082 | { | 4084 | { |
4083 | int sound_dim = ar->vht_cap_info; | 4085 | int sound_dim = ar->vht_cap_info; |
4086 | |||
4084 | sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; | 4087 | sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; |
4085 | sound_dim >>=IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; | 4088 | sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; |
4086 | 4089 | ||
4087 | /* If the sounding dimension is not advertised by the firmware, | 4090 | /* If the sounding dimension is not advertised by the firmware, |
4088 | * let's use a default value of 1 | 4091 | * let's use a default value of 1 |
@@ -4656,7 +4659,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | |||
4656 | info->use_cts_prot ? 1 : 0); | 4659 | info->use_cts_prot ? 1 : 0); |
4657 | if (ret) | 4660 | if (ret) |
4658 | ath10k_warn(ar, "failed to set protection mode %d on vdev %i: %d\n", | 4661 | ath10k_warn(ar, "failed to set protection mode %d on vdev %i: %d\n", |
4659 | info->use_cts_prot, arvif->vdev_id, ret); | 4662 | info->use_cts_prot, arvif->vdev_id, ret); |
4660 | } | 4663 | } |
4661 | 4664 | ||
4662 | if (changed & BSS_CHANGED_ERP_SLOT) { | 4665 | if (changed & BSS_CHANGED_ERP_SLOT) { |
@@ -6268,8 +6271,8 @@ ath10k_mac_update_rx_channel(struct ath10k *ar, | |||
6268 | rcu_read_lock(); | 6271 | rcu_read_lock(); |
6269 | if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) { | 6272 | if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) { |
6270 | ieee80211_iter_chan_contexts_atomic(ar->hw, | 6273 | ieee80211_iter_chan_contexts_atomic(ar->hw, |
6271 | ath10k_mac_get_any_chandef_iter, | 6274 | ath10k_mac_get_any_chandef_iter, |
6272 | &def); | 6275 | &def); |
6273 | 6276 | ||
6274 | if (vifs) | 6277 | if (vifs) |
6275 | def = &vifs[0].new_ctx->def; | 6278 | def = &vifs[0].new_ctx->def; |
@@ -7301,7 +7304,7 @@ int ath10k_mac_register(struct ath10k *ar) | |||
7301 | ath10k_reg_notifier); | 7304 | ath10k_reg_notifier); |
7302 | if (ret) { | 7305 | if (ret) { |
7303 | ath10k_err(ar, "failed to initialise regulatory: %i\n", ret); | 7306 | ath10k_err(ar, "failed to initialise regulatory: %i\n", ret); |
7304 | goto err_free; | 7307 | goto err_dfs_detector_exit; |
7305 | } | 7308 | } |
7306 | 7309 | ||
7307 | ar->hw->wiphy->cipher_suites = cipher_suites; | 7310 | ar->hw->wiphy->cipher_suites = cipher_suites; |
@@ -7310,7 +7313,7 @@ int ath10k_mac_register(struct ath10k *ar) | |||
7310 | ret = ieee80211_register_hw(ar->hw); | 7313 | ret = ieee80211_register_hw(ar->hw); |
7311 | if (ret) { | 7314 | if (ret) { |
7312 | ath10k_err(ar, "failed to register ieee80211: %d\n", ret); | 7315 | ath10k_err(ar, "failed to register ieee80211: %d\n", ret); |
7313 | goto err_free; | 7316 | goto err_dfs_detector_exit; |
7314 | } | 7317 | } |
7315 | 7318 | ||
7316 | if (!ath_is_world_regd(&ar->ath_common.regulatory)) { | 7319 | if (!ath_is_world_regd(&ar->ath_common.regulatory)) { |
@@ -7324,10 +7327,16 @@ int ath10k_mac_register(struct ath10k *ar) | |||
7324 | 7327 | ||
7325 | err_unregister: | 7328 | err_unregister: |
7326 | ieee80211_unregister_hw(ar->hw); | 7329 | ieee80211_unregister_hw(ar->hw); |
7330 | |||
7331 | err_dfs_detector_exit: | ||
7332 | if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) | ||
7333 | ar->dfs_detector->exit(ar->dfs_detector); | ||
7334 | |||
7327 | err_free: | 7335 | err_free: |
7328 | kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); | 7336 | kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); |
7329 | kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); | 7337 | kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); |
7330 | 7338 | ||
7339 | SET_IEEE80211_DEV(ar->hw, NULL); | ||
7331 | return ret; | 7340 | return ret; |
7332 | } | 7341 | } |
7333 | 7342 | ||
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 110fcad609b9..5c05b0cf54a1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c | |||
@@ -104,6 +104,10 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, | |||
104 | struct ath10k_ce_pipe *rx_pipe, | 104 | struct ath10k_ce_pipe *rx_pipe, |
105 | struct bmi_xfer *xfer); | 105 | struct bmi_xfer *xfer); |
106 | static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); | 106 | static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); |
107 | static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state); | ||
108 | static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state); | ||
109 | static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state); | ||
110 | static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state); | ||
107 | 111 | ||
108 | static const struct ce_attr host_ce_config_wlan[] = { | 112 | static const struct ce_attr host_ce_config_wlan[] = { |
109 | /* CE0: host->target HTC control and raw streams */ | 113 | /* CE0: host->target HTC control and raw streams */ |
@@ -112,6 +116,7 @@ static const struct ce_attr host_ce_config_wlan[] = { | |||
112 | .src_nentries = 16, | 116 | .src_nentries = 16, |
113 | .src_sz_max = 256, | 117 | .src_sz_max = 256, |
114 | .dest_nentries = 0, | 118 | .dest_nentries = 0, |
119 | .send_cb = ath10k_pci_htc_tx_cb, | ||
115 | }, | 120 | }, |
116 | 121 | ||
117 | /* CE1: target->host HTT + HTC control */ | 122 | /* CE1: target->host HTT + HTC control */ |
@@ -120,6 +125,7 @@ static const struct ce_attr host_ce_config_wlan[] = { | |||
120 | .src_nentries = 0, | 125 | .src_nentries = 0, |
121 | .src_sz_max = 2048, | 126 | .src_sz_max = 2048, |
122 | .dest_nentries = 512, | 127 | .dest_nentries = 512, |
128 | .recv_cb = ath10k_pci_htc_rx_cb, | ||
123 | }, | 129 | }, |
124 | 130 | ||
125 | /* CE2: target->host WMI */ | 131 | /* CE2: target->host WMI */ |
@@ -128,6 +134,7 @@ static const struct ce_attr host_ce_config_wlan[] = { | |||
128 | .src_nentries = 0, | 134 | .src_nentries = 0, |
129 | .src_sz_max = 2048, | 135 | .src_sz_max = 2048, |
130 | .dest_nentries = 128, | 136 | .dest_nentries = 128, |
137 | .recv_cb = ath10k_pci_htc_rx_cb, | ||
131 | }, | 138 | }, |
132 | 139 | ||
133 | /* CE3: host->target WMI */ | 140 | /* CE3: host->target WMI */ |
@@ -136,6 +143,7 @@ static const struct ce_attr host_ce_config_wlan[] = { | |||
136 | .src_nentries = 32, | 143 | .src_nentries = 32, |
137 | .src_sz_max = 2048, | 144 | .src_sz_max = 2048, |
138 | .dest_nentries = 0, | 145 | .dest_nentries = 0, |
146 | .send_cb = ath10k_pci_htc_tx_cb, | ||
139 | }, | 147 | }, |
140 | 148 | ||
141 | /* CE4: host->target HTT */ | 149 | /* CE4: host->target HTT */ |
@@ -144,14 +152,16 @@ static const struct ce_attr host_ce_config_wlan[] = { | |||
144 | .src_nentries = CE_HTT_H2T_MSG_SRC_NENTRIES, | 152 | .src_nentries = CE_HTT_H2T_MSG_SRC_NENTRIES, |
145 | .src_sz_max = 256, | 153 | .src_sz_max = 256, |
146 | .dest_nentries = 0, | 154 | .dest_nentries = 0, |
155 | .send_cb = ath10k_pci_htt_tx_cb, | ||
147 | }, | 156 | }, |
148 | 157 | ||
149 | /* CE5: unused */ | 158 | /* CE5: target->host HTT (HIF->HTT) */ |
150 | { | 159 | { |
151 | .flags = CE_ATTR_FLAGS, | 160 | .flags = CE_ATTR_FLAGS, |
152 | .src_nentries = 0, | 161 | .src_nentries = 0, |
153 | .src_sz_max = 0, | 162 | .src_sz_max = 512, |
154 | .dest_nentries = 0, | 163 | .dest_nentries = 512, |
164 | .recv_cb = ath10k_pci_htt_rx_cb, | ||
155 | }, | 165 | }, |
156 | 166 | ||
157 | /* CE6: target autonomous hif_memcpy */ | 167 | /* CE6: target autonomous hif_memcpy */ |
@@ -257,12 +267,12 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { | |||
257 | 267 | ||
258 | /* NB: 50% of src nentries, since tx has 2 frags */ | 268 | /* NB: 50% of src nentries, since tx has 2 frags */ |
259 | 269 | ||
260 | /* CE5: unused */ | 270 | /* CE5: target->host HTT (HIF->HTT) */ |
261 | { | 271 | { |
262 | .pipenum = __cpu_to_le32(5), | 272 | .pipenum = __cpu_to_le32(5), |
263 | .pipedir = __cpu_to_le32(PIPEDIR_OUT), | 273 | .pipedir = __cpu_to_le32(PIPEDIR_IN), |
264 | .nentries = __cpu_to_le32(32), | 274 | .nentries = __cpu_to_le32(32), |
265 | .nbytes_max = __cpu_to_le32(2048), | 275 | .nbytes_max = __cpu_to_le32(512), |
266 | .flags = __cpu_to_le32(CE_ATTR_FLAGS), | 276 | .flags = __cpu_to_le32(CE_ATTR_FLAGS), |
267 | .reserved = __cpu_to_le32(0), | 277 | .reserved = __cpu_to_le32(0), |
268 | }, | 278 | }, |
@@ -396,7 +406,7 @@ static const struct service_to_pipe target_service_to_ce_map_wlan[] = { | |||
396 | { | 406 | { |
397 | __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), | 407 | __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), |
398 | __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ | 408 | __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ |
399 | __cpu_to_le32(1), | 409 | __cpu_to_le32(5), |
400 | }, | 410 | }, |
401 | 411 | ||
402 | /* (Additions here) */ | 412 | /* (Additions here) */ |
@@ -452,8 +462,12 @@ static int ath10k_pci_wake_wait(struct ath10k *ar) | |||
452 | int curr_delay = 5; | 462 | int curr_delay = 5; |
453 | 463 | ||
454 | while (tot_delay < PCIE_WAKE_TIMEOUT) { | 464 | while (tot_delay < PCIE_WAKE_TIMEOUT) { |
455 | if (ath10k_pci_is_awake(ar)) | 465 | if (ath10k_pci_is_awake(ar)) { |
466 | if (tot_delay > PCIE_WAKE_LATE_US) | ||
467 | ath10k_warn(ar, "device wakeup took %d ms which is unusally long, otherwise it works normally.\n", | ||
468 | tot_delay / 1000); | ||
456 | return 0; | 469 | return 0; |
470 | } | ||
457 | 471 | ||
458 | udelay(curr_delay); | 472 | udelay(curr_delay); |
459 | tot_delay += curr_delay; | 473 | tot_delay += curr_delay; |
@@ -465,12 +479,53 @@ static int ath10k_pci_wake_wait(struct ath10k *ar) | |||
465 | return -ETIMEDOUT; | 479 | return -ETIMEDOUT; |
466 | } | 480 | } |
467 | 481 | ||
482 | static int ath10k_pci_force_wake(struct ath10k *ar) | ||
483 | { | ||
484 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
485 | unsigned long flags; | ||
486 | int ret = 0; | ||
487 | |||
488 | spin_lock_irqsave(&ar_pci->ps_lock, flags); | ||
489 | |||
490 | if (!ar_pci->ps_awake) { | ||
491 | iowrite32(PCIE_SOC_WAKE_V_MASK, | ||
492 | ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + | ||
493 | PCIE_SOC_WAKE_ADDRESS); | ||
494 | |||
495 | ret = ath10k_pci_wake_wait(ar); | ||
496 | if (ret == 0) | ||
497 | ar_pci->ps_awake = true; | ||
498 | } | ||
499 | |||
500 | spin_unlock_irqrestore(&ar_pci->ps_lock, flags); | ||
501 | |||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | static void ath10k_pci_force_sleep(struct ath10k *ar) | ||
506 | { | ||
507 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
508 | unsigned long flags; | ||
509 | |||
510 | spin_lock_irqsave(&ar_pci->ps_lock, flags); | ||
511 | |||
512 | iowrite32(PCIE_SOC_WAKE_RESET, | ||
513 | ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + | ||
514 | PCIE_SOC_WAKE_ADDRESS); | ||
515 | ar_pci->ps_awake = false; | ||
516 | |||
517 | spin_unlock_irqrestore(&ar_pci->ps_lock, flags); | ||
518 | } | ||
519 | |||
468 | static int ath10k_pci_wake(struct ath10k *ar) | 520 | static int ath10k_pci_wake(struct ath10k *ar) |
469 | { | 521 | { |
470 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 522 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
471 | unsigned long flags; | 523 | unsigned long flags; |
472 | int ret = 0; | 524 | int ret = 0; |
473 | 525 | ||
526 | if (ar_pci->pci_ps == 0) | ||
527 | return ret; | ||
528 | |||
474 | spin_lock_irqsave(&ar_pci->ps_lock, flags); | 529 | spin_lock_irqsave(&ar_pci->ps_lock, flags); |
475 | 530 | ||
476 | ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake refcount %lu awake %d\n", | 531 | ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake refcount %lu awake %d\n", |
@@ -502,6 +557,9 @@ static void ath10k_pci_sleep(struct ath10k *ar) | |||
502 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 557 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
503 | unsigned long flags; | 558 | unsigned long flags; |
504 | 559 | ||
560 | if (ar_pci->pci_ps == 0) | ||
561 | return; | ||
562 | |||
505 | spin_lock_irqsave(&ar_pci->ps_lock, flags); | 563 | spin_lock_irqsave(&ar_pci->ps_lock, flags); |
506 | 564 | ||
507 | ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep refcount %lu awake %d\n", | 565 | ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep refcount %lu awake %d\n", |
@@ -544,6 +602,11 @@ static void ath10k_pci_sleep_sync(struct ath10k *ar) | |||
544 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 602 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
545 | unsigned long flags; | 603 | unsigned long flags; |
546 | 604 | ||
605 | if (ar_pci->pci_ps == 0) { | ||
606 | ath10k_pci_force_sleep(ar); | ||
607 | return; | ||
608 | } | ||
609 | |||
547 | del_timer_sync(&ar_pci->ps_timer); | 610 | del_timer_sync(&ar_pci->ps_timer); |
548 | 611 | ||
549 | spin_lock_irqsave(&ar_pci->ps_lock, flags); | 612 | spin_lock_irqsave(&ar_pci->ps_lock, flags); |
@@ -682,8 +745,6 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) | |||
682 | dma_addr_t paddr; | 745 | dma_addr_t paddr; |
683 | int ret; | 746 | int ret; |
684 | 747 | ||
685 | lockdep_assert_held(&ar_pci->ce_lock); | ||
686 | |||
687 | skb = dev_alloc_skb(pipe->buf_sz); | 748 | skb = dev_alloc_skb(pipe->buf_sz); |
688 | if (!skb) | 749 | if (!skb) |
689 | return -ENOMEM; | 750 | return -ENOMEM; |
@@ -701,9 +762,10 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) | |||
701 | 762 | ||
702 | ATH10K_SKB_RXCB(skb)->paddr = paddr; | 763 | ATH10K_SKB_RXCB(skb)->paddr = paddr; |
703 | 764 | ||
765 | spin_lock_bh(&ar_pci->ce_lock); | ||
704 | ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); | 766 | ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); |
767 | spin_unlock_bh(&ar_pci->ce_lock); | ||
705 | if (ret) { | 768 | if (ret) { |
706 | ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); | ||
707 | dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), | 769 | dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), |
708 | DMA_FROM_DEVICE); | 770 | DMA_FROM_DEVICE); |
709 | dev_kfree_skb_any(skb); | 771 | dev_kfree_skb_any(skb); |
@@ -713,25 +775,27 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) | |||
713 | return 0; | 775 | return 0; |
714 | } | 776 | } |
715 | 777 | ||
716 | static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) | 778 | static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) |
717 | { | 779 | { |
718 | struct ath10k *ar = pipe->hif_ce_state; | 780 | struct ath10k *ar = pipe->hif_ce_state; |
719 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 781 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
720 | struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; | 782 | struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; |
721 | int ret, num; | 783 | int ret, num; |
722 | 784 | ||
723 | lockdep_assert_held(&ar_pci->ce_lock); | ||
724 | |||
725 | if (pipe->buf_sz == 0) | 785 | if (pipe->buf_sz == 0) |
726 | return; | 786 | return; |
727 | 787 | ||
728 | if (!ce_pipe->dest_ring) | 788 | if (!ce_pipe->dest_ring) |
729 | return; | 789 | return; |
730 | 790 | ||
791 | spin_lock_bh(&ar_pci->ce_lock); | ||
731 | num = __ath10k_ce_rx_num_free_bufs(ce_pipe); | 792 | num = __ath10k_ce_rx_num_free_bufs(ce_pipe); |
793 | spin_unlock_bh(&ar_pci->ce_lock); | ||
732 | while (num--) { | 794 | while (num--) { |
733 | ret = __ath10k_pci_rx_post_buf(pipe); | 795 | ret = __ath10k_pci_rx_post_buf(pipe); |
734 | if (ret) { | 796 | if (ret) { |
797 | if (ret == -ENOSPC) | ||
798 | break; | ||
735 | ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); | 799 | ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); |
736 | mod_timer(&ar_pci->rx_post_retry, jiffies + | 800 | mod_timer(&ar_pci->rx_post_retry, jiffies + |
737 | ATH10K_PCI_RX_POST_RETRY_MS); | 801 | ATH10K_PCI_RX_POST_RETRY_MS); |
@@ -740,25 +804,13 @@ static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) | |||
740 | } | 804 | } |
741 | } | 805 | } |
742 | 806 | ||
743 | static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) | ||
744 | { | ||
745 | struct ath10k *ar = pipe->hif_ce_state; | ||
746 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
747 | |||
748 | spin_lock_bh(&ar_pci->ce_lock); | ||
749 | __ath10k_pci_rx_post_pipe(pipe); | ||
750 | spin_unlock_bh(&ar_pci->ce_lock); | ||
751 | } | ||
752 | |||
753 | static void ath10k_pci_rx_post(struct ath10k *ar) | 807 | static void ath10k_pci_rx_post(struct ath10k *ar) |
754 | { | 808 | { |
755 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 809 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
756 | int i; | 810 | int i; |
757 | 811 | ||
758 | spin_lock_bh(&ar_pci->ce_lock); | ||
759 | for (i = 0; i < CE_COUNT; i++) | 812 | for (i = 0; i < CE_COUNT; i++) |
760 | __ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]); | 813 | ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]); |
761 | spin_unlock_bh(&ar_pci->ce_lock); | ||
762 | } | 814 | } |
763 | 815 | ||
764 | static void ath10k_pci_rx_replenish_retry(unsigned long ptr) | 816 | static void ath10k_pci_rx_replenish_retry(unsigned long ptr) |
@@ -1102,11 +1154,9 @@ static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value) | |||
1102 | } | 1154 | } |
1103 | 1155 | ||
1104 | /* Called by lower (CE) layer when a send to Target completes. */ | 1156 | /* Called by lower (CE) layer when a send to Target completes. */ |
1105 | static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) | 1157 | static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state) |
1106 | { | 1158 | { |
1107 | struct ath10k *ar = ce_state->ar; | 1159 | struct ath10k *ar = ce_state->ar; |
1108 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
1109 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; | ||
1110 | struct sk_buff_head list; | 1160 | struct sk_buff_head list; |
1111 | struct sk_buff *skb; | 1161 | struct sk_buff *skb; |
1112 | u32 ce_data; | 1162 | u32 ce_data; |
@@ -1124,16 +1174,16 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) | |||
1124 | } | 1174 | } |
1125 | 1175 | ||
1126 | while ((skb = __skb_dequeue(&list))) | 1176 | while ((skb = __skb_dequeue(&list))) |
1127 | cb->tx_completion(ar, skb); | 1177 | ath10k_htc_tx_completion_handler(ar, skb); |
1128 | } | 1178 | } |
1129 | 1179 | ||
1130 | /* Called by lower (CE) layer when data is received from the Target. */ | 1180 | static void ath10k_pci_process_rx_cb(struct ath10k_ce_pipe *ce_state, |
1131 | static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | 1181 | void (*callback)(struct ath10k *ar, |
1182 | struct sk_buff *skb)) | ||
1132 | { | 1183 | { |
1133 | struct ath10k *ar = ce_state->ar; | 1184 | struct ath10k *ar = ce_state->ar; |
1134 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 1185 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
1135 | struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; | 1186 | struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; |
1136 | struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; | ||
1137 | struct sk_buff *skb; | 1187 | struct sk_buff *skb; |
1138 | struct sk_buff_head list; | 1188 | struct sk_buff_head list; |
1139 | void *transfer_context; | 1189 | void *transfer_context; |
@@ -1168,12 +1218,56 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
1168 | ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", | 1218 | ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", |
1169 | skb->data, skb->len); | 1219 | skb->data, skb->len); |
1170 | 1220 | ||
1171 | cb->rx_completion(ar, skb); | 1221 | callback(ar, skb); |
1172 | } | 1222 | } |
1173 | 1223 | ||
1174 | ath10k_pci_rx_post_pipe(pipe_info); | 1224 | ath10k_pci_rx_post_pipe(pipe_info); |
1175 | } | 1225 | } |
1176 | 1226 | ||
1227 | /* Called by lower (CE) layer when data is received from the Target. */ | ||
1228 | static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state) | ||
1229 | { | ||
1230 | ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); | ||
1231 | } | ||
1232 | |||
1233 | /* Called by lower (CE) layer when a send to HTT Target completes. */ | ||
1234 | static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state) | ||
1235 | { | ||
1236 | struct ath10k *ar = ce_state->ar; | ||
1237 | struct sk_buff *skb; | ||
1238 | u32 ce_data; | ||
1239 | unsigned int nbytes; | ||
1240 | unsigned int transfer_id; | ||
1241 | |||
1242 | while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data, | ||
1243 | &nbytes, &transfer_id) == 0) { | ||
1244 | /* no need to call tx completion for NULL pointers */ | ||
1245 | if (!skb) | ||
1246 | continue; | ||
1247 | |||
1248 | dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, | ||
1249 | skb->len, DMA_TO_DEVICE); | ||
1250 | ath10k_htt_hif_tx_complete(ar, skb); | ||
1251 | } | ||
1252 | } | ||
1253 | |||
1254 | static void ath10k_pci_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb) | ||
1255 | { | ||
1256 | skb_pull(skb, sizeof(struct ath10k_htc_hdr)); | ||
1257 | ath10k_htt_t2h_msg_handler(ar, skb); | ||
1258 | } | ||
1259 | |||
1260 | /* Called by lower (CE) layer when HTT data is received from the Target. */ | ||
1261 | static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state) | ||
1262 | { | ||
1263 | /* CE4 polling needs to be done whenever CE pipe which transports | ||
1264 | * HTT Rx (target->host) is processed. | ||
1265 | */ | ||
1266 | ath10k_ce_per_engine_service(ce_state->ar, 4); | ||
1267 | |||
1268 | ath10k_pci_process_rx_cb(ce_state, ath10k_pci_htt_rx_deliver); | ||
1269 | } | ||
1270 | |||
1177 | static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, | 1271 | static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, |
1178 | struct ath10k_hif_sg_item *items, int n_items) | 1272 | struct ath10k_hif_sg_item *items, int n_items) |
1179 | { | 1273 | { |
@@ -1343,17 +1437,6 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, | |||
1343 | ath10k_ce_per_engine_service(ar, pipe); | 1437 | ath10k_ce_per_engine_service(ar, pipe); |
1344 | } | 1438 | } |
1345 | 1439 | ||
1346 | static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, | ||
1347 | struct ath10k_hif_cb *callbacks) | ||
1348 | { | ||
1349 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
1350 | |||
1351 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n"); | ||
1352 | |||
1353 | memcpy(&ar_pci->msg_callbacks_current, callbacks, | ||
1354 | sizeof(ar_pci->msg_callbacks_current)); | ||
1355 | } | ||
1356 | |||
1357 | static void ath10k_pci_kill_tasklet(struct ath10k *ar) | 1440 | static void ath10k_pci_kill_tasklet(struct ath10k *ar) |
1358 | { | 1441 | { |
1359 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 1442 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
@@ -1368,10 +1451,8 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) | |||
1368 | del_timer_sync(&ar_pci->rx_post_retry); | 1451 | del_timer_sync(&ar_pci->rx_post_retry); |
1369 | } | 1452 | } |
1370 | 1453 | ||
1371 | static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, | 1454 | static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, |
1372 | u16 service_id, u8 *ul_pipe, | 1455 | u8 *ul_pipe, u8 *dl_pipe) |
1373 | u8 *dl_pipe, int *ul_is_polled, | ||
1374 | int *dl_is_polled) | ||
1375 | { | 1456 | { |
1376 | const struct service_to_pipe *entry; | 1457 | const struct service_to_pipe *entry; |
1377 | bool ul_set = false, dl_set = false; | 1458 | bool ul_set = false, dl_set = false; |
@@ -1379,9 +1460,6 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, | |||
1379 | 1460 | ||
1380 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n"); | 1461 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n"); |
1381 | 1462 | ||
1382 | /* polling for received messages not supported */ | ||
1383 | *dl_is_polled = 0; | ||
1384 | |||
1385 | for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { | 1463 | for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { |
1386 | entry = &target_service_to_ce_map_wlan[i]; | 1464 | entry = &target_service_to_ce_map_wlan[i]; |
1387 | 1465 | ||
@@ -1415,25 +1493,17 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, | |||
1415 | if (WARN_ON(!ul_set || !dl_set)) | 1493 | if (WARN_ON(!ul_set || !dl_set)) |
1416 | return -ENOENT; | 1494 | return -ENOENT; |
1417 | 1495 | ||
1418 | *ul_is_polled = | ||
1419 | (host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0; | ||
1420 | |||
1421 | return 0; | 1496 | return 0; |
1422 | } | 1497 | } |
1423 | 1498 | ||
1424 | static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, | 1499 | static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, |
1425 | u8 *ul_pipe, u8 *dl_pipe) | 1500 | u8 *ul_pipe, u8 *dl_pipe) |
1426 | { | 1501 | { |
1427 | int ul_is_polled, dl_is_polled; | ||
1428 | |||
1429 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n"); | 1502 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n"); |
1430 | 1503 | ||
1431 | (void)ath10k_pci_hif_map_service_to_pipe(ar, | 1504 | (void)ath10k_pci_hif_map_service_to_pipe(ar, |
1432 | ATH10K_HTC_SVC_ID_RSVD_CTRL, | 1505 | ATH10K_HTC_SVC_ID_RSVD_CTRL, |
1433 | ul_pipe, | 1506 | ul_pipe, dl_pipe); |
1434 | dl_pipe, | ||
1435 | &ul_is_polled, | ||
1436 | &dl_is_polled); | ||
1437 | } | 1507 | } |
1438 | 1508 | ||
1439 | static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) | 1509 | static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) |
@@ -1504,6 +1574,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) | |||
1504 | static int ath10k_pci_hif_start(struct ath10k *ar) | 1574 | static int ath10k_pci_hif_start(struct ath10k *ar) |
1505 | { | 1575 | { |
1506 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 1576 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
1577 | |||
1507 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); | 1578 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); |
1508 | 1579 | ||
1509 | ath10k_pci_irq_enable(ar); | 1580 | ath10k_pci_irq_enable(ar); |
@@ -1579,7 +1650,7 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) | |||
1579 | 1650 | ||
1580 | ce_ring->per_transfer_context[i] = NULL; | 1651 | ce_ring->per_transfer_context[i] = NULL; |
1581 | 1652 | ||
1582 | ar_pci->msg_callbacks_current.tx_completion(ar, skb); | 1653 | ath10k_htc_tx_completion_handler(ar, skb); |
1583 | } | 1654 | } |
1584 | } | 1655 | } |
1585 | 1656 | ||
@@ -1999,9 +2070,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar) | |||
1999 | pipe->pipe_num = i; | 2070 | pipe->pipe_num = i; |
2000 | pipe->hif_ce_state = ar; | 2071 | pipe->hif_ce_state = ar; |
2001 | 2072 | ||
2002 | ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i], | 2073 | ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); |
2003 | ath10k_pci_ce_send_done, | ||
2004 | ath10k_pci_ce_recv_data); | ||
2005 | if (ret) { | 2074 | if (ret) { |
2006 | ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", | 2075 | ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", |
2007 | i, ret); | 2076 | i, ret); |
@@ -2257,7 +2326,7 @@ static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) | |||
2257 | ret = ath10k_pci_wait_for_target_init(ar); | 2326 | ret = ath10k_pci_wait_for_target_init(ar); |
2258 | if (ret) { | 2327 | if (ret) { |
2259 | ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", | 2328 | ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", |
2260 | ret); | 2329 | ret); |
2261 | return ret; | 2330 | return ret; |
2262 | } | 2331 | } |
2263 | 2332 | ||
@@ -2397,6 +2466,15 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) | |||
2397 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 2466 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
2398 | struct pci_dev *pdev = ar_pci->pdev; | 2467 | struct pci_dev *pdev = ar_pci->pdev; |
2399 | u32 val; | 2468 | u32 val; |
2469 | int ret = 0; | ||
2470 | |||
2471 | if (ar_pci->pci_ps == 0) { | ||
2472 | ret = ath10k_pci_force_wake(ar); | ||
2473 | if (ret) { | ||
2474 | ath10k_err(ar, "failed to wake up target: %d\n", ret); | ||
2475 | return ret; | ||
2476 | } | ||
2477 | } | ||
2400 | 2478 | ||
2401 | /* Suspend/Resume resets the PCI configuration space, so we have to | 2479 | /* Suspend/Resume resets the PCI configuration space, so we have to |
2402 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries | 2480 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries |
@@ -2407,7 +2485,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) | |||
2407 | if ((val & 0x0000ff00) != 0) | 2485 | if ((val & 0x0000ff00) != 0) |
2408 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | 2486 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); |
2409 | 2487 | ||
2410 | return 0; | 2488 | return ret; |
2411 | } | 2489 | } |
2412 | #endif | 2490 | #endif |
2413 | 2491 | ||
@@ -2421,7 +2499,6 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { | |||
2421 | .map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe, | 2499 | .map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe, |
2422 | .get_default_pipe = ath10k_pci_hif_get_default_pipe, | 2500 | .get_default_pipe = ath10k_pci_hif_get_default_pipe, |
2423 | .send_complete_check = ath10k_pci_hif_send_complete_check, | 2501 | .send_complete_check = ath10k_pci_hif_send_complete_check, |
2424 | .set_callbacks = ath10k_pci_hif_set_callbacks, | ||
2425 | .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, | 2502 | .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, |
2426 | .power_up = ath10k_pci_hif_power_up, | 2503 | .power_up = ath10k_pci_hif_power_up, |
2427 | .power_down = ath10k_pci_hif_power_down, | 2504 | .power_down = ath10k_pci_hif_power_down, |
@@ -2501,6 +2578,16 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) | |||
2501 | { | 2578 | { |
2502 | struct ath10k *ar = arg; | 2579 | struct ath10k *ar = arg; |
2503 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 2580 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
2581 | int ret; | ||
2582 | |||
2583 | if (ar_pci->pci_ps == 0) { | ||
2584 | ret = ath10k_pci_force_wake(ar); | ||
2585 | if (ret) { | ||
2586 | ath10k_warn(ar, "failed to wake device up on irq: %d\n", | ||
2587 | ret); | ||
2588 | return IRQ_NONE; | ||
2589 | } | ||
2590 | } | ||
2504 | 2591 | ||
2505 | if (ar_pci->num_msi_intrs == 0) { | 2592 | if (ar_pci->num_msi_intrs == 0) { |
2506 | if (!ath10k_pci_irq_pending(ar)) | 2593 | if (!ath10k_pci_irq_pending(ar)) |
@@ -2900,17 +2987,21 @@ static int ath10k_pci_probe(struct pci_dev *pdev, | |||
2900 | struct ath10k_pci *ar_pci; | 2987 | struct ath10k_pci *ar_pci; |
2901 | enum ath10k_hw_rev hw_rev; | 2988 | enum ath10k_hw_rev hw_rev; |
2902 | u32 chip_id; | 2989 | u32 chip_id; |
2990 | bool pci_ps; | ||
2903 | 2991 | ||
2904 | switch (pci_dev->device) { | 2992 | switch (pci_dev->device) { |
2905 | case QCA988X_2_0_DEVICE_ID: | 2993 | case QCA988X_2_0_DEVICE_ID: |
2906 | hw_rev = ATH10K_HW_QCA988X; | 2994 | hw_rev = ATH10K_HW_QCA988X; |
2995 | pci_ps = false; | ||
2907 | break; | 2996 | break; |
2908 | case QCA6164_2_1_DEVICE_ID: | 2997 | case QCA6164_2_1_DEVICE_ID: |
2909 | case QCA6174_2_1_DEVICE_ID: | 2998 | case QCA6174_2_1_DEVICE_ID: |
2910 | hw_rev = ATH10K_HW_QCA6174; | 2999 | hw_rev = ATH10K_HW_QCA6174; |
3000 | pci_ps = true; | ||
2911 | break; | 3001 | break; |
2912 | case QCA99X0_2_0_DEVICE_ID: | 3002 | case QCA99X0_2_0_DEVICE_ID: |
2913 | hw_rev = ATH10K_HW_QCA99X0; | 3003 | hw_rev = ATH10K_HW_QCA99X0; |
3004 | pci_ps = false; | ||
2914 | break; | 3005 | break; |
2915 | default: | 3006 | default: |
2916 | WARN_ON(1); | 3007 | WARN_ON(1); |
@@ -2924,19 +3015,21 @@ static int ath10k_pci_probe(struct pci_dev *pdev, | |||
2924 | return -ENOMEM; | 3015 | return -ENOMEM; |
2925 | } | 3016 | } |
2926 | 3017 | ||
2927 | ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n"); | 3018 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", |
3019 | pdev->vendor, pdev->device, | ||
3020 | pdev->subsystem_vendor, pdev->subsystem_device); | ||
2928 | 3021 | ||
2929 | ar_pci = ath10k_pci_priv(ar); | 3022 | ar_pci = ath10k_pci_priv(ar); |
2930 | ar_pci->pdev = pdev; | 3023 | ar_pci->pdev = pdev; |
2931 | ar_pci->dev = &pdev->dev; | 3024 | ar_pci->dev = &pdev->dev; |
2932 | ar_pci->ar = ar; | 3025 | ar_pci->ar = ar; |
2933 | ar->dev_id = pci_dev->device; | 3026 | ar->dev_id = pci_dev->device; |
3027 | ar_pci->pci_ps = pci_ps; | ||
2934 | 3028 | ||
2935 | if (pdev->subsystem_vendor || pdev->subsystem_device) | 3029 | ar->id.vendor = pdev->vendor; |
2936 | scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id), | 3030 | ar->id.device = pdev->device; |
2937 | "%04x:%04x:%04x:%04x", | 3031 | ar->id.subsystem_vendor = pdev->subsystem_vendor; |
2938 | pdev->vendor, pdev->device, | 3032 | ar->id.subsystem_device = pdev->subsystem_device; |
2939 | pdev->subsystem_vendor, pdev->subsystem_device); | ||
2940 | 3033 | ||
2941 | spin_lock_init(&ar_pci->ce_lock); | 3034 | spin_lock_init(&ar_pci->ce_lock); |
2942 | spin_lock_init(&ar_pci->ps_lock); | 3035 | spin_lock_init(&ar_pci->ps_lock); |
@@ -2962,6 +3055,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev, | |||
2962 | ath10k_pci_ce_deinit(ar); | 3055 | ath10k_pci_ce_deinit(ar); |
2963 | ath10k_pci_irq_disable(ar); | 3056 | ath10k_pci_irq_disable(ar); |
2964 | 3057 | ||
3058 | if (ar_pci->pci_ps == 0) { | ||
3059 | ret = ath10k_pci_force_wake(ar); | ||
3060 | if (ret) { | ||
3061 | ath10k_warn(ar, "failed to wake up device : %d\n", ret); | ||
3062 | goto err_free_pipes; | ||
3063 | } | ||
3064 | } | ||
3065 | |||
2965 | ret = ath10k_pci_init_irq(ar); | 3066 | ret = ath10k_pci_init_irq(ar); |
2966 | if (ret) { | 3067 | if (ret) { |
2967 | ath10k_err(ar, "failed to init irqs: %d\n", ret); | 3068 | ath10k_err(ar, "failed to init irqs: %d\n", ret); |
@@ -3090,13 +3191,16 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE); | |||
3090 | MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE); | 3191 | MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE); |
3091 | MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE); | 3192 | MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE); |
3092 | MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); | 3193 | MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); |
3194 | MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); | ||
3093 | 3195 | ||
3094 | /* QCA6174 2.1 firmware files */ | 3196 | /* QCA6174 2.1 firmware files */ |
3095 | MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE); | 3197 | MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE); |
3096 | MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE); | 3198 | MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE); |
3097 | MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE); | 3199 | MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE); |
3200 | MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_API2_FILE); | ||
3098 | 3201 | ||
3099 | /* QCA6174 3.1 firmware files */ | 3202 | /* QCA6174 3.1 firmware files */ |
3100 | MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE); | 3203 | MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE); |
3101 | MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE); | 3204 | MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE); |
3102 | MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); | 3205 | MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); |
3206 | MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); | ||
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 8d364fb8f743..f91bf333cb75 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h | |||
@@ -175,8 +175,6 @@ struct ath10k_pci { | |||
175 | 175 | ||
176 | struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; | 176 | struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; |
177 | 177 | ||
178 | struct ath10k_hif_cb msg_callbacks_current; | ||
179 | |||
180 | /* Copy Engine used for Diagnostic Accesses */ | 178 | /* Copy Engine used for Diagnostic Accesses */ |
181 | struct ath10k_ce_pipe *ce_diag; | 179 | struct ath10k_ce_pipe *ce_diag; |
182 | 180 | ||
@@ -221,6 +219,12 @@ struct ath10k_pci { | |||
221 | * powersave register state changes. | 219 | * powersave register state changes. |
222 | */ | 220 | */ |
223 | bool ps_awake; | 221 | bool ps_awake; |
222 | |||
223 | /* pci power save, disable for QCA988X and QCA99X0. | ||
224 | * Writing 'false' to this variable avoids frequent locking | ||
225 | * on MMIO read/write. | ||
226 | */ | ||
227 | bool pci_ps; | ||
224 | }; | 228 | }; |
225 | 229 | ||
226 | static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) | 230 | static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) |
@@ -230,7 +234,8 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) | |||
230 | 234 | ||
231 | #define ATH10K_PCI_RX_POST_RETRY_MS 50 | 235 | #define ATH10K_PCI_RX_POST_RETRY_MS 50 |
232 | #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ | 236 | #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ |
233 | #define PCIE_WAKE_TIMEOUT 10000 /* 10ms */ | 237 | #define PCIE_WAKE_TIMEOUT 30000 /* 30ms */ |
238 | #define PCIE_WAKE_LATE_US 10000 /* 10ms */ | ||
234 | 239 | ||
235 | #define BAR_NUM 0 | 240 | #define BAR_NUM 0 |
236 | 241 | ||
diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index 1a899d70dc5d..60fe562e3041 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c | |||
@@ -215,6 +215,6 @@ err_cooling_destroy: | |||
215 | 215 | ||
216 | void ath10k_thermal_unregister(struct ath10k *ar) | 216 | void ath10k_thermal_unregister(struct ath10k *ar) |
217 | { | 217 | { |
218 | thermal_cooling_device_unregister(ar->thermal.cdev); | ||
219 | sysfs_remove_link(&ar->dev->kobj, "cooling_device"); | 218 | sysfs_remove_link(&ar->dev->kobj, "cooling_device"); |
219 | thermal_cooling_device_unregister(ar->thermal.cdev); | ||
220 | } | 220 | } |
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 7db7d501726b..6d1105ab4592 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c | |||
@@ -92,11 +92,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, | |||
92 | skb_cb = ATH10K_SKB_CB(msdu); | 92 | skb_cb = ATH10K_SKB_CB(msdu); |
93 | dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); | 93 | dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
94 | 94 | ||
95 | if (skb_cb->htt.txbuf) | ||
96 | dma_pool_free(htt->tx_pool, | ||
97 | skb_cb->htt.txbuf, | ||
98 | skb_cb->htt.txbuf_paddr); | ||
99 | |||
100 | ath10k_report_offchan_tx(htt->ar, msdu); | 95 | ath10k_report_offchan_tx(htt->ar, msdu); |
101 | 96 | ||
102 | info = IEEE80211_SKB_CB(msdu); | 97 | info = IEEE80211_SKB_CB(msdu); |
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 248ffc3d6620..b54aa08cb25c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h | |||
@@ -177,6 +177,11 @@ struct wmi_ops { | |||
177 | const struct wmi_tdls_peer_capab_arg *cap, | 177 | const struct wmi_tdls_peer_capab_arg *cap, |
178 | const struct wmi_channel_arg *chan); | 178 | const struct wmi_channel_arg *chan); |
179 | struct sk_buff *(*gen_adaptive_qcs)(struct ath10k *ar, bool enable); | 179 | struct sk_buff *(*gen_adaptive_qcs)(struct ath10k *ar, bool enable); |
180 | struct sk_buff *(*gen_pdev_get_tpc_config)(struct ath10k *ar, | ||
181 | u32 param); | ||
182 | void (*fw_stats_fill)(struct ath10k *ar, | ||
183 | struct ath10k_fw_stats *fw_stats, | ||
184 | char *buf); | ||
180 | }; | 185 | }; |
181 | 186 | ||
182 | int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); | 187 | int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); |
@@ -1270,4 +1275,31 @@ ath10k_wmi_adaptive_qcs(struct ath10k *ar, bool enable) | |||
1270 | return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->adaptive_qcs_cmdid); | 1275 | return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->adaptive_qcs_cmdid); |
1271 | } | 1276 | } |
1272 | 1277 | ||
1278 | static inline int | ||
1279 | ath10k_wmi_pdev_get_tpc_config(struct ath10k *ar, u32 param) | ||
1280 | { | ||
1281 | struct sk_buff *skb; | ||
1282 | |||
1283 | if (!ar->wmi.ops->gen_pdev_get_tpc_config) | ||
1284 | return -EOPNOTSUPP; | ||
1285 | |||
1286 | skb = ar->wmi.ops->gen_pdev_get_tpc_config(ar, param); | ||
1287 | |||
1288 | if (IS_ERR(skb)) | ||
1289 | return PTR_ERR(skb); | ||
1290 | |||
1291 | return ath10k_wmi_cmd_send(ar, skb, | ||
1292 | ar->wmi.cmd->pdev_get_tpc_config_cmdid); | ||
1293 | } | ||
1294 | |||
1295 | static inline int | ||
1296 | ath10k_wmi_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats, | ||
1297 | char *buf) | ||
1298 | { | ||
1299 | if (!ar->wmi.ops->fw_stats_fill) | ||
1300 | return -EOPNOTSUPP; | ||
1301 | |||
1302 | ar->wmi.ops->fw_stats_fill(ar, fw_stats, buf); | ||
1303 | return 0; | ||
1304 | } | ||
1273 | #endif | 1305 | #endif |
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index b5849b3fd2f0..8f835480a62c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c | |||
@@ -3468,6 +3468,7 @@ static const struct wmi_ops wmi_tlv_ops = { | |||
3468 | .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state, | 3468 | .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state, |
3469 | .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, | 3469 | .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, |
3470 | .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, | 3470 | .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, |
3471 | .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, | ||
3471 | }; | 3472 | }; |
3472 | 3473 | ||
3473 | /************/ | 3474 | /************/ |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 87d9de2aa8c5..6e7d7a7f6a97 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
@@ -3018,8 +3018,6 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, | |||
3018 | memcpy(skb_put(bcn, arvif->u.ap.noa_len), | 3018 | memcpy(skb_put(bcn, arvif->u.ap.noa_len), |
3019 | arvif->u.ap.noa_data, | 3019 | arvif->u.ap.noa_data, |
3020 | arvif->u.ap.noa_len); | 3020 | arvif->u.ap.noa_len); |
3021 | |||
3022 | return; | ||
3023 | } | 3021 | } |
3024 | 3022 | ||
3025 | static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, | 3023 | static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, |
@@ -3507,7 +3505,7 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar, | |||
3507 | tsf); | 3505 | tsf); |
3508 | if (res < 0) { | 3506 | if (res < 0) { |
3509 | ath10k_dbg(ar, ATH10K_DBG_WMI, "failed to process fft report: %d\n", | 3507 | ath10k_dbg(ar, ATH10K_DBG_WMI, "failed to process fft report: %d\n", |
3510 | res); | 3508 | res); |
3511 | return; | 3509 | return; |
3512 | } | 3510 | } |
3513 | break; | 3511 | break; |
@@ -3835,9 +3833,258 @@ void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb) | |||
3835 | ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); | 3833 | ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); |
3836 | } | 3834 | } |
3837 | 3835 | ||
3836 | static u8 ath10k_tpc_config_get_rate(struct ath10k *ar, | ||
3837 | struct wmi_pdev_tpc_config_event *ev, | ||
3838 | u32 rate_idx, u32 num_chains, | ||
3839 | u32 rate_code, u8 type) | ||
3840 | { | ||
3841 | u8 tpc, num_streams, preamble, ch, stm_idx; | ||
3842 | |||
3843 | num_streams = ATH10K_HW_NSS(rate_code); | ||
3844 | preamble = ATH10K_HW_PREAMBLE(rate_code); | ||
3845 | ch = num_chains - 1; | ||
3846 | |||
3847 | tpc = min_t(u8, ev->rates_array[rate_idx], ev->max_reg_allow_pow[ch]); | ||
3848 | |||
3849 | if (__le32_to_cpu(ev->num_tx_chain) <= 1) | ||
3850 | goto out; | ||
3851 | |||
3852 | if (preamble == WMI_RATE_PREAMBLE_CCK) | ||
3853 | goto out; | ||
3854 | |||
3855 | stm_idx = num_streams - 1; | ||
3856 | if (num_chains <= num_streams) | ||
3857 | goto out; | ||
3858 | |||
3859 | switch (type) { | ||
3860 | case WMI_TPC_TABLE_TYPE_STBC: | ||
3861 | tpc = min_t(u8, tpc, | ||
3862 | ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx]); | ||
3863 | break; | ||
3864 | case WMI_TPC_TABLE_TYPE_TXBF: | ||
3865 | tpc = min_t(u8, tpc, | ||
3866 | ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx]); | ||
3867 | break; | ||
3868 | case WMI_TPC_TABLE_TYPE_CDD: | ||
3869 | tpc = min_t(u8, tpc, | ||
3870 | ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx]); | ||
3871 | break; | ||
3872 | default: | ||
3873 | ath10k_warn(ar, "unknown wmi tpc table type: %d\n", type); | ||
3874 | tpc = 0; | ||
3875 | break; | ||
3876 | } | ||
3877 | |||
3878 | out: | ||
3879 | return tpc; | ||
3880 | } | ||
3881 | |||
3882 | static void ath10k_tpc_config_disp_tables(struct ath10k *ar, | ||
3883 | struct wmi_pdev_tpc_config_event *ev, | ||
3884 | struct ath10k_tpc_stats *tpc_stats, | ||
3885 | u8 *rate_code, u16 *pream_table, u8 type) | ||
3886 | { | ||
3887 | u32 i, j, pream_idx, flags; | ||
3888 | u8 tpc[WMI_TPC_TX_N_CHAIN]; | ||
3889 | char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE]; | ||
3890 | char buff[WMI_TPC_BUF_SIZE]; | ||
3891 | |||
3892 | flags = __le32_to_cpu(ev->flags); | ||
3893 | |||
3894 | switch (type) { | ||
3895 | case WMI_TPC_TABLE_TYPE_CDD: | ||
3896 | if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) { | ||
3897 | ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n"); | ||
3898 | tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG; | ||
3899 | return; | ||
3900 | } | ||
3901 | break; | ||
3902 | case WMI_TPC_TABLE_TYPE_STBC: | ||
3903 | if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) { | ||
3904 | ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n"); | ||
3905 | tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG; | ||
3906 | return; | ||
3907 | } | ||
3908 | break; | ||
3909 | case WMI_TPC_TABLE_TYPE_TXBF: | ||
3910 | if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) { | ||
3911 | ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n"); | ||
3912 | tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG; | ||
3913 | return; | ||
3914 | } | ||
3915 | break; | ||
3916 | default: | ||
3917 | ath10k_dbg(ar, ATH10K_DBG_WMI, | ||
3918 | "invalid table type in wmi tpc event: %d\n", type); | ||
3919 | return; | ||
3920 | } | ||
3921 | |||
3922 | pream_idx = 0; | ||
3923 | for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) { | ||
3924 | memset(tpc_value, 0, sizeof(tpc_value)); | ||
3925 | memset(buff, 0, sizeof(buff)); | ||
3926 | if (i == pream_table[pream_idx]) | ||
3927 | pream_idx++; | ||
3928 | |||
3929 | for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) { | ||
3930 | if (j >= __le32_to_cpu(ev->num_tx_chain)) | ||
3931 | break; | ||
3932 | |||
3933 | tpc[j] = ath10k_tpc_config_get_rate(ar, ev, i, j + 1, | ||
3934 | rate_code[i], | ||
3935 | type); | ||
3936 | snprintf(buff, sizeof(buff), "%8d ", tpc[j]); | ||
3937 | strncat(tpc_value, buff, strlen(buff)); | ||
3938 | } | ||
3939 | tpc_stats->tpc_table[type].pream_idx[i] = pream_idx; | ||
3940 | tpc_stats->tpc_table[type].rate_code[i] = rate_code[i]; | ||
3941 | memcpy(tpc_stats->tpc_table[type].tpc_value[i], | ||
3942 | tpc_value, sizeof(tpc_value)); | ||
3943 | } | ||
3944 | } | ||
3945 | |||
3838 | void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) | 3946 | void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) |
3839 | { | 3947 | { |
3840 | ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); | 3948 | u32 i, j, pream_idx, num_tx_chain; |
3949 | u8 rate_code[WMI_TPC_RATE_MAX], rate_idx; | ||
3950 | u16 pream_table[WMI_TPC_PREAM_TABLE_MAX]; | ||
3951 | struct wmi_pdev_tpc_config_event *ev; | ||
3952 | struct ath10k_tpc_stats *tpc_stats; | ||
3953 | |||
3954 | ev = (struct wmi_pdev_tpc_config_event *)skb->data; | ||
3955 | |||
3956 | tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); | ||
3957 | if (!tpc_stats) | ||
3958 | return; | ||
3959 | |||
3960 | /* Create the rate code table based on the chains supported */ | ||
3961 | rate_idx = 0; | ||
3962 | pream_idx = 0; | ||
3963 | |||
3964 | /* Fill CCK rate code */ | ||
3965 | for (i = 0; i < 4; i++) { | ||
3966 | rate_code[rate_idx] = | ||
3967 | ATH10K_HW_RATECODE(i, 0, WMI_RATE_PREAMBLE_CCK); | ||
3968 | rate_idx++; | ||
3969 | } | ||
3970 | pream_table[pream_idx] = rate_idx; | ||
3971 | pream_idx++; | ||
3972 | |||
3973 | /* Fill OFDM rate code */ | ||
3974 | for (i = 0; i < 8; i++) { | ||
3975 | rate_code[rate_idx] = | ||
3976 | ATH10K_HW_RATECODE(i, 0, WMI_RATE_PREAMBLE_OFDM); | ||
3977 | rate_idx++; | ||
3978 | } | ||
3979 | pream_table[pream_idx] = rate_idx; | ||
3980 | pream_idx++; | ||
3981 | |||
3982 | num_tx_chain = __le32_to_cpu(ev->num_tx_chain); | ||
3983 | |||
3984 | /* Fill HT20 rate code */ | ||
3985 | for (i = 0; i < num_tx_chain; i++) { | ||
3986 | for (j = 0; j < 8; j++) { | ||
3987 | rate_code[rate_idx] = | ||
3988 | ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_HT); | ||
3989 | rate_idx++; | ||
3990 | } | ||
3991 | } | ||
3992 | pream_table[pream_idx] = rate_idx; | ||
3993 | pream_idx++; | ||
3994 | |||
3995 | /* Fill HT40 rate code */ | ||
3996 | for (i = 0; i < num_tx_chain; i++) { | ||
3997 | for (j = 0; j < 8; j++) { | ||
3998 | rate_code[rate_idx] = | ||
3999 | ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_HT); | ||
4000 | rate_idx++; | ||
4001 | } | ||
4002 | } | ||
4003 | pream_table[pream_idx] = rate_idx; | ||
4004 | pream_idx++; | ||
4005 | |||
4006 | /* Fill VHT20 rate code */ | ||
4007 | for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) { | ||
4008 | for (j = 0; j < 10; j++) { | ||
4009 | rate_code[rate_idx] = | ||
4010 | ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT); | ||
4011 | rate_idx++; | ||
4012 | } | ||
4013 | } | ||
4014 | pream_table[pream_idx] = rate_idx; | ||
4015 | pream_idx++; | ||
4016 | |||
4017 | /* Fill VHT40 rate code */ | ||
4018 | for (i = 0; i < num_tx_chain; i++) { | ||
4019 | for (j = 0; j < 10; j++) { | ||
4020 | rate_code[rate_idx] = | ||
4021 | ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT); | ||
4022 | rate_idx++; | ||
4023 | } | ||
4024 | } | ||
4025 | pream_table[pream_idx] = rate_idx; | ||
4026 | pream_idx++; | ||
4027 | |||
4028 | /* Fill VHT80 rate code */ | ||
4029 | for (i = 0; i < num_tx_chain; i++) { | ||
4030 | for (j = 0; j < 10; j++) { | ||
4031 | rate_code[rate_idx] = | ||
4032 | ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT); | ||
4033 | rate_idx++; | ||
4034 | } | ||
4035 | } | ||
4036 | pream_table[pream_idx] = rate_idx; | ||
4037 | pream_idx++; | ||
4038 | |||
4039 | rate_code[rate_idx++] = | ||
4040 | ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_CCK); | ||
4041 | rate_code[rate_idx++] = | ||
4042 | ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM); | ||
4043 | rate_code[rate_idx++] = | ||
4044 | ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_CCK); | ||
4045 | rate_code[rate_idx++] = | ||
4046 | ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM); | ||
4047 | rate_code[rate_idx++] = | ||
4048 | ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM); | ||
4049 | |||
4050 | pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END; | ||
4051 | |||
4052 | tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq); | ||
4053 | tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode); | ||
4054 | tpc_stats->ctl = __le32_to_cpu(ev->ctl); | ||
4055 | tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain); | ||
4056 | tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain); | ||
4057 | tpc_stats->twice_antenna_reduction = | ||
4058 | __le32_to_cpu(ev->twice_antenna_reduction); | ||
4059 | tpc_stats->power_limit = __le32_to_cpu(ev->power_limit); | ||
4060 | tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power); | ||
4061 | tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain); | ||
4062 | tpc_stats->rate_max = __le32_to_cpu(ev->rate_max); | ||
4063 | |||
4064 | ath10k_tpc_config_disp_tables(ar, ev, tpc_stats, | ||
4065 | rate_code, pream_table, | ||
4066 | WMI_TPC_TABLE_TYPE_CDD); | ||
4067 | ath10k_tpc_config_disp_tables(ar, ev, tpc_stats, | ||
4068 | rate_code, pream_table, | ||
4069 | WMI_TPC_TABLE_TYPE_STBC); | ||
4070 | ath10k_tpc_config_disp_tables(ar, ev, tpc_stats, | ||
4071 | rate_code, pream_table, | ||
4072 | WMI_TPC_TABLE_TYPE_TXBF); | ||
4073 | |||
4074 | ath10k_debug_tpc_stats_process(ar, tpc_stats); | ||
4075 | |||
4076 | ath10k_dbg(ar, ATH10K_DBG_WMI, | ||
4077 | "wmi event tpc config channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n", | ||
4078 | __le32_to_cpu(ev->chan_freq), | ||
4079 | __le32_to_cpu(ev->phy_mode), | ||
4080 | __le32_to_cpu(ev->ctl), | ||
4081 | __le32_to_cpu(ev->reg_domain), | ||
4082 | a_sle32_to_cpu(ev->twice_antenna_gain), | ||
4083 | __le32_to_cpu(ev->twice_antenna_reduction), | ||
4084 | __le32_to_cpu(ev->power_limit), | ||
4085 | __le32_to_cpu(ev->twice_max_rd_power) / 2, | ||
4086 | __le32_to_cpu(ev->num_tx_chain), | ||
4087 | __le32_to_cpu(ev->rate_max)); | ||
3841 | } | 4088 | } |
3842 | 4089 | ||
3843 | void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) | 4090 | void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) |
@@ -5090,7 +5337,7 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) | |||
5090 | config.rx_timeout_pri[2] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); | 5337 | config.rx_timeout_pri[2] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); |
5091 | config.rx_timeout_pri[3] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_HI_PRI); | 5338 | config.rx_timeout_pri[3] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_HI_PRI); |
5092 | 5339 | ||
5093 | config.rx_decap_mode = __cpu_to_le32(TARGET_10_4_RX_DECAP_MODE); | 5340 | config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); |
5094 | config.scan_max_pending_req = __cpu_to_le32(TARGET_10_4_SCAN_MAX_REQS); | 5341 | config.scan_max_pending_req = __cpu_to_le32(TARGET_10_4_SCAN_MAX_REQS); |
5095 | config.bmiss_offload_max_vdev = | 5342 | config.bmiss_offload_max_vdev = |
5096 | __cpu_to_le32(TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV); | 5343 | __cpu_to_le32(TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV); |
@@ -6356,6 +6603,399 @@ ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, | |||
6356 | return skb; | 6603 | return skb; |
6357 | } | 6604 | } |
6358 | 6605 | ||
6606 | static struct sk_buff * | ||
6607 | ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config(struct ath10k *ar, u32 param) | ||
6608 | { | ||
6609 | struct wmi_pdev_get_tpc_config_cmd *cmd; | ||
6610 | struct sk_buff *skb; | ||
6611 | |||
6612 | skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); | ||
6613 | if (!skb) | ||
6614 | return ERR_PTR(-ENOMEM); | ||
6615 | |||
6616 | cmd = (struct wmi_pdev_get_tpc_config_cmd *)skb->data; | ||
6617 | cmd->param = __cpu_to_le32(param); | ||
6618 | |||
6619 | ath10k_dbg(ar, ATH10K_DBG_WMI, | ||
6620 | "wmi pdev get tcp config param:%d\n", param); | ||
6621 | return skb; | ||
6622 | } | ||
6623 | |||
6624 | size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head) | ||
6625 | { | ||
6626 | struct ath10k_fw_stats_peer *i; | ||
6627 | size_t num = 0; | ||
6628 | |||
6629 | list_for_each_entry(i, head, list) | ||
6630 | ++num; | ||
6631 | |||
6632 | return num; | ||
6633 | } | ||
6634 | |||
6635 | size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head) | ||
6636 | { | ||
6637 | struct ath10k_fw_stats_vdev *i; | ||
6638 | size_t num = 0; | ||
6639 | |||
6640 | list_for_each_entry(i, head, list) | ||
6641 | ++num; | ||
6642 | |||
6643 | return num; | ||
6644 | } | ||
6645 | |||
6646 | static void | ||
6647 | ath10k_wmi_fw_pdev_base_stats_fill(const struct ath10k_fw_stats_pdev *pdev, | ||
6648 | char *buf, u32 *length) | ||
6649 | { | ||
6650 | u32 len = *length; | ||
6651 | u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6652 | |||
6653 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6654 | len += scnprintf(buf + len, buf_len - len, "%30s\n", | ||
6655 | "ath10k PDEV stats"); | ||
6656 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
6657 | "================="); | ||
6658 | |||
6659 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6660 | "Channel noise floor", pdev->ch_noise_floor); | ||
6661 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6662 | "Channel TX power", pdev->chan_tx_power); | ||
6663 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6664 | "TX frame count", pdev->tx_frame_count); | ||
6665 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6666 | "RX frame count", pdev->rx_frame_count); | ||
6667 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6668 | "RX clear count", pdev->rx_clear_count); | ||
6669 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6670 | "Cycle count", pdev->cycle_count); | ||
6671 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6672 | "PHY error count", pdev->phy_err_count); | ||
6673 | |||
6674 | *length = len; | ||
6675 | } | ||
6676 | |||
6677 | static void | ||
6678 | ath10k_wmi_fw_pdev_extra_stats_fill(const struct ath10k_fw_stats_pdev *pdev, | ||
6679 | char *buf, u32 *length) | ||
6680 | { | ||
6681 | u32 len = *length; | ||
6682 | u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6683 | |||
6684 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6685 | "RTS bad count", pdev->rts_bad); | ||
6686 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6687 | "RTS good count", pdev->rts_good); | ||
6688 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6689 | "FCS bad count", pdev->fcs_bad); | ||
6690 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6691 | "No beacon count", pdev->no_beacons); | ||
6692 | len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", | ||
6693 | "MIB int count", pdev->mib_int_count); | ||
6694 | |||
6695 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6696 | *length = len; | ||
6697 | } | ||
6698 | |||
6699 | static void | ||
6700 | ath10k_wmi_fw_pdev_tx_stats_fill(const struct ath10k_fw_stats_pdev *pdev, | ||
6701 | char *buf, u32 *length) | ||
6702 | { | ||
6703 | u32 len = *length; | ||
6704 | u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6705 | |||
6706 | len += scnprintf(buf + len, buf_len - len, "\n%30s\n", | ||
6707 | "ath10k PDEV TX stats"); | ||
6708 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
6709 | "================="); | ||
6710 | |||
6711 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6712 | "HTT cookies queued", pdev->comp_queued); | ||
6713 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6714 | "HTT cookies disp.", pdev->comp_delivered); | ||
6715 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6716 | "MSDU queued", pdev->msdu_enqued); | ||
6717 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6718 | "MPDU queued", pdev->mpdu_enqued); | ||
6719 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6720 | "MSDUs dropped", pdev->wmm_drop); | ||
6721 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6722 | "Local enqued", pdev->local_enqued); | ||
6723 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6724 | "Local freed", pdev->local_freed); | ||
6725 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6726 | "HW queued", pdev->hw_queued); | ||
6727 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6728 | "PPDUs reaped", pdev->hw_reaped); | ||
6729 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6730 | "Num underruns", pdev->underrun); | ||
6731 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6732 | "PPDUs cleaned", pdev->tx_abort); | ||
6733 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6734 | "MPDUs requed", pdev->mpdus_requed); | ||
6735 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6736 | "Excessive retries", pdev->tx_ko); | ||
6737 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6738 | "HW rate", pdev->data_rc); | ||
6739 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6740 | "Sched self tiggers", pdev->self_triggers); | ||
6741 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6742 | "Dropped due to SW retries", | ||
6743 | pdev->sw_retry_failure); | ||
6744 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6745 | "Illegal rate phy errors", | ||
6746 | pdev->illgl_rate_phy_err); | ||
6747 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6748 | "Pdev continuous xretry", pdev->pdev_cont_xretry); | ||
6749 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6750 | "TX timeout", pdev->pdev_tx_timeout); | ||
6751 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6752 | "PDEV resets", pdev->pdev_resets); | ||
6753 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6754 | "PHY underrun", pdev->phy_underrun); | ||
6755 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6756 | "MPDU is more than txop limit", pdev->txop_ovf); | ||
6757 | *length = len; | ||
6758 | } | ||
6759 | |||
6760 | static void | ||
6761 | ath10k_wmi_fw_pdev_rx_stats_fill(const struct ath10k_fw_stats_pdev *pdev, | ||
6762 | char *buf, u32 *length) | ||
6763 | { | ||
6764 | u32 len = *length; | ||
6765 | u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6766 | |||
6767 | len += scnprintf(buf + len, buf_len - len, "\n%30s\n", | ||
6768 | "ath10k PDEV RX stats"); | ||
6769 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
6770 | "================="); | ||
6771 | |||
6772 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6773 | "Mid PPDU route change", | ||
6774 | pdev->mid_ppdu_route_change); | ||
6775 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6776 | "Tot. number of statuses", pdev->status_rcvd); | ||
6777 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6778 | "Extra frags on rings 0", pdev->r0_frags); | ||
6779 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6780 | "Extra frags on rings 1", pdev->r1_frags); | ||
6781 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6782 | "Extra frags on rings 2", pdev->r2_frags); | ||
6783 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6784 | "Extra frags on rings 3", pdev->r3_frags); | ||
6785 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6786 | "MSDUs delivered to HTT", pdev->htt_msdus); | ||
6787 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6788 | "MPDUs delivered to HTT", pdev->htt_mpdus); | ||
6789 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6790 | "MSDUs delivered to stack", pdev->loc_msdus); | ||
6791 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6792 | "MPDUs delivered to stack", pdev->loc_mpdus); | ||
6793 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6794 | "Oversized AMSUs", pdev->oversize_amsdu); | ||
6795 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6796 | "PHY errors", pdev->phy_errs); | ||
6797 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6798 | "PHY errors drops", pdev->phy_err_drop); | ||
6799 | len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", | ||
6800 | "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); | ||
6801 | *length = len; | ||
6802 | } | ||
6803 | |||
6804 | static void | ||
6805 | ath10k_wmi_fw_vdev_stats_fill(const struct ath10k_fw_stats_vdev *vdev, | ||
6806 | char *buf, u32 *length) | ||
6807 | { | ||
6808 | u32 len = *length; | ||
6809 | u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6810 | int i; | ||
6811 | |||
6812 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6813 | "vdev id", vdev->vdev_id); | ||
6814 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6815 | "beacon snr", vdev->beacon_snr); | ||
6816 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6817 | "data snr", vdev->data_snr); | ||
6818 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6819 | "num rx frames", vdev->num_rx_frames); | ||
6820 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6821 | "num rts fail", vdev->num_rts_fail); | ||
6822 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6823 | "num rts success", vdev->num_rts_success); | ||
6824 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6825 | "num rx err", vdev->num_rx_err); | ||
6826 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6827 | "num rx discard", vdev->num_rx_discard); | ||
6828 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6829 | "num tx not acked", vdev->num_tx_not_acked); | ||
6830 | |||
6831 | for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++) | ||
6832 | len += scnprintf(buf + len, buf_len - len, | ||
6833 | "%25s [%02d] %u\n", | ||
6834 | "num tx frames", i, | ||
6835 | vdev->num_tx_frames[i]); | ||
6836 | |||
6837 | for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++) | ||
6838 | len += scnprintf(buf + len, buf_len - len, | ||
6839 | "%25s [%02d] %u\n", | ||
6840 | "num tx frames retries", i, | ||
6841 | vdev->num_tx_frames_retries[i]); | ||
6842 | |||
6843 | for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++) | ||
6844 | len += scnprintf(buf + len, buf_len - len, | ||
6845 | "%25s [%02d] %u\n", | ||
6846 | "num tx frames failures", i, | ||
6847 | vdev->num_tx_frames_failures[i]); | ||
6848 | |||
6849 | for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++) | ||
6850 | len += scnprintf(buf + len, buf_len - len, | ||
6851 | "%25s [%02d] 0x%08x\n", | ||
6852 | "tx rate history", i, | ||
6853 | vdev->tx_rate_history[i]); | ||
6854 | |||
6855 | for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++) | ||
6856 | len += scnprintf(buf + len, buf_len - len, | ||
6857 | "%25s [%02d] %u\n", | ||
6858 | "beacon rssi history", i, | ||
6859 | vdev->beacon_rssi_history[i]); | ||
6860 | |||
6861 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6862 | *length = len; | ||
6863 | } | ||
6864 | |||
6865 | static void | ||
6866 | ath10k_wmi_fw_peer_stats_fill(const struct ath10k_fw_stats_peer *peer, | ||
6867 | char *buf, u32 *length) | ||
6868 | { | ||
6869 | u32 len = *length; | ||
6870 | u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6871 | |||
6872 | len += scnprintf(buf + len, buf_len - len, "%30s %pM\n", | ||
6873 | "Peer MAC address", peer->peer_macaddr); | ||
6874 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6875 | "Peer RSSI", peer->peer_rssi); | ||
6876 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6877 | "Peer TX rate", peer->peer_tx_rate); | ||
6878 | len += scnprintf(buf + len, buf_len - len, "%30s %u\n", | ||
6879 | "Peer RX rate", peer->peer_rx_rate); | ||
6880 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6881 | *length = len; | ||
6882 | } | ||
6883 | |||
6884 | void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar, | ||
6885 | struct ath10k_fw_stats *fw_stats, | ||
6886 | char *buf) | ||
6887 | { | ||
6888 | u32 len = 0; | ||
6889 | u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6890 | const struct ath10k_fw_stats_pdev *pdev; | ||
6891 | const struct ath10k_fw_stats_vdev *vdev; | ||
6892 | const struct ath10k_fw_stats_peer *peer; | ||
6893 | size_t num_peers; | ||
6894 | size_t num_vdevs; | ||
6895 | |||
6896 | spin_lock_bh(&ar->data_lock); | ||
6897 | |||
6898 | pdev = list_first_entry_or_null(&fw_stats->pdevs, | ||
6899 | struct ath10k_fw_stats_pdev, list); | ||
6900 | if (!pdev) { | ||
6901 | ath10k_warn(ar, "failed to get pdev stats\n"); | ||
6902 | goto unlock; | ||
6903 | } | ||
6904 | |||
6905 | num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers); | ||
6906 | num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs); | ||
6907 | |||
6908 | ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len); | ||
6909 | ath10k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len); | ||
6910 | ath10k_wmi_fw_pdev_rx_stats_fill(pdev, buf, &len); | ||
6911 | |||
6912 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6913 | len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", | ||
6914 | "ath10k VDEV stats", num_vdevs); | ||
6915 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
6916 | "================="); | ||
6917 | |||
6918 | list_for_each_entry(vdev, &fw_stats->vdevs, list) { | ||
6919 | ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len); | ||
6920 | } | ||
6921 | |||
6922 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6923 | len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", | ||
6924 | "ath10k PEER stats", num_peers); | ||
6925 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
6926 | "================="); | ||
6927 | |||
6928 | list_for_each_entry(peer, &fw_stats->peers, list) { | ||
6929 | ath10k_wmi_fw_peer_stats_fill(peer, buf, &len); | ||
6930 | } | ||
6931 | |||
6932 | unlock: | ||
6933 | spin_unlock_bh(&ar->data_lock); | ||
6934 | |||
6935 | if (len >= buf_len) | ||
6936 | buf[len - 1] = 0; | ||
6937 | else | ||
6938 | buf[len] = 0; | ||
6939 | } | ||
6940 | |||
6941 | void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar, | ||
6942 | struct ath10k_fw_stats *fw_stats, | ||
6943 | char *buf) | ||
6944 | { | ||
6945 | unsigned int len = 0; | ||
6946 | unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE; | ||
6947 | const struct ath10k_fw_stats_pdev *pdev; | ||
6948 | const struct ath10k_fw_stats_vdev *vdev; | ||
6949 | const struct ath10k_fw_stats_peer *peer; | ||
6950 | size_t num_peers; | ||
6951 | size_t num_vdevs; | ||
6952 | |||
6953 | spin_lock_bh(&ar->data_lock); | ||
6954 | |||
6955 | pdev = list_first_entry_or_null(&fw_stats->pdevs, | ||
6956 | struct ath10k_fw_stats_pdev, list); | ||
6957 | if (!pdev) { | ||
6958 | ath10k_warn(ar, "failed to get pdev stats\n"); | ||
6959 | goto unlock; | ||
6960 | } | ||
6961 | |||
6962 | num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers); | ||
6963 | num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs); | ||
6964 | |||
6965 | ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len); | ||
6966 | ath10k_wmi_fw_pdev_extra_stats_fill(pdev, buf, &len); | ||
6967 | ath10k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len); | ||
6968 | ath10k_wmi_fw_pdev_rx_stats_fill(pdev, buf, &len); | ||
6969 | |||
6970 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6971 | len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", | ||
6972 | "ath10k VDEV stats", num_vdevs); | ||
6973 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
6974 | "================="); | ||
6975 | |||
6976 | list_for_each_entry(vdev, &fw_stats->vdevs, list) { | ||
6977 | ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len); | ||
6978 | } | ||
6979 | |||
6980 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
6981 | len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", | ||
6982 | "ath10k PEER stats", num_peers); | ||
6983 | len += scnprintf(buf + len, buf_len - len, "%30s\n\n", | ||
6984 | "================="); | ||
6985 | |||
6986 | list_for_each_entry(peer, &fw_stats->peers, list) { | ||
6987 | ath10k_wmi_fw_peer_stats_fill(peer, buf, &len); | ||
6988 | } | ||
6989 | |||
6990 | unlock: | ||
6991 | spin_unlock_bh(&ar->data_lock); | ||
6992 | |||
6993 | if (len >= buf_len) | ||
6994 | buf[len - 1] = 0; | ||
6995 | else | ||
6996 | buf[len] = 0; | ||
6997 | } | ||
6998 | |||
6359 | static const struct wmi_ops wmi_ops = { | 6999 | static const struct wmi_ops wmi_ops = { |
6360 | .rx = ath10k_wmi_op_rx, | 7000 | .rx = ath10k_wmi_op_rx, |
6361 | .map_svc = wmi_main_svc_map, | 7001 | .map_svc = wmi_main_svc_map, |
@@ -6414,6 +7054,7 @@ static const struct wmi_ops wmi_ops = { | |||
6414 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, | 7054 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, |
6415 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, | 7055 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, |
6416 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, | 7056 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, |
7057 | .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, | ||
6417 | /* .gen_bcn_tmpl not implemented */ | 7058 | /* .gen_bcn_tmpl not implemented */ |
6418 | /* .gen_prb_tmpl not implemented */ | 7059 | /* .gen_prb_tmpl not implemented */ |
6419 | /* .gen_p2p_go_bcn_ie not implemented */ | 7060 | /* .gen_p2p_go_bcn_ie not implemented */ |
@@ -6479,6 +7120,7 @@ static const struct wmi_ops wmi_10_1_ops = { | |||
6479 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, | 7120 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, |
6480 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, | 7121 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, |
6481 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, | 7122 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, |
7123 | .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, | ||
6482 | /* .gen_bcn_tmpl not implemented */ | 7124 | /* .gen_bcn_tmpl not implemented */ |
6483 | /* .gen_prb_tmpl not implemented */ | 7125 | /* .gen_prb_tmpl not implemented */ |
6484 | /* .gen_p2p_go_bcn_ie not implemented */ | 7126 | /* .gen_p2p_go_bcn_ie not implemented */ |
@@ -6545,6 +7187,7 @@ static const struct wmi_ops wmi_10_2_ops = { | |||
6545 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, | 7187 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, |
6546 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, | 7188 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, |
6547 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, | 7189 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, |
7190 | .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, | ||
6548 | }; | 7191 | }; |
6549 | 7192 | ||
6550 | static const struct wmi_ops wmi_10_2_4_ops = { | 7193 | static const struct wmi_ops wmi_10_2_4_ops = { |
@@ -6606,6 +7249,8 @@ static const struct wmi_ops wmi_10_2_4_ops = { | |||
6606 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, | 7249 | .gen_addba_send = ath10k_wmi_op_gen_addba_send, |
6607 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, | 7250 | .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, |
6608 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, | 7251 | .gen_delba_send = ath10k_wmi_op_gen_delba_send, |
7252 | .gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config, | ||
7253 | .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, | ||
6609 | /* .gen_bcn_tmpl not implemented */ | 7254 | /* .gen_bcn_tmpl not implemented */ |
6610 | /* .gen_prb_tmpl not implemented */ | 7255 | /* .gen_prb_tmpl not implemented */ |
6611 | /* .gen_p2p_go_bcn_ie not implemented */ | 7256 | /* .gen_p2p_go_bcn_ie not implemented */ |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 3e5a1591f772..6e84d1c1a6ca 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
@@ -73,6 +73,25 @@ struct wmi_cmd_hdr { | |||
73 | #define HTC_PROTOCOL_VERSION 0x0002 | 73 | #define HTC_PROTOCOL_VERSION 0x0002 |
74 | #define WMI_PROTOCOL_VERSION 0x0002 | 74 | #define WMI_PROTOCOL_VERSION 0x0002 |
75 | 75 | ||
76 | /* | ||
77 | * There is no signed version of __le32, so for a temporary solution come | ||
78 | * up with our own version. The idea is from fs/ntfs/types.h. | ||
79 | * | ||
80 | * Use a_ prefix so that it doesn't conflict if we get proper support to | ||
81 | * linux/types.h. | ||
82 | */ | ||
83 | typedef __s32 __bitwise a_sle32; | ||
84 | |||
85 | static inline a_sle32 a_cpu_to_sle32(s32 val) | ||
86 | { | ||
87 | return (__force a_sle32)cpu_to_le32(val); | ||
88 | } | ||
89 | |||
90 | static inline s32 a_sle32_to_cpu(a_sle32 val) | ||
91 | { | ||
92 | return le32_to_cpu((__force __le32)val); | ||
93 | } | ||
94 | |||
76 | enum wmi_service { | 95 | enum wmi_service { |
77 | WMI_SERVICE_BEACON_OFFLOAD = 0, | 96 | WMI_SERVICE_BEACON_OFFLOAD = 0, |
78 | WMI_SERVICE_SCAN_OFFLOAD, | 97 | WMI_SERVICE_SCAN_OFFLOAD, |
@@ -3642,8 +3661,18 @@ struct wmi_pdev_get_tpc_config_cmd { | |||
3642 | __le32 param; | 3661 | __le32 param; |
3643 | } __packed; | 3662 | } __packed; |
3644 | 3663 | ||
3664 | #define WMI_TPC_CONFIG_PARAM 1 | ||
3645 | #define WMI_TPC_RATE_MAX 160 | 3665 | #define WMI_TPC_RATE_MAX 160 |
3646 | #define WMI_TPC_TX_N_CHAIN 4 | 3666 | #define WMI_TPC_TX_N_CHAIN 4 |
3667 | #define WMI_TPC_PREAM_TABLE_MAX 10 | ||
3668 | #define WMI_TPC_FLAG 3 | ||
3669 | #define WMI_TPC_BUF_SIZE 10 | ||
3670 | |||
3671 | enum wmi_tpc_table_type { | ||
3672 | WMI_TPC_TABLE_TYPE_CDD = 0, | ||
3673 | WMI_TPC_TABLE_TYPE_STBC = 1, | ||
3674 | WMI_TPC_TABLE_TYPE_TXBF = 2, | ||
3675 | }; | ||
3647 | 3676 | ||
3648 | enum wmi_tpc_config_event_flag { | 3677 | enum wmi_tpc_config_event_flag { |
3649 | WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD = 0x1, | 3678 | WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD = 0x1, |
@@ -3657,7 +3686,7 @@ struct wmi_pdev_tpc_config_event { | |||
3657 | __le32 phy_mode; | 3686 | __le32 phy_mode; |
3658 | __le32 twice_antenna_reduction; | 3687 | __le32 twice_antenna_reduction; |
3659 | __le32 twice_max_rd_power; | 3688 | __le32 twice_max_rd_power; |
3660 | s32 twice_antenna_gain; | 3689 | a_sle32 twice_antenna_gain; |
3661 | __le32 power_limit; | 3690 | __le32 power_limit; |
3662 | __le32 rate_max; | 3691 | __le32 rate_max; |
3663 | __le32 num_tx_chain; | 3692 | __le32 num_tx_chain; |
@@ -4253,6 +4282,11 @@ enum wmi_rate_preamble { | |||
4253 | WMI_RATE_PREAMBLE_VHT, | 4282 | WMI_RATE_PREAMBLE_VHT, |
4254 | }; | 4283 | }; |
4255 | 4284 | ||
4285 | #define ATH10K_HW_NSS(rate) (1 + (((rate) >> 4) & 0x3)) | ||
4286 | #define ATH10K_HW_PREAMBLE(rate) (((rate) >> 6) & 0x3) | ||
4287 | #define ATH10K_HW_RATECODE(rate, nss, preamble) \ | ||
4288 | (((preamble) << 6) | ((nss) << 4) | (rate)) | ||
4289 | |||
4256 | /* Value to disable fixed rate setting */ | 4290 | /* Value to disable fixed rate setting */ |
4257 | #define WMI_FIXED_RATE_NONE (0xff) | 4291 | #define WMI_FIXED_RATE_NONE (0xff) |
4258 | 4292 | ||
@@ -6064,6 +6098,7 @@ struct ath10k; | |||
6064 | struct ath10k_vif; | 6098 | struct ath10k_vif; |
6065 | struct ath10k_fw_stats_pdev; | 6099 | struct ath10k_fw_stats_pdev; |
6066 | struct ath10k_fw_stats_peer; | 6100 | struct ath10k_fw_stats_peer; |
6101 | struct ath10k_fw_stats; | ||
6067 | 6102 | ||
6068 | int ath10k_wmi_attach(struct ath10k *ar); | 6103 | int ath10k_wmi_attach(struct ath10k *ar); |
6069 | void ath10k_wmi_detach(struct ath10k *ar); | 6104 | void ath10k_wmi_detach(struct ath10k *ar); |
@@ -6145,4 +6180,13 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb); | |||
6145 | int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); | 6180 | int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); |
6146 | int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf, | 6181 | int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf, |
6147 | int left_len, struct wmi_phyerr_ev_arg *arg); | 6182 | int left_len, struct wmi_phyerr_ev_arg *arg); |
6183 | void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar, | ||
6184 | struct ath10k_fw_stats *fw_stats, | ||
6185 | char *buf); | ||
6186 | void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar, | ||
6187 | struct ath10k_fw_stats *fw_stats, | ||
6188 | char *buf); | ||
6189 | size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head); | ||
6190 | size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head); | ||
6191 | |||
6148 | #endif /* _WMI_H_ */ | 6192 | #endif /* _WMI_H_ */ |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a511ef3614b9..fe38fc40de0f 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -2217,7 +2217,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
2217 | 2217 | ||
2218 | /* enter / leave wow suspend on first vif always */ | 2218 | /* enter / leave wow suspend on first vif always */ |
2219 | first_vif = ath6kl_vif_first(ar); | 2219 | first_vif = ath6kl_vif_first(ar); |
2220 | if (WARN_ON(unlikely(!first_vif)) || | 2220 | if (WARN_ON(!first_vif) || |
2221 | !ath6kl_cfg80211_ready(first_vif)) | 2221 | !ath6kl_cfg80211_ready(first_vif)) |
2222 | return -EIO; | 2222 | return -EIO; |
2223 | 2223 | ||
@@ -2297,7 +2297,7 @@ static int ath6kl_wow_resume(struct ath6kl *ar) | |||
2297 | int ret; | 2297 | int ret; |
2298 | 2298 | ||
2299 | vif = ath6kl_vif_first(ar); | 2299 | vif = ath6kl_vif_first(ar); |
2300 | if (WARN_ON(unlikely(!vif)) || | 2300 | if (WARN_ON(!vif) || |
2301 | !ath6kl_cfg80211_ready(vif)) | 2301 | !ath6kl_cfg80211_ready(vif)) |
2302 | return -EIO; | 2302 | return -EIO; |
2303 | 2303 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index e481f14b9878..fffb65b3e652 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c | |||
@@ -1085,9 +1085,7 @@ static int htc_setup_tx_complete(struct htc_target *target) | |||
1085 | send_pkt->completion = NULL; | 1085 | send_pkt->completion = NULL; |
1086 | ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0); | 1086 | ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0); |
1087 | status = ath6kl_htc_tx_issue(target, send_pkt); | 1087 | status = ath6kl_htc_tx_issue(target, send_pkt); |
1088 | 1088 | htc_reclaim_txctrl_buf(target, send_pkt); | |
1089 | if (send_pkt != NULL) | ||
1090 | htc_reclaim_txctrl_buf(target, send_pkt); | ||
1091 | 1089 | ||
1092 | return status; | 1090 | return status; |
1093 | } | 1091 | } |
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index 9d687121b2bf..2303ef96299d 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c | |||
@@ -284,10 +284,10 @@ dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event) | |||
284 | if (cd == NULL) | 284 | if (cd == NULL) |
285 | return false; | 285 | return false; |
286 | 286 | ||
287 | dpd->last_pulse_ts = event->ts; | ||
288 | /* reset detector on time stamp wraparound, caused by TSF reset */ | 287 | /* reset detector on time stamp wraparound, caused by TSF reset */ |
289 | if (event->ts < dpd->last_pulse_ts) | 288 | if (event->ts < dpd->last_pulse_ts) |
290 | dpd_reset(dpd); | 289 | dpd_reset(dpd); |
290 | dpd->last_pulse_ts = event->ts; | ||
291 | 291 | ||
292 | /* do type individual pattern matching */ | 292 | /* do type individual pattern matching */ |
293 | for (i = 0; i < dpd->num_radar_types; i++) { | 293 | for (i = 0; i < dpd->num_radar_types; i++) { |
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index ce8c0381825e..6dfedc8bd6a3 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | config WIL6210 | 1 | config WIL6210 |
2 | tristate "Wilocity 60g WiFi card wil6210 support" | 2 | tristate "Wilocity 60g WiFi card wil6210 support" |
3 | select WANT_DEV_COREDUMP | ||
3 | depends on CFG80211 | 4 | depends on CFG80211 |
4 | depends on PCI | 5 | depends on PCI |
5 | default n | 6 | default n |
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 64b432625fbb..fdf63d5fe82b 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile | |||
@@ -17,6 +17,7 @@ wil6210-y += pmc.o | |||
17 | wil6210-$(CONFIG_WIL6210_TRACING) += trace.o | 17 | wil6210-$(CONFIG_WIL6210_TRACING) += trace.o |
18 | wil6210-y += wil_platform.o | 18 | wil6210-y += wil_platform.o |
19 | wil6210-y += ethtool.o | 19 | wil6210-y += ethtool.o |
20 | wil6210-y += wil_crash_dump.o | ||
20 | 21 | ||
21 | # for tracing framework to find trace.h | 22 | # for tracing framework to find trace.h |
22 | CFLAGS_trace.o := -I$(src) | 23 | CFLAGS_trace.o := -I$(src) |
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index d1a1e160ef31..97bc186f9728 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c | |||
@@ -1373,6 +1373,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) | |||
1373 | } | 1373 | } |
1374 | } | 1374 | } |
1375 | spin_unlock_bh(&p->tid_rx_lock); | 1375 | spin_unlock_bh(&p->tid_rx_lock); |
1376 | seq_printf(s, | ||
1377 | "Rx invalid frame: non-data %lu, short %lu, large %lu\n", | ||
1378 | p->stats.rx_non_data_frame, | ||
1379 | p->stats.rx_short_frame, | ||
1380 | p->stats.rx_large_frame); | ||
1381 | |||
1376 | seq_puts(s, "Rx/MCS:"); | 1382 | seq_puts(s, "Rx/MCS:"); |
1377 | for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); | 1383 | for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); |
1378 | mcs++) | 1384 | mcs++) |
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index a371f036d054..06fc46f85c85 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. | 2 | * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. |
3 | * | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
@@ -347,7 +347,12 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | |||
347 | wil6210_mask_irq_misc(wil); | 347 | wil6210_mask_irq_misc(wil); |
348 | 348 | ||
349 | if (isr & ISR_MISC_FW_ERROR) { | 349 | if (isr & ISR_MISC_FW_ERROR) { |
350 | wil_err(wil, "Firmware error detected\n"); | 350 | u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE); |
351 | u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE); | ||
352 | |||
353 | wil_err(wil, | ||
354 | "Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n", | ||
355 | fw_assert_code, ucode_assert_code); | ||
351 | clear_bit(wil_status_fwready, wil->status); | 356 | clear_bit(wil_status_fwready, wil->status); |
352 | /* | 357 | /* |
353 | * do not clear @isr here - we do 2-nd part in thread | 358 | * do not clear @isr here - we do 2-nd part in thread |
@@ -386,6 +391,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) | |||
386 | wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); | 391 | wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); |
387 | 392 | ||
388 | if (isr & ISR_MISC_FW_ERROR) { | 393 | if (isr & ISR_MISC_FW_ERROR) { |
394 | wil_fw_core_dump(wil); | ||
389 | wil_notify_fw_error(wil); | 395 | wil_notify_fw_error(wil); |
390 | isr &= ~ISR_MISC_FW_ERROR; | 396 | isr &= ~ISR_MISC_FW_ERROR; |
391 | wil_fw_error_recovery(wil); | 397 | wil_fw_error_recovery(wil); |
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 2fb04c51da53..aade16b126c4 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -203,11 +203,13 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | |||
203 | * - disconnect single STA, already disconnected | 203 | * - disconnect single STA, already disconnected |
204 | * - disconnect all | 204 | * - disconnect all |
205 | * | 205 | * |
206 | * For "disconnect all", there are 2 options: | 206 | * For "disconnect all", there are 3 options: |
207 | * - bssid == NULL | 207 | * - bssid == NULL |
208 | * - bssid is broadcast address (ff:ff:ff:ff:ff:ff) | ||
208 | * - bssid is our MAC address | 209 | * - bssid is our MAC address |
209 | */ | 210 | */ |
210 | if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) { | 211 | if (bssid && !is_broadcast_ether_addr(bssid) && |
212 | !ether_addr_equal_unaligned(ndev->dev_addr, bssid)) { | ||
211 | cid = wil_find_cid(wil, bssid); | 213 | cid = wil_find_cid(wil, bssid); |
212 | wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", | 214 | wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", |
213 | bssid, cid, reason_code); | 215 | bssid, cid, reason_code); |
@@ -765,6 +767,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) | |||
765 | if (wil->hw_version == HW_VER_UNKNOWN) | 767 | if (wil->hw_version == HW_VER_UNKNOWN) |
766 | return -ENODEV; | 768 | return -ENODEV; |
767 | 769 | ||
770 | set_bit(wil_status_resetting, wil->status); | ||
771 | |||
768 | cancel_work_sync(&wil->disconnect_worker); | 772 | cancel_work_sync(&wil->disconnect_worker); |
769 | wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); | 773 | wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); |
770 | wil_bcast_fini(wil); | 774 | wil_bcast_fini(wil); |
@@ -851,6 +855,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) | |||
851 | void wil_fw_error_recovery(struct wil6210_priv *wil) | 855 | void wil_fw_error_recovery(struct wil6210_priv *wil) |
852 | { | 856 | { |
853 | wil_dbg_misc(wil, "starting fw error recovery\n"); | 857 | wil_dbg_misc(wil, "starting fw error recovery\n"); |
858 | |||
859 | if (test_bit(wil_status_resetting, wil->status)) { | ||
860 | wil_info(wil, "Reset already in progress\n"); | ||
861 | return; | ||
862 | } | ||
863 | |||
854 | wil->recovery_state = fw_recovery_pending; | 864 | wil->recovery_state = fw_recovery_pending; |
855 | schedule_work(&wil->fw_error_worker); | 865 | schedule_work(&wil->fw_error_worker); |
856 | } | 866 | } |
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index feff1ef10fb3..1a3142c332e1 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c | |||
@@ -260,6 +260,7 @@ static const struct pci_device_id wil6210_pcie_ids[] = { | |||
260 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); | 260 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); |
261 | 261 | ||
262 | #ifdef CONFIG_PM | 262 | #ifdef CONFIG_PM |
263 | #ifdef CONFIG_PM_SLEEP | ||
263 | 264 | ||
264 | static int wil6210_suspend(struct device *dev, bool is_runtime) | 265 | static int wil6210_suspend(struct device *dev, bool is_runtime) |
265 | { | 266 | { |
@@ -307,7 +308,6 @@ static int wil6210_resume(struct device *dev, bool is_runtime) | |||
307 | return rc; | 308 | return rc; |
308 | } | 309 | } |
309 | 310 | ||
310 | #ifdef CONFIG_PM_SLEEP | ||
311 | static int wil6210_pm_suspend(struct device *dev) | 311 | static int wil6210_pm_suspend(struct device *dev) |
312 | { | 312 | { |
313 | return wil6210_suspend(dev, false); | 313 | return wil6210_suspend(dev, false); |
diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index 8a8cdc61b25b..5ca0307a3274 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c | |||
@@ -110,7 +110,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, | |||
110 | */ | 110 | */ |
111 | for (i = 0; i < num_descriptors; i++) { | 111 | for (i = 0; i < num_descriptors; i++) { |
112 | struct vring_tx_desc *_d = &pmc->pring_va[i]; | 112 | struct vring_tx_desc *_d = &pmc->pring_va[i]; |
113 | struct vring_tx_desc dd, *d = ⅆ | 113 | struct vring_tx_desc dd = {}, *d = ⅆ |
114 | int j = 0; | 114 | int j = 0; |
115 | 115 | ||
116 | pmc->descriptors[i].va = dma_alloc_coherent(dev, | 116 | pmc->descriptors[i].va = dma_alloc_coherent(dev, |
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 9238c1ac23dd..e3d1be82f314 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c | |||
@@ -205,6 +205,32 @@ out: | |||
205 | spin_unlock(&sta->tid_rx_lock); | 205 | spin_unlock(&sta->tid_rx_lock); |
206 | } | 206 | } |
207 | 207 | ||
208 | /* process BAR frame, called in NAPI context */ | ||
209 | void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq) | ||
210 | { | ||
211 | struct wil_sta_info *sta = &wil->sta[cid]; | ||
212 | struct wil_tid_ampdu_rx *r; | ||
213 | |||
214 | spin_lock(&sta->tid_rx_lock); | ||
215 | |||
216 | r = sta->tid_rx[tid]; | ||
217 | if (!r) { | ||
218 | wil_err(wil, "BAR for non-existing CID %d TID %d\n", cid, tid); | ||
219 | goto out; | ||
220 | } | ||
221 | if (seq_less(seq, r->head_seq_num)) { | ||
222 | wil_err(wil, "BAR Seq 0x%03x preceding head 0x%03x\n", | ||
223 | seq, r->head_seq_num); | ||
224 | goto out; | ||
225 | } | ||
226 | wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n", | ||
227 | cid, tid, seq, r->head_seq_num); | ||
228 | wil_release_reorder_frames(wil, r, seq); | ||
229 | |||
230 | out: | ||
231 | spin_unlock(&sta->tid_rx_lock); | ||
232 | } | ||
233 | |||
208 | struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, | 234 | struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, |
209 | int size, u16 ssn) | 235 | int size, u16 ssn) |
210 | { | 236 | { |
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 6229110d558a..0f8b6877497e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -358,6 +358,13 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, | |||
358 | } | 358 | } |
359 | } | 359 | } |
360 | 360 | ||
361 | /* similar to ieee80211_ version, but FC contain only 1-st byte */ | ||
362 | static inline int wil_is_back_req(u8 fc) | ||
363 | { | ||
364 | return (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == | ||
365 | (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); | ||
366 | } | ||
367 | |||
361 | /** | 368 | /** |
362 | * reap 1 frame from @swhead | 369 | * reap 1 frame from @swhead |
363 | * | 370 | * |
@@ -379,14 +386,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
379 | u16 dmalen; | 386 | u16 dmalen; |
380 | u8 ftype; | 387 | u8 ftype; |
381 | int cid; | 388 | int cid; |
382 | int i = (int)vring->swhead; | 389 | int i; |
383 | struct wil_net_stats *stats; | 390 | struct wil_net_stats *stats; |
384 | 391 | ||
385 | BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); | 392 | BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); |
386 | 393 | ||
394 | again: | ||
387 | if (unlikely(wil_vring_is_empty(vring))) | 395 | if (unlikely(wil_vring_is_empty(vring))) |
388 | return NULL; | 396 | return NULL; |
389 | 397 | ||
398 | i = (int)vring->swhead; | ||
390 | _d = &vring->va[i].rx; | 399 | _d = &vring->va[i].rx; |
391 | if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) { | 400 | if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) { |
392 | /* it is not error, we just reached end of Rx done area */ | 401 | /* it is not error, we just reached end of Rx done area */ |
@@ -398,7 +407,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
398 | wil_vring_advance_head(vring, 1); | 407 | wil_vring_advance_head(vring, 1); |
399 | if (!skb) { | 408 | if (!skb) { |
400 | wil_err(wil, "No Rx skb at [%d]\n", i); | 409 | wil_err(wil, "No Rx skb at [%d]\n", i); |
401 | return NULL; | 410 | goto again; |
402 | } | 411 | } |
403 | d = wil_skb_rxdesc(skb); | 412 | d = wil_skb_rxdesc(skb); |
404 | *d = *_d; | 413 | *d = *_d; |
@@ -409,13 +418,17 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
409 | 418 | ||
410 | trace_wil6210_rx(i, d); | 419 | trace_wil6210_rx(i, d); |
411 | wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", i, dmalen); | 420 | wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", i, dmalen); |
412 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, | 421 | wil_hex_dump_txrx("RxD ", DUMP_PREFIX_NONE, 32, 4, |
413 | (const void *)d, sizeof(*d), false); | 422 | (const void *)d, sizeof(*d), false); |
414 | 423 | ||
424 | cid = wil_rxdesc_cid(d); | ||
425 | stats = &wil->sta[cid].stats; | ||
426 | |||
415 | if (unlikely(dmalen > sz)) { | 427 | if (unlikely(dmalen > sz)) { |
416 | wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); | 428 | wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); |
429 | stats->rx_large_frame++; | ||
417 | kfree_skb(skb); | 430 | kfree_skb(skb); |
418 | return NULL; | 431 | goto again; |
419 | } | 432 | } |
420 | skb_trim(skb, dmalen); | 433 | skb_trim(skb, dmalen); |
421 | 434 | ||
@@ -424,8 +437,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
424 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | 437 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, |
425 | skb->data, skb_headlen(skb), false); | 438 | skb->data, skb_headlen(skb), false); |
426 | 439 | ||
427 | cid = wil_rxdesc_cid(d); | ||
428 | stats = &wil->sta[cid].stats; | ||
429 | stats->last_mcs_rx = wil_rxdesc_mcs(d); | 440 | stats->last_mcs_rx = wil_rxdesc_mcs(d); |
430 | if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs)) | 441 | if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs)) |
431 | stats->rx_per_mcs[stats->last_mcs_rx]++; | 442 | stats->rx_per_mcs[stats->last_mcs_rx]++; |
@@ -437,24 +448,47 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
437 | /* no extra checks if in sniffer mode */ | 448 | /* no extra checks if in sniffer mode */ |
438 | if (ndev->type != ARPHRD_ETHER) | 449 | if (ndev->type != ARPHRD_ETHER) |
439 | return skb; | 450 | return skb; |
440 | /* | 451 | /* Non-data frames may be delivered through Rx DMA channel (ex: BAR) |
441 | * Non-data frames may be delivered through Rx DMA channel (ex: BAR) | ||
442 | * Driver should recognize it by frame type, that is found | 452 | * Driver should recognize it by frame type, that is found |
443 | * in Rx descriptor. If type is not data, it is 802.11 frame as is | 453 | * in Rx descriptor. If type is not data, it is 802.11 frame as is |
444 | */ | 454 | */ |
445 | ftype = wil_rxdesc_ftype(d) << 2; | 455 | ftype = wil_rxdesc_ftype(d) << 2; |
446 | if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { | 456 | if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { |
447 | wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); | 457 | u8 fc1 = wil_rxdesc_fc1(d); |
448 | /* TODO: process it */ | 458 | int mid = wil_rxdesc_mid(d); |
459 | int tid = wil_rxdesc_tid(d); | ||
460 | u16 seq = wil_rxdesc_seq(d); | ||
461 | |||
462 | wil_dbg_txrx(wil, | ||
463 | "Non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n", | ||
464 | fc1, mid, cid, tid, seq); | ||
465 | stats->rx_non_data_frame++; | ||
466 | if (wil_is_back_req(fc1)) { | ||
467 | wil_dbg_txrx(wil, | ||
468 | "BAR: MID %d CID %d TID %d Seq 0x%03x\n", | ||
469 | mid, cid, tid, seq); | ||
470 | wil_rx_bar(wil, cid, tid, seq); | ||
471 | } else { | ||
472 | /* print again all info. One can enable only this | ||
473 | * without overhead for printing every Rx frame | ||
474 | */ | ||
475 | wil_dbg_txrx(wil, | ||
476 | "Unhandled non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n", | ||
477 | fc1, mid, cid, tid, seq); | ||
478 | wil_hex_dump_txrx("RxD ", DUMP_PREFIX_NONE, 32, 4, | ||
479 | (const void *)d, sizeof(*d), false); | ||
480 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | ||
481 | skb->data, skb_headlen(skb), false); | ||
482 | } | ||
449 | kfree_skb(skb); | 483 | kfree_skb(skb); |
450 | return NULL; | 484 | goto again; |
451 | } | 485 | } |
452 | 486 | ||
453 | if (unlikely(skb->len < ETH_HLEN + snaplen)) { | 487 | if (unlikely(skb->len < ETH_HLEN + snaplen)) { |
454 | wil_err(wil, "Short frame, len = %d\n", skb->len); | 488 | wil_err(wil, "Short frame, len = %d\n", skb->len); |
455 | /* TODO: process it (i.e. BAR) */ | 489 | stats->rx_short_frame++; |
456 | kfree_skb(skb); | 490 | kfree_skb(skb); |
457 | return NULL; | 491 | goto again; |
458 | } | 492 | } |
459 | 493 | ||
460 | /* L4 IDENT is on when HW calculated checksum, check status | 494 | /* L4 IDENT is on when HW calculated checksum, check status |
@@ -1633,7 +1667,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1633 | goto drop; | 1667 | goto drop; |
1634 | } | 1668 | } |
1635 | if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { | 1669 | if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { |
1636 | wil_err(wil, "FW not connected\n"); | 1670 | wil_err_ratelimited(wil, "FW not connected\n"); |
1637 | goto drop; | 1671 | goto drop; |
1638 | } | 1672 | } |
1639 | if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) { | 1673 | if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) { |
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 82a8f9a030e7..ee7c7b4b9a17 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h | |||
@@ -464,6 +464,12 @@ static inline int wil_rxdesc_subtype(struct vring_rx_desc *d) | |||
464 | return WIL_GET_BITS(d->mac.d0, 12, 15); | 464 | return WIL_GET_BITS(d->mac.d0, 12, 15); |
465 | } | 465 | } |
466 | 466 | ||
467 | /* 1-st byte (with frame type/subtype) of FC field */ | ||
468 | static inline u8 wil_rxdesc_fc1(struct vring_rx_desc *d) | ||
469 | { | ||
470 | return (u8)(WIL_GET_BITS(d->mac.d0, 10, 15) << 2); | ||
471 | } | ||
472 | |||
467 | static inline int wil_rxdesc_seq(struct vring_rx_desc *d) | 473 | static inline int wil_rxdesc_seq(struct vring_rx_desc *d) |
468 | { | 474 | { |
469 | return WIL_GET_BITS(d->mac.d0, 16, 27); | 475 | return WIL_GET_BITS(d->mac.d0, 16, 27); |
@@ -501,6 +507,7 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) | |||
501 | 507 | ||
502 | void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); | 508 | void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); |
503 | void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); | 509 | void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); |
510 | void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq); | ||
504 | struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, | 511 | struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, |
505 | int size, u16 ssn); | 512 | int size, u16 ssn); |
506 | void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, | 513 | void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index dd4ea926b8e3..f619bf234353 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -246,6 +246,10 @@ struct RGF_ICR { | |||
246 | #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ | 246 | #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ |
247 | #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f) | 247 | #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f) |
248 | 248 | ||
249 | /* crash codes for FW/Ucode stored here */ | ||
250 | #define RGF_FW_ASSERT_CODE (0x91f020) | ||
251 | #define RGF_UCODE_ASSERT_CODE (0x91f028) | ||
252 | |||
249 | enum { | 253 | enum { |
250 | HW_VER_UNKNOWN, | 254 | HW_VER_UNKNOWN, |
251 | HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */ | 255 | HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */ |
@@ -405,6 +409,7 @@ enum { /* for wil6210_priv.status */ | |||
405 | wil_status_reset_done, | 409 | wil_status_reset_done, |
406 | wil_status_irqen, /* FIXME: interrupts enabled - for debug */ | 410 | wil_status_irqen, /* FIXME: interrupts enabled - for debug */ |
407 | wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ | 411 | wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ |
412 | wil_status_resetting, /* reset in progress */ | ||
408 | wil_status_last /* keep last */ | 413 | wil_status_last /* keep last */ |
409 | }; | 414 | }; |
410 | 415 | ||
@@ -465,6 +470,9 @@ struct wil_net_stats { | |||
465 | unsigned long tx_bytes; | 470 | unsigned long tx_bytes; |
466 | unsigned long tx_errors; | 471 | unsigned long tx_errors; |
467 | unsigned long rx_dropped; | 472 | unsigned long rx_dropped; |
473 | unsigned long rx_non_data_frame; | ||
474 | unsigned long rx_short_frame; | ||
475 | unsigned long rx_large_frame; | ||
468 | u16 last_mcs_rx; | 476 | u16 last_mcs_rx; |
469 | u64 rx_per_mcs[WIL_MCS_MAX + 1]; | 477 | u64 rx_per_mcs[WIL_MCS_MAX + 1]; |
470 | }; | 478 | }; |
@@ -820,4 +828,6 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); | |||
820 | int wil_suspend(struct wil6210_priv *wil, bool is_runtime); | 828 | int wil_suspend(struct wil6210_priv *wil, bool is_runtime); |
821 | int wil_resume(struct wil6210_priv *wil, bool is_runtime); | 829 | int wil_resume(struct wil6210_priv *wil, bool is_runtime); |
822 | 830 | ||
831 | void wil_fw_core_dump(struct wil6210_priv *wil); | ||
832 | |||
823 | #endif /* __WIL6210_H__ */ | 833 | #endif /* __WIL6210_H__ */ |
diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c new file mode 100644 index 000000000000..7e70934990ae --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "wil6210.h" | ||
18 | #include <linux/devcoredump.h> | ||
19 | |||
20 | static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil, | ||
21 | u32 *out_dump_size, u32 *out_host_min) | ||
22 | { | ||
23 | int i; | ||
24 | const struct fw_map *map; | ||
25 | u32 host_min, host_max, tmp_max; | ||
26 | |||
27 | if (!out_dump_size) | ||
28 | return -EINVAL; | ||
29 | |||
30 | /* calculate the total size of the unpacked crash dump */ | ||
31 | BUILD_BUG_ON(ARRAY_SIZE(fw_mapping) == 0); | ||
32 | map = &fw_mapping[0]; | ||
33 | host_min = map->host; | ||
34 | host_max = map->host + (map->to - map->from); | ||
35 | |||
36 | for (i = 1; i < ARRAY_SIZE(fw_mapping); i++) { | ||
37 | map = &fw_mapping[i]; | ||
38 | |||
39 | if (map->host < host_min) | ||
40 | host_min = map->host; | ||
41 | |||
42 | tmp_max = map->host + (map->to - map->from); | ||
43 | if (tmp_max > host_max) | ||
44 | host_max = tmp_max; | ||
45 | } | ||
46 | |||
47 | *out_dump_size = host_max - host_min; | ||
48 | if (out_host_min) | ||
49 | *out_host_min = host_min; | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, | ||
55 | u32 size) | ||
56 | { | ||
57 | int i; | ||
58 | const struct fw_map *map; | ||
59 | void *data; | ||
60 | u32 host_min, dump_size, offset, len; | ||
61 | |||
62 | if (wil_fw_get_crash_dump_bounds(wil, &dump_size, &host_min)) { | ||
63 | wil_err(wil, "%s: fail to obtain crash dump size\n", __func__); | ||
64 | return -EINVAL; | ||
65 | } | ||
66 | |||
67 | if (dump_size > size) { | ||
68 | wil_err(wil, "%s: not enough space for dump. Need %d have %d\n", | ||
69 | __func__, dump_size, size); | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | |||
73 | /* copy to crash dump area */ | ||
74 | for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { | ||
75 | map = &fw_mapping[i]; | ||
76 | |||
77 | data = (void * __force)wil->csr + HOSTADDR(map->host); | ||
78 | len = map->to - map->from; | ||
79 | offset = map->host - host_min; | ||
80 | |||
81 | wil_dbg_misc(wil, "%s() - dump %s, size %d, offset %d\n", | ||
82 | __func__, fw_mapping[i].name, len, offset); | ||
83 | |||
84 | wil_memcpy_fromio_32((void * __force)(dest + offset), | ||
85 | (const void __iomem * __force)data, len); | ||
86 | } | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | void wil_fw_core_dump(struct wil6210_priv *wil) | ||
92 | { | ||
93 | void *fw_dump_data; | ||
94 | u32 fw_dump_size; | ||
95 | |||
96 | if (wil_fw_get_crash_dump_bounds(wil, &fw_dump_size, NULL)) { | ||
97 | wil_err(wil, "%s: fail to get fw dump size\n", __func__); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | fw_dump_data = vzalloc(fw_dump_size); | ||
102 | if (!fw_dump_data) | ||
103 | return; | ||
104 | |||
105 | if (wil_fw_copy_crash_dump(wil, fw_dump_data, fw_dump_size)) { | ||
106 | vfree(fw_dump_data); | ||
107 | return; | ||
108 | } | ||
109 | /* fw_dump_data will be free in device coredump release function | ||
110 | * after 5 min | ||
111 | */ | ||
112 | dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size, GFP_KERNEL); | ||
113 | wil_info(wil, "%s: fw core dumped, size %d bytes\n", __func__, | ||
114 | fw_dump_size); | ||
115 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 2f35d4c51f34..61121892c6ca 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -1120,7 +1120,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) | |||
1120 | cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); | 1120 | cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); |
1121 | cmd.sniffer_cfg.phy_support = | 1121 | cmd.sniffer_cfg.phy_support = |
1122 | cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) | 1122 | cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) |
1123 | ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); | 1123 | ? WMI_SNIFFER_CP : WMI_SNIFFER_BOTH_PHYS); |
1124 | } else { | 1124 | } else { |
1125 | /* Initialize offload (in non-sniffer mode). | 1125 | /* Initialize offload (in non-sniffer mode). |
1126 | * Linux IP stack always calculates IP checksum | 1126 | * Linux IP stack always calculates IP checksum |