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 ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, 22 char __user *user_buf, 23 size_t count, loff_t *ppos) 24{ 25 struct ieee80211_sta *sta = file->private_data; 26 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 27 struct ath10k *ar = arsta->arvif->ar; 28 char buf[32]; 29 int len = 0; 30 31 mutex_lock(&ar->conf_mutex); 32 len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n", 33 (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ? 34 "auto" : "manual"); 35 mutex_unlock(&ar->conf_mutex); 36 37 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 38} 39 40static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file, 41 const char __user *user_buf, 42 size_t count, loff_t *ppos) 43{ 44 struct ieee80211_sta *sta = file->private_data; 45 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 46 struct ath10k *ar = arsta->arvif->ar; 47 u32 aggr_mode; 48 int ret; 49 50 if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) 51 return -EINVAL; 52 53 if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX) 54 return -EINVAL; 55 56 mutex_lock(&ar->conf_mutex); 57 if ((ar->state != ATH10K_STATE_ON) || 58 (aggr_mode == arsta->aggr_mode)) { 59 ret = count; 60 goto out; 61 } 62 63 ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); 64 if (ret) { 65 ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret); 66 goto out; 67 } 68 69 arsta->aggr_mode = aggr_mode; 70out: 71 mutex_unlock(&ar->conf_mutex); 72 return ret; 73} 74 75static const struct file_operations fops_aggr_mode = { 76 .read = ath10k_dbg_sta_read_aggr_mode, 77 .write = ath10k_dbg_sta_write_aggr_mode, 78 .open = simple_open, 79 .owner = THIS_MODULE, 80 .llseek = default_llseek, 81}; 82 83static ssize_t ath10k_dbg_sta_write_addba(struct file *file, 84 const char __user *user_buf, 85 size_t count, loff_t *ppos) 86{ 87 struct ieee80211_sta *sta = file->private_data; 88 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 89 struct ath10k *ar = arsta->arvif->ar; 90 u32 tid, buf_size; 91 int ret; 92 char buf[64]; 93 94 simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); 95 96 /* make sure that buf is null terminated */ 97 buf[sizeof(buf) - 1] = '\0'; 98 99 ret = sscanf(buf, "%u %u", &tid, &buf_size); 100 if (ret != 2) 101 return -EINVAL; 102 103 /* Valid TID values are 0 through 15 */ 104 if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 105 return -EINVAL; 106 107 mutex_lock(&ar->conf_mutex); 108 if ((ar->state != ATH10K_STATE_ON) || 109 (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 110 ret = count; 111 goto out; 112 } 113 114 ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, 115 tid, buf_size); 116 if (ret) { 117 ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", 118 arsta->arvif->vdev_id, sta->addr, tid, buf_size); 119 } 120 121 ret = count; 122out: 123 mutex_unlock(&ar->conf_mutex); 124 return ret; 125} 126 127static const struct file_operations fops_addba = { 128 .write = ath10k_dbg_sta_write_addba, 129 .open = simple_open, 130 .owner = THIS_MODULE, 131 .llseek = default_llseek, 132}; 133 134static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, 135 const char __user *user_buf, 136 size_t count, loff_t *ppos) 137{ 138 struct ieee80211_sta *sta = file->private_data; 139 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 140 struct ath10k *ar = arsta->arvif->ar; 141 u32 tid, status; 142 int ret; 143 char buf[64]; 144 145 simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); 146 147 /* make sure that buf is null terminated */ 148 buf[sizeof(buf) - 1] = '\0'; 149 150 ret = sscanf(buf, "%u %u", &tid, &status); 151 if (ret != 2) 152 return -EINVAL; 153 154 /* Valid TID values are 0 through 15 */ 155 if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 156 return -EINVAL; 157 158 mutex_lock(&ar->conf_mutex); 159 if ((ar->state != ATH10K_STATE_ON) || 160 (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 161 ret = count; 162 goto out; 163 } 164 165 ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, 166 tid, status); 167 if (ret) { 168 ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", 169 arsta->arvif->vdev_id, sta->addr, tid, status); 170 } 171 ret = count; 172out: 173 mutex_unlock(&ar->conf_mutex); 174 return ret; 175} 176 177static const struct file_operations fops_addba_resp = { 178 .write = ath10k_dbg_sta_write_addba_resp, 179 .open = simple_open, 180 .owner = THIS_MODULE, 181 .llseek = default_llseek, 182}; 183 184static ssize_t ath10k_dbg_sta_write_delba(struct file *file, 185 const char __user *user_buf, 186 size_t count, loff_t *ppos) 187{ 188 struct ieee80211_sta *sta = file->private_data; 189 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 190 struct ath10k *ar = arsta->arvif->ar; 191 u32 tid, initiator, reason; 192 int ret; 193 char buf[64]; 194 195 simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); 196 197 /* make sure that buf is null terminated */ 198 buf[sizeof(buf) - 1] = '\0'; 199 200 ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); 201 if (ret != 3) 202 return -EINVAL; 203 204 /* Valid TID values are 0 through 15 */ 205 if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 206 return -EINVAL; 207 208 mutex_lock(&ar->conf_mutex); 209 if ((ar->state != ATH10K_STATE_ON) || 210 (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 211 ret = count; 212 goto out; 213 } 214 215 ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, 216 tid, initiator, reason); 217 if (ret) { 218 ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", 219 arsta->arvif->vdev_id, sta->addr, tid, initiator, 220 reason); 221 } 222 ret = count; 223out: 224 mutex_unlock(&ar->conf_mutex); 225 return ret; 226} 227 228static const struct file_operations fops_delba = { 229 .write = ath10k_dbg_sta_write_delba, 230 .open = simple_open, 231 .owner = THIS_MODULE, 232 .llseek = default_llseek, 233}; 234 235void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 236 struct ieee80211_sta *sta, struct dentry *dir) 237{ 238 debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta, 239 &fops_aggr_mode); 240 debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); 241 debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); 242 debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba); 243} 244