ntb_tool.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. /*
  2. * This file is provided under a dual BSD/GPLv2 license. When using or
  3. * redistributing this file, you may do so under either license.
  4. *
  5. * GPL LICENSE SUMMARY
  6. *
  7. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of version 2 of the GNU General Public License as
  11. * published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * BSD LICENSE
  19. *
  20. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
  21. *
  22. * Redistribution and use in source and binary forms, with or without
  23. * modification, are permitted provided that the following conditions
  24. * are met:
  25. *
  26. * * Redistributions of source code must retain the above copyright
  27. * notice, this list of conditions and the following disclaimer.
  28. * * Redistributions in binary form must reproduce the above copy
  29. * notice, this list of conditions and the following disclaimer in
  30. * the documentation and/or other materials provided with the
  31. * distribution.
  32. * * Neither the name of Intel Corporation nor the names of its
  33. * contributors may be used to endorse or promote products derived
  34. * from this software without specific prior written permission.
  35. *
  36. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  37. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  38. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  39. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  40. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  43. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  44. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  45. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  46. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  47. *
  48. * PCIe NTB Debugging Tool Linux driver
  49. *
  50. * Contact Information:
  51. * Allen Hubbe <Allen.Hubbe@emc.com>
  52. */
  53. /*
  54. * How to use this tool, by example.
  55. *
  56. * Assuming $DBG_DIR is something like:
  57. * '/sys/kernel/debug/ntb_tool/0000:00:03.0'
  58. *
  59. * Eg: check if clearing the doorbell mask generates an interrupt.
  60. *
  61. * # Check the link status
  62. * root@self# cat $DBG_DIR/link
  63. *
  64. * # Block until the link is up
  65. * root@self# echo Y > $DBG_DIR/link_event
  66. *
  67. * # Set the doorbell mask
  68. * root@self# echo 's 1' > $DBG_DIR/mask
  69. *
  70. * # Ring the doorbell from the peer
  71. * root@peer# echo 's 1' > $DBG_DIR/peer_db
  72. *
  73. * # Clear the doorbell mask
  74. * root@self# echo 'c 1' > $DBG_DIR/mask
  75. *
  76. * Observe debugging output in dmesg or your console. You should see a
  77. * doorbell event triggered by clearing the mask. If not, this may indicate an
  78. * issue with the hardware that needs to be worked around in the driver.
  79. *
  80. * Eg: read and write scratchpad registers
  81. *
  82. * root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad
  83. *
  84. * root@self# cat $DBG_DIR/spad
  85. *
  86. * Observe that spad 0 and 1 have the values set by the peer.
  87. *
  88. * # Check the memory window translation info
  89. * cat $DBG_DIR/peer_trans0
  90. *
  91. * # Setup a 16k memory window buffer
  92. * echo 16384 > $DBG_DIR/peer_trans0
  93. *
  94. */
  95. #include <linux/init.h>
  96. #include <linux/kernel.h>
  97. #include <linux/module.h>
  98. #include <linux/debugfs.h>
  99. #include <linux/dma-mapping.h>
  100. #include <linux/pci.h>
  101. #include <linux/slab.h>
  102. #include <linux/uaccess.h>
  103. #include <linux/ntb.h>
  104. #define DRIVER_NAME "ntb_tool"
  105. #define DRIVER_DESCRIPTION "PCIe NTB Debugging Tool"
  106. #define DRIVER_LICENSE "Dual BSD/GPL"
  107. #define DRIVER_VERSION "1.0"
  108. #define DRIVER_RELDATE "22 April 2015"
  109. #define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>"
  110. MODULE_LICENSE(DRIVER_LICENSE);
  111. MODULE_VERSION(DRIVER_VERSION);
  112. MODULE_AUTHOR(DRIVER_AUTHOR);
  113. MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
  114. #define MAX_MWS 16
  115. static struct dentry *tool_dbgfs;
  116. struct tool_mw {
  117. int idx;
  118. struct tool_ctx *tc;
  119. resource_size_t win_size;
  120. resource_size_t size;
  121. u8 __iomem *local;
  122. u8 *peer;
  123. dma_addr_t peer_dma;
  124. struct dentry *peer_dbg_file;
  125. };
  126. struct tool_ctx {
  127. struct ntb_dev *ntb;
  128. struct dentry *dbgfs;
  129. wait_queue_head_t link_wq;
  130. int mw_count;
  131. struct tool_mw mws[MAX_MWS];
  132. };
  133. #define SPAD_FNAME_SIZE 0x10
  134. #define INT_PTR(x) ((void *)(unsigned long)x)
  135. #define PTR_INT(x) ((int)(unsigned long)x)
  136. #define TOOL_FOPS_RDWR(__name, __read, __write) \
  137. const struct file_operations __name = { \
  138. .owner = THIS_MODULE, \
  139. .open = simple_open, \
  140. .read = __read, \
  141. .write = __write, \
  142. }
  143. static void tool_link_event(void *ctx)
  144. {
  145. struct tool_ctx *tc = ctx;
  146. enum ntb_speed speed;
  147. enum ntb_width width;
  148. int up;
  149. up = ntb_link_is_up(tc->ntb, &speed, &width);
  150. dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
  151. up ? "up" : "down", speed, width);
  152. wake_up(&tc->link_wq);
  153. }
  154. static void tool_db_event(void *ctx, int vec)
  155. {
  156. struct tool_ctx *tc = ctx;
  157. u64 db_bits, db_mask;
  158. db_mask = ntb_db_vector_mask(tc->ntb, vec);
  159. db_bits = ntb_db_read(tc->ntb);
  160. dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
  161. vec, db_mask, db_bits);
  162. }
  163. static const struct ntb_ctx_ops tool_ops = {
  164. .link_event = tool_link_event,
  165. .db_event = tool_db_event,
  166. };
  167. static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf,
  168. size_t size, loff_t *offp,
  169. u64 (*db_read_fn)(struct ntb_dev *))
  170. {
  171. size_t buf_size;
  172. char *buf;
  173. ssize_t pos, rc;
  174. if (!db_read_fn)
  175. return -EINVAL;
  176. buf_size = min_t(size_t, size, 0x20);
  177. buf = kmalloc(buf_size, GFP_KERNEL);
  178. if (!buf)
  179. return -ENOMEM;
  180. pos = scnprintf(buf, buf_size, "%#llx\n",
  181. db_read_fn(tc->ntb));
  182. rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
  183. kfree(buf);
  184. return rc;
  185. }
  186. static ssize_t tool_dbfn_write(struct tool_ctx *tc,
  187. const char __user *ubuf,
  188. size_t size, loff_t *offp,
  189. int (*db_set_fn)(struct ntb_dev *, u64),
  190. int (*db_clear_fn)(struct ntb_dev *, u64))
  191. {
  192. u64 db_bits;
  193. char *buf, cmd;
  194. ssize_t rc;
  195. int n;
  196. buf = kmalloc(size + 1, GFP_KERNEL);
  197. if (!buf)
  198. return -ENOMEM;
  199. rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
  200. if (rc < 0) {
  201. kfree(buf);
  202. return rc;
  203. }
  204. buf[size] = 0;
  205. n = sscanf(buf, "%c %lli", &cmd, &db_bits);
  206. kfree(buf);
  207. if (n != 2) {
  208. rc = -EINVAL;
  209. } else if (cmd == 's') {
  210. if (!db_set_fn)
  211. rc = -EINVAL;
  212. else
  213. rc = db_set_fn(tc->ntb, db_bits);
  214. } else if (cmd == 'c') {
  215. if (!db_clear_fn)
  216. rc = -EINVAL;
  217. else
  218. rc = db_clear_fn(tc->ntb, db_bits);
  219. } else {
  220. rc = -EINVAL;
  221. }
  222. return rc ? : size;
  223. }
  224. static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
  225. size_t size, loff_t *offp,
  226. u32 (*spad_read_fn)(struct ntb_dev *, int))
  227. {
  228. size_t buf_size;
  229. char *buf;
  230. ssize_t pos, rc;
  231. int i, spad_count;
  232. if (!spad_read_fn)
  233. return -EINVAL;
  234. spad_count = ntb_spad_count(tc->ntb);
  235. /*
  236. * We multiply the number of spads by 15 to get the buffer size
  237. * this is from 3 for the %d, 10 for the largest hex value
  238. * (0x00000000) and 2 for the tab and line feed.
  239. */
  240. buf_size = min_t(size_t, size, spad_count * 15);
  241. buf = kmalloc(buf_size, GFP_KERNEL);
  242. if (!buf)
  243. return -ENOMEM;
  244. pos = 0;
  245. for (i = 0; i < spad_count; ++i) {
  246. pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
  247. i, spad_read_fn(tc->ntb, i));
  248. }
  249. rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
  250. kfree(buf);
  251. return rc;
  252. }
  253. static ssize_t tool_spadfn_write(struct tool_ctx *tc,
  254. const char __user *ubuf,
  255. size_t size, loff_t *offp,
  256. int (*spad_write_fn)(struct ntb_dev *,
  257. int, u32))
  258. {
  259. int spad_idx;
  260. u32 spad_val;
  261. char *buf, *buf_ptr;
  262. int pos, n;
  263. ssize_t rc;
  264. if (!spad_write_fn) {
  265. dev_dbg(&tc->ntb->dev, "no spad write fn\n");
  266. return -EINVAL;
  267. }
  268. buf = kmalloc(size + 1, GFP_KERNEL);
  269. if (!buf)
  270. return -ENOMEM;
  271. rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
  272. if (rc < 0) {
  273. kfree(buf);
  274. return rc;
  275. }
  276. buf[size] = 0;
  277. buf_ptr = buf;
  278. n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
  279. while (n == 2) {
  280. buf_ptr += pos;
  281. rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
  282. if (rc)
  283. break;
  284. n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
  285. }
  286. if (n < 0)
  287. rc = n;
  288. kfree(buf);
  289. return rc ? : size;
  290. }
  291. static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
  292. size_t size, loff_t *offp)
  293. {
  294. struct tool_ctx *tc = filep->private_data;
  295. return tool_dbfn_read(tc, ubuf, size, offp,
  296. tc->ntb->ops->db_read);
  297. }
  298. static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
  299. size_t size, loff_t *offp)
  300. {
  301. struct tool_ctx *tc = filep->private_data;
  302. return tool_dbfn_write(tc, ubuf, size, offp,
  303. tc->ntb->ops->db_set,
  304. tc->ntb->ops->db_clear);
  305. }
  306. static TOOL_FOPS_RDWR(tool_db_fops,
  307. tool_db_read,
  308. tool_db_write);
  309. static ssize_t tool_mask_read(struct file *filep, char __user *ubuf,
  310. size_t size, loff_t *offp)
  311. {
  312. struct tool_ctx *tc = filep->private_data;
  313. return tool_dbfn_read(tc, ubuf, size, offp,
  314. tc->ntb->ops->db_read_mask);
  315. }
  316. static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf,
  317. size_t size, loff_t *offp)
  318. {
  319. struct tool_ctx *tc = filep->private_data;
  320. return tool_dbfn_write(tc, ubuf, size, offp,
  321. tc->ntb->ops->db_set_mask,
  322. tc->ntb->ops->db_clear_mask);
  323. }
  324. static TOOL_FOPS_RDWR(tool_mask_fops,
  325. tool_mask_read,
  326. tool_mask_write);
  327. static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
  328. size_t size, loff_t *offp)
  329. {
  330. struct tool_ctx *tc = filep->private_data;
  331. return tool_dbfn_read(tc, ubuf, size, offp,
  332. tc->ntb->ops->peer_db_read);
  333. }
  334. static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
  335. size_t size, loff_t *offp)
  336. {
  337. struct tool_ctx *tc = filep->private_data;
  338. return tool_dbfn_write(tc, ubuf, size, offp,
  339. tc->ntb->ops->peer_db_set,
  340. tc->ntb->ops->peer_db_clear);
  341. }
  342. static TOOL_FOPS_RDWR(tool_peer_db_fops,
  343. tool_peer_db_read,
  344. tool_peer_db_write);
  345. static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf,
  346. size_t size, loff_t *offp)
  347. {
  348. struct tool_ctx *tc = filep->private_data;
  349. return tool_dbfn_read(tc, ubuf, size, offp,
  350. tc->ntb->ops->peer_db_read_mask);
  351. }
  352. static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf,
  353. size_t size, loff_t *offp)
  354. {
  355. struct tool_ctx *tc = filep->private_data;
  356. return tool_dbfn_write(tc, ubuf, size, offp,
  357. tc->ntb->ops->peer_db_set_mask,
  358. tc->ntb->ops->peer_db_clear_mask);
  359. }
  360. static TOOL_FOPS_RDWR(tool_peer_mask_fops,
  361. tool_peer_mask_read,
  362. tool_peer_mask_write);
  363. static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
  364. size_t size, loff_t *offp)
  365. {
  366. struct tool_ctx *tc = filep->private_data;
  367. return tool_spadfn_read(tc, ubuf, size, offp,
  368. tc->ntb->ops->spad_read);
  369. }
  370. static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
  371. size_t size, loff_t *offp)
  372. {
  373. struct tool_ctx *tc = filep->private_data;
  374. return tool_spadfn_write(tc, ubuf, size, offp,
  375. tc->ntb->ops->spad_write);
  376. }
  377. static TOOL_FOPS_RDWR(tool_spad_fops,
  378. tool_spad_read,
  379. tool_spad_write);
  380. static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
  381. size_t size, loff_t *offp)
  382. {
  383. struct tool_ctx *tc = filep->private_data;
  384. return tool_spadfn_read(tc, ubuf, size, offp,
  385. tc->ntb->ops->peer_spad_read);
  386. }
  387. static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
  388. size_t size, loff_t *offp)
  389. {
  390. struct tool_ctx *tc = filep->private_data;
  391. return tool_spadfn_write(tc, ubuf, size, offp,
  392. tc->ntb->ops->peer_spad_write);
  393. }
  394. static TOOL_FOPS_RDWR(tool_peer_spad_fops,
  395. tool_peer_spad_read,
  396. tool_peer_spad_write);
  397. static ssize_t tool_link_read(struct file *filep, char __user *ubuf,
  398. size_t size, loff_t *offp)
  399. {
  400. struct tool_ctx *tc = filep->private_data;
  401. char buf[3];
  402. buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N';
  403. buf[1] = '\n';
  404. buf[2] = '\0';
  405. return simple_read_from_buffer(ubuf, size, offp, buf, 2);
  406. }
  407. static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
  408. size_t size, loff_t *offp)
  409. {
  410. struct tool_ctx *tc = filep->private_data;
  411. char buf[32];
  412. size_t buf_size;
  413. bool val;
  414. int rc;
  415. buf_size = min(size, (sizeof(buf) - 1));
  416. if (copy_from_user(buf, ubuf, buf_size))
  417. return -EFAULT;
  418. buf[buf_size] = '\0';
  419. rc = strtobool(buf, &val);
  420. if (rc)
  421. return rc;
  422. if (val)
  423. rc = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
  424. else
  425. rc = ntb_link_disable(tc->ntb);
  426. if (rc)
  427. return rc;
  428. return size;
  429. }
  430. static TOOL_FOPS_RDWR(tool_link_fops,
  431. tool_link_read,
  432. tool_link_write);
  433. static ssize_t tool_link_event_write(struct file *filep,
  434. const char __user *ubuf,
  435. size_t size, loff_t *offp)
  436. {
  437. struct tool_ctx *tc = filep->private_data;
  438. char buf[32];
  439. size_t buf_size;
  440. bool val;
  441. int rc;
  442. buf_size = min(size, (sizeof(buf) - 1));
  443. if (copy_from_user(buf, ubuf, buf_size))
  444. return -EFAULT;
  445. buf[buf_size] = '\0';
  446. rc = strtobool(buf, &val);
  447. if (rc)
  448. return rc;
  449. if (wait_event_interruptible(tc->link_wq,
  450. ntb_link_is_up(tc->ntb, NULL, NULL) == val))
  451. return -ERESTART;
  452. return size;
  453. }
  454. static TOOL_FOPS_RDWR(tool_link_event_fops,
  455. NULL,
  456. tool_link_event_write);
  457. static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
  458. size_t size, loff_t *offp)
  459. {
  460. struct tool_mw *mw = filep->private_data;
  461. ssize_t rc;
  462. loff_t pos = *offp;
  463. void *buf;
  464. if (mw->local == NULL)
  465. return -EIO;
  466. if (pos < 0)
  467. return -EINVAL;
  468. if (pos >= mw->win_size || !size)
  469. return 0;
  470. if (size > mw->win_size - pos)
  471. size = mw->win_size - pos;
  472. buf = kmalloc(size, GFP_KERNEL);
  473. if (!buf)
  474. return -ENOMEM;
  475. memcpy_fromio(buf, mw->local + pos, size);
  476. rc = copy_to_user(ubuf, buf, size);
  477. if (rc == size) {
  478. rc = -EFAULT;
  479. goto err_free;
  480. }
  481. size -= rc;
  482. *offp = pos + size;
  483. rc = size;
  484. err_free:
  485. kfree(buf);
  486. return rc;
  487. }
  488. static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
  489. size_t size, loff_t *offp)
  490. {
  491. struct tool_mw *mw = filep->private_data;
  492. ssize_t rc;
  493. loff_t pos = *offp;
  494. void *buf;
  495. if (pos < 0)
  496. return -EINVAL;
  497. if (pos >= mw->win_size || !size)
  498. return 0;
  499. if (size > mw->win_size - pos)
  500. size = mw->win_size - pos;
  501. buf = kmalloc(size, GFP_KERNEL);
  502. if (!buf)
  503. return -ENOMEM;
  504. rc = copy_from_user(buf, ubuf, size);
  505. if (rc == size) {
  506. rc = -EFAULT;
  507. goto err_free;
  508. }
  509. size -= rc;
  510. *offp = pos + size;
  511. rc = size;
  512. memcpy_toio(mw->local + pos, buf, size);
  513. err_free:
  514. kfree(buf);
  515. return rc;
  516. }
  517. static TOOL_FOPS_RDWR(tool_mw_fops,
  518. tool_mw_read,
  519. tool_mw_write);
  520. static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
  521. size_t size, loff_t *offp)
  522. {
  523. struct tool_mw *mw = filep->private_data;
  524. if (!mw->peer)
  525. return -ENXIO;
  526. return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size);
  527. }
  528. static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
  529. size_t size, loff_t *offp)
  530. {
  531. struct tool_mw *mw = filep->private_data;
  532. if (!mw->peer)
  533. return -ENXIO;
  534. return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size);
  535. }
  536. static TOOL_FOPS_RDWR(tool_peer_mw_fops,
  537. tool_peer_mw_read,
  538. tool_peer_mw_write);
  539. static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
  540. {
  541. int rc;
  542. struct tool_mw *mw = &tc->mws[idx];
  543. phys_addr_t base;
  544. resource_size_t size, align, align_size;
  545. char buf[16];
  546. if (mw->peer)
  547. return 0;
  548. rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
  549. &align_size);
  550. if (rc)
  551. return rc;
  552. mw->size = min_t(resource_size_t, req_size, size);
  553. mw->size = round_up(mw->size, align);
  554. mw->size = round_up(mw->size, align_size);
  555. mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
  556. &mw->peer_dma, GFP_KERNEL);
  557. if (!mw->peer)
  558. return -ENOMEM;
  559. rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
  560. if (rc)
  561. goto err_free_dma;
  562. snprintf(buf, sizeof(buf), "peer_mw%d", idx);
  563. mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR,
  564. mw->tc->dbgfs, mw,
  565. &tool_peer_mw_fops);
  566. return 0;
  567. err_free_dma:
  568. dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
  569. mw->peer,
  570. mw->peer_dma);
  571. mw->peer = NULL;
  572. mw->peer_dma = 0;
  573. mw->size = 0;
  574. return rc;
  575. }
  576. static void tool_free_mw(struct tool_ctx *tc, int idx)
  577. {
  578. struct tool_mw *mw = &tc->mws[idx];
  579. if (mw->peer) {
  580. ntb_mw_clear_trans(tc->ntb, idx);
  581. dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
  582. mw->peer,
  583. mw->peer_dma);
  584. }
  585. mw->peer = NULL;
  586. mw->peer_dma = 0;
  587. debugfs_remove(mw->peer_dbg_file);
  588. mw->peer_dbg_file = NULL;
  589. }
  590. static ssize_t tool_peer_mw_trans_read(struct file *filep,
  591. char __user *ubuf,
  592. size_t size, loff_t *offp)
  593. {
  594. struct tool_mw *mw = filep->private_data;
  595. char *buf;
  596. size_t buf_size;
  597. ssize_t ret, off = 0;
  598. phys_addr_t base;
  599. resource_size_t mw_size;
  600. resource_size_t align;
  601. resource_size_t align_size;
  602. buf_size = min_t(size_t, size, 512);
  603. buf = kmalloc(buf_size, GFP_KERNEL);
  604. if (!buf)
  605. return -ENOMEM;
  606. ntb_mw_get_range(mw->tc->ntb, mw->idx,
  607. &base, &mw_size, &align, &align_size);
  608. off += scnprintf(buf + off, buf_size - off,
  609. "Peer MW %d Information:\n", mw->idx);
  610. off += scnprintf(buf + off, buf_size - off,
  611. "Physical Address \t%pa[p]\n",
  612. &base);
  613. off += scnprintf(buf + off, buf_size - off,
  614. "Window Size \t%lld\n",
  615. (unsigned long long)mw_size);
  616. off += scnprintf(buf + off, buf_size - off,
  617. "Alignment \t%lld\n",
  618. (unsigned long long)align);
  619. off += scnprintf(buf + off, buf_size - off,
  620. "Size Alignment \t%lld\n",
  621. (unsigned long long)align_size);
  622. off += scnprintf(buf + off, buf_size - off,
  623. "Ready \t%c\n",
  624. (mw->peer) ? 'Y' : 'N');
  625. off += scnprintf(buf + off, buf_size - off,
  626. "Allocated Size \t%zd\n",
  627. (mw->peer) ? (size_t)mw->size : 0);
  628. ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
  629. kfree(buf);
  630. return ret;
  631. }
  632. static ssize_t tool_peer_mw_trans_write(struct file *filep,
  633. const char __user *ubuf,
  634. size_t size, loff_t *offp)
  635. {
  636. struct tool_mw *mw = filep->private_data;
  637. char buf[32];
  638. size_t buf_size;
  639. unsigned long long val;
  640. int rc;
  641. buf_size = min(size, (sizeof(buf) - 1));
  642. if (copy_from_user(buf, ubuf, buf_size))
  643. return -EFAULT;
  644. buf[buf_size] = '\0';
  645. rc = kstrtoull(buf, 0, &val);
  646. if (rc)
  647. return rc;
  648. tool_free_mw(mw->tc, mw->idx);
  649. if (val)
  650. rc = tool_setup_mw(mw->tc, mw->idx, val);
  651. if (rc)
  652. return rc;
  653. return size;
  654. }
  655. static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
  656. tool_peer_mw_trans_read,
  657. tool_peer_mw_trans_write);
  658. static int tool_init_mw(struct tool_ctx *tc, int idx)
  659. {
  660. struct tool_mw *mw = &tc->mws[idx];
  661. phys_addr_t base;
  662. int rc;
  663. rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
  664. NULL, NULL);
  665. if (rc)
  666. return rc;
  667. mw->tc = tc;
  668. mw->idx = idx;
  669. mw->local = ioremap_wc(base, mw->win_size);
  670. if (!mw->local)
  671. return -EFAULT;
  672. return 0;
  673. }
  674. static void tool_free_mws(struct tool_ctx *tc)
  675. {
  676. int i;
  677. for (i = 0; i < tc->mw_count; i++) {
  678. tool_free_mw(tc, i);
  679. if (tc->mws[i].local)
  680. iounmap(tc->mws[i].local);
  681. tc->mws[i].local = NULL;
  682. }
  683. }
  684. static void tool_setup_dbgfs(struct tool_ctx *tc)
  685. {
  686. int i;
  687. /* This modules is useless without dbgfs... */
  688. if (!tool_dbgfs) {
  689. tc->dbgfs = NULL;
  690. return;
  691. }
  692. tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev),
  693. tool_dbgfs);
  694. if (!tc->dbgfs)
  695. return;
  696. debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs,
  697. tc, &tool_db_fops);
  698. debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs,
  699. tc, &tool_mask_fops);
  700. debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs,
  701. tc, &tool_peer_db_fops);
  702. debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs,
  703. tc, &tool_peer_mask_fops);
  704. debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs,
  705. tc, &tool_spad_fops);
  706. debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs,
  707. tc, &tool_peer_spad_fops);
  708. debugfs_create_file("link", S_IRUSR | S_IWUSR, tc->dbgfs,
  709. tc, &tool_link_fops);
  710. debugfs_create_file("link_event", S_IWUSR, tc->dbgfs,
  711. tc, &tool_link_event_fops);
  712. for (i = 0; i < tc->mw_count; i++) {
  713. char buf[30];
  714. snprintf(buf, sizeof(buf), "mw%d", i);
  715. debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
  716. &tc->mws[i], &tool_mw_fops);
  717. snprintf(buf, sizeof(buf), "peer_trans%d", i);
  718. debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
  719. &tc->mws[i], &tool_peer_mw_trans_fops);
  720. }
  721. }
  722. static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
  723. {
  724. struct tool_ctx *tc;
  725. int rc;
  726. int i;
  727. if (ntb_db_is_unsafe(ntb))
  728. dev_dbg(&ntb->dev, "doorbell is unsafe\n");
  729. if (ntb_spad_is_unsafe(ntb))
  730. dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
  731. tc = kzalloc(sizeof(*tc), GFP_KERNEL);
  732. if (!tc) {
  733. rc = -ENOMEM;
  734. goto err_tc;
  735. }
  736. tc->ntb = ntb;
  737. init_waitqueue_head(&tc->link_wq);
  738. tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
  739. for (i = 0; i < tc->mw_count; i++) {
  740. rc = tool_init_mw(tc, i);
  741. if (rc)
  742. goto err_ctx;
  743. }
  744. tool_setup_dbgfs(tc);
  745. rc = ntb_set_ctx(ntb, tc, &tool_ops);
  746. if (rc)
  747. goto err_ctx;
  748. ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
  749. ntb_link_event(ntb);
  750. return 0;
  751. err_ctx:
  752. tool_free_mws(tc);
  753. debugfs_remove_recursive(tc->dbgfs);
  754. kfree(tc);
  755. err_tc:
  756. return rc;
  757. }
  758. static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
  759. {
  760. struct tool_ctx *tc = ntb->ctx;
  761. tool_free_mws(tc);
  762. ntb_clear_ctx(ntb);
  763. ntb_link_disable(ntb);
  764. debugfs_remove_recursive(tc->dbgfs);
  765. kfree(tc);
  766. }
  767. static struct ntb_client tool_client = {
  768. .ops = {
  769. .probe = tool_probe,
  770. .remove = tool_remove,
  771. },
  772. };
  773. static int __init tool_init(void)
  774. {
  775. int rc;
  776. if (debugfs_initialized())
  777. tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
  778. rc = ntb_register_client(&tool_client);
  779. if (rc)
  780. goto err_client;
  781. return 0;
  782. err_client:
  783. debugfs_remove_recursive(tool_dbgfs);
  784. return rc;
  785. }
  786. module_init(tool_init);
  787. static void __exit tool_exit(void)
  788. {
  789. ntb_unregister_client(&tool_client);
  790. debugfs_remove_recursive(tool_dbgfs);
  791. }
  792. module_exit(tool_exit);