0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179 #include <linux/init.h>
0180 #include <linux/kernel.h>
0181 #include <linux/module.h>
0182
0183 #include <linux/debugfs.h>
0184 #include <linux/dma-mapping.h>
0185 #include <linux/pci.h>
0186 #include <linux/slab.h>
0187 #include <linux/uaccess.h>
0188
0189 #include <linux/ntb.h>
0190
0191 #define DRIVER_NAME "ntb_tool"
0192 #define DRIVER_VERSION "2.0"
0193
0194 MODULE_LICENSE("Dual BSD/GPL");
0195 MODULE_VERSION(DRIVER_VERSION);
0196 MODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>");
0197 MODULE_DESCRIPTION("PCIe NTB Debugging Tool");
0198
0199
0200
0201
0202
0203
0204
0205 struct tool_mw {
0206 int widx;
0207 int pidx;
0208 struct tool_ctx *tc;
0209 union {
0210 u8 *mm_base;
0211 u8 __iomem *io_base;
0212 };
0213 union {
0214 dma_addr_t dma_base;
0215 u64 tr_base;
0216 };
0217 resource_size_t size;
0218 struct dentry *dbgfs_file;
0219 };
0220
0221
0222
0223
0224
0225 struct tool_mw_wrap {
0226 int pidx;
0227 struct tool_mw *mw;
0228 };
0229
0230 struct tool_msg {
0231 int midx;
0232 int pidx;
0233 struct tool_ctx *tc;
0234 };
0235
0236 struct tool_spad {
0237 int sidx;
0238 int pidx;
0239 struct tool_ctx *tc;
0240 };
0241
0242 struct tool_peer {
0243 int pidx;
0244 struct tool_ctx *tc;
0245 int inmw_cnt;
0246 struct tool_mw *inmws;
0247 int outmw_cnt;
0248 struct tool_mw_wrap *outmws;
0249 int outmsg_cnt;
0250 struct tool_msg *outmsgs;
0251 int outspad_cnt;
0252 struct tool_spad *outspads;
0253 struct dentry *dbgfs_dir;
0254 };
0255
0256 struct tool_ctx {
0257 struct ntb_dev *ntb;
0258 wait_queue_head_t link_wq;
0259 wait_queue_head_t db_wq;
0260 wait_queue_head_t msg_wq;
0261 int outmw_cnt;
0262 struct tool_mw *outmws;
0263 int peer_cnt;
0264 struct tool_peer *peers;
0265 int inmsg_cnt;
0266 struct tool_msg *inmsgs;
0267 int inspad_cnt;
0268 struct tool_spad *inspads;
0269 struct dentry *dbgfs_dir;
0270 };
0271
0272 #define TOOL_FOPS_RDWR(__name, __read, __write) \
0273 const struct file_operations __name = { \
0274 .owner = THIS_MODULE, \
0275 .open = simple_open, \
0276 .read = __read, \
0277 .write = __write, \
0278 }
0279
0280 #define TOOL_BUF_LEN 32
0281
0282 static struct dentry *tool_dbgfs_topdir;
0283
0284
0285
0286
0287
0288
0289 static void tool_link_event(void *ctx)
0290 {
0291 struct tool_ctx *tc = ctx;
0292 enum ntb_speed speed;
0293 enum ntb_width width;
0294 int up;
0295
0296 up = ntb_link_is_up(tc->ntb, &speed, &width);
0297
0298 dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
0299 up ? "up" : "down", speed, width);
0300
0301 wake_up(&tc->link_wq);
0302 }
0303
0304 static void tool_db_event(void *ctx, int vec)
0305 {
0306 struct tool_ctx *tc = ctx;
0307 u64 db_bits, db_mask;
0308
0309 db_mask = ntb_db_vector_mask(tc->ntb, vec);
0310 db_bits = ntb_db_read(tc->ntb);
0311
0312 dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
0313 vec, db_mask, db_bits);
0314
0315 wake_up(&tc->db_wq);
0316 }
0317
0318 static void tool_msg_event(void *ctx)
0319 {
0320 struct tool_ctx *tc = ctx;
0321 u64 msg_sts;
0322
0323 msg_sts = ntb_msg_read_sts(tc->ntb);
0324
0325 dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts);
0326
0327 wake_up(&tc->msg_wq);
0328 }
0329
0330 static const struct ntb_ctx_ops tool_ops = {
0331 .link_event = tool_link_event,
0332 .db_event = tool_db_event,
0333 .msg_event = tool_msg_event
0334 };
0335
0336
0337
0338
0339
0340
0341 static ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf,
0342 size_t size, loff_t *offp,
0343 u64 (*fn_read)(struct ntb_dev *))
0344 {
0345 size_t buf_size;
0346 char buf[TOOL_BUF_LEN];
0347 ssize_t pos;
0348
0349 if (!fn_read)
0350 return -EINVAL;
0351
0352 buf_size = min(size, sizeof(buf));
0353
0354 pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb));
0355
0356 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
0357 }
0358
0359 static ssize_t tool_fn_write(struct tool_ctx *tc,
0360 const char __user *ubuf,
0361 size_t size, loff_t *offp,
0362 int (*fn_set)(struct ntb_dev *, u64),
0363 int (*fn_clear)(struct ntb_dev *, u64))
0364 {
0365 char *buf, cmd;
0366 ssize_t ret;
0367 u64 bits;
0368 int n;
0369
0370 if (*offp)
0371 return 0;
0372
0373 buf = kmalloc(size + 1, GFP_KERNEL);
0374 if (!buf)
0375 return -ENOMEM;
0376
0377 if (copy_from_user(buf, ubuf, size)) {
0378 kfree(buf);
0379 return -EFAULT;
0380 }
0381
0382 buf[size] = 0;
0383
0384 n = sscanf(buf, "%c %lli", &cmd, &bits);
0385
0386 kfree(buf);
0387
0388 if (n != 2) {
0389 ret = -EINVAL;
0390 } else if (cmd == 's') {
0391 if (!fn_set)
0392 ret = -EINVAL;
0393 else
0394 ret = fn_set(tc->ntb, bits);
0395 } else if (cmd == 'c') {
0396 if (!fn_clear)
0397 ret = -EINVAL;
0398 else
0399 ret = fn_clear(tc->ntb, bits);
0400 } else {
0401 ret = -EINVAL;
0402 }
0403
0404 return ret ? : size;
0405 }
0406
0407
0408
0409
0410
0411
0412 static ssize_t tool_port_read(struct file *filep, char __user *ubuf,
0413 size_t size, loff_t *offp)
0414 {
0415 struct tool_ctx *tc = filep->private_data;
0416 char buf[TOOL_BUF_LEN];
0417 int pos;
0418
0419 pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb));
0420
0421 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
0422 }
0423
0424 static TOOL_FOPS_RDWR(tool_port_fops,
0425 tool_port_read,
0426 NULL);
0427
0428 static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf,
0429 size_t size, loff_t *offp)
0430 {
0431 struct tool_peer *peer = filep->private_data;
0432 struct tool_ctx *tc = peer->tc;
0433 char buf[TOOL_BUF_LEN];
0434 int pos;
0435
0436 pos = scnprintf(buf, sizeof(buf), "%d\n",
0437 ntb_peer_port_number(tc->ntb, peer->pidx));
0438
0439 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
0440 }
0441
0442 static TOOL_FOPS_RDWR(tool_peer_port_fops,
0443 tool_peer_port_read,
0444 NULL);
0445
0446 static int tool_init_peers(struct tool_ctx *tc)
0447 {
0448 int pidx;
0449
0450 tc->peer_cnt = ntb_peer_port_count(tc->ntb);
0451 tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt,
0452 sizeof(*tc->peers), GFP_KERNEL);
0453 if (tc->peers == NULL)
0454 return -ENOMEM;
0455
0456 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
0457 tc->peers[pidx].pidx = pidx;
0458 tc->peers[pidx].tc = tc;
0459 }
0460
0461 return 0;
0462 }
0463
0464
0465
0466
0467
0468
0469 static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
0470 size_t size, loff_t *offp)
0471 {
0472 struct tool_ctx *tc = filep->private_data;
0473 bool val;
0474 int ret;
0475
0476 ret = kstrtobool_from_user(ubuf, size, &val);
0477 if (ret)
0478 return ret;
0479
0480 if (val)
0481 ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
0482 else
0483 ret = ntb_link_disable(tc->ntb);
0484
0485 if (ret)
0486 return ret;
0487
0488 return size;
0489 }
0490
0491 static TOOL_FOPS_RDWR(tool_link_fops,
0492 NULL,
0493 tool_link_write);
0494
0495 static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf,
0496 size_t size, loff_t *offp)
0497 {
0498 struct tool_peer *peer = filep->private_data;
0499 struct tool_ctx *tc = peer->tc;
0500 char buf[3];
0501
0502 if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx))
0503 buf[0] = 'Y';
0504 else
0505 buf[0] = 'N';
0506 buf[1] = '\n';
0507 buf[2] = '\0';
0508
0509 return simple_read_from_buffer(ubuf, size, offp, buf, 2);
0510 }
0511
0512 static TOOL_FOPS_RDWR(tool_peer_link_fops,
0513 tool_peer_link_read,
0514 NULL);
0515
0516 static ssize_t tool_peer_link_event_write(struct file *filep,
0517 const char __user *ubuf,
0518 size_t size, loff_t *offp)
0519 {
0520 struct tool_peer *peer = filep->private_data;
0521 struct tool_ctx *tc = peer->tc;
0522 u64 link_msk;
0523 bool val;
0524 int ret;
0525
0526 ret = kstrtobool_from_user(ubuf, size, &val);
0527 if (ret)
0528 return ret;
0529
0530 link_msk = BIT_ULL_MASK(peer->pidx);
0531
0532 if (wait_event_interruptible(tc->link_wq,
0533 !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val))
0534 return -ERESTART;
0535
0536 return size;
0537 }
0538
0539 static TOOL_FOPS_RDWR(tool_peer_link_event_fops,
0540 NULL,
0541 tool_peer_link_event_write);
0542
0543
0544
0545
0546
0547
0548 static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
0549 size_t size, loff_t *offp)
0550 {
0551 struct tool_mw *inmw = filep->private_data;
0552
0553 if (inmw->mm_base == NULL)
0554 return -ENXIO;
0555
0556 return simple_read_from_buffer(ubuf, size, offp,
0557 inmw->mm_base, inmw->size);
0558 }
0559
0560 static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
0561 size_t size, loff_t *offp)
0562 {
0563 struct tool_mw *inmw = filep->private_data;
0564
0565 if (inmw->mm_base == NULL)
0566 return -ENXIO;
0567
0568 return simple_write_to_buffer(inmw->mm_base, inmw->size, offp,
0569 ubuf, size);
0570 }
0571
0572 static TOOL_FOPS_RDWR(tool_mw_fops,
0573 tool_mw_read,
0574 tool_mw_write);
0575
0576 static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx,
0577 size_t req_size)
0578 {
0579 resource_size_t size, addr_align, size_align;
0580 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
0581 char buf[TOOL_BUF_LEN];
0582 int ret;
0583
0584 if (inmw->mm_base != NULL)
0585 return 0;
0586
0587 ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align,
0588 &size_align, &size);
0589 if (ret)
0590 return ret;
0591
0592 inmw->size = min_t(resource_size_t, req_size, size);
0593 inmw->size = round_up(inmw->size, addr_align);
0594 inmw->size = round_up(inmw->size, size_align);
0595 inmw->mm_base = dma_alloc_coherent(&tc->ntb->pdev->dev, inmw->size,
0596 &inmw->dma_base, GFP_KERNEL);
0597 if (!inmw->mm_base)
0598 return -ENOMEM;
0599
0600 if (!IS_ALIGNED(inmw->dma_base, addr_align)) {
0601 ret = -ENOMEM;
0602 goto err_free_dma;
0603 }
0604
0605 ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size);
0606 if (ret)
0607 goto err_free_dma;
0608
0609 snprintf(buf, sizeof(buf), "mw%d", widx);
0610 inmw->dbgfs_file = debugfs_create_file(buf, 0600,
0611 tc->peers[pidx].dbgfs_dir, inmw,
0612 &tool_mw_fops);
0613
0614 return 0;
0615
0616 err_free_dma:
0617 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size, inmw->mm_base,
0618 inmw->dma_base);
0619 inmw->mm_base = NULL;
0620 inmw->dma_base = 0;
0621 inmw->size = 0;
0622
0623 return ret;
0624 }
0625
0626 static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx)
0627 {
0628 struct tool_mw *inmw = &tc->peers[pidx].inmws[widx];
0629
0630 debugfs_remove(inmw->dbgfs_file);
0631
0632 if (inmw->mm_base != NULL) {
0633 ntb_mw_clear_trans(tc->ntb, pidx, widx);
0634 dma_free_coherent(&tc->ntb->pdev->dev, inmw->size,
0635 inmw->mm_base, inmw->dma_base);
0636 }
0637
0638 inmw->mm_base = NULL;
0639 inmw->dma_base = 0;
0640 inmw->size = 0;
0641 inmw->dbgfs_file = NULL;
0642 }
0643
0644 static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf,
0645 size_t size, loff_t *offp)
0646 {
0647 struct tool_mw *inmw = filep->private_data;
0648 resource_size_t addr_align;
0649 resource_size_t size_align;
0650 resource_size_t size_max;
0651 ssize_t ret, off = 0;
0652 size_t buf_size;
0653 char *buf;
0654
0655 buf_size = min_t(size_t, size, 512);
0656
0657 buf = kmalloc(buf_size, GFP_KERNEL);
0658 if (!buf)
0659 return -ENOMEM;
0660
0661 ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx,
0662 &addr_align, &size_align, &size_max);
0663 if (ret)
0664 goto err;
0665
0666 off += scnprintf(buf + off, buf_size - off,
0667 "Inbound MW \t%d\n",
0668 inmw->widx);
0669
0670 off += scnprintf(buf + off, buf_size - off,
0671 "Port \t%d (%d)\n",
0672 ntb_peer_port_number(inmw->tc->ntb, inmw->pidx),
0673 inmw->pidx);
0674
0675 off += scnprintf(buf + off, buf_size - off,
0676 "Window Address \t0x%pK\n", inmw->mm_base);
0677
0678 off += scnprintf(buf + off, buf_size - off,
0679 "DMA Address \t%pad\n",
0680 &inmw->dma_base);
0681
0682 off += scnprintf(buf + off, buf_size - off,
0683 "Window Size \t%pap\n",
0684 &inmw->size);
0685
0686 off += scnprintf(buf + off, buf_size - off,
0687 "Alignment \t%pap\n",
0688 &addr_align);
0689
0690 off += scnprintf(buf + off, buf_size - off,
0691 "Size Alignment \t%pap\n",
0692 &size_align);
0693
0694 off += scnprintf(buf + off, buf_size - off,
0695 "Size Max \t%pap\n",
0696 &size_max);
0697
0698 ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
0699
0700 err:
0701 kfree(buf);
0702
0703 return ret;
0704 }
0705
0706 static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf,
0707 size_t size, loff_t *offp)
0708 {
0709 struct tool_mw *inmw = filep->private_data;
0710 unsigned int val;
0711 int ret;
0712
0713 ret = kstrtouint_from_user(ubuf, size, 0, &val);
0714 if (ret)
0715 return ret;
0716
0717 tool_free_mw(inmw->tc, inmw->pidx, inmw->widx);
0718 if (val) {
0719 ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val);
0720 if (ret)
0721 return ret;
0722 }
0723
0724 return size;
0725 }
0726
0727 static TOOL_FOPS_RDWR(tool_mw_trans_fops,
0728 tool_mw_trans_read,
0729 tool_mw_trans_write);
0730
0731 static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
0732 size_t size, loff_t *offp)
0733 {
0734 struct tool_mw *outmw = filep->private_data;
0735 loff_t pos = *offp;
0736 ssize_t ret;
0737 void *buf;
0738
0739 if (outmw->io_base == NULL)
0740 return -EIO;
0741
0742 if (pos >= outmw->size || !size)
0743 return 0;
0744
0745 if (size > outmw->size - pos)
0746 size = outmw->size - pos;
0747
0748 buf = kmalloc(size, GFP_KERNEL);
0749 if (!buf)
0750 return -ENOMEM;
0751
0752 memcpy_fromio(buf, outmw->io_base + pos, size);
0753 ret = copy_to_user(ubuf, buf, size);
0754 if (ret == size) {
0755 ret = -EFAULT;
0756 goto err_free;
0757 }
0758
0759 size -= ret;
0760 *offp = pos + size;
0761 ret = size;
0762
0763 err_free:
0764 kfree(buf);
0765
0766 return ret;
0767 }
0768
0769 static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
0770 size_t size, loff_t *offp)
0771 {
0772 struct tool_mw *outmw = filep->private_data;
0773 ssize_t ret;
0774 loff_t pos = *offp;
0775 void *buf;
0776
0777 if (outmw->io_base == NULL)
0778 return -EIO;
0779
0780 if (pos >= outmw->size || !size)
0781 return 0;
0782 if (size > outmw->size - pos)
0783 size = outmw->size - pos;
0784
0785 buf = kmalloc(size, GFP_KERNEL);
0786 if (!buf)
0787 return -ENOMEM;
0788
0789 ret = copy_from_user(buf, ubuf, size);
0790 if (ret == size) {
0791 ret = -EFAULT;
0792 goto err_free;
0793 }
0794
0795 size -= ret;
0796 *offp = pos + size;
0797 ret = size;
0798
0799 memcpy_toio(outmw->io_base + pos, buf, size);
0800
0801 err_free:
0802 kfree(buf);
0803
0804 return ret;
0805 }
0806
0807 static TOOL_FOPS_RDWR(tool_peer_mw_fops,
0808 tool_peer_mw_read,
0809 tool_peer_mw_write);
0810
0811 static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx,
0812 u64 req_addr, size_t req_size)
0813 {
0814 struct tool_mw *outmw = &tc->outmws[widx];
0815 resource_size_t map_size;
0816 phys_addr_t map_base;
0817 char buf[TOOL_BUF_LEN];
0818 int ret;
0819
0820 if (outmw->io_base != NULL)
0821 return 0;
0822
0823 ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size);
0824 if (ret)
0825 return ret;
0826
0827 ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size);
0828 if (ret)
0829 return ret;
0830
0831 outmw->io_base = ioremap_wc(map_base, map_size);
0832 if (outmw->io_base == NULL) {
0833 ret = -EFAULT;
0834 goto err_clear_trans;
0835 }
0836
0837 outmw->tr_base = req_addr;
0838 outmw->size = req_size;
0839 outmw->pidx = pidx;
0840
0841 snprintf(buf, sizeof(buf), "peer_mw%d", widx);
0842 outmw->dbgfs_file = debugfs_create_file(buf, 0600,
0843 tc->peers[pidx].dbgfs_dir, outmw,
0844 &tool_peer_mw_fops);
0845
0846 return 0;
0847
0848 err_clear_trans:
0849 ntb_peer_mw_clear_trans(tc->ntb, pidx, widx);
0850
0851 return ret;
0852 }
0853
0854 static void tool_free_peer_mw(struct tool_ctx *tc, int widx)
0855 {
0856 struct tool_mw *outmw = &tc->outmws[widx];
0857
0858 debugfs_remove(outmw->dbgfs_file);
0859
0860 if (outmw->io_base != NULL) {
0861 iounmap(tc->outmws[widx].io_base);
0862 ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx);
0863 }
0864
0865 outmw->io_base = NULL;
0866 outmw->tr_base = 0;
0867 outmw->size = 0;
0868 outmw->pidx = -1;
0869 outmw->dbgfs_file = NULL;
0870 }
0871
0872 static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf,
0873 size_t size, loff_t *offp)
0874 {
0875 struct tool_mw_wrap *outmw_wrap = filep->private_data;
0876 struct tool_mw *outmw = outmw_wrap->mw;
0877 resource_size_t map_size;
0878 phys_addr_t map_base;
0879 ssize_t off = 0;
0880 size_t buf_size;
0881 char *buf;
0882 int ret;
0883
0884 ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx,
0885 &map_base, &map_size);
0886 if (ret)
0887 return ret;
0888
0889 buf_size = min_t(size_t, size, 512);
0890
0891 buf = kmalloc(buf_size, GFP_KERNEL);
0892 if (!buf)
0893 return -ENOMEM;
0894
0895 off += scnprintf(buf + off, buf_size - off,
0896 "Outbound MW: \t%d\n", outmw->widx);
0897
0898 if (outmw->io_base != NULL) {
0899 off += scnprintf(buf + off, buf_size - off,
0900 "Port attached \t%d (%d)\n",
0901 ntb_peer_port_number(outmw->tc->ntb, outmw->pidx),
0902 outmw->pidx);
0903 } else {
0904 off += scnprintf(buf + off, buf_size - off,
0905 "Port attached \t-1 (-1)\n");
0906 }
0907
0908 off += scnprintf(buf + off, buf_size - off,
0909 "Virtual address \t0x%pK\n", outmw->io_base);
0910
0911 off += scnprintf(buf + off, buf_size - off,
0912 "Phys Address \t%pap\n", &map_base);
0913
0914 off += scnprintf(buf + off, buf_size - off,
0915 "Mapping Size \t%pap\n", &map_size);
0916
0917 off += scnprintf(buf + off, buf_size - off,
0918 "Translation Address \t0x%016llx\n", outmw->tr_base);
0919
0920 off += scnprintf(buf + off, buf_size - off,
0921 "Window Size \t%pap\n", &outmw->size);
0922
0923 ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
0924 kfree(buf);
0925
0926 return ret;
0927 }
0928
0929 static ssize_t tool_peer_mw_trans_write(struct file *filep,
0930 const char __user *ubuf,
0931 size_t size, loff_t *offp)
0932 {
0933 struct tool_mw_wrap *outmw_wrap = filep->private_data;
0934 struct tool_mw *outmw = outmw_wrap->mw;
0935 size_t buf_size, wsize;
0936 char buf[TOOL_BUF_LEN];
0937 int ret, n;
0938 u64 addr;
0939
0940 buf_size = min(size, (sizeof(buf) - 1));
0941 if (copy_from_user(buf, ubuf, buf_size))
0942 return -EFAULT;
0943
0944 buf[buf_size] = '\0';
0945
0946 n = sscanf(buf, "%lli:%zi", &addr, &wsize);
0947 if (n != 2)
0948 return -EINVAL;
0949
0950 tool_free_peer_mw(outmw->tc, outmw->widx);
0951 if (wsize) {
0952 ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx,
0953 outmw->widx, addr, wsize);
0954 if (ret)
0955 return ret;
0956 }
0957
0958 return size;
0959 }
0960
0961 static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
0962 tool_peer_mw_trans_read,
0963 tool_peer_mw_trans_write);
0964
0965 static int tool_init_mws(struct tool_ctx *tc)
0966 {
0967 int widx, pidx;
0968
0969
0970 tc->outmw_cnt = ntb_peer_mw_count(tc->ntb);
0971 tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt,
0972 sizeof(*tc->outmws), GFP_KERNEL);
0973 if (tc->outmws == NULL)
0974 return -ENOMEM;
0975
0976 for (widx = 0; widx < tc->outmw_cnt; widx++) {
0977 tc->outmws[widx].widx = widx;
0978 tc->outmws[widx].pidx = -1;
0979 tc->outmws[widx].tc = tc;
0980 }
0981
0982
0983 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
0984 tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx);
0985 tc->peers[pidx].inmws =
0986 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt,
0987 sizeof(*tc->peers[pidx].inmws), GFP_KERNEL);
0988 if (tc->peers[pidx].inmws == NULL)
0989 return -ENOMEM;
0990
0991 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
0992 tc->peers[pidx].inmws[widx].widx = widx;
0993 tc->peers[pidx].inmws[widx].pidx = pidx;
0994 tc->peers[pidx].inmws[widx].tc = tc;
0995 }
0996
0997 tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb);
0998 tc->peers[pidx].outmws =
0999 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt,
1000 sizeof(*tc->peers[pidx].outmws), GFP_KERNEL);
1001
1002 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
1003 tc->peers[pidx].outmws[widx].pidx = pidx;
1004 tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx];
1005 }
1006 }
1007
1008 return 0;
1009 }
1010
1011 static void tool_clear_mws(struct tool_ctx *tc)
1012 {
1013 int widx, pidx;
1014
1015
1016 for (widx = 0; widx < tc->outmw_cnt; widx++)
1017 tool_free_peer_mw(tc, widx);
1018
1019
1020 for (pidx = 0; pidx < tc->peer_cnt; pidx++)
1021 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++)
1022 tool_free_mw(tc, pidx, widx);
1023 }
1024
1025
1026
1027
1028
1029
1030 static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
1031 size_t size, loff_t *offp)
1032 {
1033 struct tool_ctx *tc = filep->private_data;
1034
1035 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read);
1036 }
1037
1038 static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
1039 size_t size, loff_t *offp)
1040 {
1041 struct tool_ctx *tc = filep->private_data;
1042
1043 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set,
1044 tc->ntb->ops->db_clear);
1045 }
1046
1047 static TOOL_FOPS_RDWR(tool_db_fops,
1048 tool_db_read,
1049 tool_db_write);
1050
1051 static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf,
1052 size_t size, loff_t *offp)
1053 {
1054 struct tool_ctx *tc = filep->private_data;
1055
1056 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask);
1057 }
1058
1059 static TOOL_FOPS_RDWR(tool_db_valid_mask_fops,
1060 tool_db_valid_mask_read,
1061 NULL);
1062
1063 static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf,
1064 size_t size, loff_t *offp)
1065 {
1066 struct tool_ctx *tc = filep->private_data;
1067
1068 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask);
1069 }
1070
1071 static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf,
1072 size_t size, loff_t *offp)
1073 {
1074 struct tool_ctx *tc = filep->private_data;
1075
1076 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask,
1077 tc->ntb->ops->db_clear_mask);
1078 }
1079
1080 static TOOL_FOPS_RDWR(tool_db_mask_fops,
1081 tool_db_mask_read,
1082 tool_db_mask_write);
1083
1084 static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
1085 size_t size, loff_t *offp)
1086 {
1087 struct tool_ctx *tc = filep->private_data;
1088
1089 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read);
1090 }
1091
1092 static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
1093 size_t size, loff_t *offp)
1094 {
1095 struct tool_ctx *tc = filep->private_data;
1096
1097 return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set,
1098 tc->ntb->ops->peer_db_clear);
1099 }
1100
1101 static TOOL_FOPS_RDWR(tool_peer_db_fops,
1102 tool_peer_db_read,
1103 tool_peer_db_write);
1104
1105 static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf,
1106 size_t size, loff_t *offp)
1107 {
1108 struct tool_ctx *tc = filep->private_data;
1109
1110 return tool_fn_read(tc, ubuf, size, offp,
1111 tc->ntb->ops->peer_db_read_mask);
1112 }
1113
1114 static ssize_t tool_peer_db_mask_write(struct file *filep,
1115 const char __user *ubuf,
1116 size_t size, loff_t *offp)
1117 {
1118 struct tool_ctx *tc = filep->private_data;
1119
1120 return tool_fn_write(tc, ubuf, size, offp,
1121 tc->ntb->ops->peer_db_set_mask,
1122 tc->ntb->ops->peer_db_clear_mask);
1123 }
1124
1125 static TOOL_FOPS_RDWR(tool_peer_db_mask_fops,
1126 tool_peer_db_mask_read,
1127 tool_peer_db_mask_write);
1128
1129 static ssize_t tool_db_event_write(struct file *filep,
1130 const char __user *ubuf,
1131 size_t size, loff_t *offp)
1132 {
1133 struct tool_ctx *tc = filep->private_data;
1134 u64 val;
1135 int ret;
1136
1137 ret = kstrtou64_from_user(ubuf, size, 0, &val);
1138 if (ret)
1139 return ret;
1140
1141 if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val))
1142 return -ERESTART;
1143
1144 return size;
1145 }
1146
1147 static TOOL_FOPS_RDWR(tool_db_event_fops,
1148 NULL,
1149 tool_db_event_write);
1150
1151
1152
1153
1154
1155
1156 static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
1157 size_t size, loff_t *offp)
1158 {
1159 struct tool_spad *spad = filep->private_data;
1160 char buf[TOOL_BUF_LEN];
1161 ssize_t pos;
1162
1163 if (!spad->tc->ntb->ops->spad_read)
1164 return -EINVAL;
1165
1166 pos = scnprintf(buf, sizeof(buf), "%#x\n",
1167 ntb_spad_read(spad->tc->ntb, spad->sidx));
1168
1169 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1170 }
1171
1172 static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
1173 size_t size, loff_t *offp)
1174 {
1175 struct tool_spad *spad = filep->private_data;
1176 u32 val;
1177 int ret;
1178
1179 if (!spad->tc->ntb->ops->spad_write) {
1180 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1181 return -EINVAL;
1182 }
1183
1184 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1185 if (ret)
1186 return ret;
1187
1188 ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val);
1189
1190 return ret ?: size;
1191 }
1192
1193 static TOOL_FOPS_RDWR(tool_spad_fops,
1194 tool_spad_read,
1195 tool_spad_write);
1196
1197 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
1198 size_t size, loff_t *offp)
1199 {
1200 struct tool_spad *spad = filep->private_data;
1201 char buf[TOOL_BUF_LEN];
1202 ssize_t pos;
1203
1204 if (!spad->tc->ntb->ops->peer_spad_read)
1205 return -EINVAL;
1206
1207 pos = scnprintf(buf, sizeof(buf), "%#x\n",
1208 ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx));
1209
1210 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1211 }
1212
1213 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
1214 size_t size, loff_t *offp)
1215 {
1216 struct tool_spad *spad = filep->private_data;
1217 u32 val;
1218 int ret;
1219
1220 if (!spad->tc->ntb->ops->peer_spad_write) {
1221 dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n");
1222 return -EINVAL;
1223 }
1224
1225 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1226 if (ret)
1227 return ret;
1228
1229 ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val);
1230
1231 return ret ?: size;
1232 }
1233
1234 static TOOL_FOPS_RDWR(tool_peer_spad_fops,
1235 tool_peer_spad_read,
1236 tool_peer_spad_write);
1237
1238 static int tool_init_spads(struct tool_ctx *tc)
1239 {
1240 int sidx, pidx;
1241
1242
1243 tc->inspad_cnt = ntb_spad_count(tc->ntb);
1244 tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt,
1245 sizeof(*tc->inspads), GFP_KERNEL);
1246 if (tc->inspads == NULL)
1247 return -ENOMEM;
1248
1249 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1250 tc->inspads[sidx].sidx = sidx;
1251 tc->inspads[sidx].pidx = -1;
1252 tc->inspads[sidx].tc = tc;
1253 }
1254
1255
1256 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1257 tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb);
1258 tc->peers[pidx].outspads =
1259 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt,
1260 sizeof(*tc->peers[pidx].outspads), GFP_KERNEL);
1261 if (tc->peers[pidx].outspads == NULL)
1262 return -ENOMEM;
1263
1264 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1265 tc->peers[pidx].outspads[sidx].sidx = sidx;
1266 tc->peers[pidx].outspads[sidx].pidx = pidx;
1267 tc->peers[pidx].outspads[sidx].tc = tc;
1268 }
1269 }
1270
1271 return 0;
1272 }
1273
1274
1275
1276
1277
1278
1279 static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf,
1280 size_t size, loff_t *offp)
1281 {
1282 struct tool_msg *msg = filep->private_data;
1283 char buf[TOOL_BUF_LEN];
1284 ssize_t pos;
1285 u32 data;
1286 int pidx;
1287
1288 data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx);
1289
1290 pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx);
1291
1292 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
1293 }
1294
1295 static TOOL_FOPS_RDWR(tool_inmsg_fops,
1296 tool_inmsg_read,
1297 NULL);
1298
1299 static ssize_t tool_outmsg_write(struct file *filep,
1300 const char __user *ubuf,
1301 size_t size, loff_t *offp)
1302 {
1303 struct tool_msg *msg = filep->private_data;
1304 u32 val;
1305 int ret;
1306
1307 ret = kstrtou32_from_user(ubuf, size, 0, &val);
1308 if (ret)
1309 return ret;
1310
1311 ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val);
1312
1313 return ret ? : size;
1314 }
1315
1316 static TOOL_FOPS_RDWR(tool_outmsg_fops,
1317 NULL,
1318 tool_outmsg_write);
1319
1320 static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf,
1321 size_t size, loff_t *offp)
1322 {
1323 struct tool_ctx *tc = filep->private_data;
1324
1325 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts);
1326 }
1327
1328 static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf,
1329 size_t size, loff_t *offp)
1330 {
1331 struct tool_ctx *tc = filep->private_data;
1332
1333 return tool_fn_write(tc, ubuf, size, offp, NULL,
1334 tc->ntb->ops->msg_clear_sts);
1335 }
1336
1337 static TOOL_FOPS_RDWR(tool_msg_sts_fops,
1338 tool_msg_sts_read,
1339 tool_msg_sts_write);
1340
1341 static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf,
1342 size_t size, loff_t *offp)
1343 {
1344 struct tool_ctx *tc = filep->private_data;
1345
1346 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits);
1347 }
1348
1349 static TOOL_FOPS_RDWR(tool_msg_inbits_fops,
1350 tool_msg_inbits_read,
1351 NULL);
1352
1353 static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf,
1354 size_t size, loff_t *offp)
1355 {
1356 struct tool_ctx *tc = filep->private_data;
1357
1358 return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits);
1359 }
1360
1361 static TOOL_FOPS_RDWR(tool_msg_outbits_fops,
1362 tool_msg_outbits_read,
1363 NULL);
1364
1365 static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf,
1366 size_t size, loff_t *offp)
1367 {
1368 struct tool_ctx *tc = filep->private_data;
1369
1370 return tool_fn_write(tc, ubuf, size, offp,
1371 tc->ntb->ops->msg_set_mask,
1372 tc->ntb->ops->msg_clear_mask);
1373 }
1374
1375 static TOOL_FOPS_RDWR(tool_msg_mask_fops,
1376 NULL,
1377 tool_msg_mask_write);
1378
1379 static ssize_t tool_msg_event_write(struct file *filep,
1380 const char __user *ubuf,
1381 size_t size, loff_t *offp)
1382 {
1383 struct tool_ctx *tc = filep->private_data;
1384 u64 val;
1385 int ret;
1386
1387 ret = kstrtou64_from_user(ubuf, size, 0, &val);
1388 if (ret)
1389 return ret;
1390
1391 if (wait_event_interruptible(tc->msg_wq,
1392 ntb_msg_read_sts(tc->ntb) == val))
1393 return -ERESTART;
1394
1395 return size;
1396 }
1397
1398 static TOOL_FOPS_RDWR(tool_msg_event_fops,
1399 NULL,
1400 tool_msg_event_write);
1401
1402 static int tool_init_msgs(struct tool_ctx *tc)
1403 {
1404 int midx, pidx;
1405
1406
1407 tc->inmsg_cnt = ntb_msg_count(tc->ntb);
1408 tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt,
1409 sizeof(*tc->inmsgs), GFP_KERNEL);
1410 if (tc->inmsgs == NULL)
1411 return -ENOMEM;
1412
1413 for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1414 tc->inmsgs[midx].midx = midx;
1415 tc->inmsgs[midx].pidx = -1;
1416 tc->inmsgs[midx].tc = tc;
1417 }
1418
1419
1420 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1421 tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb);
1422 tc->peers[pidx].outmsgs =
1423 devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt,
1424 sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL);
1425 if (tc->peers[pidx].outmsgs == NULL)
1426 return -ENOMEM;
1427
1428 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1429 tc->peers[pidx].outmsgs[midx].midx = midx;
1430 tc->peers[pidx].outmsgs[midx].pidx = pidx;
1431 tc->peers[pidx].outmsgs[midx].tc = tc;
1432 }
1433 }
1434
1435 return 0;
1436 }
1437
1438
1439
1440
1441
1442
1443 static struct tool_ctx *tool_create_data(struct ntb_dev *ntb)
1444 {
1445 struct tool_ctx *tc;
1446
1447 tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL);
1448 if (tc == NULL)
1449 return ERR_PTR(-ENOMEM);
1450
1451 tc->ntb = ntb;
1452 init_waitqueue_head(&tc->link_wq);
1453 init_waitqueue_head(&tc->db_wq);
1454 init_waitqueue_head(&tc->msg_wq);
1455
1456 if (ntb_db_is_unsafe(ntb))
1457 dev_dbg(&ntb->dev, "doorbell is unsafe\n");
1458
1459 if (ntb_spad_is_unsafe(ntb))
1460 dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
1461
1462 return tc;
1463 }
1464
1465 static void tool_clear_data(struct tool_ctx *tc)
1466 {
1467 wake_up(&tc->link_wq);
1468 wake_up(&tc->db_wq);
1469 wake_up(&tc->msg_wq);
1470 }
1471
1472 static int tool_init_ntb(struct tool_ctx *tc)
1473 {
1474 return ntb_set_ctx(tc->ntb, tc, &tool_ops);
1475 }
1476
1477 static void tool_clear_ntb(struct tool_ctx *tc)
1478 {
1479 ntb_clear_ctx(tc->ntb);
1480 ntb_link_disable(tc->ntb);
1481 }
1482
1483 static void tool_setup_dbgfs(struct tool_ctx *tc)
1484 {
1485 int pidx, widx, sidx, midx;
1486 char buf[TOOL_BUF_LEN];
1487
1488
1489 if (!tool_dbgfs_topdir) {
1490 tc->dbgfs_dir = NULL;
1491 return;
1492 }
1493
1494 tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev),
1495 tool_dbgfs_topdir);
1496 if (!tc->dbgfs_dir)
1497 return;
1498
1499 debugfs_create_file("port", 0600, tc->dbgfs_dir,
1500 tc, &tool_port_fops);
1501
1502 debugfs_create_file("link", 0600, tc->dbgfs_dir,
1503 tc, &tool_link_fops);
1504
1505 debugfs_create_file("db", 0600, tc->dbgfs_dir,
1506 tc, &tool_db_fops);
1507
1508 debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir,
1509 tc, &tool_db_valid_mask_fops);
1510
1511 debugfs_create_file("db_mask", 0600, tc->dbgfs_dir,
1512 tc, &tool_db_mask_fops);
1513
1514 debugfs_create_file("db_event", 0600, tc->dbgfs_dir,
1515 tc, &tool_db_event_fops);
1516
1517 debugfs_create_file("peer_db", 0600, tc->dbgfs_dir,
1518 tc, &tool_peer_db_fops);
1519
1520 debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir,
1521 tc, &tool_peer_db_mask_fops);
1522
1523 if (tc->inspad_cnt != 0) {
1524 for (sidx = 0; sidx < tc->inspad_cnt; sidx++) {
1525 snprintf(buf, sizeof(buf), "spad%d", sidx);
1526
1527 debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1528 &tc->inspads[sidx], &tool_spad_fops);
1529 }
1530 }
1531
1532 if (tc->inmsg_cnt != 0) {
1533 for (midx = 0; midx < tc->inmsg_cnt; midx++) {
1534 snprintf(buf, sizeof(buf), "msg%d", midx);
1535 debugfs_create_file(buf, 0600, tc->dbgfs_dir,
1536 &tc->inmsgs[midx], &tool_inmsg_fops);
1537 }
1538
1539 debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir,
1540 tc, &tool_msg_sts_fops);
1541
1542 debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir,
1543 tc, &tool_msg_inbits_fops);
1544
1545 debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir,
1546 tc, &tool_msg_outbits_fops);
1547
1548 debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir,
1549 tc, &tool_msg_mask_fops);
1550
1551 debugfs_create_file("msg_event", 0600, tc->dbgfs_dir,
1552 tc, &tool_msg_event_fops);
1553 }
1554
1555 for (pidx = 0; pidx < tc->peer_cnt; pidx++) {
1556 snprintf(buf, sizeof(buf), "peer%d", pidx);
1557 tc->peers[pidx].dbgfs_dir =
1558 debugfs_create_dir(buf, tc->dbgfs_dir);
1559
1560 debugfs_create_file("port", 0600,
1561 tc->peers[pidx].dbgfs_dir,
1562 &tc->peers[pidx], &tool_peer_port_fops);
1563
1564 debugfs_create_file("link", 0200,
1565 tc->peers[pidx].dbgfs_dir,
1566 &tc->peers[pidx], &tool_peer_link_fops);
1567
1568 debugfs_create_file("link_event", 0200,
1569 tc->peers[pidx].dbgfs_dir,
1570 &tc->peers[pidx], &tool_peer_link_event_fops);
1571
1572 for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) {
1573 snprintf(buf, sizeof(buf), "mw_trans%d", widx);
1574 debugfs_create_file(buf, 0600,
1575 tc->peers[pidx].dbgfs_dir,
1576 &tc->peers[pidx].inmws[widx],
1577 &tool_mw_trans_fops);
1578 }
1579
1580 for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) {
1581 snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx);
1582 debugfs_create_file(buf, 0600,
1583 tc->peers[pidx].dbgfs_dir,
1584 &tc->peers[pidx].outmws[widx],
1585 &tool_peer_mw_trans_fops);
1586 }
1587
1588 for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) {
1589 snprintf(buf, sizeof(buf), "spad%d", sidx);
1590
1591 debugfs_create_file(buf, 0600,
1592 tc->peers[pidx].dbgfs_dir,
1593 &tc->peers[pidx].outspads[sidx],
1594 &tool_peer_spad_fops);
1595 }
1596
1597 for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) {
1598 snprintf(buf, sizeof(buf), "msg%d", midx);
1599 debugfs_create_file(buf, 0600,
1600 tc->peers[pidx].dbgfs_dir,
1601 &tc->peers[pidx].outmsgs[midx],
1602 &tool_outmsg_fops);
1603 }
1604 }
1605 }
1606
1607 static void tool_clear_dbgfs(struct tool_ctx *tc)
1608 {
1609 debugfs_remove_recursive(tc->dbgfs_dir);
1610 }
1611
1612 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
1613 {
1614 struct tool_ctx *tc;
1615 int ret;
1616
1617 tc = tool_create_data(ntb);
1618 if (IS_ERR(tc))
1619 return PTR_ERR(tc);
1620
1621 ret = tool_init_peers(tc);
1622 if (ret != 0)
1623 goto err_clear_data;
1624
1625 ret = tool_init_mws(tc);
1626 if (ret != 0)
1627 goto err_clear_data;
1628
1629 ret = tool_init_spads(tc);
1630 if (ret != 0)
1631 goto err_clear_mws;
1632
1633 ret = tool_init_msgs(tc);
1634 if (ret != 0)
1635 goto err_clear_mws;
1636
1637 ret = tool_init_ntb(tc);
1638 if (ret != 0)
1639 goto err_clear_mws;
1640
1641 tool_setup_dbgfs(tc);
1642
1643 return 0;
1644
1645 err_clear_mws:
1646 tool_clear_mws(tc);
1647
1648 err_clear_data:
1649 tool_clear_data(tc);
1650
1651 return ret;
1652 }
1653
1654 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
1655 {
1656 struct tool_ctx *tc = ntb->ctx;
1657
1658 tool_clear_dbgfs(tc);
1659
1660 tool_clear_ntb(tc);
1661
1662 tool_clear_mws(tc);
1663
1664 tool_clear_data(tc);
1665 }
1666
1667 static struct ntb_client tool_client = {
1668 .ops = {
1669 .probe = tool_probe,
1670 .remove = tool_remove,
1671 }
1672 };
1673
1674 static int __init tool_init(void)
1675 {
1676 int ret;
1677
1678 if (debugfs_initialized())
1679 tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
1680
1681 ret = ntb_register_client(&tool_client);
1682 if (ret)
1683 debugfs_remove_recursive(tool_dbgfs_topdir);
1684
1685 return ret;
1686 }
1687 module_init(tool_init);
1688
1689 static void __exit tool_exit(void)
1690 {
1691 ntb_unregister_client(&tool_client);
1692 debugfs_remove_recursive(tool_dbgfs_topdir);
1693 }
1694 module_exit(tool_exit);