.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * mac80211 debugfs for wireless PHYs |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> |
---|
5 | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
---|
6 | | - * |
---|
7 | | - * GPLv2 |
---|
8 | | - * |
---|
| 7 | + * Copyright (C) 2018 - 2019 Intel Corporation |
---|
9 | 8 | */ |
---|
10 | 9 | |
---|
11 | 10 | #include <linux/debugfs.h> |
---|
.. | .. |
---|
60 | 59 | debugfs_create_file(#name, mode, phyd, local, &name## _ops); |
---|
61 | 60 | |
---|
62 | 61 | |
---|
| 62 | +DEBUGFS_READONLY_FILE(hw_conf, "%x", |
---|
| 63 | + local->hw.conf.flags); |
---|
63 | 64 | DEBUGFS_READONLY_FILE(user_power, "%d", |
---|
64 | 65 | local->user_power_level); |
---|
65 | 66 | DEBUGFS_READONLY_FILE(power, "%d", |
---|
.. | .. |
---|
119 | 120 | { |
---|
120 | 121 | struct ieee80211_local *local = file->private_data; |
---|
121 | 122 | char buf[100]; |
---|
122 | | - size_t len; |
---|
123 | 123 | |
---|
124 | | - if (count > sizeof(buf)) |
---|
| 124 | + if (count >= sizeof(buf)) |
---|
125 | 125 | return -EINVAL; |
---|
126 | 126 | |
---|
127 | 127 | if (copy_from_user(buf, user_buf, count)) |
---|
128 | 128 | return -EFAULT; |
---|
129 | 129 | |
---|
130 | | - buf[sizeof(buf) - 1] = '\0'; |
---|
131 | | - len = strlen(buf); |
---|
132 | | - if (len > 0 && buf[len-1] == '\n') |
---|
133 | | - buf[len-1] = 0; |
---|
| 130 | + if (count && buf[count - 1] == '\n') |
---|
| 131 | + buf[count - 1] = '\0'; |
---|
| 132 | + else |
---|
| 133 | + buf[count] = '\0'; |
---|
134 | 134 | |
---|
135 | 135 | if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1) |
---|
136 | 136 | return count; |
---|
.. | .. |
---|
145 | 145 | static const struct file_operations aqm_ops = { |
---|
146 | 146 | .write = aqm_write, |
---|
147 | 147 | .read = aqm_read, |
---|
| 148 | + .open = simple_open, |
---|
| 149 | + .llseek = default_llseek, |
---|
| 150 | +}; |
---|
| 151 | + |
---|
| 152 | +static ssize_t airtime_flags_read(struct file *file, |
---|
| 153 | + char __user *user_buf, |
---|
| 154 | + size_t count, loff_t *ppos) |
---|
| 155 | +{ |
---|
| 156 | + struct ieee80211_local *local = file->private_data; |
---|
| 157 | + char buf[128] = {}, *pos, *end; |
---|
| 158 | + |
---|
| 159 | + pos = buf; |
---|
| 160 | + end = pos + sizeof(buf) - 1; |
---|
| 161 | + |
---|
| 162 | + if (local->airtime_flags & AIRTIME_USE_TX) |
---|
| 163 | + pos += scnprintf(pos, end - pos, "AIRTIME_TX\t(%lx)\n", |
---|
| 164 | + AIRTIME_USE_TX); |
---|
| 165 | + if (local->airtime_flags & AIRTIME_USE_RX) |
---|
| 166 | + pos += scnprintf(pos, end - pos, "AIRTIME_RX\t(%lx)\n", |
---|
| 167 | + AIRTIME_USE_RX); |
---|
| 168 | + |
---|
| 169 | + return simple_read_from_buffer(user_buf, count, ppos, buf, |
---|
| 170 | + strlen(buf)); |
---|
| 171 | +} |
---|
| 172 | + |
---|
| 173 | +static ssize_t airtime_flags_write(struct file *file, |
---|
| 174 | + const char __user *user_buf, |
---|
| 175 | + size_t count, loff_t *ppos) |
---|
| 176 | +{ |
---|
| 177 | + struct ieee80211_local *local = file->private_data; |
---|
| 178 | + char buf[16]; |
---|
| 179 | + |
---|
| 180 | + if (count >= sizeof(buf)) |
---|
| 181 | + return -EINVAL; |
---|
| 182 | + |
---|
| 183 | + if (copy_from_user(buf, user_buf, count)) |
---|
| 184 | + return -EFAULT; |
---|
| 185 | + |
---|
| 186 | + if (count && buf[count - 1] == '\n') |
---|
| 187 | + buf[count - 1] = '\0'; |
---|
| 188 | + else |
---|
| 189 | + buf[count] = '\0'; |
---|
| 190 | + |
---|
| 191 | + if (kstrtou16(buf, 0, &local->airtime_flags)) |
---|
| 192 | + return -EINVAL; |
---|
| 193 | + |
---|
| 194 | + return count; |
---|
| 195 | +} |
---|
| 196 | + |
---|
| 197 | +static const struct file_operations airtime_flags_ops = { |
---|
| 198 | + .write = airtime_flags_write, |
---|
| 199 | + .read = airtime_flags_read, |
---|
| 200 | + .open = simple_open, |
---|
| 201 | + .llseek = default_llseek, |
---|
| 202 | +}; |
---|
| 203 | + |
---|
| 204 | +static ssize_t aql_txq_limit_read(struct file *file, |
---|
| 205 | + char __user *user_buf, |
---|
| 206 | + size_t count, |
---|
| 207 | + loff_t *ppos) |
---|
| 208 | +{ |
---|
| 209 | + struct ieee80211_local *local = file->private_data; |
---|
| 210 | + char buf[400]; |
---|
| 211 | + int len = 0; |
---|
| 212 | + |
---|
| 213 | + len = scnprintf(buf, sizeof(buf), |
---|
| 214 | + "AC AQL limit low AQL limit high\n" |
---|
| 215 | + "VO %u %u\n" |
---|
| 216 | + "VI %u %u\n" |
---|
| 217 | + "BE %u %u\n" |
---|
| 218 | + "BK %u %u\n", |
---|
| 219 | + local->aql_txq_limit_low[IEEE80211_AC_VO], |
---|
| 220 | + local->aql_txq_limit_high[IEEE80211_AC_VO], |
---|
| 221 | + local->aql_txq_limit_low[IEEE80211_AC_VI], |
---|
| 222 | + local->aql_txq_limit_high[IEEE80211_AC_VI], |
---|
| 223 | + local->aql_txq_limit_low[IEEE80211_AC_BE], |
---|
| 224 | + local->aql_txq_limit_high[IEEE80211_AC_BE], |
---|
| 225 | + local->aql_txq_limit_low[IEEE80211_AC_BK], |
---|
| 226 | + local->aql_txq_limit_high[IEEE80211_AC_BK]); |
---|
| 227 | + return simple_read_from_buffer(user_buf, count, ppos, |
---|
| 228 | + buf, len); |
---|
| 229 | +} |
---|
| 230 | + |
---|
| 231 | +static ssize_t aql_txq_limit_write(struct file *file, |
---|
| 232 | + const char __user *user_buf, |
---|
| 233 | + size_t count, |
---|
| 234 | + loff_t *ppos) |
---|
| 235 | +{ |
---|
| 236 | + struct ieee80211_local *local = file->private_data; |
---|
| 237 | + char buf[100]; |
---|
| 238 | + u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old; |
---|
| 239 | + struct sta_info *sta; |
---|
| 240 | + |
---|
| 241 | + if (count >= sizeof(buf)) |
---|
| 242 | + return -EINVAL; |
---|
| 243 | + |
---|
| 244 | + if (copy_from_user(buf, user_buf, count)) |
---|
| 245 | + return -EFAULT; |
---|
| 246 | + |
---|
| 247 | + if (count && buf[count - 1] == '\n') |
---|
| 248 | + buf[count - 1] = '\0'; |
---|
| 249 | + else |
---|
| 250 | + buf[count] = '\0'; |
---|
| 251 | + |
---|
| 252 | + if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3) |
---|
| 253 | + return -EINVAL; |
---|
| 254 | + |
---|
| 255 | + if (ac >= IEEE80211_NUM_ACS) |
---|
| 256 | + return -EINVAL; |
---|
| 257 | + |
---|
| 258 | + q_limit_low_old = local->aql_txq_limit_low[ac]; |
---|
| 259 | + q_limit_high_old = local->aql_txq_limit_high[ac]; |
---|
| 260 | + |
---|
| 261 | + local->aql_txq_limit_low[ac] = q_limit_low; |
---|
| 262 | + local->aql_txq_limit_high[ac] = q_limit_high; |
---|
| 263 | + |
---|
| 264 | + mutex_lock(&local->sta_mtx); |
---|
| 265 | + list_for_each_entry(sta, &local->sta_list, list) { |
---|
| 266 | + /* If a sta has customized queue limits, keep it */ |
---|
| 267 | + if (sta->airtime[ac].aql_limit_low == q_limit_low_old && |
---|
| 268 | + sta->airtime[ac].aql_limit_high == q_limit_high_old) { |
---|
| 269 | + sta->airtime[ac].aql_limit_low = q_limit_low; |
---|
| 270 | + sta->airtime[ac].aql_limit_high = q_limit_high; |
---|
| 271 | + } |
---|
| 272 | + } |
---|
| 273 | + mutex_unlock(&local->sta_mtx); |
---|
| 274 | + return count; |
---|
| 275 | +} |
---|
| 276 | + |
---|
| 277 | +static const struct file_operations aql_txq_limit_ops = { |
---|
| 278 | + .write = aql_txq_limit_write, |
---|
| 279 | + .read = aql_txq_limit_read, |
---|
| 280 | + .open = simple_open, |
---|
| 281 | + .llseek = default_llseek, |
---|
| 282 | +}; |
---|
| 283 | + |
---|
| 284 | +static ssize_t force_tx_status_read(struct file *file, |
---|
| 285 | + char __user *user_buf, |
---|
| 286 | + size_t count, |
---|
| 287 | + loff_t *ppos) |
---|
| 288 | +{ |
---|
| 289 | + struct ieee80211_local *local = file->private_data; |
---|
| 290 | + char buf[3]; |
---|
| 291 | + int len = 0; |
---|
| 292 | + |
---|
| 293 | + len = scnprintf(buf, sizeof(buf), "%d\n", (int)local->force_tx_status); |
---|
| 294 | + |
---|
| 295 | + return simple_read_from_buffer(user_buf, count, ppos, |
---|
| 296 | + buf, len); |
---|
| 297 | +} |
---|
| 298 | + |
---|
| 299 | +static ssize_t force_tx_status_write(struct file *file, |
---|
| 300 | + const char __user *user_buf, |
---|
| 301 | + size_t count, |
---|
| 302 | + loff_t *ppos) |
---|
| 303 | +{ |
---|
| 304 | + struct ieee80211_local *local = file->private_data; |
---|
| 305 | + char buf[3]; |
---|
| 306 | + |
---|
| 307 | + if (count >= sizeof(buf)) |
---|
| 308 | + return -EINVAL; |
---|
| 309 | + |
---|
| 310 | + if (copy_from_user(buf, user_buf, count)) |
---|
| 311 | + return -EFAULT; |
---|
| 312 | + |
---|
| 313 | + if (count && buf[count - 1] == '\n') |
---|
| 314 | + buf[count - 1] = '\0'; |
---|
| 315 | + else |
---|
| 316 | + buf[count] = '\0'; |
---|
| 317 | + |
---|
| 318 | + if (buf[0] == '0' && buf[1] == '\0') |
---|
| 319 | + local->force_tx_status = 0; |
---|
| 320 | + else if (buf[0] == '1' && buf[1] == '\0') |
---|
| 321 | + local->force_tx_status = 1; |
---|
| 322 | + else |
---|
| 323 | + return -EINVAL; |
---|
| 324 | + |
---|
| 325 | + return count; |
---|
| 326 | +} |
---|
| 327 | + |
---|
| 328 | +static const struct file_operations force_tx_status_ops = { |
---|
| 329 | + .write = force_tx_status_write, |
---|
| 330 | + .read = force_tx_status_read, |
---|
148 | 331 | .open = simple_open, |
---|
149 | 332 | .llseek = default_llseek, |
---|
150 | 333 | }; |
---|
.. | .. |
---|
214 | 397 | FLAG(SUPPORTS_TDLS_BUFFER_STA), |
---|
215 | 398 | FLAG(DEAUTH_NEED_MGD_TX_PREP), |
---|
216 | 399 | FLAG(DOESNT_SUPPORT_QOS_NDP), |
---|
| 400 | + FLAG(BUFF_MMPDU_TXQ), |
---|
| 401 | + FLAG(SUPPORTS_VHT_EXT_NSS_BW), |
---|
| 402 | + FLAG(STA_MMPDU_TXQ), |
---|
| 403 | + FLAG(TX_STATUS_NO_AMPDU_LEN), |
---|
| 404 | + FLAG(SUPPORTS_MULTI_BSSID), |
---|
| 405 | + FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), |
---|
| 406 | + FLAG(AMPDU_KEYBORDER_SUPPORT), |
---|
| 407 | + FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), |
---|
217 | 408 | #undef FLAG |
---|
218 | 409 | }; |
---|
219 | 410 | |
---|
.. | .. |
---|
375 | 566 | DEBUGFS_ADD(hwflags); |
---|
376 | 567 | DEBUGFS_ADD(user_power); |
---|
377 | 568 | DEBUGFS_ADD(power); |
---|
| 569 | + DEBUGFS_ADD(hw_conf); |
---|
| 570 | + DEBUGFS_ADD_MODE(force_tx_status, 0600); |
---|
378 | 571 | |
---|
379 | 572 | if (local->ops->wake_tx_queue) |
---|
380 | 573 | DEBUGFS_ADD_MODE(aqm, 0600); |
---|
381 | 574 | |
---|
| 575 | + DEBUGFS_ADD_MODE(airtime_flags, 0600); |
---|
| 576 | + |
---|
| 577 | + DEBUGFS_ADD(aql_txq_limit); |
---|
| 578 | + debugfs_create_u32("aql_threshold", 0600, |
---|
| 579 | + phyd, &local->aql_threshold); |
---|
| 580 | + |
---|
382 | 581 | statsd = debugfs_create_dir("statistics", phyd); |
---|
383 | 582 | |
---|
384 | 583 | /* if the dir failed, don't put all the other things into the root! */ |
---|