1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179#include <linux/init.h>
180#include <linux/kernel.h>
181#include <linux/module.h>
182
183#include <linux/debugfs.h>
184#include <linux/dma-mapping.h>
185#include <linux/pci.h>
186#include <linux/slab.h>
187#include <linux/uaccess.h>
188
189#include <linux/ntb.h>
190
191#define DRIVER_NAME "ntb_tool"
192#define DRIVER_VERSION "2.0"
193
194MODULE_LICENSE("Dual BSD/GPL");
195MODULE_VERSION(DRIVER_VERSION);
196MODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>");
197MODULE_DESCRIPTION("PCIe NTB Debugging Tool");
198
199
200
201
202
203
204
205struct tool_mw {
206 int widx;
207 int pidx;
208 struct tool_ctx *tc;
209 union {
210 u8 *mm_base;
211 u8 __iomem *io_base;
212 };
213 union {
214 dma_addr_t dma_base;
215 u64 tr_base;
216 };
217 resource_size_t size;
218 struct dentry *dbgfs_file;
219};
220
221
222
223
224
225struct tool_mw_wrap {
226 int pidx;
227 struct tool_mw *mw;
228};
229
230struct tool_msg {
231 int midx;
232 int pidx;
233 struct tool_ctx *tc;
234};
235
236struct tool_spad {
237 int sidx;
238 int pidx;
239 struct tool_ctx *tc;
240};
241
242struct tool_peer {
243 int pidx;
244 struct tool_ctx *tc;
245 int inmw_cnt;
246 struct tool_mw *inmws;
247 int outmw_cnt;
248 struct tool_mw_wrap *outmws;
249 int outmsg_cnt;
250 struct tool_msg *outmsgs;
251 int outspad_cnt;
252 struct tool_spad *outspads;
253 struct dentry *dbgfs_dir;
254};
255
256struct tool_ctx {
257 struct ntb_dev *ntb;
258 wait_queue_head_t link_wq;
259 wait_queue_head_t db_wq;
260 wait_queue_head_t msg_wq;
261 int outmw_cnt;
262 struct tool_mw *outmws;
263 int peer_cnt;
264 struct tool_peer *peers;
265 int inmsg_cnt;
266 struct tool_msg *inmsgs;
267 int inspad_cnt;
268 struct tool_spad *inspads;
269 struct dentry *dbgfs_dir;
270};
271
272#define TOOL_FOPS_RDWR(__name, __read, __write) \
273 const struct file_operations __name = { \
274 .owner = THIS_MODULE, \
275 .open = simple_open, \
276 .read = __read, \
277 .write = __write, \
278 }
279
280#define TOOL_BUF_LEN 32
281
282static struct dentry *tool_dbgfs_topdir;
283
284
285
286
287
288
289static void tool_link_event(void *ctx)
290{
291 struct tool_ctx *tc = ctx;
292 enum ntb_speed speed;
293 enum ntb_width width;
294 int up;
295
296 up = ntb_link_is_up(tc->ntb, &speed, &width);
297
298 dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
299 up ? "up" : "down", speed, width);
300
301 wake_up(&tc->link_wq);
302}
303
304static void tool_db_event(void *ctx, int vec)
305{
306 struct tool_ctx *tc = ctx;
307 u64 db_bits, db_mask;
308
309 db_mask = ntb_db_vector_mask(tc->ntb, vec);
310 db_bits = ntb_db_read(tc->ntb);
311
312 dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
313 vec, db_mask, db_bits);
314
315 wake_up(&tc->db_wq);
316}
317
318static void tool_msg_event(void *ctx)
319{
320 struct tool_ctx *tc = ctx;
321 u64 msg_sts;
322
323 msg_sts = ntb_msg_read_sts(tc->ntb);
324
325 dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts);
326
327 wake_up(&tc->msg_wq);
328}
329
330static const struct ntb_ctx_ops tool_ops = {
331 .link_event = tool_link_event,
332 .db_event = tool_db_event,
333 .msg_event = tool_msg_event
334};
335
336
337
338
339
340
341static ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf,
342 size_t size, loff_t *offp,
343 u64 (*fn_read)(struct ntb_dev *))
344{
345 size_t buf_size;
346 char buf[TOOL_BUF_LEN];
347 ssize_t pos;
348
349 if (!fn_read)
350 return -EINVAL;
351
352 buf_size = min(size, sizeof(buf));
353
354 pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb));
355
356 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
357}
358
359static ssize_t tool_fn_write(struct tool_ctx *tc,
360 const char __user *ubuf,
361 size_t size, loff_t *offp,
362 int (*fn_set)(struct ntb_dev *, u64),
363 int (*fn_clear)(struct ntb_dev *, u64))
364{
365 char *buf, cmd;
366 ssize_t ret;
367 u64 bits;
368 int n;
369
370 buf = kmalloc(size + 1, GFP_KERNEL);
371 if (!buf)
372 return -ENOMEM;
373
374 ret = simple_write_to_buffer(buf, size, offp, ubuf, size);
375 if (ret < 0) {
376 kfree(buf);
377 return ret;
378 }
379
380 buf[size] = 0;
381
382 n = sscanf(buf, "%c %lli", &cmd, &bits);
383
384 kfree(buf);
385
386 if (n != 2) {
387 ret = -EINVAL;
388 } else if (cmd == 's') {
389 if (!fn_set)
390 ret = -EINVAL;
391 else
392 ret = fn_set(tc->ntb, bits);
393 } else if (cmd == 'c') {
394 if (!fn_clear)
395 ret = -EINVAL;
396 else
397 ret = fn_clear(tc->ntb, bits);
398 } else {
399 ret = -EINVAL;
400 }
401
402 return ret ? : size;
403}
404
405
406
407
408
409
410static ssize_t tool_port_read(struct file *filep, char __user *ubuf,
411 size_t size, loff_t *offp)
412{
413 struct tool_ctx *tc = filep->private_data;
414 char buf[TOOL_BUF_LEN];
415 int pos;
416
417 pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb));
418
419 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
420}
421
422static TOOL_FOPS_RDWR(tool_port_fops,
423 tool_port_read,
424 NULL);
425
426static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf,
427 size_t size, loff_t *offp)
428{
429 struct tool_peer *peer = filep->private_data;
430 struct tool_ctx *tc = peer->tc;
431 char buf[TOOL_BUF_LEN];
432 int pos;
433
434 pos = scnprintf(buf, sizeof(buf), "%d\n",
435 ntb_peer_port_number(tc->ntb, peer->pidx));
436
437 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
438}
439
440static TOOL_FOPS_RDWR(tool_peer_port_fops,
441 tool_peer_port_read,
442 NULL);
443
444static int tool_init_peers(struct tool_ctx *tc)
445{
446 int pidx;
447
448 tc->peer_cnt = ntb_peer_port_count(tc->ntb);
449 tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt,
450 sizeof(*tc->peers), GFP_KERNEL);
451 if (tc->peers == NULL)
452 return -ENOMEM;
453
454 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
455 tc->peers[pidx].pidx = pidx;
456 tc->peers[pidx].tc = tc;
457 }
458
459 return 0;
460}
461
462
463
464
465
466
467static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
468 size_t size, loff_t *offp)
469{
470 struct tool_ctx *tc = filep->private_data;
471 bool val;
472 int ret;
473
474 ret = kstrtobool_from_user(ubuf, size, &val);
475 if (ret)
476 return ret;
477
478 if (val)
479 ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
480 else
481 ret = ntb_link_disable(tc->ntb);
482
483 if (ret)
484 return ret;
485
486 return size;
487}
488
489static TOOL_FOPS_RDWR(tool_link_fops,
490 NULL,
491 tool_link_write);
492
493static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf,
494 size_t size, loff_t *offp)
495{
496 struct tool_peer *peer = filep->private_data;
497 struct tool_ctx *tc = peer->tc;
498 char buf[3];
499
500 if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx))
501 buf[0] = 'Y';
502 else
503 buf[0] = 'N';
504 buf[1] = '\n';
505 buf[2] = '\0';
506
507 return simple_read_from_buffer(ubuf, size, offp, buf, 2);
508}
509
510static TOOL_FOPS_RDWR(tool_peer_link_fops,
511 tool_peer_link_read,
512 NULL);
513
514static ssize_t tool_peer_link_event_write(struct file *filep,
515 const char __user *ubuf,
516 size_t size, loff_t *offp)
517{
518 struct tool_peer *peer = filep->private_data;
519 struct tool_ctx *tc = peer->tc;
520 u64 link_msk;
521 bool val;
522 int ret;
523
524 ret = kstrtobool_from_user(ubuf, size, &val);
525 if (ret)
526 return ret;
527
528 link_msk = BIT_ULL_MASK(peer->pidx);
529
530 if (wait_event_interruptible(tc->link_wq,
531 !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val))
532 return -ERESTART;
533
534 return size;
535}
536
537static TOOL_FOPS_RDWR(tool_peer_link_event_fops,
538 NULL,
539 tool_peer_link_event_write);
540
541
542
543
544
545
546static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
547 size_t size, loff_t *offp)
548{
549 struct tool_mw *inmw = filep->private_data;
550
551 if (inmw->mm_base == NULL)
552 return -ENXIO;
553
554 return simple_read_from_buffer(ubuf, size, offp,
555 inmw->mm_base, inmw->size);
556}
557
558static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
559 size_t size, loff_t *offp)
560{
561 struct tool_mw *inmw = filep->private_data;
562
563 if (inmw->mm_base == NULL)
564 return -ENXIO;
565
566 return simple_write_to_buffer(inmw->mm_base, inmw->size, offp,
567 ubuf, size);
568}
569
570static TOOL_FOPS_RDWR(tool_mw_fops,
571 tool_mw_read,
572 tool_mw_write);
573
574static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx,
575 size_t req_size)
576{
577 resource_size_t size, addr_align, size_align;
578 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
579 char buf[TOOL_BUF_LEN];
580 int ret;
581
582 if (inmw->mm_base != NULL)
583 return 0;
584
585 ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align,
586 &size_align, &size);
587 if (ret)
588 return ret;
589
590 inmw->size = min_t(resource_size_t, req_size, size);
591 inmw->size = round_up(inmw->size, addr_align);
592 inmw->size = round_up(inmw->size, size_align);
593 inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size,
594 &inmw->dma_base, GFP_KERNEL);
595 if (!inmw->mm_base)
596 return -ENOMEM;
597
598 if (!IS_ALIGNED(inmw->dma_base, addr_align)) {
599 ret = -ENOMEM;
600 goto err_free_dma;
601 }
602
603 ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size);
604 if (ret)
605 goto err_free_dma;
606
607 snprintf(buf, sizeof(buf), "mw%d", widx);
608 inmw->dbgfs_file = debugfs_create_file(buf, 0600,
609 tc->peers[pidx].dbgfs_dir, inmw,
610 &tool_mw_fops);
611
612 return 0;
613
614err_free_dma:
615 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base,
616 inmw->dma_base);
617 inmw->mm_base = NULL;
618 inmw->dma_base = 0;
619 inmw->size = 0;
620
621 return ret;
622}
623
624static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx)
625{
626 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
627
628 debugfs_remove(inmw->dbgfs_file);
629
630 if (inmw->mm_base != NULL) {
631 ntb_mw_clear_trans(tc->ntb, pidx, widx);
632 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size,
633 inmw->mm_base, inmw->dma_base);
634 }
635
636 inmw->mm_base = NULL;
637 inmw->dma_base = 0;
638 inmw->size = 0;
639 inmw->dbgfs_file = NULL;
640}
641
642static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf,
643 size_t size, loff_t *offp)
644{
645 struct tool_mw *inmw = filep->private_data;
646 resource_size_t addr_align;
647 resource_size_t size_align;
648 resource_size_t size_max;
649 ssize_t ret, off = 0;
650 size_t buf_size;
651 char *buf;
652
653 buf_size = min_t(size_t, size, 512);
654
655 buf = kmalloc(buf_size, GFP_KERNEL);
656 if (!buf)
657 return -ENOMEM;
658
659 ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx,
660 &addr_align, &size_align, &size_max);
661 if (ret)
662 goto err;
663
664 off += scnprintf(buf + off, buf_size - off,
665 "Inbound MW \t%d\n",
666 inmw->widx);
667
668 off += scnprintf(buf + off, buf_size - off,
669 "Port \t%d (%d)\n",
670 ntb_peer_port_number(inmw->tc->ntb, inmw->pidx),
671 inmw->pidx);
672
673 off += scnprintf(buf + off, buf_size - off,
674 "Window Address \t0x%pK\n", inmw->mm_base);
675
676 off += scnprintf(buf + off, buf_size - off,
677 "DMA Address \t%pad\n",
678 &inmw->dma_base);
679
680 off += scnprintf(buf + off, buf_size - off,
681 "Window Size \t%pap\n",
682 &inmw->size);
683
684 off += scnprintf(buf + off, buf_size - off,
685 "Alignment \t%pap\n",
686 &addr_align);
687
688 off += scnprintf(buf + off, buf_size - off,
689 "Size Alignment \t%pap\n",
690 &size_align);
691
692 off += scnprintf(buf + off, buf_size - off,
693 "Size Max \t%pap\n",
694 &size_max);
695
696 ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
697
698err:
699 kfree(buf);
700
701 return ret;
702}
703
704static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf,
705 size_t size, loff_t *offp)
706{
707 struct tool_mw *inmw = filep->private_data;
708 unsigned int val;
709 int ret;
710
711 ret = kstrtouint_from_user(ubuf, size, 0, &val);
712 if (ret)
713 return ret;
714
715 tool_free_mw(inmw->tc, inmw->pidx, inmw->widx);
716 if (val) {
717 ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val);
718 if (ret)
719 return ret;
720 }
721
722 return size;
723}
724
725static TOOL_FOPS_RDWR(tool_mw_trans_fops,
726 tool_mw_trans_read,
727 tool_mw_trans_write);
728
729static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
730 size_t size, loff_t *offp)
731{
732 struct tool_mw *outmw = filep->private_data;
733 loff_t pos = *offp;
734 ssize_t ret;
735 void *buf;
736
737 if (outmw->io_base == NULL)
738 return -EIO;
739
740 if (pos >= outmw->size || !size)
741 return 0;
742
743 if (size > outmw->size - pos)
744 size = outmw->size - pos;
745
746 buf = kmalloc(size, GFP_KERNEL);
747 if (!buf)
748 return -ENOMEM;
749
750 memcpy_fromio(buf, outmw->io_base + pos, size);
751 ret = copy_to_user(ubuf, buf, size);
752 if (ret == size) {
753 ret = -EFAULT;
754 goto err_free;
755 }
756
757 size -= ret;
758 *offp = pos + size;
759 ret = size;
760
761err_free:
762 kfree(buf);
763
764 return ret;
765}
766
767static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
768 size_t size, loff_t *offp)
769{
770 struct tool_mw *outmw = filep->private_data;
771 ssize_t ret;
772 loff_t pos = *offp;
773 void *buf;
774
775 if (outmw->io_base == NULL)
776 return -EIO;
777
778 if (pos >= outmw->size || !size)
779 return 0;
780 if (size > outmw->size - pos)
781 size = outmw->size - pos;
782
783 buf = kmalloc(size, GFP_KERNEL);
784 if (!buf)
785 return -ENOMEM;
786
787 ret = copy_from_user(buf, ubuf, size);
788 if (ret == size) {
789 ret = -EFAULT;
790 goto err_free;
791 }
792
793 size -= ret;
794 *offp = pos + size;
795 ret = size;
796
797 memcpy_toio(outmw->io_base + pos, buf, size);
798
799err_free:
800 kfree(buf);
801
802 return ret;
803}
804
805static TOOL_FOPS_RDWR(tool_peer_mw_fops,
806 tool_peer_mw_read,
807 tool_peer_mw_write);
808
809static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx,
810 u64 req_addr, size_t req_size)
811{
812 struct tool_mw *outmw = &tc->outmws[widx];
813 resource_size_t map_size;
814 phys_addr_t map_base;
815 char buf[TOOL_BUF_LEN];
816 int ret;
817
818 if (outmw->io_base != NULL)
819 return 0;
820
821 ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size);
822 if (ret)
823 return ret;
824
825 ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size);
826 if (ret)
827 return ret;
828
829 outmw->io_base = ioremap_wc(map_base, map_size);
830 if (outmw->io_base == NULL) {
831 ret = -EFAULT;
832 goto err_clear_trans;
833 }
834
835 outmw->tr_base = req_addr;
836 outmw->size = req_size;
837 outmw->pidx = pidx;
838
839 snprintf(buf, sizeof(buf), "peer_mw%d", widx);
840 outmw->dbgfs_file = debugfs_create_file(buf, 0600,
841 tc->peers[pidx].dbgfs_dir, outmw,
842 &tool_peer_mw_fops);
843
844 return 0;
845
846err_clear_trans:
847 ntb_peer_mw_clear_trans(tc->ntb, pidx, widx);
848
849 return ret;
850}
851
852static void tool_free_peer_mw(struct tool_ctx *tc, int widx)
853{
854 struct tool_mw *outmw = &tc->outmws[widx];
855
856 debugfs_remove(outmw->dbgfs_file);
857
858 if (outmw->io_base != NULL) {
859 iounmap(tc->outmws[widx].io_base);
860 ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx);
861 }
862
863 outmw->io_base = NULL;
864 outmw->tr_base = 0;
865 outmw->size = 0;
866 outmw->pidx = -1;
867 outmw->dbgfs_file = NULL;
868}
869
870static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf,
871 size_t size, loff_t *offp)
872{
873 struct tool_mw_wrap *outmw_wrap = filep->private_data;
874 struct tool_mw *outmw = outmw_wrap->mw;
875 resource_size_t map_size;
876 phys_addr_t map_base;
877 ssize_t off = 0;
878 size_t buf_size;
879 char *buf;
880 int ret;
881
882 ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx,
883 &map_base, &map_size);
884 if (ret)
885 return ret;
886
887 buf_size = min_t(size_t, size, 512);
888
889 buf = kmalloc(buf_size, GFP_KERNEL);
890 if (!buf)
891 return -ENOMEM;
892
893 off += scnprintf(buf + off, buf_size - off,
894 "Outbound MW: \t%d\n", outmw->widx);
895
896 if (outmw->io_base != NULL) {
897 off += scnprintf(buf + off, buf_size - off,
898 "Port attached \t%d (%d)\n",
899 ntb_peer_port_number(outmw->tc->ntb, outmw->pidx),
900 outmw->pidx);
901 } else {
902 off += scnprintf(buf + off, buf_size - off,
903 "Port attached \t-1 (-1)\n");
904 }
905
906 off += scnprintf(buf + off, buf_size - off,
907 "Virtual address \t0x%pK\n", outmw->io_base);
908
909 off += scnprintf(buf + off, buf_size - off,
910 "Phys Address \t%pap\n", &map_base);
911
912 off += scnprintf(buf + off, buf_size - off,
913 "Mapping Size \t%pap\n", &map_size);
914
915 off += scnprintf(buf + off, buf_size - off,
916 "Translation Address \t0x%016llx\n", outmw->tr_base);
917
918 off += scnprintf(buf + off, buf_size - off,
919 "Window Size \t%pap\n", &outmw->size);
920
921 ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
922 kfree(buf);
923
924 return ret;
925}
926
927static ssize_t tool_peer_mw_trans_write(struct file *filep,
928 const char __user *ubuf,
929 size_t size, loff_t *offp)
930{
931 struct tool_mw_wrap *outmw_wrap = filep->private_data;
932 struct tool_mw *outmw = outmw_wrap->mw;
933 size_t buf_size, wsize;
934 char buf[TOOL_BUF_LEN];
935 int ret, n;
936 u64 addr;
937
938 buf_size = min(size, (sizeof(buf) - 1));
939 if (copy_from_user(buf, ubuf, buf_size))
940 return -EFAULT;
941
942 buf[buf_size] = '\0';
943
944 n = sscanf(buf, "%lli:%zi", &addr, &wsize);
945 if (n != 2)
946 return -EINVAL;
947
948 tool_free_peer_mw(outmw->tc, outmw->widx);
949 if (wsize) {
950 ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx,
951 outmw->widx, addr, wsize);
952 if (ret)
953 return ret;
954 }
955
956 return size;
957}
958
959static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
960 tool_peer_mw_trans_read,
961 tool_peer_mw_trans_write);
962
963static int tool_init_mws(struct tool_ctx *tc)
964{
965 int widx, pidx;
966
967
968 tc->outmw_cnt = ntb_peer_mw_count(tc->ntb);
969 tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt,
970 sizeof(*tc->outmws), GFP_KERNEL);
971 if (tc->outmws == NULL)
972 return -ENOMEM;
973
974 for (widx = 0; widx < tc->outmw_cnt; widx++) {
975 tc->outmws[widx].widx = widx;
976 tc->outmws[widx].pidx = -1;
977 tc->outmws[widx].tc = tc;
978 }
979
980
981 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
982 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx);
983 tc->peers[pidx].inmws =
984 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt,
985 sizeof(*tc->peers[pidx].inmws), GFP_KERNEL);
986 if (tc->peers[pidx].inmws == NULL)
987 return -ENOMEM;
988
989 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
990 tc->peers[pidx].inmws[widx].widx = widx;
991 tc->peers[pidx].inmws[widx].pidx = pidx;
992 tc->peers[pidx].inmws[widx].tc = tc;
993 }
994
995 tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb);
996 tc->peers[pidx].outmws =
997 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt,
998 sizeof(*tc->peers[pidx].outmws), GFP_KERNEL);
999
1000 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
1001 tc->peers[pidx].outmws[widx].pidx = pidx;
1002 tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx];
1003 }
1004 }
1005
1006 return 0;
1007}
1008
1009static void tool_clear_mws(struct tool_ctx *tc)
1010{
1011 int widx, pidx;
1012
1013
1014 for (widx = 0; widx < tc->outmw_cnt; widx++)
1015 tool_free_peer_mw(tc, widx);
1016
1017
1018 for (pidx = 0; pidx < tc->peer_cnt; pidx++)
1019 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++)
1020 tool_free_mw(tc, pidx, widx);
1021}
1022
1023
1024
1025
1026
1027
1028static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
1029 size_t size, loff_t *offp)
1030{
1031 struct tool_ctx *tc = filep->private_data;
1032
1033 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read);
1034}
1035
1036static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
1037 size_t size, loff_t *offp)
1038{
1039 struct tool_ctx *tc = filep->private_data;
1040
1041 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set,
1042 tc->ntb->ops->db_clear);
1043}
1044
1045static TOOL_FOPS_RDWR(tool_db_fops,
1046 tool_db_read,
1047 tool_db_write);
1048
1049static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf,
1050 size_t size, loff_t *offp)
1051{
1052 struct tool_ctx *tc = filep->private_data;
1053
1054 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask);
1055}
1056
1057static TOOL_FOPS_RDWR(tool_db_valid_mask_fops,
1058 tool_db_valid_mask_read,
1059 NULL);
1060
1061static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf,
1062 size_t size, loff_t *offp)
1063{
1064 struct tool_ctx *tc = filep->private_data;
1065
1066 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask);
1067}
1068
1069static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf,
1070 size_t size, loff_t *offp)
1071{
1072 struct tool_ctx *tc = filep->private_data;
1073
1074 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask,
1075 tc->ntb->ops->db_clear_mask);
1076}
1077
1078static TOOL_FOPS_RDWR(tool_db_mask_fops,
1079 tool_db_mask_read,
1080 tool_db_mask_write);
1081
1082static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
1083 size_t size, loff_t *offp)
1084{
1085 struct tool_ctx *tc = filep->private_data;
1086
1087 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read);
1088}
1089
1090static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
1091 size_t size, loff_t *offp)
1092{
1093 struct tool_ctx *tc = filep->private_data;
1094
1095 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set,
1096 tc->ntb->ops->peer_db_clear);
1097}
1098
1099static TOOL_FOPS_RDWR(tool_peer_db_fops,
1100 tool_peer_db_read,
1101 tool_peer_db_write);
1102
1103static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf,
1104 size_t size, loff_t *offp)
1105{
1106 struct tool_ctx *tc = filep->private_data;
1107
1108 return tool_fn_read(tc, ubuf, size, offp,
1109 tc->ntb->ops->peer_db_read_mask);
1110}
1111
1112static ssize_t tool_peer_db_mask_write(struct file *filep,
1113 const char __user *ubuf,
1114 size_t size, loff_t *offp)
1115{
1116 struct tool_ctx *tc = filep->private_data;
1117
1118 return tool_fn_write(tc, ubuf, size, offp,
1119 tc->ntb->ops->peer_db_set_mask,
1120 tc->ntb->ops->peer_db_clear_mask);
1121}
1122
1123static TOOL_FOPS_RDWR(tool_peer_db_mask_fops,
1124 tool_peer_db_mask_read,
1125 tool_peer_db_mask_write);
1126
1127static ssize_t tool_db_event_write(struct file *filep,
1128 const char __user *ubuf,
1129 size_t size, loff_t *offp)
1130{
1131 struct tool_ctx *tc = filep->private_data;
1132 u64 val;
1133 int ret;
1134
1135 ret = kstrtou64_from_user(ubuf, size, 0, &val);
1136 if (ret)
1137 return ret;
1138
1139 if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val))
1140 return -ERESTART;
1141
1142 return size;
1143}
1144
1145static TOOL_FOPS_RDWR(tool_db_event_fops,
1146 NULL,
1147 tool_db_event_write);
1148
1149
1150
1151
1152
1153
1154static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
1155 size_t size, loff_t *offp)
1156{
1157 struct tool_spad *spad = filep->private_data;
1158 char buf[TOOL_BUF_LEN];
1159 ssize_t pos;
1160
1161 if (!spad->tc->ntb->ops->spad_read)
1162 return -EINVAL;
1163
1164 pos = scnprintf(buf, sizeof(buf), "%#x\n",
1165 ntb_spad_read(spad->tc->ntb, spad->sidx));
1166
1167 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1168}
1169
1170static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
1171 size_t size, loff_t *offp)
1172{
1173 struct tool_spad *spad = filep->private_data;
1174 u32 val;
1175 int ret;
1176
1177 if (!spad->tc->ntb->ops->spad_write) {
1178 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1179 return -EINVAL;
1180 }
1181
1182 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1183 if (ret)
1184 return ret;
1185
1186 ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val);
1187
1188 return ret ?: size;
1189}
1190
1191static TOOL_FOPS_RDWR(tool_spad_fops,
1192 tool_spad_read,
1193 tool_spad_write);
1194
1195static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
1196 size_t size, loff_t *offp)
1197{
1198 struct tool_spad *spad = filep->private_data;
1199 char buf[TOOL_BUF_LEN];
1200 ssize_t pos;
1201
1202 if (!spad->tc->ntb->ops->peer_spad_read)
1203 return -EINVAL;
1204
1205 pos = scnprintf(buf, sizeof(buf), "%#x\n",
1206 ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx));
1207
1208 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1209}
1210
1211static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
1212 size_t size, loff_t *offp)
1213{
1214 struct tool_spad *spad = filep->private_data;
1215 u32 val;
1216 int ret;
1217
1218 if (!spad->tc->ntb->ops->peer_spad_write) {
1219 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1220 return -EINVAL;
1221 }
1222
1223 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1224 if (ret)
1225 return ret;
1226
1227 ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val);
1228
1229 return ret ?: size;
1230}
1231
1232static TOOL_FOPS_RDWR(tool_peer_spad_fops,
1233 tool_peer_spad_read,
1234 tool_peer_spad_write);
1235
1236static int tool_init_spads(struct tool_ctx *tc)
1237{
1238 int sidx, pidx;
1239
1240
1241 tc->inspad_cnt = ntb_spad_count(tc->ntb);
1242 tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt,
1243 sizeof(*tc->inspads), GFP_KERNEL);
1244 if (tc->inspads == NULL)
1245 return -ENOMEM;
1246
1247 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1248 tc->inspads[sidx].sidx = sidx;
1249 tc->inspads[sidx].pidx = -1;
1250 tc->inspads[sidx].tc = tc;
1251 }
1252
1253
1254 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1255 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb);
1256 tc->peers[pidx].outspads =
1257 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt,
1258 sizeof(*tc->peers[pidx].outspads), GFP_KERNEL);
1259 if (tc->peers[pidx].outspads == NULL)
1260 return -ENOMEM;
1261
1262 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1263 tc->peers[pidx].outspads[sidx].sidx = sidx;
1264 tc->peers[pidx].outspads[sidx].pidx = pidx;
1265 tc->peers[pidx].outspads[sidx].tc = tc;
1266 }
1267 }
1268
1269 return 0;
1270}
1271
1272
1273
1274
1275
1276
1277static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf,
1278 size_t size, loff_t *offp)
1279{
1280 struct tool_msg *msg = filep->private_data;
1281 char buf[TOOL_BUF_LEN];
1282 ssize_t pos;
1283 u32 data;
1284 int pidx;
1285
1286 data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx);
1287
1288 pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx);
1289
1290 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1291}
1292
1293static TOOL_FOPS_RDWR(tool_inmsg_fops,
1294 tool_inmsg_read,
1295 NULL);
1296
1297static ssize_t tool_outmsg_write(struct file *filep,
1298 const char __user *ubuf,
1299 size_t size, loff_t *offp)
1300{
1301 struct tool_msg *msg = filep->private_data;
1302 u32 val;
1303 int ret;
1304
1305 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1306 if (ret)
1307 return ret;
1308
1309 ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val);
1310
1311 return ret ? : size;
1312}
1313
1314static TOOL_FOPS_RDWR(tool_outmsg_fops,
1315 NULL,
1316 tool_outmsg_write);
1317
1318static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf,
1319 size_t size, loff_t *offp)
1320{
1321 struct tool_ctx *tc = filep->private_data;
1322
1323 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts);
1324}
1325
1326static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf,
1327 size_t size, loff_t *offp)
1328{
1329 struct tool_ctx *tc = filep->private_data;
1330
1331 return tool_fn_write(tc, ubuf, size, offp, NULL,
1332 tc->ntb->ops->msg_clear_sts);
1333}
1334
1335static TOOL_FOPS_RDWR(tool_msg_sts_fops,
1336 tool_msg_sts_read,
1337 tool_msg_sts_write);
1338
1339static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf,
1340 size_t size, loff_t *offp)
1341{
1342 struct tool_ctx *tc = filep->private_data;
1343
1344 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits);
1345}
1346
1347static TOOL_FOPS_RDWR(tool_msg_inbits_fops,
1348 tool_msg_inbits_read,
1349 NULL);
1350
1351static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf,
1352 size_t size, loff_t *offp)
1353{
1354 struct tool_ctx *tc = filep->private_data;
1355
1356 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits);
1357}
1358
1359static TOOL_FOPS_RDWR(tool_msg_outbits_fops,
1360 tool_msg_outbits_read,
1361 NULL);
1362
1363static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf,
1364 size_t size, loff_t *offp)
1365{
1366 struct tool_ctx *tc = filep->private_data;
1367
1368 return tool_fn_write(tc, ubuf, size, offp,
1369 tc->ntb->ops->msg_set_mask,
1370 tc->ntb->ops->msg_clear_mask);
1371}
1372
1373static TOOL_FOPS_RDWR(tool_msg_mask_fops,
1374 NULL,
1375 tool_msg_mask_write);
1376
1377static ssize_t tool_msg_event_write(struct file *filep,
1378 const char __user *ubuf,
1379 size_t size, loff_t *offp)
1380{
1381 struct tool_ctx *tc = filep->private_data;
1382 u64 val;
1383 int ret;
1384
1385 ret = kstrtou64_from_user(ubuf, size, 0, &val);
1386 if (ret)
1387 return ret;
1388
1389 if (wait_event_interruptible(tc->msg_wq,
1390 ntb_msg_read_sts(tc->ntb) == val))
1391 return -ERESTART;
1392
1393 return size;
1394}
1395
1396static TOOL_FOPS_RDWR(tool_msg_event_fops,
1397 NULL,
1398 tool_msg_event_write);
1399
1400static int tool_init_msgs(struct tool_ctx *tc)
1401{
1402 int midx, pidx;
1403
1404
1405 tc->inmsg_cnt = ntb_msg_count(tc->ntb);
1406 tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt,
1407 sizeof(*tc->inmsgs), GFP_KERNEL);
1408 if (tc->inmsgs == NULL)
1409 return -ENOMEM;
1410
1411 for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1412 tc->inmsgs[midx].midx = midx;
1413 tc->inmsgs[midx].pidx = -1;
1414 tc->inmsgs[midx].tc = tc;
1415 }
1416
1417
1418 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1419 tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb);
1420 tc->peers[pidx].outmsgs =
1421 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt,
1422 sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL);
1423 if (tc->peers[pidx].outmsgs == NULL)
1424 return -ENOMEM;
1425
1426 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1427 tc->peers[pidx].outmsgs[midx].midx = midx;
1428 tc->peers[pidx].outmsgs[midx].pidx = pidx;
1429 tc->peers[pidx].outmsgs[midx].tc = tc;
1430 }
1431 }
1432
1433 return 0;
1434}
1435
1436
1437
1438
1439
1440
1441static struct tool_ctx *tool_create_data(struct ntb_dev *ntb)
1442{
1443 struct tool_ctx *tc;
1444
1445 tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL);
1446 if (tc == NULL)
1447 return ERR_PTR(-ENOMEM);
1448
1449 tc->ntb = ntb;
1450 init_waitqueue_head(&tc->link_wq);
1451 init_waitqueue_head(&tc->db_wq);
1452 init_waitqueue_head(&tc->msg_wq);
1453
1454 if (ntb_db_is_unsafe(ntb))
1455 dev_dbg(&ntb->dev, "doorbell is unsafe\n");
1456
1457 if (ntb_spad_is_unsafe(ntb))
1458 dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
1459
1460 return tc;
1461}
1462
1463static void tool_clear_data(struct tool_ctx *tc)
1464{
1465 wake_up(&tc->link_wq);
1466 wake_up(&tc->db_wq);
1467 wake_up(&tc->msg_wq);
1468}
1469
1470static int tool_init_ntb(struct tool_ctx *tc)
1471{
1472 return ntb_set_ctx(tc->ntb, tc, &tool_ops);
1473}
1474
1475static void tool_clear_ntb(struct tool_ctx *tc)
1476{
1477 ntb_clear_ctx(tc->ntb);
1478 ntb_link_disable(tc->ntb);
1479}
1480
1481static void tool_setup_dbgfs(struct tool_ctx *tc)
1482{
1483 int pidx, widx, sidx, midx;
1484 char buf[TOOL_BUF_LEN];
1485
1486
1487 if (!tool_dbgfs_topdir) {
1488 tc->dbgfs_dir = NULL;
1489 return;
1490 }
1491
1492 tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev),
1493 tool_dbgfs_topdir);
1494 if (!tc->dbgfs_dir)
1495 return;
1496
1497 debugfs_create_file("port", 0600, tc->dbgfs_dir,
1498 tc, &tool_port_fops);
1499
1500 debugfs_create_file("link", 0600, tc->dbgfs_dir,
1501 tc, &tool_link_fops);
1502
1503 debugfs_create_file("db", 0600, tc->dbgfs_dir,
1504 tc, &tool_db_fops);
1505
1506 debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir,
1507 tc, &tool_db_valid_mask_fops);
1508
1509 debugfs_create_file("db_mask", 0600, tc->dbgfs_dir,
1510 tc, &tool_db_mask_fops);
1511
1512 debugfs_create_file("db_event", 0600, tc->dbgfs_dir,
1513 tc, &tool_db_event_fops);
1514
1515 debugfs_create_file("peer_db", 0600, tc->dbgfs_dir,
1516 tc, &tool_peer_db_fops);
1517
1518 debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir,
1519 tc, &tool_peer_db_mask_fops);
1520
1521 if (tc->inspad_cnt != 0) {
1522 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1523 snprintf(buf, sizeof(buf), "spad%d", sidx);
1524
1525 debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1526 &tc->inspads[sidx], &tool_spad_fops);
1527 }
1528 }
1529
1530 if (tc->inmsg_cnt != 0) {
1531 for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1532 snprintf(buf, sizeof(buf), "msg%d", midx);
1533 debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1534 &tc->inmsgs[midx], &tool_inmsg_fops);
1535 }
1536
1537 debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir,
1538 tc, &tool_msg_sts_fops);
1539
1540 debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir,
1541 tc, &tool_msg_inbits_fops);
1542
1543 debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir,
1544 tc, &tool_msg_outbits_fops);
1545
1546 debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir,
1547 tc, &tool_msg_mask_fops);
1548
1549 debugfs_create_file("msg_event", 0600, tc->dbgfs_dir,
1550 tc, &tool_msg_event_fops);
1551 }
1552
1553 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1554 snprintf(buf, sizeof(buf), "peer%d", pidx);
1555 tc->peers[pidx].dbgfs_dir =
1556 debugfs_create_dir(buf, tc->dbgfs_dir);
1557
1558 debugfs_create_file("port", 0600,
1559 tc->peers[pidx].dbgfs_dir,
1560 &tc->peers[pidx], &tool_peer_port_fops);
1561
1562 debugfs_create_file("link", 0200,
1563 tc->peers[pidx].dbgfs_dir,
1564 &tc->peers[pidx], &tool_peer_link_fops);
1565
1566 debugfs_create_file("link_event", 0200,
1567 tc->peers[pidx].dbgfs_dir,
1568 &tc->peers[pidx], &tool_peer_link_event_fops);
1569
1570 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
1571 snprintf(buf, sizeof(buf), "mw_trans%d", widx);
1572 debugfs_create_file(buf, 0600,
1573 tc->peers[pidx].dbgfs_dir,
1574 &tc->peers[pidx].inmws[widx],
1575 &tool_mw_trans_fops);
1576 }
1577
1578 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
1579 snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx);
1580 debugfs_create_file(buf, 0600,
1581 tc->peers[pidx].dbgfs_dir,
1582 &tc->peers[pidx].outmws[widx],
1583 &tool_peer_mw_trans_fops);
1584 }
1585
1586 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1587 snprintf(buf, sizeof(buf), "spad%d", sidx);
1588
1589 debugfs_create_file(buf, 0600,
1590 tc->peers[pidx].dbgfs_dir,
1591 &tc->peers[pidx].outspads[sidx],
1592 &tool_peer_spad_fops);
1593 }
1594
1595 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1596 snprintf(buf, sizeof(buf), "msg%d", midx);
1597 debugfs_create_file(buf, 0600,
1598 tc->peers[pidx].dbgfs_dir,
1599 &tc->peers[pidx].outmsgs[midx],
1600 &tool_outmsg_fops);
1601 }
1602 }
1603}
1604
1605static void tool_clear_dbgfs(struct tool_ctx *tc)
1606{
1607 debugfs_remove_recursive(tc->dbgfs_dir);
1608}
1609
1610static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
1611{
1612 struct tool_ctx *tc;
1613 int ret;
1614
1615 tc = tool_create_data(ntb);
1616 if (IS_ERR(tc))
1617 return PTR_ERR(tc);
1618
1619 ret = tool_init_peers(tc);
1620 if (ret != 0)
1621 goto err_clear_data;
1622
1623 ret = tool_init_mws(tc);
1624 if (ret != 0)
1625 goto err_clear_data;
1626
1627 ret = tool_init_spads(tc);
1628 if (ret != 0)
1629 goto err_clear_mws;
1630
1631 ret = tool_init_msgs(tc);
1632 if (ret != 0)
1633 goto err_clear_mws;
1634
1635 ret = tool_init_ntb(tc);
1636 if (ret != 0)
1637 goto err_clear_mws;
1638
1639 tool_setup_dbgfs(tc);
1640
1641 return 0;
1642
1643err_clear_mws:
1644 tool_clear_mws(tc);
1645
1646err_clear_data:
1647 tool_clear_data(tc);
1648
1649 return ret;
1650}
1651
1652static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
1653{
1654 struct tool_ctx *tc = ntb->ctx;
1655
1656 tool_clear_dbgfs(tc);
1657
1658 tool_clear_ntb(tc);
1659
1660 tool_clear_mws(tc);
1661
1662 tool_clear_data(tc);
1663}
1664
1665static struct ntb_client tool_client = {
1666 .ops = {
1667 .probe = tool_probe,
1668 .remove = tool_remove,
1669 }
1670};
1671
1672static int __init tool_init(void)
1673{
1674 int ret;
1675
1676 if (debugfs_initialized())
1677 tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
1678
1679 ret = ntb_register_client(&tool_client);
1680 if (ret)
1681 debugfs_remove_recursive(tool_dbgfs_topdir);
1682
1683 return ret;
1684}
1685module_init(tool_init);
1686
1687static void __exit tool_exit(void)
1688{
1689 ntb_unregister_client(&tool_client);
1690 debugfs_remove_recursive(tool_dbgfs_topdir);
1691}
1692module_exit(tool_exit);
1693