diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/debugfs.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/debugfs.c | 485 |
1 files changed, 475 insertions, 10 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 369d4c90e669..1b52deea6081 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -60,11 +60,14 @@ | |||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include <linux/vmalloc.h> | ||
64 | |||
63 | #include "mvm.h" | 65 | #include "mvm.h" |
64 | #include "sta.h" | 66 | #include "sta.h" |
65 | #include "iwl-io.h" | 67 | #include "iwl-io.h" |
66 | #include "iwl-prph.h" | 68 | #include "iwl-prph.h" |
67 | #include "debugfs.h" | 69 | #include "debugfs.h" |
70 | #include "fw-error-dump.h" | ||
68 | 71 | ||
69 | static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, | 72 | static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, |
70 | size_t count, loff_t *ppos) | 73 | size_t count, loff_t *ppos) |
@@ -90,7 +93,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, | |||
90 | static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, | 93 | static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, |
91 | size_t count, loff_t *ppos) | 94 | size_t count, loff_t *ppos) |
92 | { | 95 | { |
93 | struct ieee80211_sta *sta; | 96 | struct iwl_mvm_sta *mvmsta; |
94 | int sta_id, drain, ret; | 97 | int sta_id, drain, ret; |
95 | 98 | ||
96 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) | 99 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) |
@@ -105,19 +108,63 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, | |||
105 | 108 | ||
106 | mutex_lock(&mvm->mutex); | 109 | mutex_lock(&mvm->mutex); |
107 | 110 | ||
108 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | 111 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); |
109 | lockdep_is_held(&mvm->mutex)); | 112 | |
110 | if (IS_ERR_OR_NULL(sta)) | 113 | if (!mvmsta) |
111 | ret = -ENOENT; | 114 | ret = -ENOENT; |
112 | else | 115 | else |
113 | ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? : | 116 | ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count; |
114 | count; | ||
115 | 117 | ||
116 | mutex_unlock(&mvm->mutex); | 118 | mutex_unlock(&mvm->mutex); |
117 | 119 | ||
118 | return ret; | 120 | return ret; |
119 | } | 121 | } |
120 | 122 | ||
123 | static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) | ||
124 | { | ||
125 | struct iwl_mvm *mvm = inode->i_private; | ||
126 | int ret; | ||
127 | |||
128 | if (!mvm) | ||
129 | return -EINVAL; | ||
130 | |||
131 | mutex_lock(&mvm->mutex); | ||
132 | if (!mvm->fw_error_dump) { | ||
133 | ret = -ENODATA; | ||
134 | goto out; | ||
135 | } | ||
136 | |||
137 | file->private_data = mvm->fw_error_dump; | ||
138 | mvm->fw_error_dump = NULL; | ||
139 | kfree(mvm->fw_error_sram); | ||
140 | mvm->fw_error_sram = NULL; | ||
141 | mvm->fw_error_sram_len = 0; | ||
142 | ret = 0; | ||
143 | |||
144 | out: | ||
145 | mutex_unlock(&mvm->mutex); | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, | ||
150 | char __user *user_buf, | ||
151 | size_t count, loff_t *ppos) | ||
152 | { | ||
153 | struct iwl_fw_error_dump_file *dump_file = file->private_data; | ||
154 | |||
155 | return simple_read_from_buffer(user_buf, count, ppos, | ||
156 | dump_file, | ||
157 | le32_to_cpu(dump_file->file_len)); | ||
158 | } | ||
159 | |||
160 | static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, | ||
161 | struct file *file) | ||
162 | { | ||
163 | vfree(file->private_data); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
121 | static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, | 168 | static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, |
122 | size_t count, loff_t *ppos) | 169 | size_t count, loff_t *ppos) |
123 | { | 170 | { |
@@ -251,7 +298,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, | |||
251 | } | 298 | } |
252 | 299 | ||
253 | mutex_lock(&mvm->mutex); | 300 | mutex_lock(&mvm->mutex); |
254 | ret = iwl_mvm_power_update_device_mode(mvm); | 301 | ret = iwl_mvm_power_update_device(mvm); |
255 | mutex_unlock(&mvm->mutex); | 302 | mutex_unlock(&mvm->mutex); |
256 | 303 | ||
257 | return ret ?: count; | 304 | return ret ?: count; |
@@ -351,6 +398,9 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, | |||
351 | le32_to_cpu(notif->secondary_ch_lut)); | 398 | le32_to_cpu(notif->secondary_ch_lut)); |
352 | pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n", | 399 | pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n", |
353 | le32_to_cpu(notif->bt_activity_grading)); | 400 | le32_to_cpu(notif->bt_activity_grading)); |
401 | pos += scnprintf(buf+pos, bufsz-pos, | ||
402 | "antenna isolation = %d CORUN LUT index = %d\n", | ||
403 | mvm->last_ant_isol, mvm->last_corun_lut); | ||
354 | 404 | ||
355 | mutex_unlock(&mvm->mutex); | 405 | mutex_unlock(&mvm->mutex); |
356 | 406 | ||
@@ -393,6 +443,22 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, | |||
393 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 443 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
394 | } | 444 | } |
395 | 445 | ||
446 | static ssize_t | ||
447 | iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, | ||
448 | size_t count, loff_t *ppos) | ||
449 | { | ||
450 | u32 bt_tx_prio; | ||
451 | |||
452 | if (sscanf(buf, "%u", &bt_tx_prio) != 1) | ||
453 | return -EINVAL; | ||
454 | if (bt_tx_prio > 4) | ||
455 | return -EINVAL; | ||
456 | |||
457 | mvm->bt_tx_prio = bt_tx_prio; | ||
458 | |||
459 | return count; | ||
460 | } | ||
461 | |||
396 | #define PRINT_STATS_LE32(_str, _val) \ | 462 | #define PRINT_STATS_LE32(_str, _val) \ |
397 | pos += scnprintf(buf + pos, bufsz - pos, \ | 463 | pos += scnprintf(buf + pos, bufsz - pos, \ |
398 | fmt_table, _str, \ | 464 | fmt_table, _str, \ |
@@ -532,6 +598,80 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, | |||
532 | } | 598 | } |
533 | #undef PRINT_STAT_LE32 | 599 | #undef PRINT_STAT_LE32 |
534 | 600 | ||
601 | static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, | ||
602 | char __user *user_buf, size_t count, | ||
603 | loff_t *ppos, | ||
604 | struct iwl_mvm_frame_stats *stats) | ||
605 | { | ||
606 | char *buff, *pos, *endpos; | ||
607 | int idx, i; | ||
608 | int ret; | ||
609 | static const size_t bufsz = 1024; | ||
610 | |||
611 | buff = kmalloc(bufsz, GFP_KERNEL); | ||
612 | if (!buff) | ||
613 | return -ENOMEM; | ||
614 | |||
615 | spin_lock_bh(&mvm->drv_stats_lock); | ||
616 | |||
617 | pos = buff; | ||
618 | endpos = pos + bufsz; | ||
619 | |||
620 | pos += scnprintf(pos, endpos - pos, | ||
621 | "Legacy/HT/VHT\t:\t%d/%d/%d\n", | ||
622 | stats->legacy_frames, | ||
623 | stats->ht_frames, | ||
624 | stats->vht_frames); | ||
625 | pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n", | ||
626 | stats->bw_20_frames, | ||
627 | stats->bw_40_frames, | ||
628 | stats->bw_80_frames); | ||
629 | pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n", | ||
630 | stats->ngi_frames, | ||
631 | stats->sgi_frames); | ||
632 | pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n", | ||
633 | stats->siso_frames, | ||
634 | stats->mimo2_frames); | ||
635 | pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n", | ||
636 | stats->fail_frames, | ||
637 | stats->success_frames); | ||
638 | pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n", | ||
639 | stats->agg_frames); | ||
640 | pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n", | ||
641 | stats->ampdu_count); | ||
642 | pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n", | ||
643 | stats->ampdu_count > 0 ? | ||
644 | (stats->agg_frames / stats->ampdu_count) : 0); | ||
645 | |||
646 | pos += scnprintf(pos, endpos - pos, "Last Rates\n"); | ||
647 | |||
648 | idx = stats->last_frame_idx - 1; | ||
649 | for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) { | ||
650 | idx = (idx + 1) % ARRAY_SIZE(stats->last_rates); | ||
651 | if (stats->last_rates[idx] == 0) | ||
652 | continue; | ||
653 | pos += scnprintf(pos, endpos - pos, "Rate[%d]: ", | ||
654 | (int)(ARRAY_SIZE(stats->last_rates) - i)); | ||
655 | pos += rs_pretty_print_rate(pos, stats->last_rates[idx]); | ||
656 | } | ||
657 | spin_unlock_bh(&mvm->drv_stats_lock); | ||
658 | |||
659 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); | ||
660 | kfree(buff); | ||
661 | |||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file, | ||
666 | char __user *user_buf, size_t count, | ||
667 | loff_t *ppos) | ||
668 | { | ||
669 | struct iwl_mvm *mvm = file->private_data; | ||
670 | |||
671 | return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos, | ||
672 | &mvm->drv_rx_stats); | ||
673 | } | ||
674 | |||
535 | static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, | 675 | static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, |
536 | size_t count, loff_t *ppos) | 676 | size_t count, loff_t *ppos) |
537 | { | 677 | { |
@@ -592,7 +732,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, | |||
592 | return -EINVAL; | 732 | return -EINVAL; |
593 | if (scan_rx_ant > ANT_ABC) | 733 | if (scan_rx_ant > ANT_ABC) |
594 | return -EINVAL; | 734 | return -EINVAL; |
595 | if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw)) | 735 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) |
596 | return -EINVAL; | 736 | return -EINVAL; |
597 | 737 | ||
598 | mvm->scan_rx_ant = scan_rx_ant; | 738 | mvm->scan_rx_ant = scan_rx_ant; |
@@ -600,6 +740,187 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, | |||
600 | return count; | 740 | return count; |
601 | } | 741 | } |
602 | 742 | ||
743 | #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) | ||
744 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
745 | static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, | ||
746 | char __user *user_buf, | ||
747 | size_t count, loff_t *ppos) | ||
748 | { | ||
749 | struct iwl_mvm *mvm = file->private_data; | ||
750 | struct iwl_bcast_filter_cmd cmd; | ||
751 | const struct iwl_fw_bcast_filter *filter; | ||
752 | char *buf; | ||
753 | int bufsz = 1024; | ||
754 | int i, j, pos = 0; | ||
755 | ssize_t ret; | ||
756 | |||
757 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
758 | if (!buf) | ||
759 | return -ENOMEM; | ||
760 | |||
761 | mutex_lock(&mvm->mutex); | ||
762 | if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { | ||
763 | ADD_TEXT("None\n"); | ||
764 | mutex_unlock(&mvm->mutex); | ||
765 | goto out; | ||
766 | } | ||
767 | mutex_unlock(&mvm->mutex); | ||
768 | |||
769 | for (i = 0; cmd.filters[i].attrs[0].mask; i++) { | ||
770 | filter = &cmd.filters[i]; | ||
771 | |||
772 | ADD_TEXT("Filter [%d]:\n", i); | ||
773 | ADD_TEXT("\tDiscard=%d\n", filter->discard); | ||
774 | ADD_TEXT("\tFrame Type: %s\n", | ||
775 | filter->frame_type ? "IPv4" : "Generic"); | ||
776 | |||
777 | for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) { | ||
778 | const struct iwl_fw_bcast_filter_attr *attr; | ||
779 | |||
780 | attr = &filter->attrs[j]; | ||
781 | if (!attr->mask) | ||
782 | break; | ||
783 | |||
784 | ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n", | ||
785 | j, attr->offset, | ||
786 | attr->offset_type ? "IP End" : | ||
787 | "Payload Start", | ||
788 | be32_to_cpu(attr->mask), | ||
789 | be32_to_cpu(attr->val), | ||
790 | le16_to_cpu(attr->reserved1)); | ||
791 | } | ||
792 | } | ||
793 | out: | ||
794 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
795 | kfree(buf); | ||
796 | return ret; | ||
797 | } | ||
798 | |||
799 | static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf, | ||
800 | size_t count, loff_t *ppos) | ||
801 | { | ||
802 | int pos, next_pos; | ||
803 | struct iwl_fw_bcast_filter filter = {}; | ||
804 | struct iwl_bcast_filter_cmd cmd; | ||
805 | u32 filter_id, attr_id, mask, value; | ||
806 | int err = 0; | ||
807 | |||
808 | if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard, | ||
809 | &filter.frame_type, &pos) != 3) | ||
810 | return -EINVAL; | ||
811 | |||
812 | if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) || | ||
813 | filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4) | ||
814 | return -EINVAL; | ||
815 | |||
816 | for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs); | ||
817 | attr_id++) { | ||
818 | struct iwl_fw_bcast_filter_attr *attr = | ||
819 | &filter.attrs[attr_id]; | ||
820 | |||
821 | if (pos >= count) | ||
822 | break; | ||
823 | |||
824 | if (sscanf(&buf[pos], "%hhi %hhi %i %i %n", | ||
825 | &attr->offset, &attr->offset_type, | ||
826 | &mask, &value, &next_pos) != 4) | ||
827 | return -EINVAL; | ||
828 | |||
829 | attr->mask = cpu_to_be32(mask); | ||
830 | attr->val = cpu_to_be32(value); | ||
831 | if (mask) | ||
832 | filter.num_attrs++; | ||
833 | |||
834 | pos += next_pos; | ||
835 | } | ||
836 | |||
837 | mutex_lock(&mvm->mutex); | ||
838 | memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id], | ||
839 | &filter, sizeof(filter)); | ||
840 | |||
841 | /* send updated bcast filtering configuration */ | ||
842 | if (mvm->dbgfs_bcast_filtering.override && | ||
843 | iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) | ||
844 | err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, | ||
845 | sizeof(cmd), &cmd); | ||
846 | mutex_unlock(&mvm->mutex); | ||
847 | |||
848 | return err ?: count; | ||
849 | } | ||
850 | |||
851 | static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file, | ||
852 | char __user *user_buf, | ||
853 | size_t count, loff_t *ppos) | ||
854 | { | ||
855 | struct iwl_mvm *mvm = file->private_data; | ||
856 | struct iwl_bcast_filter_cmd cmd; | ||
857 | char *buf; | ||
858 | int bufsz = 1024; | ||
859 | int i, pos = 0; | ||
860 | ssize_t ret; | ||
861 | |||
862 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
863 | if (!buf) | ||
864 | return -ENOMEM; | ||
865 | |||
866 | mutex_lock(&mvm->mutex); | ||
867 | if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { | ||
868 | ADD_TEXT("None\n"); | ||
869 | mutex_unlock(&mvm->mutex); | ||
870 | goto out; | ||
871 | } | ||
872 | mutex_unlock(&mvm->mutex); | ||
873 | |||
874 | for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) { | ||
875 | const struct iwl_fw_bcast_mac *mac = &cmd.macs[i]; | ||
876 | |||
877 | ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n", | ||
878 | i, mac->default_discard, mac->attached_filters); | ||
879 | } | ||
880 | out: | ||
881 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
882 | kfree(buf); | ||
883 | return ret; | ||
884 | } | ||
885 | |||
886 | static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, | ||
887 | char *buf, size_t count, | ||
888 | loff_t *ppos) | ||
889 | { | ||
890 | struct iwl_bcast_filter_cmd cmd; | ||
891 | struct iwl_fw_bcast_mac mac = {}; | ||
892 | u32 mac_id, attached_filters; | ||
893 | int err = 0; | ||
894 | |||
895 | if (!mvm->bcast_filters) | ||
896 | return -ENOENT; | ||
897 | |||
898 | if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard, | ||
899 | &attached_filters) != 3) | ||
900 | return -EINVAL; | ||
901 | |||
902 | if (mac_id >= ARRAY_SIZE(cmd.macs) || | ||
903 | mac.default_discard > 1 || | ||
904 | attached_filters >= BIT(ARRAY_SIZE(cmd.filters))) | ||
905 | return -EINVAL; | ||
906 | |||
907 | mac.attached_filters = cpu_to_le16(attached_filters); | ||
908 | |||
909 | mutex_lock(&mvm->mutex); | ||
910 | memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id], | ||
911 | &mac, sizeof(mac)); | ||
912 | |||
913 | /* send updated bcast filtering configuration */ | ||
914 | if (mvm->dbgfs_bcast_filtering.override && | ||
915 | iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) | ||
916 | err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, | ||
917 | sizeof(cmd), &cmd); | ||
918 | mutex_unlock(&mvm->mutex); | ||
919 | |||
920 | return err ?: count; | ||
921 | } | ||
922 | #endif | ||
923 | |||
603 | #ifdef CONFIG_PM_SLEEP | 924 | #ifdef CONFIG_PM_SLEEP |
604 | static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, | 925 | static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, |
605 | size_t count, loff_t *ppos) | 926 | size_t count, loff_t *ppos) |
@@ -658,15 +979,117 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, | |||
658 | } | 979 | } |
659 | #endif | 980 | #endif |
660 | 981 | ||
982 | #define PRINT_MVM_REF(ref) do { \ | ||
983 | if (test_bit(ref, mvm->ref_bitmap)) \ | ||
984 | pos += scnprintf(buf + pos, bufsz - pos, \ | ||
985 | "\t(0x%lx) %s\n", \ | ||
986 | BIT(ref), #ref); \ | ||
987 | } while (0) | ||
988 | |||
989 | static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, | ||
990 | char __user *user_buf, | ||
991 | size_t count, loff_t *ppos) | ||
992 | { | ||
993 | struct iwl_mvm *mvm = file->private_data; | ||
994 | int pos = 0; | ||
995 | char buf[256]; | ||
996 | const size_t bufsz = sizeof(buf); | ||
997 | |||
998 | pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n", | ||
999 | mvm->ref_bitmap[0]); | ||
1000 | |||
1001 | PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); | ||
1002 | PRINT_MVM_REF(IWL_MVM_REF_SCAN); | ||
1003 | PRINT_MVM_REF(IWL_MVM_REF_ROC); | ||
1004 | PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); | ||
1005 | PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); | ||
1006 | PRINT_MVM_REF(IWL_MVM_REF_USER); | ||
1007 | |||
1008 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1009 | } | ||
1010 | |||
1011 | static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, | ||
1012 | size_t count, loff_t *ppos) | ||
1013 | { | ||
1014 | unsigned long value; | ||
1015 | int ret; | ||
1016 | bool taken; | ||
1017 | |||
1018 | ret = kstrtoul(buf, 10, &value); | ||
1019 | if (ret < 0) | ||
1020 | return ret; | ||
1021 | |||
1022 | mutex_lock(&mvm->mutex); | ||
1023 | |||
1024 | taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap); | ||
1025 | if (value == 1 && !taken) | ||
1026 | iwl_mvm_ref(mvm, IWL_MVM_REF_USER); | ||
1027 | else if (value == 0 && taken) | ||
1028 | iwl_mvm_unref(mvm, IWL_MVM_REF_USER); | ||
1029 | else | ||
1030 | ret = -EINVAL; | ||
1031 | |||
1032 | mutex_unlock(&mvm->mutex); | ||
1033 | |||
1034 | if (ret < 0) | ||
1035 | return ret; | ||
1036 | return count; | ||
1037 | } | ||
1038 | |||
661 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ | 1039 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ |
662 | _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) | 1040 | _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) |
663 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ | 1041 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ |
664 | _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) | 1042 | _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) |
665 | #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ | 1043 | #define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ |
666 | if (!debugfs_create_file(#name, mode, parent, mvm, \ | 1044 | if (!debugfs_create_file(alias, mode, parent, mvm, \ |
667 | &iwl_dbgfs_##name##_ops)) \ | 1045 | &iwl_dbgfs_##name##_ops)) \ |
668 | goto err; \ | 1046 | goto err; \ |
669 | } while (0) | 1047 | } while (0) |
1048 | #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ | ||
1049 | MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) | ||
1050 | |||
1051 | static ssize_t | ||
1052 | iwl_dbgfs_prph_reg_read(struct file *file, | ||
1053 | char __user *user_buf, | ||
1054 | size_t count, loff_t *ppos) | ||
1055 | { | ||
1056 | struct iwl_mvm *mvm = file->private_data; | ||
1057 | int pos = 0; | ||
1058 | char buf[32]; | ||
1059 | const size_t bufsz = sizeof(buf); | ||
1060 | |||
1061 | if (!mvm->dbgfs_prph_reg_addr) | ||
1062 | return -EINVAL; | ||
1063 | |||
1064 | pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", | ||
1065 | mvm->dbgfs_prph_reg_addr, | ||
1066 | iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); | ||
1067 | |||
1068 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1069 | } | ||
1070 | |||
1071 | static ssize_t | ||
1072 | iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, | ||
1073 | size_t count, loff_t *ppos) | ||
1074 | { | ||
1075 | u8 args; | ||
1076 | u32 value; | ||
1077 | |||
1078 | args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); | ||
1079 | /* if we only want to set the reg address - nothing more to do */ | ||
1080 | if (args == 1) | ||
1081 | goto out; | ||
1082 | |||
1083 | /* otherwise, make sure we have both address and value */ | ||
1084 | if (args != 2) | ||
1085 | return -EINVAL; | ||
1086 | |||
1087 | iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); | ||
1088 | out: | ||
1089 | return count; | ||
1090 | } | ||
1091 | |||
1092 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); | ||
670 | 1093 | ||
671 | /* Device wide debugfs entries */ | 1094 | /* Device wide debugfs entries */ |
672 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); | 1095 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); |
@@ -677,9 +1100,23 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | |||
677 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); | 1100 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); |
678 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); | 1101 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); |
679 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); | 1102 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); |
1103 | MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); | ||
680 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); | 1104 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); |
681 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); | 1105 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); |
1106 | MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); | ||
682 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); | 1107 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); |
1108 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); | ||
1109 | |||
1110 | static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { | ||
1111 | .open = iwl_dbgfs_fw_error_dump_open, | ||
1112 | .read = iwl_dbgfs_fw_error_dump_read, | ||
1113 | .release = iwl_dbgfs_fw_error_dump_release, | ||
1114 | }; | ||
1115 | |||
1116 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
1117 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); | ||
1118 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); | ||
1119 | #endif | ||
683 | 1120 | ||
684 | #ifdef CONFIG_PM_SLEEP | 1121 | #ifdef CONFIG_PM_SLEEP |
685 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); | 1122 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); |
@@ -687,24 +1124,52 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); | |||
687 | 1124 | ||
688 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | 1125 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) |
689 | { | 1126 | { |
1127 | struct dentry *bcast_dir __maybe_unused; | ||
690 | char buf[100]; | 1128 | char buf[100]; |
691 | 1129 | ||
1130 | spin_lock_init(&mvm->drv_stats_lock); | ||
1131 | |||
692 | mvm->debugfs_dir = dbgfs_dir; | 1132 | mvm->debugfs_dir = dbgfs_dir; |
693 | 1133 | ||
694 | MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); | 1134 | MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); |
695 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); | 1135 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); |
696 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | 1136 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); |
697 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); | 1137 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); |
1138 | MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); | ||
698 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); | 1139 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); |
699 | MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); | 1140 | MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); |
700 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) | 1141 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) |
701 | MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, | 1142 | MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, |
702 | S_IRUSR | S_IWUSR); | 1143 | S_IRUSR | S_IWUSR); |
703 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); | 1144 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); |
1145 | MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); | ||
704 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); | 1146 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); |
705 | MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); | 1147 | MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); |
1148 | MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); | ||
706 | MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, | 1149 | MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, |
707 | S_IWUSR | S_IRUSR); | 1150 | S_IWUSR | S_IRUSR); |
1151 | MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | ||
1152 | MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | ||
1153 | |||
1154 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
1155 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { | ||
1156 | bcast_dir = debugfs_create_dir("bcast_filtering", | ||
1157 | mvm->debugfs_dir); | ||
1158 | if (!bcast_dir) | ||
1159 | goto err; | ||
1160 | |||
1161 | if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR, | ||
1162 | bcast_dir, | ||
1163 | &mvm->dbgfs_bcast_filtering.override)) | ||
1164 | goto err; | ||
1165 | |||
1166 | MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters, | ||
1167 | bcast_dir, S_IWUSR | S_IRUSR); | ||
1168 | MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs, | ||
1169 | bcast_dir, S_IWUSR | S_IRUSR); | ||
1170 | } | ||
1171 | #endif | ||
1172 | |||
708 | #ifdef CONFIG_PM_SLEEP | 1173 | #ifdef CONFIG_PM_SLEEP |
709 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | 1174 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); |
710 | MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); | 1175 | MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); |