Commit d2caad52 authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg
Browse files

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: default avatarBenjamin Berg <benjamin.berg@intel.com>
[add missing inlines if !CONFIG_MAC80211_DEBUGFS]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 1d9e4c91
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -3790,6 +3790,13 @@ struct ieee80211_prep_tx_info {
 *	should be within a CONFIG_MAC80211_DEBUGFS conditional. This
 *	callback can sleep.
 *
 * @link_sta_add_debugfs: Drivers can use this callback to add debugfs files
 *	when a link is added to a mac80211 station. This callback
 *	should be within a CPTCFG_MAC80211_DEBUGFS conditional. This
 *	callback can sleep.
 *	For non-MLO the callback will be called once for the deflink with the
 *	station's directory rather than a separate subdirectory.
 *
 * @sta_notify: Notifies low level driver about power state transition of an
 *	associated station, AP,  IBSS/WDS/mesh peer etc. For a VIF operating
 *	in AP mode, this callback will not be called when the flag
@@ -4260,6 +4267,10 @@ struct ieee80211_ops {
				struct ieee80211_vif *vif,
				struct ieee80211_sta *sta,
				struct dentry *dir);
	void (*link_sta_add_debugfs)(struct ieee80211_hw *hw,
				     struct ieee80211_vif *vif,
				     struct ieee80211_link_sta *link_sta,
				     struct dentry *dir);
#endif
	void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			enum sta_notify_cmd, struct ieee80211_sta *sta);
+105 −22
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
 * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
 * Copyright 2013-2014  Intel Mobile Communications GmbH
 * Copyright(c) 2016 Intel Deutschland GmbH
 * Copyright (C) 2018 - 2021 Intel Corporation
 * Copyright (C) 2018 - 2022 Intel Corporation
 */

#include <linux/debugfs.h>
@@ -435,7 +435,15 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
}
STA_OPS_RW(agg_status);

static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
/* link sta attributes */
#define LINK_STA_OPS(name)						\
static const struct file_operations link_sta_ ##name## _ops = {		\
	.read = link_sta_##name##_read,					\
	.open = simple_open,						\
	.llseek = generic_file_llseek,					\
}

static ssize_t link_sta_ht_capa_read(struct file *file, char __user *userbuf,
				     size_t count, loff_t *ppos)
{
#define PRINT_HT_CAP(_cond, _str) \
@@ -446,8 +454,8 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
	char *buf, *p;
	int i;
	ssize_t bufsz = 512;
	struct sta_info *sta = file->private_data;
	struct ieee80211_sta_ht_cap *htc = &sta->sta.deflink.ht_cap;
	struct link_sta_info *link_sta = file->private_data;
	struct ieee80211_sta_ht_cap *htc = &link_sta->pub->ht_cap;
	ssize_t ret;

	buf = kzalloc(bufsz, GFP_KERNEL);
@@ -524,14 +532,14 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
	kfree(buf);
	return ret;
}
STA_OPS(ht_capa);
LINK_STA_OPS(ht_capa);

static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
static ssize_t link_sta_vht_capa_read(struct file *file, char __user *userbuf,
				      size_t count, loff_t *ppos)
{
	char *buf, *p;
	struct sta_info *sta = file->private_data;
	struct ieee80211_sta_vht_cap *vhtc = &sta->sta.deflink.vht_cap;
	struct link_sta_info *link_sta = file->private_data;
	struct ieee80211_sta_vht_cap *vhtc = &link_sta->pub->vht_cap;
	ssize_t ret;
	ssize_t bufsz = 512;

@@ -638,15 +646,15 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
	kfree(buf);
	return ret;
}
STA_OPS(vht_capa);
LINK_STA_OPS(vht_capa);

