From e16e606c956892bda991ffc50dedc85042ddd3ca Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Mon, 4 Jan 2021 23:47:57 +0530 Subject: [PATCH 2/2] ath11k/mac80211: Add support to account memory stats Memory allocations in the driver & mac80211 are logged and populate those values to the user space via debugfs. This stats will give the snapshot of the memory being used by the driver at the time of dumping these memory stats. Command: cat /sys/kernel/debug/ath11k/ipq8074\ hw2.0/memory_stats Sample output of the stats MEMORY STATS IN BYTES: malloc size : 6287583 ce_ring_alloc size: 109308 dma_alloc size:: 10831860 htc_skb_alloc size: 3840 wmi alloc size: 0 per peer object: 4644 rx_post_buf size: 5091840 Total size: 22329075 User can disable/enable the memory stats accounting with the below command. echo N > /sys/kernel/debug/ath11k/ipq8074\ hw2.0/enable_memory_stats where N = 0 to disable logging, 1 to enable the logging. Note: This should be enabled/disabled only after wifi is down. User shouldn't enable/disable when the wifi is up to avoid accounting the negative values which cause incorrect values in the memory stats. Command: cat /sys/kernel/debug/ieee80211/phyX/memory_stats memory stats: malloc_size: 108 Signed-off-by: Maharaja Kennadyrajan --- net/mac80211/chan.c | 12 ++++++++++++ net/mac80211/debugfs.c | 4 ++++ net/mac80211/ieee80211_i.h | 6 ++++++ net/mac80211/iface.c | 5 +++++ net/mac80211/mesh.c | 4 ++++ net/mac80211/mesh_hwmp.c | 5 +++++ net/mac80211/mesh_pathtbl.c | 12 ++++++++++++ net/mac80211/offchannel.c | 7 +++++++ net/mac80211/scan.c | 18 ++++++++++++++++++ net/mac80211/sta_info.c | 16 ++++++++++++++++ 10 files changed, 89 insertions(+) --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -631,6 +631,9 @@ ieee80211_alloc_chanctx(struct ieee80211 if (!ctx) return NULL; + atomic_add(sizeof(*ctx) + local->hw.chanctx_data_size, + &local->memory_stats.malloc_size); + INIT_LIST_HEAD(&ctx->assigned_links); INIT_LIST_HEAD(&ctx->reserved_links); ctx->conf.def = *chandef; @@ -691,6 +694,8 @@ ieee80211_new_chanctx(struct ieee80211_l err = ieee80211_add_chanctx(local, ctx); if (err) { + atomic_sub(sizeof(*ctx) + local->hw.chanctx_data_size, + &local->memory_stats.malloc_size); kfree(ctx); return ERR_PTR(err); } @@ -743,6 +748,8 @@ static void ieee80211_free_chanctx(struc list_del_rcu(&ctx->list); ieee80211_del_chanctx(local, ctx); + atomic_sub(sizeof(*ctx) + local->hw.chanctx_data_size, + &local->memory_stats.malloc_size); kfree_rcu(ctx, rcu_head); } @@ -1420,6 +1427,9 @@ static int ieee80211_chsw_switch_vifs(st if (!vif_chsw) return -ENOMEM; + atomic_add(sizeof(vif_chsw[0]) * n_vifs, + &local->memory_stats.malloc_size); + i = 0; list_for_each_entry(ctx, &local->chanctx_list, list) { if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) @@ -1449,6 +1459,8 @@ static int ieee80211_chsw_switch_vifs(st CHANCTX_SWMODE_SWAP_CONTEXTS); out: + atomic_sub(sizeof(vif_chsw[0]) * n_vifs, + &local->memory_stats.malloc_size); kfree(vif_chsw); return err; } --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -71,6 +71,8 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", local->wep_iv & 0xffffff); DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); +DEBUGFS_READONLY_FILE(memory_stats, "memory stats: malloc_size: %u", + atomic_read(&local->memory_stats.malloc_size)); static ssize_t aqm_read(struct file *file, char __user *user_buf, @@ -680,6 +682,8 @@ void debugfs_hw_add(struct ieee80211_loc if (!statsd) return; + DEBUGFS_ADD(memory_stats); + #ifdef CPTCFG_MAC80211_DEBUG_COUNTERS DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount); DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount); --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1270,6 +1270,10 @@ enum mac80211_scan_state { DECLARE_STATIC_KEY_FALSE(aql_disable); +struct mac80211_memory_stats { + atomic_t malloc_size; +}; + struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -1555,6 +1559,8 @@ struct ieee80211_local { struct ieee80211_sub_if_data __rcu *monitor_sdata; struct cfg80211_chan_def monitor_chandef; + struct mac80211_memory_stats memory_stats; + /* extended capabilities provided by mac80211 */ u8 ext_capa[8]; }; --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1365,6 +1365,9 @@ int ieee80211_add_virtual_monitor(struct return ret; } + atomic_add(sizeof(*sdata) + local->hw.vif_data_size, + &local->memory_stats.malloc_size); + skb_queue_head_init(&sdata->skb_queue); skb_queue_head_init(&sdata->status_queue); INIT_WORK(&sdata->work, ieee80211_iface_work); @@ -1402,6 +1405,8 @@ void ieee80211_del_virtual_monitor(struc drv_remove_interface(local, sdata); + atomic_sub(sizeof(*sdata) + local->hw.vif_data_size, + &local->memory_stats.malloc_size); kfree(sdata); } --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -174,6 +174,8 @@ int mesh_rmc_init(struct ieee80211_sub_i sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); if (!sdata->u.mesh.rmc) return -ENOMEM; + atomic_add(sizeof(struct mesh_rmc), + &sdata->local->memory_stats.malloc_size); sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; for (i = 0; i < RMC_BUCKETS; i++) INIT_HLIST_HEAD(&sdata->u.mesh.rmc->bucket[i]); @@ -197,6 +199,8 @@ void mesh_rmc_free(struct ieee80211_sub_ } } + atomic_sub(sizeof(struct mesh_rmc), + &sdata->local->memory_stats.malloc_size); kfree(rmc); sdata->u.mesh.rmc = NULL; } --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1006,6 +1006,9 @@ static void mesh_queue_preq(struct mesh_ return; } + atomic_add(sizeof(struct mesh_preq_queue), + &sdata->local->memory_stats.malloc_size); + memcpy(preq_node->dst, mpath->dst, ETH_ALEN); preq_node->flags = flags; @@ -1120,6 +1123,8 @@ void mesh_path_start_discovery(struct ie enddiscovery: rcu_read_unlock(); + atomic_sub(sizeof(struct mesh_preq_queue), + &sdata->local->memory_stats.malloc_size); kfree(preq_node); } --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -170,6 +170,7 @@ void ieee80211_offchannel_return(struct static void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) { + struct ieee80211_sub_if_data *sdata = roc->sdata; /* was never transmitted */ if (roc->frame) { cfg80211_mgmt_tx_status(&roc->sdata->wdev, roc->mgmt_tx_cookie, @@ -188,6 +189,8 @@ static void ieee80211_roc_notify_destroy roc->chan, GFP_KERNEL); list_del(&roc->list); + atomic_sub(sizeof(*roc), + &sdata->local->memory_stats.malloc_size); kfree(roc); } @@ -550,6 +553,8 @@ static int ieee80211_start_roc_work(stru if (!roc) return -ENOMEM; + atomic_add(sizeof(*roc), &local->memory_stats.malloc_size); + /* * If the duration is zero, then the driver * wouldn't actually do anything. Set it to @@ -595,6 +600,8 @@ static int ieee80211_start_roc_work(stru ret = drv_remain_on_channel(local, sdata, channel, duration, type); if (ret) { + atomic_sub(sizeof(*roc), + &local->memory_stats.malloc_size); kfree(roc); return ret; } --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -469,6 +469,12 @@ static void __ieee80211_scan_completed(s scan_req = rcu_dereference_protected(local->scan_req, lockdep_is_held(&local->mtx)); + atomic_sub(sizeof(*local->hw_scan_req) + + scan_req->n_channels * + sizeof(scan_req->channels[0]) + + local->hw_scan_ies_bufsize, + &local->memory_stats.malloc_size); + if (scan_req != local->int_scan_req) { local->scan_info.aborted = aborted; cfg80211_scan_done(scan_req, &local->scan_info); @@ -738,6 +744,12 @@ static int __ieee80211_start_scan(struct if (!local->hw_scan_req) return -ENOMEM; + atomic_add(sizeof(*local->hw_scan_req) + + req->n_channels * + sizeof(req->channels[0]) + + local->hw_scan_ies_bufsize, + &local->memory_stats.malloc_size); + local->hw_scan_req->req.chandef = req->chandef; local->hw_scan_req->req.ssids = req->ssids; local->hw_scan_req->req.n_ssids = req->n_ssids; @@ -829,6 +841,12 @@ static int __ieee80211_start_scan(struct } if (rc) { + atomic_sub(sizeof(*local->hw_scan_req) + + req->n_channels * + sizeof(req->channels[0]) + + local->hw_scan_ies_bufsize, + &local->memory_stats.malloc_size); + kfree(local->hw_scan_req); local->hw_scan_req = NULL; local->scanning = 0; --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -354,6 +354,7 @@ static void sta_remove_link(struct sta_i */ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { + struct ieee80211_hw *hw = &local->hw; int i; for (i = 0; i < ARRAY_SIZE(sta->link); i++) { @@ -390,9 +391,13 @@ void sta_info_free(struct ieee80211_loca kfree(to_txq_info(sta->sta.txq[0])); kfree(rcu_dereference_raw(sta->sta.rates)); #ifdef CPTCFG_MAC80211_MESH + if (sta->mesh) + atomic_sub(sizeof(*sta->mesh), + &local->memory_stats.malloc_size); kfree(sta->mesh); #endif - + atomic_sub(sizeof(*sta) + hw->sta_data_size, + &local->memory_stats.malloc_size); sta_info_free_link(&sta->deflink); kfree(sta); } @@ -493,6 +498,9 @@ __sta_info_alloc(struct ieee80211_sub_if sta->local = local; sta->sdata = sdata; + atomic_add(sizeof(*sta) + hw->sta_data_size, + &local->memory_stats.malloc_size); + if (sta_info_alloc_link(local, &sta->deflink, gfp)) return NULL; @@ -514,6 +522,8 @@ __sta_info_alloc(struct ieee80211_sub_if sta->mesh = kzalloc(sizeof(*sta->mesh), gfp); if (!sta->mesh) goto free; + atomic_add(sizeof(*sta->mesh), + &local->memory_stats.malloc_size); sta->mesh->plink_sta = sta; spin_lock_init(&sta->mesh->plink_lock); if (!sdata->u.mesh.user_mpm) @@ -645,8 +655,12 @@ free_txq: free: sta_info_free_link(&sta->deflink); #ifdef CPTCFG_MAC80211_MESH + atomic_sub(sizeof(*sta->mesh), + &local->memory_stats.malloc_size); kfree(sta->mesh); #endif + atomic_sub(sizeof(*sta) + hw->sta_data_size, + &local->memory_stats.malloc_size); kfree(sta); return NULL; }