]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/ntb/test/ntb_tool.c
Merge remote-tracking branches 'spi/fix/lock', 'spi/fix/maintainers', 'spi/fix/put...
[karo-tx-linux.git] / drivers / ntb / test / ntb_tool.c
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 /*
55  * How to use this tool, by example.
56  *
57  * Assuming $DBG_DIR is something like:
58  * '/sys/kernel/debug/ntb_tool/0000:00:03.0'
59  *
60  * Eg: check if clearing the doorbell mask generates an interrupt.
61  *
62  * # Check the link status
63  * root@self# cat $DBG_DIR/link
64  *
65  * # Block until the link is up
66  * root@self# echo Y > $DBG_DIR/link_event
67  *
68  * # Set the doorbell mask
69  * root@self# echo 's 1' > $DBG_DIR/mask
70  *
71  * # Ring the doorbell from the peer
72  * root@peer# echo 's 1' > $DBG_DIR/peer_db
73  *
74  * # Clear the doorbell mask
75  * root@self# echo 'c 1' > $DBG_DIR/mask
76  *
77  * Observe debugging output in dmesg or your console.  You should see a
78  * doorbell event triggered by clearing the mask.  If not, this may indicate an
79  * issue with the hardware that needs to be worked around in the driver.
80  *
81  * Eg: read and write scratchpad registers
82  *
83  * root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad
84  *
85  * root@self# cat $DBG_DIR/spad
86  *
87  * Observe that spad 0 and 1 have the values set by the peer.
88  *
89  * # Check the memory window translation info
90  * cat $DBG_DIR/peer_trans0
91  *
92  * # Setup a 16k memory window buffer
93  * echo 16384 > $DBG_DIR/peer_trans0
94  *
95  */
96
97 #include <linux/init.h>
98 #include <linux/kernel.h>
99 #include <linux/module.h>
100
101 #include <linux/debugfs.h>
102 #include <linux/dma-mapping.h>
103 #include <linux/pci.h>
104 #include <linux/slab.h>
105 #include <linux/uaccess.h>
106
107 #include <linux/ntb.h>
108
109 #define DRIVER_NAME                     "ntb_tool"
110 #define DRIVER_DESCRIPTION              "PCIe NTB Debugging Tool"
111
112 #define DRIVER_LICENSE                  "Dual BSD/GPL"
113 #define DRIVER_VERSION                  "1.0"
114 #define DRIVER_RELDATE                  "22 April 2015"
115 #define DRIVER_AUTHOR                   "Allen Hubbe <Allen.Hubbe@emc.com>"
116
117 MODULE_LICENSE(DRIVER_LICENSE);
118 MODULE_VERSION(DRIVER_VERSION);
119 MODULE_AUTHOR(DRIVER_AUTHOR);
120 MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
121
122 #define MAX_MWS 16
123
124 static struct dentry *tool_dbgfs;
125
126 struct tool_mw {
127         int idx;
128         struct tool_ctx *tc;
129         resource_size_t win_size;
130         resource_size_t size;
131         u8 __iomem *local;
132         u8 *peer;
133         dma_addr_t peer_dma;
134         struct dentry *peer_dbg_file;
135 };
136
137 struct tool_ctx {
138         struct ntb_dev *ntb;
139         struct dentry *dbgfs;
140         wait_queue_head_t link_wq;
141         int mw_count;
142         struct tool_mw mws[MAX_MWS];
143 };
144
145 #define SPAD_FNAME_SIZE 0x10
146 #define INT_PTR(x) ((void *)(unsigned long)x)
147 #define PTR_INT(x) ((int)(unsigned long)x)
148
149 #define TOOL_FOPS_RDWR(__name, __read, __write) \
150         const struct file_operations __name = { \
151                 .owner = THIS_MODULE,           \
152                 .open = simple_open,            \
153                 .read = __read,                 \
154                 .write = __write,               \
155         }
156
157 static void tool_link_event(void *ctx)
158 {
159         struct tool_ctx *tc = ctx;
160         enum ntb_speed speed;
161         enum ntb_width width;
162         int up;
163
164         up = ntb_link_is_up(tc->ntb, &speed, &width);
165
166         dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
167                 up ? "up" : "down", speed, width);
168
169         wake_up(&tc->link_wq);
170 }
171
172 static void tool_db_event(void *ctx, int vec)
173 {
174         struct tool_ctx *tc = ctx;
175         u64 db_bits, db_mask;
176
177         db_mask = ntb_db_vector_mask(tc->ntb, vec);
178         db_bits = ntb_db_read(tc->ntb);
179
180         dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
181                 vec, db_mask, db_bits);
182 }
183
184 static const struct ntb_ctx_ops tool_ops = {
185         .link_event = tool_link_event,
186         .db_event = tool_db_event,
187 };
188
189 static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf,
190                               size_t size, loff_t *offp,
191                               u64 (*db_read_fn)(struct ntb_dev *))
192 {
193         size_t buf_size;
194         char *buf;
195         ssize_t pos, rc;
196
197         if (!db_read_fn)
198                 return -EINVAL;
199
200         buf_size = min_t(size_t, size, 0x20);
201
202         buf = kmalloc(buf_size, GFP_KERNEL);
203         if (!buf)
204                 return -ENOMEM;
205
206         pos = scnprintf(buf, buf_size, "%#llx\n",
207                         db_read_fn(tc->ntb));
208
209         rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
210
211         kfree(buf);
212
213         return rc;
214 }
215
216 static ssize_t tool_dbfn_write(struct tool_ctx *tc,
217                                const char __user *ubuf,
218                                size_t size, loff_t *offp,
219                                int (*db_set_fn)(struct ntb_dev *, u64),
220                                int (*db_clear_fn)(struct ntb_dev *, u64))
221 {
222         u64 db_bits;
223         char *buf, cmd;
224         ssize_t rc;
225         int n;
226
227         buf = kmalloc(size + 1, GFP_KERNEL);
228         if (!buf)
229                 return -ENOMEM;
230
231         rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
232         if (rc < 0) {
233                 kfree(buf);
234                 return rc;
235         }
236
237         buf[size] = 0;
238
239         n = sscanf(buf, "%c %lli", &cmd, &db_bits);
240
241         kfree(buf);
242
243         if (n != 2) {
244                 rc = -EINVAL;
245         } else if (cmd == 's') {
246                 if (!db_set_fn)
247                         rc = -EINVAL;
248                 else
249                         rc = db_set_fn(tc->ntb, db_bits);
250         } else if (cmd == 'c') {
251                 if (!db_clear_fn)
252                         rc = -EINVAL;
253                 else
254                         rc = db_clear_fn(tc->ntb, db_bits);
255         } else {
256                 rc = -EINVAL;
257         }
258
259         return rc ? : size;
260 }
261
262 static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
263                                 size_t size, loff_t *offp,
264                                 u32 (*spad_read_fn)(struct ntb_dev *, int))
265 {
266         size_t buf_size;
267         char *buf;
268         ssize_t pos, rc;
269         int i, spad_count;
270
271         if (!spad_read_fn)
272                 return -EINVAL;
273
274         spad_count = ntb_spad_count(tc->ntb);
275
276         /*
277          * We multiply the number of spads by 15 to get the buffer size
278          * this is from 3 for the %d, 10 for the largest hex value
279          * (0x00000000) and 2 for the tab and line feed.
280          */
281         buf_size = min_t(size_t, size, spad_count * 15);
282
283         buf = kmalloc(buf_size, GFP_KERNEL);
284         if (!buf)
285                 return -ENOMEM;
286
287         pos = 0;
288
289         for (i = 0; i < spad_count; ++i) {
290                 pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
291                                  i, spad_read_fn(tc->ntb, i));
292         }
293
294         rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
295
296         kfree(buf);
297
298         return rc;
299 }
300
301 static ssize_t tool_spadfn_write(struct tool_ctx *tc,
302                                  const char __user *ubuf,
303                                  size_t size, loff_t *offp,
304                                  int (*spad_write_fn)(struct ntb_dev *,
305                                                       int, u32))
306 {
307         int spad_idx;
308         u32 spad_val;
309         char *buf, *buf_ptr;
310         int pos, n;
311         ssize_t rc;
312
313         if (!spad_write_fn) {
314                 dev_dbg(&tc->ntb->dev, "no spad write fn\n");
315                 return -EINVAL;
316         }
317
318         buf = kmalloc(size + 1, GFP_KERNEL);
319         if (!buf)
320                 return -ENOMEM;
321
322         rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
323         if (rc < 0) {
324                 kfree(buf);
325                 return rc;
326         }
327
328         buf[size] = 0;
329         buf_ptr = buf;
330         n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
331         while (n == 2) {
332                 buf_ptr += pos;
333                 rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
334                 if (rc)
335                         break;
336
337                 n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
338         }
339
340         if (n < 0)
341                 rc = n;
342
343         kfree(buf);
344
345         return rc ? : size;
346 }
347
348 static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
349                             size_t size, loff_t *offp)
350 {
351         struct tool_ctx *tc = filep->private_data;
352
353         return tool_dbfn_read(tc, ubuf, size, offp,
354                               tc->ntb->ops->db_read);
355 }
356
357 static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
358                              size_t size, loff_t *offp)
359 {
360         struct tool_ctx *tc = filep->private_data;
361
362         return tool_dbfn_write(tc, ubuf, size, offp,
363                                tc->ntb->ops->db_set,
364                                tc->ntb->ops->db_clear);
365 }
366
367 static TOOL_FOPS_RDWR(tool_db_fops,
368                       tool_db_read,
369                       tool_db_write);
370
371 static ssize_t tool_mask_read(struct file *filep, char __user *ubuf,
372                               size_t size, loff_t *offp)
373 {
374         struct tool_ctx *tc = filep->private_data;
375
376         return tool_dbfn_read(tc, ubuf, size, offp,
377                               tc->ntb->ops->db_read_mask);
378 }
379
380 static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf,
381                                size_t size, loff_t *offp)
382 {
383         struct tool_ctx *tc = filep->private_data;
384
385         return tool_dbfn_write(tc, ubuf, size, offp,
386                                tc->ntb->ops->db_set_mask,
387                                tc->ntb->ops->db_clear_mask);
388 }
389
390 static TOOL_FOPS_RDWR(tool_mask_fops,
391                       tool_mask_read,
392                       tool_mask_write);
393
394 static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
395                                  size_t size, loff_t *offp)
396 {
397         struct tool_ctx *tc = filep->private_data;
398
399         return tool_dbfn_read(tc, ubuf, size, offp,
400                               tc->ntb->ops->peer_db_read);
401 }
402
403 static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
404                                   size_t size, loff_t *offp)
405 {
406         struct tool_ctx *tc = filep->private_data;
407
408         return tool_dbfn_write(tc, ubuf, size, offp,
409                                tc->ntb->ops->peer_db_set,
410                                tc->ntb->ops->peer_db_clear);
411 }
412
413 static TOOL_FOPS_RDWR(tool_peer_db_fops,
414                       tool_peer_db_read,
415                       tool_peer_db_write);
416
417 static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf,
418                                    size_t size, loff_t *offp)
419 {
420         struct tool_ctx *tc = filep->private_data;
421
422         return tool_dbfn_read(tc, ubuf, size, offp,
423                               tc->ntb->ops->peer_db_read_mask);
424 }
425
426 static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf,
427                                     size_t size, loff_t *offp)
428 {
429         struct tool_ctx *tc = filep->private_data;
430
431         return tool_dbfn_write(tc, ubuf, size, offp,
432                                tc->ntb->ops->peer_db_set_mask,
433                                tc->ntb->ops->peer_db_clear_mask);
434 }
435
436 static TOOL_FOPS_RDWR(tool_peer_mask_fops,
437                       tool_peer_mask_read,
438                       tool_peer_mask_write);
439
440 static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
441                               size_t size, loff_t *offp)
442 {
443         struct tool_ctx *tc = filep->private_data;
444
445         return tool_spadfn_read(tc, ubuf, size, offp,
446                                 tc->ntb->ops->spad_read);
447 }
448
449 static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
450                                size_t size, loff_t *offp)
451 {
452         struct tool_ctx *tc = filep->private_data;
453
454         return tool_spadfn_write(tc, ubuf, size, offp,
455                                  tc->ntb->ops->spad_write);
456 }
457
458 static TOOL_FOPS_RDWR(tool_spad_fops,
459                       tool_spad_read,
460                       tool_spad_write);
461
462 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
463                                    size_t size, loff_t *offp)
464 {
465         struct tool_ctx *tc = filep->private_data;
466
467         return tool_spadfn_read(tc, ubuf, size, offp,
468                                 tc->ntb->ops->peer_spad_read);
469 }
470
471 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
472                                     size_t size, loff_t *offp)
473 {
474         struct tool_ctx *tc = filep->private_data;
475
476         return tool_spadfn_write(tc, ubuf, size, offp,
477                                  tc->ntb->ops->peer_spad_write);
478 }
479
480 static TOOL_FOPS_RDWR(tool_peer_spad_fops,
481                       tool_peer_spad_read,
482                       tool_peer_spad_write);
483
484 static ssize_t tool_link_read(struct file *filep, char __user *ubuf,
485                               size_t size, loff_t *offp)
486 {
487         struct tool_ctx *tc = filep->private_data;
488         char buf[3];
489
490         buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N';
491         buf[1] = '\n';
492         buf[2] = '\0';
493
494         return simple_read_from_buffer(ubuf, size, offp, buf, 2);
495 }
496
497 static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
498                                size_t size, loff_t *offp)
499 {
500         struct tool_ctx *tc = filep->private_data;
501         char buf[32];
502         size_t buf_size;
503         bool val;
504         int rc;
505
506         buf_size = min(size, (sizeof(buf) - 1));
507         if (copy_from_user(buf, ubuf, buf_size))
508                 return -EFAULT;
509
510         buf[buf_size] = '\0';
511
512         rc = strtobool(buf, &val);
513         if (rc)
514                 return rc;
515
516         if (val)
517                 rc = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
518         else
519                 rc = ntb_link_disable(tc->ntb);
520
521         if (rc)
522                 return rc;
523
524         return size;
525 }
526
527 static TOOL_FOPS_RDWR(tool_link_fops,
528                       tool_link_read,
529                       tool_link_write);
530
531 static ssize_t tool_link_event_write(struct file *filep,
532                                      const char __user *ubuf,
533                                      size_t size, loff_t *offp)
534 {
535         struct tool_ctx *tc = filep->private_data;
536         char buf[32];
537         size_t buf_size;
538         bool val;
539         int rc;
540
541         buf_size = min(size, (sizeof(buf) - 1));
542         if (copy_from_user(buf, ubuf, buf_size))
543                 return -EFAULT;
544
545         buf[buf_size] = '\0';
546
547         rc = strtobool(buf, &val);
548         if (rc)
549                 return rc;
550
551         if (wait_event_interruptible(tc->link_wq,
552                 ntb_link_is_up(tc->ntb, NULL, NULL) == val))
553                 return -ERESTART;
554
555         return size;
556 }
557
558 static TOOL_FOPS_RDWR(tool_link_event_fops,
559                       NULL,
560                       tool_link_event_write);
561
562 static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
563                             size_t size, loff_t *offp)
564 {
565         struct tool_mw *mw = filep->private_data;
566         ssize_t rc;
567         loff_t pos = *offp;
568         void *buf;
569
570         if (mw->local == NULL)
571                 return -EIO;
572         if (pos < 0)
573                 return -EINVAL;
574         if (pos >= mw->win_size || !size)
575                 return 0;
576         if (size > mw->win_size - pos)
577                 size = mw->win_size - pos;
578
579         buf = kmalloc(size, GFP_KERNEL);
580         if (!buf)
581                 return -ENOMEM;
582
583         memcpy_fromio(buf, mw->local + pos, size);
584         rc = copy_to_user(ubuf, buf, size);
585         if (rc == size) {
586                 rc = -EFAULT;
587                 goto err_free;
588         }
589
590         size -= rc;
591         *offp = pos + size;
592         rc = size;
593
594 err_free:
595         kfree(buf);
596
597         return rc;
598 }
599
600 static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
601                              size_t size, loff_t *offp)
602 {
603         struct tool_mw *mw = filep->private_data;
604         ssize_t rc;
605         loff_t pos = *offp;
606         void *buf;
607
608         if (pos < 0)
609                 return -EINVAL;
610         if (pos >= mw->win_size || !size)
611                 return 0;
612         if (size > mw->win_size - pos)
613                 size = mw->win_size - pos;
614
615         buf = kmalloc(size, GFP_KERNEL);
616         if (!buf)
617                 return -ENOMEM;
618
619         rc = copy_from_user(buf, ubuf, size);
620         if (rc == size) {
621                 rc = -EFAULT;
622                 goto err_free;
623         }
624
625         size -= rc;
626         *offp = pos + size;
627         rc = size;
628
629         memcpy_toio(mw->local + pos, buf, size);
630
631 err_free:
632         kfree(buf);
633
634         return rc;
635 }
636
637 static TOOL_FOPS_RDWR(tool_mw_fops,
638                       tool_mw_read,
639                       tool_mw_write);
640
641 static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
642                                  size_t size, loff_t *offp)
643 {
644         struct tool_mw *mw = filep->private_data;
645
646         if (!mw->peer)
647                 return -ENXIO;
648
649         return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size);
650 }
651
652 static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
653                                   size_t size, loff_t *offp)
654 {
655         struct tool_mw *mw = filep->private_data;
656
657         if (!mw->peer)
658                 return -ENXIO;
659
660         return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size);
661 }
662
663 static TOOL_FOPS_RDWR(tool_peer_mw_fops,
664                       tool_peer_mw_read,
665                       tool_peer_mw_write);
666
667 static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
668 {
669         int rc;
670         struct tool_mw *mw = &tc->mws[idx];
671         phys_addr_t base;
672         resource_size_t size, align, align_size;
673         char buf[16];
674
675         if (mw->peer)
676                 return 0;
677
678         rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
679                               &align_size);
680         if (rc)
681                 return rc;
682
683         mw->size = min_t(resource_size_t, req_size, size);
684         mw->size = round_up(mw->size, align);
685         mw->size = round_up(mw->size, align_size);
686         mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
687                                       &mw->peer_dma, GFP_KERNEL);
688
689         if (!mw->peer)
690                 return -ENOMEM;
691
692         rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
693         if (rc)
694                 goto err_free_dma;
695
696         snprintf(buf, sizeof(buf), "peer_mw%d", idx);
697         mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR,
698                                                 mw->tc->dbgfs, mw,
699                                                 &tool_peer_mw_fops);
700
701         return 0;
702
703 err_free_dma:
704         dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
705                           mw->peer,
706                           mw->peer_dma);
707         mw->peer = NULL;
708         mw->peer_dma = 0;
709         mw->size = 0;
710
711         return rc;
712 }
713
714 static void tool_free_mw(struct tool_ctx *tc, int idx)
715 {
716         struct tool_mw *mw = &tc->mws[idx];
717
718         if (mw->peer) {
719                 ntb_mw_clear_trans(tc->ntb, idx);
720                 dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
721                                   mw->peer,
722                                   mw->peer_dma);
723         }
724
725         mw->peer = NULL;
726         mw->peer_dma = 0;
727
728         debugfs_remove(mw->peer_dbg_file);
729
730         mw->peer_dbg_file = NULL;
731 }
732
733 static ssize_t tool_peer_mw_trans_read(struct file *filep,
734                                        char __user *ubuf,
735                                        size_t size, loff_t *offp)
736 {
737         struct tool_mw *mw = filep->private_data;
738
739         char *buf;
740         size_t buf_size;
741         ssize_t ret, off = 0;
742
743         phys_addr_t base;
744         resource_size_t mw_size;
745         resource_size_t align;
746         resource_size_t align_size;
747
748         buf_size = min_t(size_t, size, 512);
749
750         buf = kmalloc(buf_size, GFP_KERNEL);
751         if (!buf)
752                 return -ENOMEM;
753
754         ntb_mw_get_range(mw->tc->ntb, mw->idx,
755                          &base, &mw_size, &align, &align_size);
756
757         off += scnprintf(buf + off, buf_size - off,
758                          "Peer MW %d Information:\n", mw->idx);
759
760         off += scnprintf(buf + off, buf_size - off,
761                          "Physical Address      \t%pa[p]\n",
762                          &base);
763
764         off += scnprintf(buf + off, buf_size - off,
765                          "Window Size           \t%lld\n",
766                          (unsigned long long)mw_size);
767
768         off += scnprintf(buf + off, buf_size - off,
769                          "Alignment             \t%lld\n",
770                          (unsigned long long)align);
771
772         off += scnprintf(buf + off, buf_size - off,
773                          "Size Alignment        \t%lld\n",
774                          (unsigned long long)align_size);
775
776         off += scnprintf(buf + off, buf_size - off,
777                          "Ready                 \t%c\n",
778                          (mw->peer) ? 'Y' : 'N');
779
780         off += scnprintf(buf + off, buf_size - off,
781                          "Allocated Size       \t%zd\n",
782                          (mw->peer) ? (size_t)mw->size : 0);
783
784         ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
785         kfree(buf);
786         return ret;
787 }
788
789 static ssize_t tool_peer_mw_trans_write(struct file *filep,
790                                         const char __user *ubuf,
791                                         size_t size, loff_t *offp)
792 {
793         struct tool_mw *mw = filep->private_data;
794
795         char buf[32];
796         size_t buf_size;
797         unsigned long long val;
798         int rc;
799
800         buf_size = min(size, (sizeof(buf) - 1));
801         if (copy_from_user(buf, ubuf, buf_size))
802                 return -EFAULT;
803
804         buf[buf_size] = '\0';
805
806         rc = kstrtoull(buf, 0, &val);
807         if (rc)
808                 return rc;
809
810         tool_free_mw(mw->tc, mw->idx);
811         if (val)
812                 rc = tool_setup_mw(mw->tc, mw->idx, val);
813
814         if (rc)
815                 return rc;
816
817         return size;
818 }
819
820 static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
821                       tool_peer_mw_trans_read,
822                       tool_peer_mw_trans_write);
823
824 static int tool_init_mw(struct tool_ctx *tc, int idx)
825 {
826         struct tool_mw *mw = &tc->mws[idx];
827         phys_addr_t base;
828         int rc;
829
830         rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
831                               NULL, NULL);
832         if (rc)
833                 return rc;
834
835         mw->tc = tc;
836         mw->idx = idx;
837         mw->local = ioremap_wc(base, mw->win_size);
838         if (!mw->local)
839                 return -EFAULT;
840
841         return 0;
842 }
843
844 static void tool_free_mws(struct tool_ctx *tc)
845 {
846         int i;
847
848         for (i = 0; i < tc->mw_count; i++) {
849                 tool_free_mw(tc, i);
850
851                 if (tc->mws[i].local)
852                         iounmap(tc->mws[i].local);
853
854                 tc->mws[i].local = NULL;
855         }
856 }
857
858 static void tool_setup_dbgfs(struct tool_ctx *tc)
859 {
860         int i;
861
862         /* This modules is useless without dbgfs... */
863         if (!tool_dbgfs) {
864                 tc->dbgfs = NULL;
865                 return;
866         }
867
868         tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev),
869                                        tool_dbgfs);
870         if (!tc->dbgfs)
871                 return;
872
873         debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs,
874                             tc, &tool_db_fops);
875
876         debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs,
877                             tc, &tool_mask_fops);
878
879         debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs,
880                             tc, &tool_peer_db_fops);
881
882         debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs,
883                             tc, &tool_peer_mask_fops);
884
885         debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs,
886                             tc, &tool_spad_fops);
887
888         debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs,
889                             tc, &tool_peer_spad_fops);
890
891         debugfs_create_file("link", S_IRUSR | S_IWUSR, tc->dbgfs,
892                             tc, &tool_link_fops);
893
894         debugfs_create_file("link_event", S_IWUSR, tc->dbgfs,
895                             tc, &tool_link_event_fops);
896
897         for (i = 0; i < tc->mw_count; i++) {
898                 char buf[30];
899
900                 snprintf(buf, sizeof(buf), "mw%d", i);
901                 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
902                                     &tc->mws[i], &tool_mw_fops);
903
904                 snprintf(buf, sizeof(buf), "peer_trans%d", i);
905                 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
906                                     &tc->mws[i], &tool_peer_mw_trans_fops);
907         }
908 }
909
910 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
911 {
912         struct tool_ctx *tc;
913         int rc;
914         int i;
915
916         if (ntb_db_is_unsafe(ntb))
917                 dev_dbg(&ntb->dev, "doorbell is unsafe\n");
918
919         if (ntb_spad_is_unsafe(ntb))
920                 dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
921
922         tc = kzalloc(sizeof(*tc), GFP_KERNEL);
923         if (!tc) {
924                 rc = -ENOMEM;
925                 goto err_tc;
926         }
927
928         tc->ntb = ntb;
929         init_waitqueue_head(&tc->link_wq);
930
931         tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
932         for (i = 0; i < tc->mw_count; i++) {
933                 rc = tool_init_mw(tc, i);
934                 if (rc)
935                         goto err_ctx;
936         }
937
938         tool_setup_dbgfs(tc);
939
940         rc = ntb_set_ctx(ntb, tc, &tool_ops);
941         if (rc)
942                 goto err_ctx;
943
944         ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
945         ntb_link_event(ntb);
946
947         return 0;
948
949 err_ctx:
950         tool_free_mws(tc);
951         debugfs_remove_recursive(tc->dbgfs);
952         kfree(tc);
953 err_tc:
954         return rc;
955 }
956
957 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
958 {
959         struct tool_ctx *tc = ntb->ctx;
960
961         tool_free_mws(tc);
962
963         ntb_clear_ctx(ntb);
964         ntb_link_disable(ntb);
965
966         debugfs_remove_recursive(tc->dbgfs);
967         kfree(tc);
968 }
969
970 static struct ntb_client tool_client = {
971         .ops = {
972                 .probe = tool_probe,
973                 .remove = tool_remove,
974         },
975 };
976
977 static int __init tool_init(void)
978 {
979         int rc;
980
981         if (debugfs_initialized())
982                 tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
983
984         rc = ntb_register_client(&tool_client);
985         if (rc)
986                 goto err_client;
987
988         return 0;
989
990 err_client:
991         debugfs_remove_recursive(tool_dbgfs);
992         return rc;
993 }
994 module_init(tool_init);
995
996 static void __exit tool_exit(void)
997 {
998         ntb_unregister_client(&tool_client);
999         debugfs_remove_recursive(tool_dbgfs);
1000 }
1001 module_exit(tool_exit);