debugfs.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /******************************************************************************
  2. *
  3. * This file is provided under a dual BSD/GPLv2 license. When using or
  4. * redistributing this file, you may do so under either license.
  5. *
  6. * GPL LICENSE SUMMARY
  7. *
  8. * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of version 2 of the GNU General Public License as
  12. * published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  22. * USA
  23. *
  24. * The full GNU General Public License is included in this distribution
  25. * in the file called LICENSE.GPL.
  26. *
  27. * Contact Information:
  28. * Intel Linux Wireless <ilw@linux.intel.com>
  29. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  30. *
  31. * BSD LICENSE
  32. *
  33. * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
  34. * All rights reserved.
  35. *
  36. * Redistribution and use in source and binary forms, with or without
  37. * modification, are permitted provided that the following conditions
  38. * are met:
  39. *
  40. * * Redistributions of source code must retain the above copyright
  41. * notice, this list of conditions and the following disclaimer.
  42. * * Redistributions in binary form must reproduce the above copyright
  43. * notice, this list of conditions and the following disclaimer in
  44. * the documentation and/or other materials provided with the
  45. * distribution.
  46. * * Neither the name Intel Corporation nor the names of its
  47. * contributors may be used to endorse or promote products derived
  48. * from this software without specific prior written permission.
  49. *
  50. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  54. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  55. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  56. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  57. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  58. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  59. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  60. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61. *
  62. *****************************************************************************/
  63. #include "mvm.h"
  64. #include "sta.h"
  65. #include "iwl-io.h"
  66. struct iwl_dbgfs_mvm_ctx {
  67. struct iwl_mvm *mvm;
  68. struct ieee80211_vif *vif;
  69. };
  70. static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
  71. {
  72. file->private_data = inode->i_private;
  73. return 0;
  74. }
  75. static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
  76. const char __user *user_buf,
  77. size_t count, loff_t *ppos)
  78. {
  79. struct iwl_mvm *mvm = file->private_data;
  80. char buf[16];
  81. int buf_size, ret;
  82. u32 scd_q_msk;
  83. if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
  84. return -EIO;
  85. memset(buf, 0, sizeof(buf));
  86. buf_size = min(count, sizeof(buf) - 1);
  87. if (copy_from_user(buf, user_buf, buf_size))
  88. return -EFAULT;
  89. if (sscanf(buf, "%x", &scd_q_msk) != 1)
  90. return -EINVAL;
  91. IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
  92. mutex_lock(&mvm->mutex);
  93. ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count;
  94. mutex_unlock(&mvm->mutex);
  95. return ret;
  96. }
  97. static ssize_t iwl_dbgfs_sta_drain_write(struct file *file,
  98. const char __user *user_buf,
  99. size_t count, loff_t *ppos)
  100. {
  101. struct iwl_mvm *mvm = file->private_data;
  102. struct ieee80211_sta *sta;
  103. char buf[8];
  104. int buf_size, sta_id, drain, ret;
  105. if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
  106. return -EIO;
  107. memset(buf, 0, sizeof(buf));
  108. buf_size = min(count, sizeof(buf) - 1);
  109. if (copy_from_user(buf, user_buf, buf_size))
  110. return -EFAULT;
  111. if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
  112. return -EINVAL;
  113. mutex_lock(&mvm->mutex);
  114. sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
  115. lockdep_is_held(&mvm->mutex));
  116. if (IS_ERR_OR_NULL(sta))
  117. ret = -ENOENT;
  118. else
  119. ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? :
  120. count;
  121. mutex_unlock(&mvm->mutex);
  122. return ret;
  123. }
  124. static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
  125. size_t count, loff_t *ppos)
  126. {
  127. struct iwl_mvm *mvm = file->private_data;
  128. const struct fw_img *img;
  129. int ofs, len, pos = 0;
  130. size_t bufsz, ret;
  131. char *buf;
  132. u8 *ptr;
  133. /* default is to dump the entire data segment */
  134. if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
  135. mvm->dbgfs_sram_offset = 0x800000;
  136. if (!mvm->ucode_loaded)
  137. return -EINVAL;
  138. img = &mvm->fw->img[mvm->cur_ucode];
  139. mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
  140. }
  141. len = mvm->dbgfs_sram_len;
  142. bufsz = len * 4 + 256;
  143. buf = kzalloc(bufsz, GFP_KERNEL);
  144. if (!buf)
  145. return -ENOMEM;
  146. ptr = kzalloc(len, GFP_KERNEL);
  147. if (!ptr) {
  148. kfree(buf);
  149. return -ENOMEM;
  150. }
  151. pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
  152. pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
  153. mvm->dbgfs_sram_offset);
  154. iwl_trans_read_mem_bytes(mvm->trans,
  155. mvm->dbgfs_sram_offset,
  156. ptr, len);
  157. for (ofs = 0; ofs < len; ofs += 16) {
  158. pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs);
  159. hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
  160. bufsz - pos, false);
  161. pos += strlen(buf + pos);
  162. if (bufsz - pos > 0)
  163. buf[pos++] = '\n';
  164. }
  165. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  166. kfree(buf);
  167. kfree(ptr);
  168. return ret;
  169. }
  170. static ssize_t iwl_dbgfs_sram_write(struct file *file,
  171. const char __user *user_buf, size_t count,
  172. loff_t *ppos)
  173. {
  174. struct iwl_mvm *mvm = file->private_data;
  175. char buf[64];
  176. int buf_size;
  177. u32 offset, len;
  178. memset(buf, 0, sizeof(buf));
  179. buf_size = min(count, sizeof(buf) - 1);
  180. if (copy_from_user(buf, user_buf, buf_size))
  181. return -EFAULT;
  182. if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
  183. if ((offset & 0x3) || (len & 0x3))
  184. return -EINVAL;
  185. mvm->dbgfs_sram_offset = offset;
  186. mvm->dbgfs_sram_len = len;
  187. } else {
  188. mvm->dbgfs_sram_offset = 0;
  189. mvm->dbgfs_sram_len = 0;
  190. }
  191. return count;
  192. }
  193. static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
  194. size_t count, loff_t *ppos)
  195. {
  196. struct iwl_mvm *mvm = file->private_data;
  197. struct ieee80211_sta *sta;
  198. char buf[400];
  199. int i, pos = 0, bufsz = sizeof(buf);
  200. mutex_lock(&mvm->mutex);
  201. for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
  202. pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
  203. sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
  204. lockdep_is_held(&mvm->mutex));
  205. if (!sta)
  206. pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
  207. else if (IS_ERR(sta))
  208. pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
  209. PTR_ERR(sta));
  210. else
  211. pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
  212. sta->addr);
  213. }
  214. mutex_unlock(&mvm->mutex);
  215. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  216. }
  217. static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file,
  218. const char __user *user_buf,
  219. size_t count, loff_t *ppos)
  220. {
  221. struct iwl_mvm *mvm = file->private_data;
  222. char buf[8] = {};
  223. int allow;
  224. if (!mvm->ucode_loaded)
  225. return -EIO;
  226. if (copy_from_user(buf, user_buf, sizeof(buf)))
  227. return -EFAULT;
  228. if (sscanf(buf, "%d", &allow) != 1)
  229. return -EINVAL;
  230. IWL_DEBUG_POWER(mvm, "%s device power down\n",
  231. allow ? "allow" : "prevent");
  232. /*
  233. * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it
  234. */
  235. return count;
  236. }
  237. static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
  238. const char __user *user_buf,
  239. size_t count, loff_t *ppos)
  240. {
  241. struct iwl_mvm *mvm = file->private_data;
  242. char buf[8] = {};
  243. int allow;
  244. if (copy_from_user(buf, user_buf, sizeof(buf)))
  245. return -EFAULT;
  246. if (sscanf(buf, "%d", &allow) != 1)
  247. return -EINVAL;
  248. IWL_DEBUG_POWER(mvm, "%s device power down in d3\n",
  249. allow ? "allow" : "prevent");
  250. /*
  251. * TODO: When WoWLAN FW alive notification happens, driver will send
  252. * REPLY_DEBUG_CMD setting power_down_allow flag according to
  253. * mvm->prevent_power_down_d3
  254. */
  255. mvm->prevent_power_down_d3 = !allow;
  256. return count;
  257. }
  258. #define MVM_DEBUGFS_READ_FILE_OPS(name) \
  259. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  260. .read = iwl_dbgfs_##name##_read, \
  261. .open = iwl_dbgfs_open_file_generic, \
  262. .llseek = generic_file_llseek, \
  263. }
  264. #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \
  265. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  266. .write = iwl_dbgfs_##name##_write, \
  267. .read = iwl_dbgfs_##name##_read, \
  268. .open = iwl_dbgfs_open_file_generic, \
  269. .llseek = generic_file_llseek, \
  270. };
  271. #define MVM_DEBUGFS_WRITE_FILE_OPS(name) \
  272. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  273. .write = iwl_dbgfs_##name##_write, \
  274. .open = iwl_dbgfs_open_file_generic, \
  275. .llseek = generic_file_llseek, \
  276. };
  277. #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \
  278. if (!debugfs_create_file(#name, mode, parent, mvm, \
  279. &iwl_dbgfs_##name##_ops)) \
  280. goto err; \
  281. } while (0)
  282. #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
  283. if (!debugfs_create_file(#name, mode, parent, vif, \
  284. &iwl_dbgfs_##name##_ops)) \
  285. goto err; \
  286. } while (0)
  287. /* Device wide debugfs entries */
  288. MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
  289. MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
  290. MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
  291. MVM_DEBUGFS_READ_FILE_OPS(stations);
  292. MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
  293. MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
  294. int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
  295. {
  296. char buf[100];
  297. mvm->debugfs_dir = dbgfs_dir;
  298. MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
  299. MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
  300. MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
  301. MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
  302. MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
  303. MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
  304. /*
  305. * Create a symlink with mac80211. It will be removed when mac80211
  306. * exists (before the opmode exists which removes the target.)
  307. */
  308. snprintf(buf, 100, "../../%s/%s",
  309. dbgfs_dir->d_parent->d_parent->d_name.name,
  310. dbgfs_dir->d_parent->d_name.name);
  311. if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
  312. goto err;
  313. return 0;
  314. err:
  315. IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
  316. return -ENOMEM;
  317. }