linux/drivers/ntb/test/ntb_tool.c
<<
>>
Prefs
   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
 117MODULE_LICENSE(DRIVER_LICENSE);
 118MODULE_VERSION(DRIVER_VERSION);
 119MODULE_AUTHOR(DRIVER_AUTHOR);
 120MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
 121
 122#define MAX_MWS 16
 123
 124static struct dentry *tool_dbgfs;
 125
 126struct 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
 137struct 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
 157static 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
 172static 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
 184static const struct ntb_ctx_ops tool_ops = {
 185        .link_event = tool_link_event,
 186        .db_event = tool_db_event,
 187};
 188
 189static 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
 216static 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
 262static 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
 301static 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
 348static 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
 357static 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
 367static TOOL_FOPS_RDWR(tool_db_fops,
 368                      tool_db_read,
 369                      tool_db_write);
 370
 371static 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
 380static 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
 390static TOOL_FOPS_RDWR(tool_mask_fops,
 391                      tool_mask_read,
 392                      tool_mask_write);
 393
 394static 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
 403static 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
 413static TOOL_FOPS_RDWR(tool_peer_db_fops,
 414                      tool_peer_db_read,
 415                      tool_peer_db_write);
 416
 417static 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
 426static 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
 436static TOOL_FOPS_RDWR(tool_peer_mask_fops,
 437                      tool_peer_mask_read,
 438                      tool_peer_mask_write);
 439
 440static 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
 449static 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
 458static TOOL_FOPS_RDWR(tool_spad_fops,
 459                      tool_spad_read,
 460                      tool_spad_write);
 461
 462static 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
 471static 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
 480static TOOL_FOPS_RDWR(tool_peer_spad_fops,
 481                      tool_peer_spad_read,
 482                      tool_peer_spad_write);
 483
 484static 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
 497static 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
 527static TOOL_FOPS_RDWR(tool_link_fops,
 528                      tool_link_read,
 529                      tool_link_write);
 530
 531static 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
 558static TOOL_FOPS_RDWR(tool_link_event_fops,
 559                      NULL,
 560                      tool_link_event_write);
 561
 562static 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
 594err_free:
 595        kfree(buf);
 596
 597        return rc;
 598}
 599
 600static 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
 631err_free:
 632        kfree(buf);
 633
 634        return rc;
 635}
 636
 637static TOOL_FOPS_RDWR(tool_mw_fops,
 638                      tool_mw_read,
 639                      tool_mw_write);
 640
 641static 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
 652static 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
 663static TOOL_FOPS_RDWR(tool_peer_mw_fops,
 664                      tool_peer_mw_read,
 665                      tool_peer_mw_write);
 666
 667static 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
 703err_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
 714static 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
 733static 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
 789static 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
 820static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
 821                      tool_peer_mw_trans_read,
 822                      tool_peer_mw_trans_write);
 823
 824static 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
 844static 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
 858static 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
 910static 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
 949err_ctx:
 950        tool_free_mws(tc);
 951        debugfs_remove_recursive(tc->dbgfs);
 952        kfree(tc);
 953err_tc:
 954        return rc;
 955}
 956
 957static 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
 970static struct ntb_client tool_client = {
 971        .ops = {
 972                .probe = tool_probe,
 973                .remove = tool_remove,
 974        },
 975};
 976
 977static 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
 990err_client:
 991        debugfs_remove_recursive(tool_dbgfs);
 992        return rc;
 993}
 994module_init(tool_init);
 995
 996static void __exit tool_exit(void)
 997{
 998        ntb_unregister_client(&tool_client);
 999        debugfs_remove_recursive(tool_dbgfs);
1000}
1001module_exit(tool_exit);
1002