static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf,
static ssize_t link_sta_he_capa_read(struct file *file, char __user *userbuf,
				     size_t count, loff_t *ppos)
{
	char *buf, *p;
	size_t buf_sz = PAGE_SIZE;
	struct sta_info *sta = file->private_data;
	struct ieee80211_sta_he_cap *hec = &sta->sta.deflink.he_cap;
	struct link_sta_info *link_sta = file->private_data;
	struct ieee80211_sta_he_cap *hec = &link_sta->pub->he_cap;
	struct ieee80211_he_mcs_nss_supp *nss = &hec->he_mcs_nss_supp;
	u8 ppe_size;
	u8 *cap;
@@ -1011,7 +1019,7 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf,
	kfree(buf);
	return ret;
}
STA_OPS(he_capa);
LINK_STA_OPS(he_capa);

#define DEBUGFS_ADD(name) \
	debugfs_create_file(#name, 0400, \
@@ -1048,12 +1056,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
	DEBUGFS_ADD(num_ps_buf_frames);
	DEBUGFS_ADD(last_seq_ctrl);
	DEBUGFS_ADD(agg_status);
	DEBUGFS_ADD(ht_capa);
	DEBUGFS_ADD(vht_capa);
	DEBUGFS_ADD(he_capa);

	DEBUGFS_ADD_COUNTER(rx_duplicates, deflink.rx_stats.num_duplicates);
	DEBUGFS_ADD_COUNTER(rx_fragments, deflink.rx_stats.fragments);
	/* FIXME: Kept here as the statistics are only done on the deflink */
	DEBUGFS_ADD_COUNTER(tx_filtered, deflink.status_stats.filtered);

	if (local->ops->wake_tx_queue) {
@@ -1076,3 +1079,83 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta)
	debugfs_remove_recursive(sta->debugfs_dir);
	sta->debugfs_dir = NULL;
}

#undef DEBUGFS_ADD
#undef DEBUGFS_ADD_COUNTER

