linux/drivers/net/wireless/ath/ath10k/debugfs_sta.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include "core.h"
  18#include "wmi-ops.h"
  19#include "debug.h"
  20
  21static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
  22                                                     struct ath10k_fw_stats *stats)
  23{
  24        struct ath10k_fw_extd_stats_peer *peer;
  25        struct ieee80211_sta *sta;
  26        struct ath10k_sta *arsta;
  27
  28        rcu_read_lock();
  29        list_for_each_entry(peer, &stats->peers_extd, list) {
  30                sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
  31                                                   NULL);
  32                if (!sta)
  33                        continue;
  34                arsta = (struct ath10k_sta *)sta->drv_priv;
  35                arsta->rx_duration += (u64)peer->rx_duration;
  36        }
  37        rcu_read_unlock();
  38}
  39
  40static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
  41                                                struct ath10k_fw_stats *stats)
  42{
  43        struct ath10k_fw_stats_peer *peer;
  44        struct ieee80211_sta *sta;
  45        struct ath10k_sta *arsta;
  46
  47        rcu_read_lock();
  48        list_for_each_entry(peer, &stats->peers, list) {
  49                sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
  50                                                   NULL);
  51                if (!sta)
  52                        continue;
  53                arsta = (struct ath10k_sta *)sta->drv_priv;
  54                arsta->rx_duration += (u64)peer->rx_duration;
  55        }
  56        rcu_read_unlock();
  57}
  58
  59void ath10k_sta_update_rx_duration(struct ath10k *ar,
  60                                   struct ath10k_fw_stats *stats)
  61{
  62        if (stats->extended)
  63                ath10k_sta_update_extd_stats_rx_duration(ar, stats);
  64        else
  65                ath10k_sta_update_stats_rx_duration(ar, stats);
  66}
  67
  68void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  69                           struct ieee80211_sta *sta,
  70                           struct station_info *sinfo)
  71{
  72        struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
  73        struct ath10k *ar = arsta->arvif->ar;
  74
  75        if (!ath10k_peer_stats_enabled(ar))
  76                return;
  77
  78        sinfo->rx_duration = arsta->rx_duration;
  79        sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
  80}
  81
  82static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
  83                                             char __user *user_buf,
  84                                             size_t count, loff_t *ppos)
  85{
  86        struct ieee80211_sta *sta = file->private_data;
  87        struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
  88        struct ath10k *ar = arsta->arvif->ar;
  89        char buf[32];
  90        int len = 0;
  91
  92        mutex_lock(&ar->conf_mutex);
  93        len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
  94                        (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
  95                        "auto" : "manual");
  96        mutex_unlock(&ar->conf_mutex);
  97
  98        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  99}
 100
 101static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
 102                                              const char __user *user_buf,
 103                                              size_t count, loff_t *ppos)
 104{
 105        struct ieee80211_sta *sta = file->private_data;
 106        struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
 107        struct ath10k *ar = arsta->arvif->ar;
 108        u32 aggr_mode;
 109        int ret;
 110
 111        if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
 112                return -EINVAL;
 113
 114        if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
 115                return -EINVAL;
 116
 117        mutex_lock(&ar->conf_mutex);
 118        if ((ar->state != ATH10K_STATE_ON) ||
 119            (aggr_mode == arsta->aggr_mode)) {
 120                ret = count;
 121                goto out;
 122        }
 123
 124        ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
 125        if (ret) {
 126                ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
 127                goto out;
 128        }
 129
 130        arsta->aggr_mode = aggr_mode;
 131out:
 132        mutex_unlock(&ar->conf_mutex);
 133        return ret;
 134}
 135
 136static const struct file_operations fops_aggr_mode = {
 137        .read = ath10k_dbg_sta_read_aggr_mode,
 138        .write = ath10k_dbg_sta_write_aggr_mode,
 139        .open = simple_open,
 140        .owner = THIS_MODULE,
 141        .llseek = default_llseek,
 142};
 143
 144static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
 145                                          const char __user *user_buf,
 146                                          size_t count, loff_t *ppos)
 147{
 148        struct ieee80211_sta *sta = file->private_data;
 149        struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
 150        struct ath10k *ar = arsta->arvif->ar;
 151        u32 tid, buf_size;
 152        int ret;
 153        char buf[64];
 154
 155        simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
 156
 157        /* make sure that buf is null terminated */
 158        buf[sizeof(buf) - 1] = '\0';
 159
 160        ret = sscanf(buf, "%u %u", &tid, &buf_size);
 161        if (ret != 2)
 162                return -EINVAL;
 163
 164        /* Valid TID values are 0 through 15 */
 165        if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
 166                return -EINVAL;
 167
 168        mutex_lock(&ar->conf_mutex);
 169        if ((ar->state != ATH10K_STATE_ON) ||
 170            (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
 171                ret = count;
 172                goto out;
 173        }
 174
 175        ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
 176                                    tid, buf_size);
 177        if (ret) {
 178                ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
 179                            arsta->arvif->vdev_id, sta->addr, tid, buf_size);
 180        }
 181
 182        ret = count;
 183out:
 184        mutex_unlock(&ar->conf_mutex);
 185        return ret;
 186}
 187
 188static const struct file_operations fops_addba = {
 189        .write = ath10k_dbg_sta_write_addba,
 190        .open = simple_open,
 191        .owner = THIS_MODULE,
 192        .llseek = default_llseek,
 193};
 194
 195static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
 196                                               const char __user *user_buf,
 197                                               size_t count, loff_t *ppos)
 198{
 199        struct ieee80211_sta *sta = file->private_data;
 200        struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
 201        struct ath10k *ar = arsta->arvif->ar;
 202        u32 tid, status;
 203        int ret;
 204        char buf[64];
 205
 206        simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
 207
 208        /* make sure that buf is null terminated */
 209        buf[sizeof(buf) - 1] = '\0';
 210
 211        ret = sscanf(buf, "%u %u", &tid, &status);
 212        if (ret != 2)
 213                return -EINVAL;
 214
 215        /* Valid TID values are 0 through 15 */
 216        if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
 217                return -EINVAL;
 218
 219        mutex_lock(&ar->conf_mutex);
 220        if ((ar->state != ATH10K_STATE_ON) ||
 221            (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
 222                ret = count;
 223                goto out;
 224        }
 225
 226        ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
 227                                        tid, status);
 228        if (ret) {
 229                ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
 230                            arsta->arvif->vdev_id, sta->addr, tid, status);
 231        }
 232        ret = count;
 233out:
 234        mutex_unlock(&ar->conf_mutex);
 235        return ret;
 236}
 237
 238static const struct file_operations fops_addba_resp = {
 239        .write = ath10k_dbg_sta_write_addba_resp,
 240        .open = simple_open,
 241        .owner = THIS_MODULE,
 242        .llseek = default_llseek,
 243};
 244
 245static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
 246                                          const char __user *user_buf,
 247                                          size_t count, loff_t *ppos)
 248{
 249        struct ieee80211_sta *sta = file->private_data;
 250        struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
 251        struct ath10k *ar = arsta->arvif->ar;
 252        u32 tid, initiator, reason;
 253        int ret;
 254        char buf[64];
 255
 256        simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
 257
 258        /* make sure that buf is null terminated */
 259        buf[sizeof(buf) - 1] = '\0';
 260
 261        ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
 262        if (ret != 3)
 263                return -EINVAL;
 264
 265        /* Valid TID values are 0 through 15 */
 266        if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
 267                return -EINVAL;
 268
 269        mutex_lock(&ar->conf_mutex);
 270        if ((ar->state != ATH10K_STATE_ON) ||
 271            (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
 272                ret = count;
 273                goto out;
 274        }
 275
 276        ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
 277                                    tid, initiator, reason);
 278        if (ret) {
 279                ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
 280                            arsta->arvif->vdev_id, sta->addr, tid, initiator,
 281                            reason);
 282        }
 283        ret = count;
 284out:
 285        mutex_unlock(&ar->conf_mutex);
 286        return ret;
 287}
 288
 289static const struct file_operations fops_delba = {
 290        .write = ath10k_dbg_sta_write_delba,
 291        .open = simple_open,
 292        .owner = THIS_MODULE,
 293        .llseek = default_llseek,
 294};
 295
 296void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 297                            struct ieee80211_sta *sta, struct dentry *dir)
 298{
 299        debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta,
 300                            &fops_aggr_mode);
 301        debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
 302        debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
 303        debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
 304}
 305