debugfs.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455
  1. /*
  2. * Copyright (c) 2012-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. #include <linux/module.h>
  17. #include <linux/debugfs.h>
  18. #include <linux/seq_file.h>
  19. #include <linux/pci.h>
  20. #include <linux/rtnetlink.h>
  21. #include <linux/power_supply.h>
  22. #include "wil6210.h"
  23. #include "wmi.h"
  24. #include "txrx.h"
  25. /* Nasty hack. Better have per device instances */
  26. static u32 mem_addr;
  27. static u32 dbg_txdesc_index;
  28. static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
  29. u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */
  30. enum dbg_off_type {
  31. doff_u32 = 0,
  32. doff_x32 = 1,
  33. doff_ulong = 2,
  34. doff_io32 = 3,
  35. };
  36. /* offset to "wil" */
  37. struct dbg_off {
  38. const char *name;
  39. umode_t mode;
  40. ulong off;
  41. enum dbg_off_type type;
  42. };
  43. static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
  44. const char *name, struct vring *vring,
  45. char _s, char _h)
  46. {
  47. void __iomem *x = wmi_addr(wil, vring->hwtail);
  48. u32 v;
  49. seq_printf(s, "VRING %s = {\n", name);
  50. seq_printf(s, " pa = %pad\n", &vring->pa);
  51. seq_printf(s, " va = 0x%p\n", vring->va);
  52. seq_printf(s, " size = %d\n", vring->size);
  53. seq_printf(s, " swtail = %d\n", vring->swtail);
  54. seq_printf(s, " swhead = %d\n", vring->swhead);
  55. seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail);
  56. if (x) {
  57. v = ioread32(x);
  58. seq_printf(s, "0x%08x = %d\n", v, v);
  59. } else {
  60. seq_puts(s, "???\n");
  61. }
  62. if (vring->va && (vring->size < 1025)) {
  63. uint i;
  64. for (i = 0; i < vring->size; i++) {
  65. volatile struct vring_tx_desc *d = &vring->va[i].tx;
  66. if ((i % 64) == 0 && (i != 0))
  67. seq_puts(s, "\n");
  68. seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
  69. _s : (vring->ctx[i].skb ? _h : 'h'));
  70. }
  71. seq_puts(s, "\n");
  72. }
  73. seq_puts(s, "}\n");
  74. }
  75. static int wil_vring_debugfs_show(struct seq_file *s, void *data)
  76. {
  77. uint i;
  78. struct wil6210_priv *wil = s->private;
  79. wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
  80. for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
  81. struct vring *vring = &wil->vring_tx[i];
  82. struct vring_tx_data *txdata = &wil->vring_tx_data[i];
  83. if (vring->va) {
  84. int cid = wil->vring2cid_tid[i][0];
  85. int tid = wil->vring2cid_tid[i][1];
  86. u32 swhead = vring->swhead;
  87. u32 swtail = vring->swtail;
  88. int used = (vring->size + swhead - swtail)
  89. % vring->size;
  90. int avail = vring->size - used - 1;
  91. char name[10];
  92. char sidle[10];
  93. /* performance monitoring */
  94. cycles_t now = get_cycles();
  95. uint64_t idle = txdata->idle * 100;
  96. uint64_t total = now - txdata->begin;
  97. if (total != 0) {
  98. do_div(idle, total);
  99. snprintf(sidle, sizeof(sidle), "%3d%%",
  100. (int)idle);
  101. } else {
  102. snprintf(sidle, sizeof(sidle), "N/A");
  103. }
  104. txdata->begin = now;
  105. txdata->idle = 0ULL;
  106. snprintf(name, sizeof(name), "tx_%2d", i);
  107. seq_printf(s,
  108. "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n",
  109. wil->sta[cid].addr, cid, tid,
  110. txdata->agg_wsize, txdata->agg_timeout,
  111. txdata->agg_amsdu ? "+" : "-",
  112. used, avail, sidle);
  113. wil_print_vring(s, wil, name, vring, '_', 'H');
  114. }
  115. }
  116. return 0;
  117. }
  118. static int wil_vring_seq_open(struct inode *inode, struct file *file)
  119. {
  120. return single_open(file, wil_vring_debugfs_show, inode->i_private);
  121. }
  122. static const struct file_operations fops_vring = {
  123. .open = wil_vring_seq_open,
  124. .release = single_release,
  125. .read = seq_read,
  126. .llseek = seq_lseek,
  127. };
  128. static void wil_print_ring(struct seq_file *s, const char *prefix,
  129. void __iomem *off)
  130. {
  131. struct wil6210_priv *wil = s->private;
  132. struct wil6210_mbox_ring r;
  133. int rsize;
  134. uint i;
  135. wil_memcpy_fromio_32(&r, off, sizeof(r));
  136. wil_mbox_ring_le2cpus(&r);
  137. /*
  138. * we just read memory block from NIC. This memory may be
  139. * garbage. Check validity before using it.
  140. */
  141. rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
  142. seq_printf(s, "ring %s = {\n", prefix);
  143. seq_printf(s, " base = 0x%08x\n", r.base);
  144. seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize);
  145. seq_printf(s, " tail = 0x%08x\n", r.tail);
  146. seq_printf(s, " head = 0x%08x\n", r.head);
  147. seq_printf(s, " entry size = %d\n", r.entry_size);
  148. if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
  149. seq_printf(s, " ??? size is not multiple of %zd, garbage?\n",
  150. sizeof(struct wil6210_mbox_ring_desc));
  151. goto out;
  152. }
  153. if (!wmi_addr(wil, r.base) ||
  154. !wmi_addr(wil, r.tail) ||
  155. !wmi_addr(wil, r.head)) {
  156. seq_puts(s, " ??? pointers are garbage?\n");
  157. goto out;
  158. }
  159. for (i = 0; i < rsize; i++) {
  160. struct wil6210_mbox_ring_desc d;
  161. struct wil6210_mbox_hdr hdr;
  162. size_t delta = i * sizeof(d);
  163. void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
  164. wil_memcpy_fromio_32(&d, x, sizeof(d));
  165. seq_printf(s, " [%2x] %s %s%s 0x%08x", i,
  166. d.sync ? "F" : "E",
  167. (r.tail - r.base == delta) ? "t" : " ",
  168. (r.head - r.base == delta) ? "h" : " ",
  169. le32_to_cpu(d.addr));
  170. if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
  171. u16 len = le16_to_cpu(hdr.len);
  172. seq_printf(s, " -> %04x %04x %04x %02x\n",
  173. le16_to_cpu(hdr.seq), len,
  174. le16_to_cpu(hdr.type), hdr.flags);
  175. if (len <= MAX_MBOXITEM_SIZE) {
  176. int n = 0;
  177. char printbuf[16 * 3 + 2];
  178. unsigned char databuf[MAX_MBOXITEM_SIZE];
  179. void __iomem *src = wmi_buffer(wil, d.addr) +
  180. sizeof(struct wil6210_mbox_hdr);
  181. /*
  182. * No need to check @src for validity -
  183. * we already validated @d.addr while
  184. * reading header
  185. */
  186. wil_memcpy_fromio_32(databuf, src, len);
  187. while (n < len) {
  188. int l = min(len - n, 16);
  189. hex_dump_to_buffer(databuf + n, l,
  190. 16, 1, printbuf,
  191. sizeof(printbuf),
  192. false);
  193. seq_printf(s, " : %s\n", printbuf);
  194. n += l;
  195. }
  196. }
  197. } else {
  198. seq_puts(s, "\n");
  199. }
  200. }
  201. out:
  202. seq_puts(s, "}\n");
  203. }
  204. static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
  205. {
  206. struct wil6210_priv *wil = s->private;
  207. wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
  208. offsetof(struct wil6210_mbox_ctl, tx));
  209. wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
  210. offsetof(struct wil6210_mbox_ctl, rx));
  211. return 0;
  212. }
  213. static int wil_mbox_seq_open(struct inode *inode, struct file *file)
  214. {
  215. return single_open(file, wil_mbox_debugfs_show, inode->i_private);
  216. }
  217. static const struct file_operations fops_mbox = {
  218. .open = wil_mbox_seq_open,
  219. .release = single_release,
  220. .read = seq_read,
  221. .llseek = seq_lseek,
  222. };
  223. static int wil_debugfs_iomem_x32_set(void *data, u64 val)
  224. {
  225. iowrite32(val, (void __iomem *)data);
  226. wmb(); /* make sure write propagated to HW */
  227. return 0;
  228. }
  229. static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
  230. {
  231. *val = ioread32((void __iomem *)data);
  232. return 0;
  233. }
  234. DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
  235. wil_debugfs_iomem_x32_set, "0x%08llx\n");
  236. static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
  237. umode_t mode,
  238. struct dentry *parent,
  239. void *value)
  240. {
  241. return debugfs_create_file(name, mode, parent, value,
  242. &fops_iomem_x32);
  243. }
  244. static int wil_debugfs_ulong_set(void *data, u64 val)
  245. {
  246. *(ulong *)data = val;
  247. return 0;
  248. }
  249. static int wil_debugfs_ulong_get(void *data, u64 *val)
  250. {
  251. *val = *(ulong *)data;
  252. return 0;
  253. }
  254. DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
  255. wil_debugfs_ulong_set, "%llu\n");
  256. static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
  257. struct dentry *parent,
  258. ulong *value)
  259. {
  260. return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
  261. }
  262. /**
  263. * wil6210_debugfs_init_offset - create set of debugfs files
  264. * @wil - driver's context, used for printing
  265. * @dbg - directory on the debugfs, where files will be created
  266. * @base - base address used in address calculation
  267. * @tbl - table with file descriptions. Should be terminated with empty element.
  268. *
  269. * Creates files accordingly to the @tbl.
  270. */
  271. static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
  272. struct dentry *dbg, void *base,
  273. const struct dbg_off * const tbl)
  274. {
  275. int i;
  276. for (i = 0; tbl[i].name; i++) {
  277. struct dentry *f;
  278. switch (tbl[i].type) {
  279. case doff_u32:
  280. f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
  281. base + tbl[i].off);
  282. break;
  283. case doff_x32:
  284. f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
  285. base + tbl[i].off);
  286. break;
  287. case doff_ulong:
  288. f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
  289. dbg, base + tbl[i].off);
  290. break;
  291. case doff_io32:
  292. f = wil_debugfs_create_iomem_x32(tbl[i].name,
  293. tbl[i].mode, dbg,
  294. base + tbl[i].off);
  295. break;
  296. default:
  297. f = ERR_PTR(-EINVAL);
  298. }
  299. if (IS_ERR_OR_NULL(f))
  300. wil_err(wil, "Create file \"%s\": err %ld\n",
  301. tbl[i].name, PTR_ERR(f));
  302. }
  303. }
  304. static const struct dbg_off isr_off[] = {
  305. {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
  306. {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
  307. {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
  308. {"ICS", S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
  309. {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
  310. {"IMS", S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
  311. {"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
  312. {},
  313. };
  314. static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
  315. const char *name,
  316. struct dentry *parent, u32 off)
  317. {
  318. struct dentry *d = debugfs_create_dir(name, parent);
  319. if (IS_ERR_OR_NULL(d))
  320. return -ENODEV;
  321. wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
  322. isr_off);
  323. return 0;
  324. }
  325. static const struct dbg_off pseudo_isr_off[] = {
  326. {"CAUSE", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
  327. {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
  328. {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
  329. {},
  330. };
  331. static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
  332. struct dentry *parent)
  333. {
  334. struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
  335. if (IS_ERR_OR_NULL(d))
  336. return -ENODEV;
  337. wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
  338. pseudo_isr_off);
  339. return 0;
  340. }
  341. static const struct dbg_off lgc_itr_cnt_off[] = {
  342. {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
  343. {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
  344. {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
  345. {},
  346. };
  347. static const struct dbg_off tx_itr_cnt_off[] = {
  348. {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
  349. doff_io32},
  350. {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
  351. doff_io32},
  352. {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
  353. doff_io32},
  354. {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
  355. doff_io32},
  356. {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
  357. doff_io32},
  358. {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
  359. doff_io32},
  360. {},
  361. };
  362. static const struct dbg_off rx_itr_cnt_off[] = {
  363. {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
  364. doff_io32},
  365. {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
  366. doff_io32},
  367. {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
  368. doff_io32},
  369. {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
  370. doff_io32},
  371. {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
  372. doff_io32},
  373. {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
  374. doff_io32},
  375. {},
  376. };
  377. static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
  378. struct dentry *parent)
  379. {
  380. struct dentry *d, *dtx, *drx;
  381. d = debugfs_create_dir("ITR_CNT", parent);
  382. if (IS_ERR_OR_NULL(d))
  383. return -ENODEV;
  384. dtx = debugfs_create_dir("TX", d);
  385. drx = debugfs_create_dir("RX", d);
  386. if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
  387. return -ENODEV;
  388. wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
  389. lgc_itr_cnt_off);
  390. wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
  391. tx_itr_cnt_off);
  392. wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
  393. rx_itr_cnt_off);
  394. return 0;
  395. }
  396. static int wil_memread_debugfs_show(struct seq_file *s, void *data)
  397. {
  398. struct wil6210_priv *wil = s->private;
  399. void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
  400. if (a)
  401. seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a));
  402. else
  403. seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
  404. return 0;
  405. }
  406. static int wil_memread_seq_open(struct inode *inode, struct file *file)
  407. {
  408. return single_open(file, wil_memread_debugfs_show, inode->i_private);
  409. }
  410. static const struct file_operations fops_memread = {
  411. .open = wil_memread_seq_open,
  412. .release = single_release,
  413. .read = seq_read,
  414. .llseek = seq_lseek,
  415. };
  416. static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
  417. size_t count, loff_t *ppos)
  418. {
  419. enum { max_count = 4096 };
  420. struct debugfs_blob_wrapper *blob = file->private_data;
  421. loff_t pos = *ppos;
  422. size_t available = blob->size;
  423. void *buf;
  424. size_t ret;
  425. if (pos < 0)
  426. return -EINVAL;
  427. if (pos >= available || !count)
  428. return 0;
  429. if (count > available - pos)
  430. count = available - pos;
  431. if (count > max_count)
  432. count = max_count;
  433. buf = kmalloc(count, GFP_KERNEL);
  434. if (!buf)
  435. return -ENOMEM;
  436. wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
  437. pos, count);
  438. ret = copy_to_user(user_buf, buf, count);
  439. kfree(buf);
  440. if (ret == count)
  441. return -EFAULT;
  442. count -= ret;
  443. *ppos = pos + count;
  444. return count;
  445. }
  446. static const struct file_operations fops_ioblob = {
  447. .read = wil_read_file_ioblob,
  448. .open = simple_open,
  449. .llseek = default_llseek,
  450. };
  451. static
  452. struct dentry *wil_debugfs_create_ioblob(const char *name,
  453. umode_t mode,
  454. struct dentry *parent,
  455. struct debugfs_blob_wrapper *blob)
  456. {
  457. return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
  458. }
  459. /*---reset---*/
  460. static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
  461. size_t len, loff_t *ppos)
  462. {
  463. struct wil6210_priv *wil = file->private_data;
  464. struct net_device *ndev = wil_to_ndev(wil);
  465. /**
  466. * BUG:
  467. * this code does NOT sync device state with the rest of system
  468. * use with care, debug only!!!
  469. */
  470. rtnl_lock();
  471. dev_close(ndev);
  472. ndev->flags &= ~IFF_UP;
  473. rtnl_unlock();
  474. wil_reset(wil, true);
  475. return len;
  476. }
  477. static const struct file_operations fops_reset = {
  478. .write = wil_write_file_reset,
  479. .open = simple_open,
  480. };
  481. /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
  482. static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
  483. size_t len, loff_t *ppos)
  484. {
  485. struct wil6210_priv *wil = file->private_data;
  486. int rc;
  487. long channel;
  488. bool on;
  489. char *kbuf = kmalloc(len + 1, GFP_KERNEL);
  490. if (!kbuf)
  491. return -ENOMEM;
  492. if (copy_from_user(kbuf, buf, len)) {
  493. kfree(kbuf);
  494. return -EIO;
  495. }
  496. kbuf[len] = '\0';
  497. rc = kstrtol(kbuf, 0, &channel);
  498. kfree(kbuf);
  499. if (rc)
  500. return rc;
  501. if ((channel < 0) || (channel > 4)) {
  502. wil_err(wil, "Invalid channel %ld\n", channel);
  503. return -EINVAL;
  504. }
  505. on = !!channel;
  506. if (on) {
  507. rc = wmi_set_channel(wil, (int)channel);
  508. if (rc)
  509. return rc;
  510. }
  511. rc = wmi_rxon(wil, on);
  512. if (rc)
  513. return rc;
  514. return len;
  515. }
  516. static const struct file_operations fops_rxon = {
  517. .write = wil_write_file_rxon,
  518. .open = simple_open,
  519. };
  520. /* block ack control, write:
  521. * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
  522. * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
  523. * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
  524. */
  525. static ssize_t wil_write_back(struct file *file, const char __user *buf,
  526. size_t len, loff_t *ppos)
  527. {
  528. struct wil6210_priv *wil = file->private_data;
  529. int rc;
  530. char *kbuf = kmalloc(len + 1, GFP_KERNEL);
  531. char cmd[9];
  532. int p1, p2, p3;
  533. if (!kbuf)
  534. return -ENOMEM;
  535. rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
  536. if (rc != len) {
  537. kfree(kbuf);
  538. return rc >= 0 ? -EIO : rc;
  539. }
  540. kbuf[len] = '\0';
  541. rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
  542. kfree(kbuf);
  543. if (rc < 0)
  544. return rc;
  545. if (rc < 2)
  546. return -EINVAL;
  547. if (0 == strcmp(cmd, "add")) {
  548. if (rc < 3) {
  549. wil_err(wil, "BACK: add require at least 2 params\n");
  550. return -EINVAL;
  551. }
  552. if (rc < 4)
  553. p3 = 0;
  554. wmi_addba(wil, p1, p2, p3);
  555. } else if (0 == strcmp(cmd, "del_tx")) {
  556. if (rc < 3)
  557. p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
  558. wmi_delba_tx(wil, p1, p2);
  559. } else if (0 == strcmp(cmd, "del_rx")) {
  560. if (rc < 3) {
  561. wil_err(wil,
  562. "BACK: del_rx require at least 2 params\n");
  563. return -EINVAL;
  564. }
  565. if (rc < 4)
  566. p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
  567. wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
  568. } else {
  569. wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
  570. return -EINVAL;
  571. }
  572. return len;
  573. }
  574. static ssize_t wil_read_back(struct file *file, char __user *user_buf,
  575. size_t count, loff_t *ppos)
  576. {
  577. static const char text[] = "block ack control, write:\n"
  578. " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
  579. "If missing, <timeout> defaults to 0\n"
  580. " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
  581. " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
  582. "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
  583. return simple_read_from_buffer(user_buf, count, ppos, text,
  584. sizeof(text));
  585. }
  586. static const struct file_operations fops_back = {
  587. .read = wil_read_back,
  588. .write = wil_write_back,
  589. .open = simple_open,
  590. };
  591. /*---tx_mgmt---*/
  592. /* Write mgmt frame to this file to send it */
  593. static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
  594. size_t len, loff_t *ppos)
  595. {
  596. struct wil6210_priv *wil = file->private_data;
  597. struct wiphy *wiphy = wil_to_wiphy(wil);
  598. struct wireless_dev *wdev = wil_to_wdev(wil);
  599. struct cfg80211_mgmt_tx_params params;
  600. int rc;
  601. void *frame = kmalloc(len, GFP_KERNEL);
  602. if (!frame)
  603. return -ENOMEM;
  604. if (copy_from_user(frame, buf, len)) {
  605. kfree(frame);
  606. return -EIO;
  607. }
  608. params.buf = frame;
  609. params.len = len;
  610. params.chan = wdev->preset_chandef.chan;
  611. rc = wil_cfg80211_mgmt_tx(wiphy, wdev, &params, NULL);
  612. kfree(frame);
  613. wil_info(wil, "%s() -> %d\n", __func__, rc);
  614. return len;
  615. }
  616. static const struct file_operations fops_txmgmt = {
  617. .write = wil_write_file_txmgmt,
  618. .open = simple_open,
  619. };
  620. /* Write WMI command (w/o mbox header) to this file to send it
  621. * WMI starts from wil6210_mbox_hdr_wmi header
  622. */
  623. static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
  624. size_t len, loff_t *ppos)
  625. {
  626. struct wil6210_priv *wil = file->private_data;
  627. struct wil6210_mbox_hdr_wmi *wmi;
  628. void *cmd;
  629. int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi);
  630. u16 cmdid;
  631. int rc, rc1;
  632. if (cmdlen <= 0)
  633. return -EINVAL;
  634. wmi = kmalloc(len, GFP_KERNEL);
  635. if (!wmi)
  636. return -ENOMEM;
  637. rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
  638. if (rc < 0) {
  639. kfree(wmi);
  640. return rc;
  641. }
  642. cmd = &wmi[1];
  643. cmdid = le16_to_cpu(wmi->id);
  644. rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
  645. kfree(wmi);
  646. wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1);
  647. return rc;
  648. }
  649. static const struct file_operations fops_wmi = {
  650. .write = wil_write_file_wmi,
  651. .open = simple_open,
  652. };
  653. static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
  654. const char *prefix)
  655. {
  656. char printbuf[16 * 3 + 2];
  657. int i = 0;
  658. while (i < len) {
  659. int l = min(len - i, 16);
  660. hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
  661. sizeof(printbuf), false);
  662. seq_printf(s, "%s%s\n", prefix, printbuf);
  663. i += l;
  664. }
  665. }
  666. static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
  667. {
  668. int i = 0;
  669. int len = skb_headlen(skb);
  670. void *p = skb->data;
  671. int nr_frags = skb_shinfo(skb)->nr_frags;
  672. seq_printf(s, " len = %d\n", len);
  673. wil_seq_hexdump(s, p, len, " : ");
  674. if (nr_frags) {
  675. seq_printf(s, " nr_frags = %d\n", nr_frags);
  676. for (i = 0; i < nr_frags; i++) {
  677. const struct skb_frag_struct *frag =
  678. &skb_shinfo(skb)->frags[i];
  679. len = skb_frag_size(frag);
  680. p = skb_frag_address_safe(frag);
  681. seq_printf(s, " [%2d] : len = %d\n", i, len);
  682. wil_seq_hexdump(s, p, len, " : ");
  683. }
  684. }
  685. }
  686. /*---------Tx/Rx descriptor------------*/
  687. static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
  688. {
  689. struct wil6210_priv *wil = s->private;
  690. struct vring *vring;
  691. bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
  692. vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
  693. if (!vring->va) {
  694. if (tx)
  695. seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
  696. else
  697. seq_puts(s, "No Rx VRING\n");
  698. return 0;
  699. }
  700. if (dbg_txdesc_index < vring->size) {
  701. /* use struct vring_tx_desc for Rx as well,
  702. * only field used, .dma.length, is the same
  703. */
  704. volatile struct vring_tx_desc *d =
  705. &vring->va[dbg_txdesc_index].tx;
  706. volatile u32 *u = (volatile u32 *)d;
  707. struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
  708. if (tx)
  709. seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
  710. dbg_txdesc_index);
  711. else
  712. seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
  713. seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
  714. u[0], u[1], u[2], u[3]);
  715. seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
  716. u[4], u[5], u[6], u[7]);
  717. seq_printf(s, " SKB = 0x%p\n", skb);
  718. if (skb) {
  719. skb_get(skb);
  720. wil_seq_print_skb(s, skb);
  721. kfree_skb(skb);
  722. }
  723. seq_puts(s, "}\n");
  724. } else {
  725. if (tx)
  726. seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
  727. dbg_vring_index, dbg_txdesc_index,
  728. vring->size);
  729. else
  730. seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
  731. dbg_txdesc_index, vring->size);
  732. }
  733. return 0;
  734. }
  735. static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
  736. {
  737. return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
  738. }
  739. static const struct file_operations fops_txdesc = {
  740. .open = wil_txdesc_seq_open,
  741. .release = single_release,
  742. .read = seq_read,
  743. .llseek = seq_lseek,
  744. };
  745. /*---------beamforming------------*/
  746. static char *wil_bfstatus_str(u32 status)
  747. {
  748. switch (status) {
  749. case 0:
  750. return "Failed";
  751. case 1:
  752. return "OK";
  753. case 2:
  754. return "Retrying";
  755. default:
  756. return "??";
  757. }
  758. }
  759. static bool is_all_zeros(void * const x_, size_t sz)
  760. {
  761. /* if reply is all-0, ignore this CID */
  762. u32 *x = x_;
  763. int n;
  764. for (n = 0; n < sz / sizeof(*x); n++)
  765. if (x[n])
  766. return false;
  767. return true;
  768. }
  769. static int wil_bf_debugfs_show(struct seq_file *s, void *data)
  770. {
  771. int rc;
  772. int i;
  773. struct wil6210_priv *wil = s->private;
  774. struct wmi_notify_req_cmd cmd = {
  775. .interval_usec = 0,
  776. };
  777. struct {
  778. struct wil6210_mbox_hdr_wmi wmi;
  779. struct wmi_notify_req_done_event evt;
  780. } __packed reply;
  781. for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
  782. u32 status;
  783. cmd.cid = i;
  784. rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
  785. WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
  786. sizeof(reply), 20);
  787. /* if reply is all-0, ignore this CID */
  788. if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
  789. continue;
  790. status = le32_to_cpu(reply.evt.status);
  791. seq_printf(s, "CID %d {\n"
  792. " TSF = 0x%016llx\n"
  793. " TxMCS = %2d TxTpt = %4d\n"
  794. " SQI = %4d\n"
  795. " Status = 0x%08x %s\n"
  796. " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
  797. " Goodput(rx:tx) %4d:%4d\n"
  798. "}\n",
  799. i,
  800. le64_to_cpu(reply.evt.tsf),
  801. le16_to_cpu(reply.evt.bf_mcs),
  802. le32_to_cpu(reply.evt.tx_tpt),
  803. reply.evt.sqi,
  804. status, wil_bfstatus_str(status),
  805. le16_to_cpu(reply.evt.my_rx_sector),
  806. le16_to_cpu(reply.evt.my_tx_sector),
  807. le16_to_cpu(reply.evt.other_rx_sector),
  808. le16_to_cpu(reply.evt.other_tx_sector),
  809. le32_to_cpu(reply.evt.rx_goodput),
  810. le32_to_cpu(reply.evt.tx_goodput));
  811. }
  812. return 0;
  813. }
  814. static int wil_bf_seq_open(struct inode *inode, struct file *file)
  815. {
  816. return single_open(file, wil_bf_debugfs_show, inode->i_private);
  817. }
  818. static const struct file_operations fops_bf = {
  819. .open = wil_bf_seq_open,
  820. .release = single_release,
  821. .read = seq_read,
  822. .llseek = seq_lseek,
  823. };
  824. /*---------SSID------------*/
  825. static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
  826. size_t count, loff_t *ppos)
  827. {
  828. struct wil6210_priv *wil = file->private_data;
  829. struct wireless_dev *wdev = wil_to_wdev(wil);
  830. return simple_read_from_buffer(user_buf, count, ppos,
  831. wdev->ssid, wdev->ssid_len);
  832. }
  833. static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
  834. size_t count, loff_t *ppos)
  835. {
  836. struct wil6210_priv *wil = file->private_data;
  837. struct wireless_dev *wdev = wil_to_wdev(wil);
  838. struct net_device *ndev = wil_to_ndev(wil);
  839. if (*ppos != 0) {
  840. wil_err(wil, "Unable to set SSID substring from [%d]\n",
  841. (int)*ppos);
  842. return -EINVAL;
  843. }
  844. if (count > sizeof(wdev->ssid)) {
  845. wil_err(wil, "SSID too long, len = %d\n", (int)count);
  846. return -EINVAL;
  847. }
  848. if (netif_running(ndev)) {
  849. wil_err(wil, "Unable to change SSID on running interface\n");
  850. return -EINVAL;
  851. }
  852. wdev->ssid_len = count;
  853. return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos,
  854. buf, count);
  855. }
  856. static const struct file_operations fops_ssid = {
  857. .read = wil_read_file_ssid,
  858. .write = wil_write_file_ssid,
  859. .open = simple_open,
  860. };
  861. /*---------temp------------*/
  862. static void print_temp(struct seq_file *s, const char *prefix, u32 t)
  863. {
  864. switch (t) {
  865. case 0:
  866. case ~(u32)0:
  867. seq_printf(s, "%s N/A\n", prefix);
  868. break;
  869. default:
  870. seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
  871. break;
  872. }
  873. }
  874. static int wil_temp_debugfs_show(struct seq_file *s, void *data)
  875. {
  876. struct wil6210_priv *wil = s->private;
  877. u32 t_m, t_r;
  878. int rc = wmi_get_temperature(wil, &t_m, &t_r);
  879. if (rc) {
  880. seq_puts(s, "Failed\n");
  881. return 0;
  882. }
  883. print_temp(s, "T_mac =", t_m);
  884. print_temp(s, "T_radio =", t_r);
  885. return 0;
  886. }
  887. static int wil_temp_seq_open(struct inode *inode, struct file *file)
  888. {
  889. return single_open(file, wil_temp_debugfs_show, inode->i_private);
  890. }
  891. static const struct file_operations fops_temp = {
  892. .open = wil_temp_seq_open,
  893. .release = single_release,
  894. .read = seq_read,
  895. .llseek = seq_lseek,
  896. };
  897. /*---------freq------------*/
  898. static int wil_freq_debugfs_show(struct seq_file *s, void *data)
  899. {
  900. struct wil6210_priv *wil = s->private;
  901. struct wireless_dev *wdev = wil_to_wdev(wil);
  902. u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
  903. seq_printf(s, "Freq = %d\n", freq);
  904. return 0;
  905. }
  906. static int wil_freq_seq_open(struct inode *inode, struct file *file)
  907. {
  908. return single_open(file, wil_freq_debugfs_show, inode->i_private);
  909. }
  910. static const struct file_operations fops_freq = {
  911. .open = wil_freq_seq_open,
  912. .release = single_release,
  913. .read = seq_read,
  914. .llseek = seq_lseek,
  915. };
  916. /*---------link------------*/
  917. static int wil_link_debugfs_show(struct seq_file *s, void *data)
  918. {
  919. struct wil6210_priv *wil = s->private;
  920. struct station_info sinfo;
  921. int i, rc;
  922. for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
  923. struct wil_sta_info *p = &wil->sta[i];
  924. char *status = "unknown";
  925. switch (p->status) {
  926. case wil_sta_unused:
  927. status = "unused ";
  928. break;
  929. case wil_sta_conn_pending:
  930. status = "pending ";
  931. break;
  932. case wil_sta_connected:
  933. status = "connected";
  934. break;
  935. }
  936. seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
  937. (p->data_port_open ? " data_port_open" : ""));
  938. if (p->status == wil_sta_connected) {
  939. rc = wil_cid_fill_sinfo(wil, i, &sinfo);
  940. if (rc)
  941. return rc;
  942. seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs);
  943. seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs);
  944. seq_printf(s, " SQ = %d\n", sinfo.signal);
  945. }
  946. }
  947. return 0;
  948. }
  949. static int wil_link_seq_open(struct inode *inode, struct file *file)
  950. {
  951. return single_open(file, wil_link_debugfs_show, inode->i_private);
  952. }
  953. static const struct file_operations fops_link = {
  954. .open = wil_link_seq_open,
  955. .release = single_release,
  956. .read = seq_read,
  957. .llseek = seq_lseek,
  958. };
  959. /*---------info------------*/
  960. static int wil_info_debugfs_show(struct seq_file *s, void *data)
  961. {
  962. struct wil6210_priv *wil = s->private;
  963. struct net_device *ndev = wil_to_ndev(wil);
  964. int is_ac = power_supply_is_system_supplied();
  965. int rx = atomic_xchg(&wil->isr_count_rx, 0);
  966. int tx = atomic_xchg(&wil->isr_count_tx, 0);
  967. static ulong rxf_old, txf_old;
  968. ulong rxf = ndev->stats.rx_packets;
  969. ulong txf = ndev->stats.tx_packets;
  970. unsigned int i;
  971. /* >0 : AC; 0 : battery; <0 : error */
  972. seq_printf(s, "AC powered : %d\n", is_ac);
  973. seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
  974. seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
  975. rxf_old = rxf;
  976. txf_old = txf;
  977. #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
  978. " " __stringify(x) : ""
  979. for (i = 0; i < ndev->num_tx_queues; i++) {
  980. struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
  981. unsigned long state = txq->state;
  982. seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
  983. CHECK_QSTATE(DRV_XOFF),
  984. CHECK_QSTATE(STACK_XOFF),
  985. CHECK_QSTATE(FROZEN)
  986. );
  987. }
  988. #undef CHECK_QSTATE
  989. return 0;
  990. }
  991. static int wil_info_seq_open(struct inode *inode, struct file *file)
  992. {
  993. return single_open(file, wil_info_debugfs_show, inode->i_private);
  994. }
  995. static const struct file_operations fops_info = {
  996. .open = wil_info_seq_open,
  997. .release = single_release,
  998. .read = seq_read,
  999. .llseek = seq_lseek,
  1000. };
  1001. /*---------recovery------------*/
  1002. /* mode = [manual|auto]
  1003. * state = [idle|pending|running]
  1004. */
  1005. static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
  1006. size_t count, loff_t *ppos)
  1007. {
  1008. struct wil6210_priv *wil = file->private_data;
  1009. char buf[80];
  1010. int n;
  1011. static const char * const sstate[] = {"idle", "pending", "running"};
  1012. n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
  1013. no_fw_recovery ? "manual" : "auto",
  1014. sstate[wil->recovery_state]);
  1015. n = min_t(int, n, sizeof(buf));
  1016. return simple_read_from_buffer(user_buf, count, ppos,
  1017. buf, n);
  1018. }
  1019. static ssize_t wil_write_file_recovery(struct file *file,
  1020. const char __user *buf_,
  1021. size_t count, loff_t *ppos)
  1022. {
  1023. struct wil6210_priv *wil = file->private_data;
  1024. static const char run_command[] = "run";
  1025. char buf[sizeof(run_command) + 1]; /* to detect "runx" */
  1026. ssize_t rc;
  1027. if (wil->recovery_state != fw_recovery_pending) {
  1028. wil_err(wil, "No recovery pending\n");
  1029. return -EINVAL;
  1030. }
  1031. if (*ppos != 0) {
  1032. wil_err(wil, "Offset [%d]\n", (int)*ppos);
  1033. return -EINVAL;
  1034. }
  1035. if (count > sizeof(buf)) {
  1036. wil_err(wil, "Input too long, len = %d\n", (int)count);
  1037. return -EINVAL;
  1038. }
  1039. rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
  1040. if (rc < 0)
  1041. return rc;
  1042. buf[rc] = '\0';
  1043. if (0 == strcmp(buf, run_command))
  1044. wil_set_recovery_state(wil, fw_recovery_running);
  1045. else
  1046. wil_err(wil, "Bad recovery command \"%s\"\n", buf);
  1047. return rc;
  1048. }
  1049. static const struct file_operations fops_recovery = {
  1050. .read = wil_read_file_recovery,
  1051. .write = wil_write_file_recovery,
  1052. .open = simple_open,
  1053. };
  1054. /*---------Station matrix------------*/
  1055. static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
  1056. {
  1057. int i;
  1058. u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
  1059. seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
  1060. r->head_seq_num);
  1061. for (i = 0; i < r->buf_size; i++) {
  1062. if (i == index)
  1063. seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
  1064. else
  1065. seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
  1066. }
  1067. seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop);
  1068. }
  1069. static int wil_sta_debugfs_show(struct seq_file *s, void *data)
  1070. __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
  1071. {
  1072. struct wil6210_priv *wil = s->private;
  1073. int i, tid;
  1074. for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
  1075. struct wil_sta_info *p = &wil->sta[i];
  1076. char *status = "unknown";
  1077. switch (p->status) {
  1078. case wil_sta_unused:
  1079. status = "unused ";
  1080. break;
  1081. case wil_sta_conn_pending:
  1082. status = "pending ";
  1083. break;
  1084. case wil_sta_connected:
  1085. status = "connected";
  1086. break;
  1087. }
  1088. seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
  1089. (p->data_port_open ? " data_port_open" : ""));
  1090. if (p->status == wil_sta_connected) {
  1091. spin_lock_bh(&p->tid_rx_lock);
  1092. for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
  1093. struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
  1094. if (r) {
  1095. seq_printf(s, "[%2d] ", tid);
  1096. wil_print_rxtid(s, r);
  1097. }
  1098. }
  1099. spin_unlock_bh(&p->tid_rx_lock);
  1100. }
  1101. }
  1102. return 0;
  1103. }
  1104. static int wil_sta_seq_open(struct inode *inode, struct file *file)
  1105. {
  1106. return single_open(file, wil_sta_debugfs_show, inode->i_private);
  1107. }
  1108. static const struct file_operations fops_sta = {
  1109. .open = wil_sta_seq_open,
  1110. .release = single_release,
  1111. .read = seq_read,
  1112. .llseek = seq_lseek,
  1113. };
  1114. /*----------------*/
  1115. static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
  1116. struct dentry *dbg)
  1117. {
  1118. int i;
  1119. char name[32];
  1120. for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
  1121. struct debugfs_blob_wrapper *blob = &wil->blobs[i];
  1122. const struct fw_map *map = &fw_mapping[i];
  1123. if (!map->name)
  1124. continue;
  1125. blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
  1126. blob->size = map->to - map->from;
  1127. snprintf(name, sizeof(name), "blob_%s", map->name);
  1128. wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob);
  1129. }
  1130. }
  1131. /* misc files */
  1132. static const struct {
  1133. const char *name;
  1134. umode_t mode;
  1135. const struct file_operations *fops;
  1136. } dbg_files[] = {
  1137. {"mbox", S_IRUGO, &fops_mbox},
  1138. {"vrings", S_IRUGO, &fops_vring},
  1139. {"stations", S_IRUGO, &fops_sta},
  1140. {"desc", S_IRUGO, &fops_txdesc},
  1141. {"bf", S_IRUGO, &fops_bf},
  1142. {"ssid", S_IRUGO | S_IWUSR, &fops_ssid},
  1143. {"mem_val", S_IRUGO, &fops_memread},
  1144. {"reset", S_IWUSR, &fops_reset},
  1145. {"rxon", S_IWUSR, &fops_rxon},
  1146. {"tx_mgmt", S_IWUSR, &fops_txmgmt},
  1147. {"wmi_send", S_IWUSR, &fops_wmi},
  1148. {"back", S_IRUGO | S_IWUSR, &fops_back},
  1149. {"temp", S_IRUGO, &fops_temp},
  1150. {"freq", S_IRUGO, &fops_freq},
  1151. {"link", S_IRUGO, &fops_link},
  1152. {"info", S_IRUGO, &fops_info},
  1153. {"recovery", S_IRUGO | S_IWUSR, &fops_recovery},
  1154. };
  1155. static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
  1156. struct dentry *dbg)
  1157. {
  1158. int i;
  1159. for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
  1160. debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
  1161. wil, dbg_files[i].fops);
  1162. }
  1163. /* interrupt control blocks */
  1164. static const struct {
  1165. const char *name;
  1166. u32 icr_off;
  1167. } dbg_icr[] = {
  1168. {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)},
  1169. {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)},
  1170. {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)},
  1171. {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)},
  1172. };
  1173. static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
  1174. struct dentry *dbg)
  1175. {
  1176. int i;
  1177. for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
  1178. wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
  1179. dbg_icr[i].icr_off);
  1180. }
  1181. #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
  1182. offsetof(struct wil6210_priv, name), type}
  1183. /* fields in struct wil6210_priv */
  1184. static const struct dbg_off dbg_wil_off[] = {
  1185. WIL_FIELD(privacy, S_IRUGO, doff_u32),
  1186. WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong),
  1187. WIL_FIELD(fw_version, S_IRUGO, doff_u32),
  1188. WIL_FIELD(hw_version, S_IRUGO, doff_x32),
  1189. WIL_FIELD(recovery_count, S_IRUGO, doff_u32),
  1190. {},
  1191. };
  1192. static const struct dbg_off dbg_wil_regs[] = {
  1193. {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
  1194. doff_io32},
  1195. {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
  1196. {},
  1197. };
  1198. /* static parameters */
  1199. static const struct dbg_off dbg_statics[] = {
  1200. {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
  1201. {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
  1202. {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
  1203. {"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh,
  1204. doff_u32},
  1205. {},
  1206. };
  1207. int wil6210_debugfs_init(struct wil6210_priv *wil)
  1208. {
  1209. struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
  1210. wil_to_wiphy(wil)->debugfsdir);
  1211. if (IS_ERR_OR_NULL(dbg))
  1212. return -ENODEV;
  1213. wil6210_debugfs_init_files(wil, dbg);
  1214. wil6210_debugfs_init_isr(wil, dbg);
  1215. wil6210_debugfs_init_blobs(wil, dbg);
  1216. wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
  1217. wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
  1218. dbg_wil_regs);
  1219. wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
  1220. wil6210_debugfs_create_pseudo_ISR(wil, dbg);
  1221. wil6210_debugfs_create_ITR_CNT(wil, dbg);
  1222. return 0;
  1223. }
  1224. void wil6210_debugfs_remove(struct wil6210_priv *wil)
  1225. {
  1226. debugfs_remove_recursive(wil->debug);
  1227. wil->debug = NULL;
  1228. }