#define DEBUGFS_ADD(name) \
	debugfs_create_file(#name, 0400, \
		link_sta->debugfs_dir, link_sta, &link_sta_ ##name## _ops)
#define DEBUGFS_ADD_COUNTER(name, field)				\
	debugfs_create_ulong(#name, 0400, link_sta->debugfs_dir, &link_sta->field)

void ieee80211_link_sta_debugfs_add(struct link_sta_info *link_sta)
{
	if (WARN_ON(!link_sta->sta->debugfs_dir))
		return;

	/* For non-MLO, leave the files in the main directory. */
	if (link_sta->sta->sta.valid_links) {
		char link_dir_name[10];

		snprintf(link_dir_name, sizeof(link_dir_name),
			 "link-%d", link_sta->link_id);

		link_sta->debugfs_dir =
			debugfs_create_dir(link_dir_name,
					   link_sta->sta->debugfs_dir);
	} else {
		if (WARN_ON(link_sta != &link_sta->sta->deflink))
			return;

		link_sta->debugfs_dir = link_sta->sta->debugfs_dir;
	}

	DEBUGFS_ADD(ht_capa);
	DEBUGFS_ADD(vht_capa);
	DEBUGFS_ADD(he_capa);

	DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates);
	DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
}

void ieee80211_link_sta_debugfs_remove(struct link_sta_info *link_sta)
{
	if (!link_sta->debugfs_dir || !link_sta->sta->debugfs_dir) {
		link_sta->debugfs_dir = NULL;
		return;
	}

	if (link_sta->debugfs_dir == link_sta->sta->debugfs_dir) {
		WARN_ON(link_sta != &link_sta->sta->deflink);
		link_sta->sta->debugfs_dir = NULL;
		return;
	}

	debugfs_remove_recursive(link_sta->debugfs_dir);
	link_sta->debugfs_dir = NULL;
}

void ieee80211_link_sta_debugfs_drv_add(struct link_sta_info *link_sta)
{
	if (WARN_ON(!link_sta->debugfs_dir))
		return;

	drv_link_sta_add_debugfs(link_sta->sta->local, link_sta->sta->sdata,
				 link_sta->pub, link_sta->debugfs_dir);
}

void ieee80211_link_sta_debugfs_drv_remove(struct link_sta_info *link_sta)
{
	if (!link_sta->debugfs_dir)
		return;

	if (WARN_ON(link_sta->debugfs_dir == link_sta->sta->debugfs_dir))
		return;

	/* Recreate the directory excluding the driver data */
	debugfs_remove_recursive(link_sta->debugfs_dir);
	link_sta->debugfs_dir = NULL;

	ieee80211_link_sta_debugfs_add(link_sta);
}
+12 −0
Original line number Diff line number Diff line
@@ -7,9 +7,21 @@
#ifdef CONFIG_MAC80211_DEBUGFS
void ieee80211_sta_debugfs_add(struct sta_info *sta);
void ieee80211_sta_debugfs_remove(struct sta_info *sta);

void ieee80211_link_sta_debugfs_add(struct link_sta_info *link_sta);
void ieee80211_link_sta_debugfs_remove(struct link_sta_info *link_sta);

void ieee80211_link_sta_debugfs_drv_add(struct link_sta_info *link_sta);
void ieee80211_link_sta_debugfs_drv_remove(struct link_sta_info *link_sta);
#else
static inline void ieee80211_sta_debugfs_add(struct sta_info *sta) {}
static inline void ieee80211_sta_debugfs_remove(struct sta_info *sta) {}

static inline void ieee80211_link_sta_debugfs_add(struct link_sta_info *link_sta) {}
static inline void ieee80211_link_sta_debugfs_remove(struct link_sta_info *link_sta) {}

static inline void ieee80211_link_sta_debugfs_drv_add(struct link_sta_info *link_sta) {}
static inline void ieee80211_link_sta_debugfs_drv_remove(struct link_sta_info *link_sta) {}
#endif

#endif /* __MAC80211_DEBUGFS_STA_H */
+26 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include "ieee80211_i.h"
#include "trace.h"
#include "driver-ops.h"
#include "debugfs_sta.h"

int drv_start(struct ieee80211_local *local)
{
@@ -497,6 +498,11 @@ int drv_change_sta_links(struct ieee80211_local *local,
			 struct ieee80211_sta *sta,
			 u16 old_links, u16 new_links)
{
	struct sta_info *info = container_of(sta, struct sta_info, sta);
	struct link_sta_info *link_sta;
	unsigned long links_to_add;
	unsigned long links_to_rem;
	unsigned int link_id;
	int ret = -EOPNOTSUPP;

	might_sleep();
@@ -510,11 +516,30 @@ int drv_change_sta_links(struct ieee80211_local *local,
	if (old_links == new_links)
		return 0;

	links_to_add = ~old_links & new_links;
	links_to_rem = old_links & ~new_links;

	for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) {
		link_sta = rcu_dereference_protected(info->link[link_id],
						     lockdep_is_held(&local->sta_mtx));

		ieee80211_link_sta_debugfs_drv_remove(link_sta);
	}

	trace_drv_change_sta_links(local, sdata, sta, old_links, new_links);
	if (local->ops->change_sta_links)
		ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta,
						   old_links, new_links);
	trace_drv_return_int(local, ret);

	if (ret)
		return ret;

	for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
		link_sta = rcu_dereference_protected(info->link[link_id],
						     lockdep_is_held(&local->sta_mtx));
		ieee80211_link_sta_debugfs_drv_add(link_sta);
	}

	return 0;
}
+16 −0
Original line number Diff line number Diff line
@@ -480,6 +480,22 @@ static inline void drv_sta_add_debugfs(struct ieee80211_local *local,
		local->ops->sta_add_debugfs(&local->hw, &sdata->vif,
					    sta, dir);
}

static inline void drv_link_sta_add_debugfs(struct ieee80211_local *local,
					    struct ieee80211_sub_if_data *sdata,
					    struct ieee80211_link_sta *link_sta,
					    struct dentry *dir)
{
	might_sleep();

	sdata = get_bss_sdata(sdata);
	if (!check_sdata_in_driver(sdata))
		return;

	if (local->ops->link_sta_add_debugfs)
		local->ops->link_sta_add_debugfs(&local->hw, &sdata->vif,
						 link_sta, dir);
}
#endif

static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local,
Loading