Skip to content

Commit

Permalink
wifi: ath12k: Add Support to Parse TPC Event from Firmware
Browse files Browse the repository at this point in the history
Host receives four Transmit Power Control(TPC) events from firmware on
sending TPC request. Fixed param TLV is present as part of all event to
indicate the event count and end of event. TPC config parameters along
with regulatory power array comes as first event. Rates array comes as
second and third event as it cannot be packed in single event.
Conformance Test Limit (CTL) power array comes as the fourth event.
Firmware packs different sets of array params which includes array
length and type inside master TLV as different subtlvs. And the actual
content of array is packed one after the other inside a separate TLV as
single buffer.

Parse various events and save it in local structures. Create tpc_stats
file using debugfs to store these local structures. Create function to
handle TPC stats read to relay the information to the user.

Command usage:
cat > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/tpc_stats

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1

Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
Co-developed-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
Signed-off-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
Co-developed-by: Roopni Devanathan <quic_rdevanat@quicinc.com>
Signed-off-by: Roopni Devanathan <quic_rdevanat@quicinc.com>
Reviewed-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
Link: https://patch.msgid.link/20250130061104.962124-2-quic_rdevanat@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
  • Loading branch information
Sowmiya Sree Elavalagan authored and Jeff Johnson committed Feb 4, 2025
1 parent 7a3e8ee commit f0c3bb7
Show file tree
Hide file tree
Showing 5 changed files with 696 additions and 0 deletions.
4 changes: 4 additions & 0 deletions drivers/net/wireless/ath/ath12k/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,10 @@ struct ath12k_debug {
struct dentry *debugfs_pdev;
struct dentry *debugfs_pdev_symlink;
struct ath12k_dbg_htt_stats htt_stats;
enum wmi_halphy_ctrl_path_stats_id tpc_stats_type;
bool tpc_request;
struct completion tpc_complete;
struct wmi_tpc_stats_arg *tpc_stats;
};

struct ath12k_per_peer_tx_stats {
Expand Down
96 changes: 96 additions & 0 deletions drivers/net/wireless/ath/ath12k/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,99 @@ static const struct file_operations fops_simulate_radar = {
.open = simple_open
};

static int ath12k_debug_tpc_stats_request(struct ath12k *ar)
{
enum wmi_halphy_ctrl_path_stats_id tpc_stats_sub_id;
struct ath12k_base *ab = ar->ab;
int ret;

lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);

reinit_completion(&ar->debug.tpc_complete);

spin_lock_bh(&ar->data_lock);
ar->debug.tpc_request = true;
tpc_stats_sub_id = ar->debug.tpc_stats_type;
spin_unlock_bh(&ar->data_lock);

ret = ath12k_wmi_send_tpc_stats_request(ar, tpc_stats_sub_id);
if (ret) {
ath12k_warn(ab, "failed to request pdev tpc stats: %d\n", ret);
spin_lock_bh(&ar->data_lock);
ar->debug.tpc_request = false;
spin_unlock_bh(&ar->data_lock);
return ret;
}

return 0;
}

static int ath12k_open_tpc_stats(struct inode *inode, struct file *file)
{
struct ath12k *ar = inode->i_private;
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
int ret;

guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);

if (ah->state != ATH12K_HW_STATE_ON) {
ath12k_warn(ar->ab, "Interface not up\n");
return -ENETDOWN;
}

void *buf __free(kfree) = kzalloc(ATH12K_TPC_STATS_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;

ret = ath12k_debug_tpc_stats_request(ar);
if (ret) {
ath12k_warn(ar->ab, "failed to request tpc stats: %d\n",
ret);
return ret;
}

if (!wait_for_completion_timeout(&ar->debug.tpc_complete, TPC_STATS_WAIT_TIME)) {
spin_lock_bh(&ar->data_lock);
ath12k_wmi_free_tpc_stats_mem(ar);
ar->debug.tpc_request = false;
spin_unlock_bh(&ar->data_lock);
return -ETIMEDOUT;
}

file->private_data = no_free_ptr(buf);

spin_lock_bh(&ar->data_lock);
ath12k_wmi_free_tpc_stats_mem(ar);
spin_unlock_bh(&ar->data_lock);

return 0;
}

static ssize_t ath12k_read_tpc_stats(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
const char *buf = file->private_data;
size_t len = strlen(buf);

return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static int ath12k_release_tpc_stats(struct inode *inode,
struct file *file)
{
kfree(file->private_data);
return 0;
}

static const struct file_operations fops_tpc_stats = {
.open = ath12k_open_tpc_stats,
.release = ath12k_release_tpc_stats,
.read = ath12k_read_tpc_stats,
.owner = THIS_MODULE,
.llseek = default_llseek,
};

void ath12k_debugfs_soc_create(struct ath12k_base *ab)
{
bool dput_needed;
Expand Down Expand Up @@ -468,6 +561,9 @@ void ath12k_debugfs_register(struct ath12k *ar)
&fops_simulate_radar);
}

debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_pdev, ar,
&fops_tpc_stats);

ath12k_debugfs_htt_stats_register(ar);
ath12k_debugfs_fw_stats_register(ar);
}
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/ath/ath12k/debugfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ void ath12k_debugfs_unregister(struct ath12k *ar);
void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
struct ath12k_fw_stats *stats);
void ath12k_debugfs_fw_stats_reset(struct ath12k *ar);

#define TPC_STATS_WAIT_TIME (1 * HZ)
#define TPC_STATS_TOT_ROW 700
#define TPC_STATS_TOT_COLUMN 100
#define ATH12K_TPC_STATS_BUF_SIZE (TPC_STATS_TOT_ROW * TPC_STATS_TOT_COLUMN)

#else
static inline void ath12k_debugfs_soc_create(struct ath12k_base *ab)
{
Expand Down
Loading

0 comments on commit f0c3bb7

Please sign in to comment.