Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: mac80211: add API to show the link STAs in debugfs

Create debugfs data per-link. For drivers, there is a new operation
link_sta_add_debugfs which will always be called.

For non-MLO, the station directory will be used directly rather than
creating a corresponding subdirectory. As such, non-MLO drivers can
simply continue to create the data from sta_debugfs_add.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
[add missing inlines if !CONFIG_MAC80211_DEBUGFS]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Benjamin Berg and committed by
Johannes Berg
d2caad52 1d9e4c91

+200 -23
+11
include/net/mac80211.h
··· 3790 3790 * should be within a CONFIG_MAC80211_DEBUGFS conditional. This 3791 3791 * callback can sleep. 3792 3792 * 3793 + * @link_sta_add_debugfs: Drivers can use this callback to add debugfs files 3794 + * when a link is added to a mac80211 station. This callback 3795 + * should be within a CPTCFG_MAC80211_DEBUGFS conditional. This 3796 + * callback can sleep. 3797 + * For non-MLO the callback will be called once for the deflink with the 3798 + * station's directory rather than a separate subdirectory. 3799 + * 3793 3800 * @sta_notify: Notifies low level driver about power state transition of an 3794 3801 * associated station, AP, IBSS/WDS/mesh peer etc. For a VIF operating 3795 3802 * in AP mode, this callback will not be called when the flag ··· 4267 4260 struct ieee80211_vif *vif, 4268 4261 struct ieee80211_sta *sta, 4269 4262 struct dentry *dir); 4263 + void (*link_sta_add_debugfs)(struct ieee80211_hw *hw, 4264 + struct ieee80211_vif *vif, 4265 + struct ieee80211_link_sta *link_sta, 4266 + struct dentry *dir); 4270 4267 #endif 4271 4268 void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4272 4269 enum sta_notify_cmd, struct ieee80211_sta *sta);
+105 -22
net/mac80211/debugfs_sta.c
··· 5 5 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 6 6 * Copyright 2013-2014 Intel Mobile Communications GmbH 7 7 * Copyright(c) 2016 Intel Deutschland GmbH 8 - * Copyright (C) 2018 - 2021 Intel Corporation 8 + * Copyright (C) 2018 - 2022 Intel Corporation 9 9 */ 10 10 11 11 #include <linux/debugfs.h> ··· 435 435 } 436 436 STA_OPS_RW(agg_status); 437 437 438 - static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, 439 - size_t count, loff_t *ppos) 438 + /* link sta attributes */ 439 + #define LINK_STA_OPS(name) \ 440 + static const struct file_operations link_sta_ ##name## _ops = { \ 441 + .read = link_sta_##name##_read, \ 442 + .open = simple_open, \ 443 + .llseek = generic_file_llseek, \ 444 + } 445 + 446 + static ssize_t link_sta_ht_capa_read(struct file *file, char __user *userbuf, 447 + size_t count, loff_t *ppos) 440 448 { 441 449 #define PRINT_HT_CAP(_cond, _str) \ 442 450 do { \ ··· 454 446 char *buf, *p; 455 447 int i; 456 448 ssize_t bufsz = 512; 457 - struct sta_info *sta = file->private_data; 458 - struct ieee80211_sta_ht_cap *htc = &sta->sta.deflink.ht_cap; 449 + struct link_sta_info *link_sta = file->private_data; 450 + struct ieee80211_sta_ht_cap *htc = &link_sta->pub->ht_cap; 459 451 ssize_t ret; 460 452 461 453 buf = kzalloc(bufsz, GFP_KERNEL); ··· 532 524 kfree(buf); 533 525 return ret; 534 526 } 535 - STA_OPS(ht_capa); 527 + LINK_STA_OPS(ht_capa); 536 528 537 - static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf, 538 - size_t count, loff_t *ppos) 529 + static ssize_t link_sta_vht_capa_read(struct file *file, char __user *userbuf, 530 + size_t count, loff_t *ppos) 539 531 { 540 532 char *buf, *p; 541 - struct sta_info *sta = file->private_data; 542 - struct ieee80211_sta_vht_cap *vhtc = &sta->sta.deflink.vht_cap; 533 + struct link_sta_info *link_sta = file->private_data; 534 + struct ieee80211_sta_vht_cap *vhtc = &link_sta->pub->vht_cap; 543 535 ssize_t ret; 544 536 ssize_t bufsz = 512; 545 537 ··· 646 638 kfree(buf); 647 639 return ret; 648 640 } 649 - STA_OPS(vht_capa); 641 + LINK_STA_OPS(vht_capa); 650 642 651 - static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf, 652 - size_t count, loff_t *ppos) 643 + static ssize_t link_sta_he_capa_read(struct file *file, char __user *userbuf, 644 + size_t count, loff_t *ppos) 653 645 { 654 646 char *buf, *p; 655 647 size_t buf_sz = PAGE_SIZE; 656 - struct sta_info *sta = file->private_data; 657 - struct ieee80211_sta_he_cap *hec = &sta->sta.deflink.he_cap; 648 + struct link_sta_info *link_sta = file->private_data; 649 + struct ieee80211_sta_he_cap *hec = &link_sta->pub->he_cap; 658 650 struct ieee80211_he_mcs_nss_supp *nss = &hec->he_mcs_nss_supp; 659 651 u8 ppe_size; 660 652 u8 *cap; ··· 1019 1011 kfree(buf); 1020 1012 return ret; 1021 1013 } 1022 - STA_OPS(he_capa); 1014 + LINK_STA_OPS(he_capa); 1023 1015 1024 1016 #define DEBUGFS_ADD(name) \ 1025 1017 debugfs_create_file(#name, 0400, \ ··· 1056 1048 DEBUGFS_ADD(num_ps_buf_frames); 1057 1049 DEBUGFS_ADD(last_seq_ctrl); 1058 1050 DEBUGFS_ADD(agg_status); 1059 - DEBUGFS_ADD(ht_capa); 1060 - DEBUGFS_ADD(vht_capa); 1061 - DEBUGFS_ADD(he_capa); 1062 - 1063 - DEBUGFS_ADD_COUNTER(rx_duplicates, deflink.rx_stats.num_duplicates); 1064 - DEBUGFS_ADD_COUNTER(rx_fragments, deflink.rx_stats.fragments); 1051 + /* FIXME: Kept here as the statistics are only done on the deflink */ 1065 1052 DEBUGFS_ADD_COUNTER(tx_filtered, deflink.status_stats.filtered); 1066 1053 1067 1054 if (local->ops->wake_tx_queue) { ··· 1078 1075 { 1079 1076 debugfs_remove_recursive(sta->debugfs_dir); 1080 1077 sta->debugfs_dir = NULL; 1078 + } 1079 + 1080 + #undef DEBUGFS_ADD 1081 + #undef DEBUGFS_ADD_COUNTER 1082 + 1083 + #define DEBUGFS_ADD(name) \ 1084 + debugfs_create_file(#name, 0400, \ 1085 + link_sta->debugfs_dir, link_sta, &link_sta_ ##name## _ops) 1086 + #define DEBUGFS_ADD_COUNTER(name, field) \ 1087 + debugfs_create_ulong(#name, 0400, link_sta->debugfs_dir, &link_sta->field) 1088 + 1089 + void ieee80211_link_sta_debugfs_add(struct link_sta_info *link_sta) 1090 + { 1091 + if (WARN_ON(!link_sta->sta->debugfs_dir)) 1092 + return; 1093 + 1094 + /* For non-MLO, leave the files in the main directory. */ 1095 + if (link_sta->sta->sta.valid_links) { 1096 + char link_dir_name[10]; 1097 + 1098 + snprintf(link_dir_name, sizeof(link_dir_name), 1099 + "link-%d", link_sta->link_id); 1100 + 1101 + link_sta->debugfs_dir = 1102 + debugfs_create_dir(link_dir_name, 1103 + link_sta->sta->debugfs_dir); 1104 + } else { 1105 + if (WARN_ON(link_sta != &link_sta->sta->deflink)) 1106 + return; 1107 + 1108 + link_sta->debugfs_dir = link_sta->sta->debugfs_dir; 1109 + } 1110 + 1111 + DEBUGFS_ADD(ht_capa); 1112 + DEBUGFS_ADD(vht_capa); 1113 + DEBUGFS_ADD(he_capa); 1114 + 1115 + DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates); 1116 + DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments); 1117 + } 1118 + 1119 + void ieee80211_link_sta_debugfs_remove(struct link_sta_info *link_sta) 1120 + { 1121 + if (!link_sta->debugfs_dir || !link_sta->sta->debugfs_dir) { 1122 + link_sta->debugfs_dir = NULL; 1123 + return; 1124 + } 1125 + 1126 + if (link_sta->debugfs_dir == link_sta->sta->debugfs_dir) { 1127 + WARN_ON(link_sta != &link_sta->sta->deflink); 1128 + link_sta->sta->debugfs_dir = NULL; 1129 + return; 1130 + } 1131 + 1132 + debugfs_remove_recursive(link_sta->debugfs_dir); 1133 + link_sta->debugfs_dir = NULL; 1134 + } 1135 + 1136 + void ieee80211_link_sta_debugfs_drv_add(struct link_sta_info *link_sta) 1137 + { 1138 + if (WARN_ON(!link_sta->debugfs_dir)) 1139 + return; 1140 + 1141 + drv_link_sta_add_debugfs(link_sta->sta->local, link_sta->sta->sdata, 1142 + link_sta->pub, link_sta->debugfs_dir); 1143 + } 1144 + 1145 + void ieee80211_link_sta_debugfs_drv_remove(struct link_sta_info *link_sta) 1146 + { 1147 + if (!link_sta->debugfs_dir) 1148 + return; 1149 + 1150 + if (WARN_ON(link_sta->debugfs_dir == link_sta->sta->debugfs_dir)) 1151 + return; 1152 + 1153 + /* Recreate the directory excluding the driver data */ 1154 + debugfs_remove_recursive(link_sta->debugfs_dir); 1155 + link_sta->debugfs_dir = NULL; 1156 + 1157 + ieee80211_link_sta_debugfs_add(link_sta); 1081 1158 }
+12
net/mac80211/debugfs_sta.h
··· 7 7 #ifdef CONFIG_MAC80211_DEBUGFS 8 8 void ieee80211_sta_debugfs_add(struct sta_info *sta); 9 9 void ieee80211_sta_debugfs_remove(struct sta_info *sta); 10 + 11 + void ieee80211_link_sta_debugfs_add(struct link_sta_info *link_sta); 12 + void ieee80211_link_sta_debugfs_remove(struct link_sta_info *link_sta); 13 + 14 + void ieee80211_link_sta_debugfs_drv_add(struct link_sta_info *link_sta); 15 + void ieee80211_link_sta_debugfs_drv_remove(struct link_sta_info *link_sta); 10 16 #else 11 17 static inline void ieee80211_sta_debugfs_add(struct sta_info *sta) {} 12 18 static inline void ieee80211_sta_debugfs_remove(struct sta_info *sta) {} 19 + 20 + static inline void ieee80211_link_sta_debugfs_add(struct link_sta_info *link_sta) {} 21 + static inline void ieee80211_link_sta_debugfs_remove(struct link_sta_info *link_sta) {} 22 + 23 + static inline void ieee80211_link_sta_debugfs_drv_add(struct link_sta_info *link_sta) {} 24 + static inline void ieee80211_link_sta_debugfs_drv_remove(struct link_sta_info *link_sta) {} 13 25 #endif 14 26 15 27 #endif /* __MAC80211_DEBUGFS_STA_H */
+26 -1
net/mac80211/driver-ops.c
··· 7 7 #include "ieee80211_i.h" 8 8 #include "trace.h" 9 9 #include "driver-ops.h" 10 + #include "debugfs_sta.h" 10 11 11 12 int drv_start(struct ieee80211_local *local) 12 13 { ··· 498 497 struct ieee80211_sta *sta, 499 498 u16 old_links, u16 new_links) 500 499 { 500 + struct sta_info *info = container_of(sta, struct sta_info, sta); 501 + struct link_sta_info *link_sta; 502 + unsigned long links_to_add; 503 + unsigned long links_to_rem; 504 + unsigned int link_id; 501 505 int ret = -EOPNOTSUPP; 502 506 503 507 might_sleep(); ··· 516 510 if (old_links == new_links) 517 511 return 0; 518 512 513 + links_to_add = ~old_links & new_links; 514 + links_to_rem = old_links & ~new_links; 515 + 516 + for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) { 517 + link_sta = rcu_dereference_protected(info->link[link_id], 518 + lockdep_is_held(&local->sta_mtx)); 519 + 520 + ieee80211_link_sta_debugfs_drv_remove(link_sta); 521 + } 522 + 519 523 trace_drv_change_sta_links(local, sdata, sta, old_links, new_links); 520 524 if (local->ops->change_sta_links) 521 525 ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta, 522 526 old_links, new_links); 523 527 trace_drv_return_int(local, ret); 524 528 525 - return ret; 529 + if (ret) 530 + return ret; 531 + 532 + for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) { 533 + link_sta = rcu_dereference_protected(info->link[link_id], 534 + lockdep_is_held(&local->sta_mtx)); 535 + ieee80211_link_sta_debugfs_drv_add(link_sta); 536 + } 537 + 538 + return 0; 526 539 }
+16
net/mac80211/driver-ops.h
··· 480 480 local->ops->sta_add_debugfs(&local->hw, &sdata->vif, 481 481 sta, dir); 482 482 } 483 + 484 + static inline void drv_link_sta_add_debugfs(struct ieee80211_local *local, 485 + struct ieee80211_sub_if_data *sdata, 486 + struct ieee80211_link_sta *link_sta, 487 + struct dentry *dir) 488 + { 489 + might_sleep(); 490 + 491 + sdata = get_bss_sdata(sdata); 492 + if (!check_sdata_in_driver(sdata)) 493 + return; 494 + 495 + if (local->ops->link_sta_add_debugfs) 496 + local->ops->link_sta_add_debugfs(&local->hw, &sdata->vif, 497 + link_sta, dir); 498 + } 483 499 #endif 484 500 485 501 static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local,
+25
net/mac80211/sta_info.c
··· 366 366 if (unhash) 367 367 link_sta_info_hash_del(sta->local, link_sta); 368 368 369 + if (test_sta_flag(sta, WLAN_STA_INSERTED)) 370 + ieee80211_link_sta_debugfs_remove(link_sta); 371 + 369 372 if (link_sta != &sta->deflink) 370 373 alloc = container_of(link_sta, typeof(*alloc), info); 371 374 ··· 878 875 879 876 ieee80211_sta_debugfs_add(sta); 880 877 rate_control_add_sta_debugfs(sta); 878 + if (sta->sta.valid_links) { 879 + int i; 880 + 881 + for (i = 0; i < ARRAY_SIZE(sta->link); i++) { 882 + struct link_sta_info *link_sta; 883 + 884 + link_sta = rcu_dereference_protected(sta->link[i], 885 + lockdep_is_held(&local->sta_mtx)); 886 + 887 + if (!link_sta) 888 + continue; 889 + 890 + ieee80211_link_sta_debugfs_add(link_sta); 891 + if (sdata->vif.active_links & BIT(i)) 892 + ieee80211_link_sta_debugfs_drv_add(link_sta); 893 + } 894 + } else { 895 + ieee80211_link_sta_debugfs_add(&sta->deflink); 896 + ieee80211_link_sta_debugfs_drv_add(&sta->deflink); 897 + } 881 898 882 899 sinfo->generation = local->sta_generation; 883 900 cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL); ··· 2846 2823 } 2847 2824 2848 2825 sta_info_add_link(sta, link_id, &alloc->info, &alloc->sta); 2826 + 2827 + ieee80211_link_sta_debugfs_add(&alloc->info); 2849 2828 2850 2829 return 0; 2851 2830 }
+5
net/mac80211/sta_info.h
··· 513 513 * @status_stats.avg_ack_signal: average ACK signal 514 514 * @cur_max_bandwidth: maximum bandwidth to use for TX to the station, 515 515 * taken from HT/VHT capabilities or VHT operating mode notification 516 + * @debugfs_dir: debug filesystem directory dentry 516 517 * @pub: public (driver visible) link STA data 517 518 * TODO Move other link params from sta_info as required for MLD operation 518 519 */ ··· 560 559 } tx_stats; 561 560 562 561 enum ieee80211_sta_rx_bandwidth cur_max_bandwidth; 562 + 563 + #ifdef CONFIG_MAC80211_DEBUGFS 564 + struct dentry *debugfs_dir; 565 + #endif 563 566 564 567 struct ieee80211_link_sta *pub; 565 568 };