Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'ntb-4.8' of git://github.com/jonmason/ntb

Pull NTB updates from Jon Mason:
"NTB bug fixes for the ntb_tool and ntb_perf, and improvements to the
ntb_perf and ntb_pingpong for increased debugability.

Also, modification to the ntb_transport layer to increase/decrease
the number of transport entries depending on the ring size"

* tag 'ntb-4.8' of git://github.com/jonmason/ntb:
NTB: ntb_hw_intel: use local variable pdev
NTB: ntb_hw_intel: show BAR size in debugfs info
ntb_test: Add a selftest script for the NTB subsystem
ntb_perf: clear link_is_up flag when the link goes down.
ntb_pingpong: Add a debugfs file to get the ping count
ntb_tool: Add link status and files to debugfs
ntb_tool: Postpone memory window initialization for the user
ntb_perf: Wait for link before running test
ntb_perf: Return results by reading the run file
ntb_perf: Improve thread handling to increase robustness
ntb_perf: Schedule based on time not on performance
ntb_transport: Check the number of spads the hardware supports
ntb_tool: Add memory window debug support
ntb_perf: Allow limiting the size of the memory windows
NTB: allocate number transport entries depending on size of ring size
ntb_tool: BUG: Ensure the buffer size is large enough to return all spads
ntb_tool: Fix infinite loop bug when writing spad/peer_spad file

+1176 -103
+1
MAINTAINERS
··· 8341 8341 F: drivers/net/ntb_netdev.c 8342 8342 F: include/linux/ntb.h 8343 8343 F: include/linux/ntb_transport.h 8344 + F: tools/testing/selftests/ntb/ 8344 8345 8345 8346 NTB INTEL DRIVER 8346 8347 M: Jon Mason <jdmason@kudzu.us>
+43 -6
drivers/ntb/hw/intel/ntb_hw_intel.c
··· 551 551 size_t count, loff_t *offp) 552 552 { 553 553 struct intel_ntb_dev *ndev; 554 + struct pci_dev *pdev; 554 555 void __iomem *mmio; 555 556 char *buf; 556 557 size_t buf_size; 557 558 ssize_t ret, off; 558 - union { u64 v64; u32 v32; u16 v16; } u; 559 + union { u64 v64; u32 v32; u16 v16; u8 v8; } u; 559 560 560 561 ndev = filp->private_data; 562 + pdev = ndev_pdev(ndev); 561 563 mmio = ndev->self_mmio; 562 564 563 565 buf_size = min(count, 0x800ul); ··· 634 632 "Doorbell Bell -\t\t%#llx\n", u.v64); 635 633 636 634 off += scnprintf(buf + off, buf_size - off, 635 + "\nNTB Window Size:\n"); 636 + 637 + pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &u.v8); 638 + off += scnprintf(buf + off, buf_size - off, 639 + "PBAR23SZ %hhu\n", u.v8); 640 + if (!ndev->bar4_split) { 641 + pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &u.v8); 642 + off += scnprintf(buf + off, buf_size - off, 643 + "PBAR45SZ %hhu\n", u.v8); 644 + } else { 645 + pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &u.v8); 646 + off += scnprintf(buf + off, buf_size - off, 647 + "PBAR4SZ %hhu\n", u.v8); 648 + pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &u.v8); 649 + off += scnprintf(buf + off, buf_size - off, 650 + "PBAR5SZ %hhu\n", u.v8); 651 + } 652 + 653 + pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &u.v8); 654 + off += scnprintf(buf + off, buf_size - off, 655 + "SBAR23SZ %hhu\n", u.v8); 656 + if (!ndev->bar4_split) { 657 + pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &u.v8); 658 + off += scnprintf(buf + off, buf_size - off, 659 + "SBAR45SZ %hhu\n", u.v8); 660 + } else { 661 + pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &u.v8); 662 + off += scnprintf(buf + off, buf_size - off, 663 + "SBAR4SZ %hhu\n", u.v8); 664 + pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &u.v8); 665 + off += scnprintf(buf + off, buf_size - off, 666 + "SBAR5SZ %hhu\n", u.v8); 667 + } 668 + 669 + off += scnprintf(buf + off, buf_size - off, 637 670 "\nNTB Incoming XLAT:\n"); 638 671 639 672 u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2)); ··· 706 669 "LMT45 -\t\t\t%#018llx\n", u.v64); 707 670 } 708 671 709 - if (pdev_is_xeon(ndev->ntb.pdev)) { 672 + if (pdev_is_xeon(pdev)) { 710 673 if (ntb_topo_is_b2b(ndev->ntb.topo)) { 711 674 off += scnprintf(buf + off, buf_size - off, 712 675 "\nNTB Outgoing B2B XLAT:\n"); ··· 787 750 off += scnprintf(buf + off, buf_size - off, 788 751 "\nXEON NTB Hardware Errors:\n"); 789 752 790 - if (!pci_read_config_word(ndev->ntb.pdev, 753 + if (!pci_read_config_word(pdev, 791 754 XEON_DEVSTS_OFFSET, &u.v16)) 792 755 off += scnprintf(buf + off, buf_size - off, 793 756 "DEVSTS -\t\t%#06x\n", u.v16); 794 757 795 - if (!pci_read_config_word(ndev->ntb.pdev, 758 + if (!pci_read_config_word(pdev, 796 759 XEON_LINK_STATUS_OFFSET, &u.v16)) 797 760 off += scnprintf(buf + off, buf_size - off, 798 761 "LNKSTS -\t\t%#06x\n", u.v16); 799 762 800 - if (!pci_read_config_dword(ndev->ntb.pdev, 763 + if (!pci_read_config_dword(pdev, 801 764 XEON_UNCERRSTS_OFFSET, &u.v32)) 802 765 off += scnprintf(buf + off, buf_size - off, 803 766 "UNCERRSTS -\t\t%#06x\n", u.v32); 804 767 805 - if (!pci_read_config_dword(ndev->ntb.pdev, 768 + if (!pci_read_config_dword(pdev, 806 769 XEON_CORERRSTS_OFFSET, &u.v32)) 807 770 off += scnprintf(buf + off, buf_size - off, 808 771 "CORERRSTS -\t\t%#06x\n", u.v32);
+34 -4
drivers/ntb/ntb_transport.c
··· 153 153 unsigned int rx_index; 154 154 unsigned int rx_max_entry; 155 155 unsigned int rx_max_frame; 156 + unsigned int rx_alloc_entry; 156 157 dma_cookie_t last_cookie; 157 158 struct tasklet_struct rxc_db_work; 158 159 ··· 481 480 out_offset += snprintf(buf + out_offset, out_count - out_offset, 482 481 "rx_index - \t%u\n", qp->rx_index); 483 482 out_offset += snprintf(buf + out_offset, out_count - out_offset, 484 - "rx_max_entry - \t%u\n\n", qp->rx_max_entry); 483 + "rx_max_entry - \t%u\n", qp->rx_max_entry); 484 + out_offset += snprintf(buf + out_offset, out_count - out_offset, 485 + "rx_alloc_entry - \t%u\n\n", qp->rx_alloc_entry); 485 486 486 487 out_offset += snprintf(buf + out_offset, out_count - out_offset, 487 488 "tx_bytes - \t%llu\n", qp->tx_bytes); ··· 600 597 { 601 598 struct ntb_transport_qp *qp = &nt->qp_vec[qp_num]; 602 599 struct ntb_transport_mw *mw; 600 + struct ntb_dev *ndev = nt->ndev; 601 + struct ntb_queue_entry *entry; 603 602 unsigned int rx_size, num_qps_mw; 604 603 unsigned int mw_num, mw_count, qp_count; 605 604 unsigned int i; 605 + int node; 606 606 607 607 mw_count = nt->mw_count; 608 608 qp_count = nt->qp_count; ··· 631 625 qp->rx_max_frame = min(transport_mtu, rx_size / 2); 632 626 qp->rx_max_entry = rx_size / qp->rx_max_frame; 633 627 qp->rx_index = 0; 628 + 629 + /* 630 + * Checking to see if we have more entries than the default. 631 + * We should add additional entries if that is the case so we 632 + * can be in sync with the transport frames. 633 + */ 634 + node = dev_to_node(&ndev->dev); 635 + for (i = qp->rx_alloc_entry; i < qp->rx_max_entry; i++) { 636 + entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); 637 + if (!entry) 638 + return -ENOMEM; 639 + 640 + entry->qp = qp; 641 + ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, 642 + &qp->rx_free_q); 643 + qp->rx_alloc_entry++; 644 + } 634 645 635 646 qp->remote_rx_info->entry = qp->rx_max_entry - 1; 636 647 ··· 1060 1037 int node; 1061 1038 int rc, i; 1062 1039 1040 + mw_count = ntb_mw_count(ndev); 1041 + if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) { 1042 + dev_err(&ndev->dev, "Not enough scratch pad registers for %s", 1043 + NTB_TRANSPORT_NAME); 1044 + return -EIO; 1045 + } 1046 + 1063 1047 if (ntb_db_is_unsafe(ndev)) 1064 1048 dev_dbg(&ndev->dev, 1065 1049 "doorbell is unsafe, proceed anyway...\n"); ··· 1081 1051 return -ENOMEM; 1082 1052 1083 1053 nt->ndev = ndev; 1084 - 1085 - mw_count = ntb_mw_count(ndev); 1086 1054 1087 1055 nt->mw_count = mw_count; 1088 1056 ··· 1750 1722 ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, 1751 1723 &qp->rx_free_q); 1752 1724 } 1725 + qp->rx_alloc_entry = NTB_QP_DEF_NUM_ENTRIES; 1753 1726 1754 - for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { 1727 + for (i = 0; i < qp->tx_max_entry; i++) { 1755 1728 entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); 1756 1729 if (!entry) 1757 1730 goto err2; ··· 1773 1744 while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) 1774 1745 kfree(entry); 1775 1746 err1: 1747 + qp->rx_alloc_entry = 0; 1776 1748 while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q))) 1777 1749 kfree(entry); 1778 1750 if (qp->tx_dma_chan)
+163 -85
drivers/ntb/test/ntb_perf.c
··· 58 58 #include <linux/delay.h> 59 59 #include <linux/sizes.h> 60 60 #include <linux/ntb.h> 61 + #include <linux/mutex.h> 61 62 62 63 #define DRIVER_NAME "ntb_perf" 63 64 #define DRIVER_DESCRIPTION "PCIe NTB Performance Measurement Tool" ··· 83 82 MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 84 83 85 84 static struct dentry *perf_debugfs_dir; 85 + 86 + static unsigned long max_mw_size; 87 + module_param(max_mw_size, ulong, 0644); 88 + MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows"); 86 89 87 90 static unsigned int seg_order = 19; /* 512K */ 88 91 module_param(seg_order, uint, 0644); ··· 122 117 int dma_prep_err; 123 118 int src_idx; 124 119 void *srcs[MAX_SRCS]; 120 + wait_queue_head_t *wq; 121 + int status; 122 + u64 copied; 123 + u64 diff_us; 125 124 }; 126 125 127 126 struct perf_ctx { ··· 133 124 spinlock_t db_lock; 134 125 struct perf_mw mw; 135 126 bool link_is_up; 136 - struct work_struct link_cleanup; 137 127 struct delayed_work link_work; 128 + wait_queue_head_t link_wq; 138 129 struct dentry *debugfs_node_dir; 139 130 struct dentry *debugfs_run; 140 131 struct dentry *debugfs_threads; 141 132 u8 perf_threads; 142 - bool run; 133 + /* mutex ensures only one set of threads run at once */ 134 + struct mutex run_mutex; 143 135 struct pthr_ctx pthr_ctx[MAX_THREADS]; 144 136 atomic_t tsync; 137 + atomic_t tdone; 145 138 }; 146 139 147 140 enum { 148 141 VERSION = 0, 149 142 MW_SZ_HIGH, 150 143 MW_SZ_LOW, 151 - SPAD_MSG, 152 - SPAD_ACK, 153 144 MAX_SPAD 154 145 }; 155 146 ··· 157 148 { 158 149 struct perf_ctx *perf = ctx; 159 150 160 - if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) 151 + if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) { 161 152 schedule_delayed_work(&perf->link_work, 2*HZ); 162 - else 163 - schedule_work(&perf->link_cleanup); 153 + } else { 154 + dev_dbg(&perf->ntb->pdev->dev, "link down\n"); 155 + 156 + if (!perf->link_is_up) 157 + cancel_delayed_work_sync(&perf->link_work); 158 + 159 + perf->link_is_up = false; 160 + } 164 161 } 165 162 166 163 static void perf_db_event(void *ctx, int vec) ··· 286 271 char __iomem *tmp = dst; 287 272 u64 perf, diff_us; 288 273 ktime_t kstart, kstop, kdiff; 274 + unsigned long last_sleep = jiffies; 289 275 290 276 chunks = div64_u64(win_size, buf_size); 291 277 total_chunks = div64_u64(total, buf_size); ··· 302 286 } else 303 287 tmp += buf_size; 304 288 305 - /* Probably should schedule every 4GB to prevent soft hang. */ 306 - if (((copied % SZ_4G) == 0) && !use_dma) { 289 + /* Probably should schedule every 5s to prevent soft hang. */ 290 + if (unlikely((jiffies - last_sleep) > 5 * HZ)) { 291 + last_sleep = jiffies; 307 292 set_current_state(TASK_INTERRUPTIBLE); 308 293 schedule_timeout(1); 309 294 } 295 + 296 + if (unlikely(kthread_should_stop())) 297 + break; 310 298 } 311 299 312 300 if (use_dma) { 313 - pr_info("%s: All DMA descriptors submitted\n", current->comm); 314 - while (atomic_read(&pctx->dma_sync) != 0) 301 + pr_debug("%s: All DMA descriptors submitted\n", current->comm); 302 + while (atomic_read(&pctx->dma_sync) != 0) { 303 + if (kthread_should_stop()) 304 + break; 315 305 msleep(20); 306 + } 316 307 } 317 308 318 309 kstop = ktime_get(); 319 310 kdiff = ktime_sub(kstop, kstart); 320 311 diff_us = ktime_to_us(kdiff); 321 312 322 - pr_info("%s: copied %llu bytes\n", current->comm, copied); 313 + pr_debug("%s: copied %llu bytes\n", current->comm, copied); 323 314 324 - pr_info("%s: lasted %llu usecs\n", current->comm, diff_us); 315 + pr_debug("%s: lasted %llu usecs\n", current->comm, diff_us); 325 316 326 317 perf = div64_u64(copied, diff_us); 327 318 328 - pr_info("%s: MBytes/s: %llu\n", current->comm, perf); 319 + pr_debug("%s: MBytes/s: %llu\n", current->comm, perf); 320 + 321 + pctx->copied = copied; 322 + pctx->diff_us = diff_us; 329 323 330 324 return 0; 331 325 } ··· 357 331 int rc, node, i; 358 332 struct dma_chan *dma_chan = NULL; 359 333 360 - pr_info("kthread %s starting...\n", current->comm); 334 + pr_debug("kthread %s starting...\n", current->comm); 361 335 362 336 node = dev_to_node(&pdev->dev); 363 337 ··· 415 389 pctx->srcs[i] = NULL; 416 390 } 417 391 418 - return 0; 392 + atomic_inc(&perf->tdone); 393 + wake_up(pctx->wq); 394 + rc = 0; 395 + goto done; 419 396 420 397 err: 421 398 for (i = 0; i < MAX_SRCS; i++) { ··· 430 401 dma_release_channel(dma_chan); 431 402 pctx->dma_chan = NULL; 432 403 } 404 + 405 + done: 406 + /* Wait until we are told to stop */ 407 + for (;;) { 408 + set_current_state(TASK_INTERRUPTIBLE); 409 + if (kthread_should_stop()) 410 + break; 411 + schedule(); 412 + } 413 + __set_current_state(TASK_RUNNING); 433 414 434 415 return rc; 435 416 } ··· 511 472 dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__); 512 473 513 474 size = perf->mw.phys_size; 475 + 476 + if (max_mw_size && size > max_mw_size) 477 + size = max_mw_size; 478 + 514 479 ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size)); 515 480 ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size)); 516 481 ntb_peer_spad_write(ndev, VERSION, PERF_VERSION); ··· 539 496 goto out1; 540 497 541 498 perf->link_is_up = true; 499 + wake_up(&perf->link_wq); 542 500 543 501 return; 544 502 ··· 550 506 if (ntb_link_is_up(ndev, NULL, NULL) == 1) 551 507 schedule_delayed_work(&perf->link_work, 552 508 msecs_to_jiffies(PERF_LINK_DOWN_TIMEOUT)); 553 - } 554 - 555 - static void perf_link_cleanup(struct work_struct *work) 556 - { 557 - struct perf_ctx *perf = container_of(work, 558 - struct perf_ctx, 559 - link_cleanup); 560 - 561 - dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__); 562 - 563 - if (!perf->link_is_up) 564 - cancel_delayed_work_sync(&perf->link_work); 565 509 } 566 510 567 511 static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf) ··· 576 544 { 577 545 struct perf_ctx *perf = filp->private_data; 578 546 char *buf; 579 - ssize_t ret, out_offset; 547 + ssize_t ret, out_off = 0; 548 + struct pthr_ctx *pctx; 549 + int i; 550 + u64 rate; 580 551 581 552 if (!perf) 582 553 return 0; 583 554 584 - buf = kmalloc(64, GFP_KERNEL); 555 + buf = kmalloc(1024, GFP_KERNEL); 585 556 if (!buf) 586 557 return -ENOMEM; 587 - out_offset = snprintf(buf, 64, "%d\n", perf->run); 588 - ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); 558 + 559 + if (mutex_is_locked(&perf->run_mutex)) { 560 + out_off = snprintf(buf, 64, "running\n"); 561 + goto read_from_buf; 562 + } 563 + 564 + for (i = 0; i < MAX_THREADS; i++) { 565 + pctx = &perf->pthr_ctx[i]; 566 + 567 + if (pctx->status == -ENODATA) 568 + break; 569 + 570 + if (pctx->status) { 571 + out_off += snprintf(buf + out_off, 1024 - out_off, 572 + "%d: error %d\n", i, 573 + pctx->status); 574 + continue; 575 + } 576 + 577 + rate = div64_u64(pctx->copied, pctx->diff_us); 578 + out_off += snprintf(buf + out_off, 1024 - out_off, 579 + "%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n", 580 + i, pctx->copied, pctx->diff_us, rate); 581 + } 582 + 583 + read_from_buf: 584 + ret = simple_read_from_buffer(ubuf, count, offp, buf, out_off); 589 585 kfree(buf); 590 586 591 587 return ret; ··· 624 564 struct pthr_ctx *pctx; 625 565 int i; 626 566 627 - perf->run = false; 628 567 for (i = 0; i < MAX_THREADS; i++) { 629 568 pctx = &perf->pthr_ctx[i]; 630 569 if (pctx->thread) { 631 - kthread_stop(pctx->thread); 570 + pctx->status = kthread_stop(pctx->thread); 632 571 pctx->thread = NULL; 633 572 } 634 573 } 574 + } 575 + 576 + static void perf_clear_thread_status(struct perf_ctx *perf) 577 + { 578 + int i; 579 + 580 + for (i = 0; i < MAX_THREADS; i++) 581 + perf->pthr_ctx[i].status = -ENODATA; 635 582 } 636 583 637 584 static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf, ··· 646 579 { 647 580 struct perf_ctx *perf = filp->private_data; 648 581 int node, i; 582 + DECLARE_WAIT_QUEUE_HEAD(wq); 649 583 650 - if (!perf->link_is_up) 651 - return 0; 584 + if (wait_event_interruptible(perf->link_wq, perf->link_is_up)) 585 + return -ENOLINK; 652 586 653 587 if (perf->perf_threads == 0) 654 - return 0; 588 + return -EINVAL; 655 589 656 - if (atomic_read(&perf->tsync) == 0) 657 - perf->run = false; 590 + if (!mutex_trylock(&perf->run_mutex)) 591 + return -EBUSY; 658 592 659 - if (perf->run) 660 - threads_cleanup(perf); 661 - else { 662 - perf->run = true; 593 + perf_clear_thread_status(perf); 663 594 664 - if (perf->perf_threads > MAX_THREADS) { 665 - perf->perf_threads = MAX_THREADS; 666 - pr_info("Reset total threads to: %u\n", MAX_THREADS); 667 - } 668 - 669 - /* no greater than 1M */ 670 - if (seg_order > MAX_SEG_ORDER) { 671 - seg_order = MAX_SEG_ORDER; 672 - pr_info("Fix seg_order to %u\n", seg_order); 673 - } 674 - 675 - if (run_order < seg_order) { 676 - run_order = seg_order; 677 - pr_info("Fix run_order to %u\n", run_order); 678 - } 679 - 680 - node = dev_to_node(&perf->ntb->pdev->dev); 681 - /* launch kernel thread */ 682 - for (i = 0; i < perf->perf_threads; i++) { 683 - struct pthr_ctx *pctx; 684 - 685 - pctx = &perf->pthr_ctx[i]; 686 - atomic_set(&pctx->dma_sync, 0); 687 - pctx->perf = perf; 688 - pctx->thread = 689 - kthread_create_on_node(ntb_perf_thread, 690 - (void *)pctx, 691 - node, "ntb_perf %d", i); 692 - if (IS_ERR(pctx->thread)) { 693 - pctx->thread = NULL; 694 - goto err; 695 - } else 696 - wake_up_process(pctx->thread); 697 - 698 - if (perf->run == false) 699 - return -ENXIO; 700 - } 701 - 595 + if (perf->perf_threads > MAX_THREADS) { 596 + perf->perf_threads = MAX_THREADS; 597 + pr_info("Reset total threads to: %u\n", MAX_THREADS); 702 598 } 703 599 600 + /* no greater than 1M */ 601 + if (seg_order > MAX_SEG_ORDER) { 602 + seg_order = MAX_SEG_ORDER; 603 + pr_info("Fix seg_order to %u\n", seg_order); 604 + } 605 + 606 + if (run_order < seg_order) { 607 + run_order = seg_order; 608 + pr_info("Fix run_order to %u\n", run_order); 609 + } 610 + 611 + node = dev_to_node(&perf->ntb->pdev->dev); 612 + atomic_set(&perf->tdone, 0); 613 + 614 + /* launch kernel thread */ 615 + for (i = 0; i < perf->perf_threads; i++) { 616 + struct pthr_ctx *pctx; 617 + 618 + pctx = &perf->pthr_ctx[i]; 619 + atomic_set(&pctx->dma_sync, 0); 620 + pctx->perf = perf; 621 + pctx->wq = &wq; 622 + pctx->thread = 623 + kthread_create_on_node(ntb_perf_thread, 624 + (void *)pctx, 625 + node, "ntb_perf %d", i); 626 + if (IS_ERR(pctx->thread)) { 627 + pctx->thread = NULL; 628 + goto err; 629 + } else { 630 + wake_up_process(pctx->thread); 631 + } 632 + } 633 + 634 + wait_event_interruptible(wq, 635 + atomic_read(&perf->tdone) == perf->perf_threads); 636 + 637 + threads_cleanup(perf); 638 + mutex_unlock(&perf->run_mutex); 704 639 return count; 705 640 706 641 err: 707 642 threads_cleanup(perf); 643 + mutex_unlock(&perf->run_mutex); 708 644 return -ENXIO; 709 645 } 710 646 ··· 758 688 int node; 759 689 int rc = 0; 760 690 691 + if (ntb_spad_count(ntb) < MAX_SPAD) { 692 + dev_err(&ntb->dev, "Not enough scratch pad registers for %s", 693 + DRIVER_NAME); 694 + return -EIO; 695 + } 696 + 761 697 node = dev_to_node(&pdev->dev); 762 698 763 699 perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node); ··· 775 699 perf->ntb = ntb; 776 700 perf->perf_threads = 1; 777 701 atomic_set(&perf->tsync, 0); 778 - perf->run = false; 702 + mutex_init(&perf->run_mutex); 779 703 spin_lock_init(&perf->db_lock); 780 704 perf_setup_mw(ntb, perf); 705 + init_waitqueue_head(&perf->link_wq); 781 706 INIT_DELAYED_WORK(&perf->link_work, perf_link_work); 782 - INIT_WORK(&perf->link_cleanup, perf_link_cleanup); 783 707 784 708 rc = ntb_set_ctx(ntb, perf, &perf_ops); 785 709 if (rc) ··· 793 717 if (rc) 794 718 goto err_ctx; 795 719 720 + perf_clear_thread_status(perf); 721 + 796 722 return 0; 797 723 798 724 err_ctx: 799 725 cancel_delayed_work_sync(&perf->link_work); 800 - cancel_work_sync(&perf->link_cleanup); 801 726 kfree(perf); 802 727 err_perf: 803 728 return rc; ··· 811 734 812 735 dev_dbg(&perf->ntb->dev, "%s called\n", __func__); 813 736 737 + mutex_lock(&perf->run_mutex); 738 + 814 739 cancel_delayed_work_sync(&perf->link_work); 815 - cancel_work_sync(&perf->link_cleanup); 816 740 817 741 ntb_clear_ctx(ntb); 818 742 ntb_link_disable(ntb);
+61 -1
drivers/ntb/test/ntb_pingpong.c
··· 61 61 #include <linux/pci.h> 62 62 #include <linux/slab.h> 63 63 #include <linux/spinlock.h> 64 + #include <linux/debugfs.h> 64 65 65 66 #include <linux/ntb.h> 66 67 ··· 97 96 spinlock_t db_lock; 98 97 struct timer_list db_timer; 99 98 unsigned long db_delay; 99 + struct dentry *debugfs_node_dir; 100 + struct dentry *debugfs_count; 101 + atomic_t count; 100 102 }; 103 + 104 + static struct dentry *pp_debugfs_dir; 101 105 102 106 static void pp_ping(unsigned long ctx) 103 107 { ··· 177 171 dev_dbg(&pp->ntb->dev, 178 172 "Pong vec %d bits %#llx\n", 179 173 vec, db_bits); 174 + atomic_inc(&pp->count); 180 175 } 181 176 spin_unlock_irqrestore(&pp->db_lock, irqflags); 177 + } 178 + 179 + static int pp_debugfs_setup(struct pp_ctx *pp) 180 + { 181 + struct pci_dev *pdev = pp->ntb->pdev; 182 + 183 + if (!pp_debugfs_dir) 184 + return -ENODEV; 185 + 186 + pp->debugfs_node_dir = debugfs_create_dir(pci_name(pdev), 187 + pp_debugfs_dir); 188 + if (!pp->debugfs_node_dir) 189 + return -ENODEV; 190 + 191 + pp->debugfs_count = debugfs_create_atomic_t("count", S_IRUSR | S_IWUSR, 192 + pp->debugfs_node_dir, 193 + &pp->count); 194 + if (!pp->debugfs_count) 195 + return -ENODEV; 196 + 197 + return 0; 182 198 } 183 199 184 200 static const struct ntb_ctx_ops pp_ops = { ··· 238 210 239 211 pp->ntb = ntb; 240 212 pp->db_bits = 0; 213 + atomic_set(&pp->count, 0); 241 214 spin_lock_init(&pp->db_lock); 242 215 setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp); 243 216 pp->db_delay = msecs_to_jiffies(delay_ms); 244 217 245 218 rc = ntb_set_ctx(ntb, pp, &pp_ops); 219 + if (rc) 220 + goto err_ctx; 221 + 222 + rc = pp_debugfs_setup(pp); 246 223 if (rc) 247 224 goto err_ctx; 248 225 ··· 267 234 { 268 235 struct pp_ctx *pp = ntb->ctx; 269 236 237 + debugfs_remove_recursive(pp->debugfs_node_dir); 238 + 270 239 ntb_clear_ctx(ntb); 271 240 del_timer_sync(&pp->db_timer); 272 241 ntb_link_disable(ntb); ··· 282 247 .remove = pp_remove, 283 248 }, 284 249 }; 285 - module_ntb_client(pp_client); 250 + 251 + static int __init pp_init(void) 252 + { 253 + int rc; 254 + 255 + if (debugfs_initialized()) 256 + pp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 257 + 258 + rc = ntb_register_client(&pp_client); 259 + if (rc) 260 + goto err_client; 261 + 262 + return 0; 263 + 264 + err_client: 265 + debugfs_remove_recursive(pp_debugfs_dir); 266 + return rc; 267 + } 268 + module_init(pp_init); 269 + 270 + static void __exit pp_exit(void) 271 + { 272 + ntb_unregister_client(&pp_client); 273 + debugfs_remove_recursive(pp_debugfs_dir); 274 + } 275 + module_exit(pp_exit);
+452 -7
drivers/ntb/test/ntb_tool.c
··· 59 59 * 60 60 * Eg: check if clearing the doorbell mask generates an interrupt. 61 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 + * 62 68 * # Set the doorbell mask 63 69 * root@self# echo 's 1' > $DBG_DIR/mask 64 70 * ··· 85 79 * root@self# cat $DBG_DIR/spad 86 80 * 87 81 * Observe that spad 0 and 1 have the values set by the peer. 82 + * 83 + * # Check the memory window translation info 84 + * cat $DBG_DIR/peer_trans0 85 + * 86 + * # Setup a 16k memory window buffer 87 + * echo 16384 > $DBG_DIR/peer_trans0 88 + * 88 89 */ 89 90 90 91 #include <linux/init.h> ··· 102 89 #include <linux/dma-mapping.h> 103 90 #include <linux/pci.h> 104 91 #include <linux/slab.h> 92 + #include <linux/uaccess.h> 105 93 106 94 #include <linux/ntb.h> 107 95 ··· 119 105 MODULE_AUTHOR(DRIVER_AUTHOR); 120 106 MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 121 107 108 + #define MAX_MWS 16 109 + 122 110 static struct dentry *tool_dbgfs; 111 + 112 + struct tool_mw { 113 + int idx; 114 + struct tool_ctx *tc; 115 + resource_size_t win_size; 116 + resource_size_t size; 117 + u8 __iomem *local; 118 + u8 *peer; 119 + dma_addr_t peer_dma; 120 + struct dentry *peer_dbg_file; 121 + }; 123 122 124 123 struct tool_ctx { 125 124 struct ntb_dev *ntb; 126 125 struct dentry *dbgfs; 126 + wait_queue_head_t link_wq; 127 + int mw_count; 128 + struct tool_mw mws[MAX_MWS]; 127 129 }; 128 130 129 131 #define SPAD_FNAME_SIZE 0x10 ··· 165 135 166 136 dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n", 167 137 up ? "up" : "down", speed, width); 138 + 139 + wake_up(&tc->link_wq); 168 140 } 169 141 170 142 static void tool_db_event(void *ctx, int vec) ··· 271 239 if (!spad_read_fn) 272 240 return -EINVAL; 273 241 274 - buf_size = min_t(size_t, size, 0x100); 242 + spad_count = ntb_spad_count(tc->ntb); 243 + 244 + /* 245 + * We multiply the number of spads by 15 to get the buffer size 246 + * this is from 3 for the %d, 10 for the largest hex value 247 + * (0x00000000) and 2 for the tab and line feed. 248 + */ 249 + buf_size = min_t(size_t, size, spad_count * 15); 275 250 276 251 buf = kmalloc(buf_size, GFP_KERNEL); 277 252 if (!buf) ··· 286 247 287 248 pos = 0; 288 249 289 - spad_count = ntb_spad_count(tc->ntb); 290 250 for (i = 0; i < spad_count; ++i) { 291 251 pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n", 292 252 i, spad_read_fn(tc->ntb, i)); ··· 306 268 { 307 269 int spad_idx; 308 270 u32 spad_val; 309 - char *buf; 271 + char *buf, *buf_ptr; 310 272 int pos, n; 311 273 ssize_t rc; 312 274 ··· 326 288 } 327 289 328 290 buf[size] = 0; 329 - 330 - n = sscanf(buf, "%d %i%n", &spad_idx, &spad_val, &pos); 291 + buf_ptr = buf; 292 + n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos); 331 293 while (n == 2) { 294 + buf_ptr += pos; 332 295 rc = spad_write_fn(tc->ntb, spad_idx, spad_val); 333 296 if (rc) 334 297 break; 335 298 336 - n = sscanf(buf + pos, "%d %i%n", &spad_idx, &spad_val, &pos); 299 + n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos); 337 300 } 338 301 339 302 if (n < 0) ··· 481 442 tool_peer_spad_read, 482 443 tool_peer_spad_write); 483 444 445 + static ssize_t tool_link_read(struct file *filep, char __user *ubuf, 446 + size_t size, loff_t *offp) 447 + { 448 + struct tool_ctx *tc = filep->private_data; 449 + char buf[3]; 450 + 451 + buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N'; 452 + buf[1] = '\n'; 453 + buf[2] = '\0'; 454 + 455 + return simple_read_from_buffer(ubuf, size, offp, buf, 2); 456 + } 457 + 458 + static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, 459 + size_t size, loff_t *offp) 460 + { 461 + struct tool_ctx *tc = filep->private_data; 462 + char buf[32]; 463 + size_t buf_size; 464 + bool val; 465 + int rc; 466 + 467 + buf_size = min(size, (sizeof(buf) - 1)); 468 + if (copy_from_user(buf, ubuf, buf_size)) 469 + return -EFAULT; 470 + 471 + buf[buf_size] = '\0'; 472 + 473 + rc = strtobool(buf, &val); 474 + if (rc) 475 + return rc; 476 + 477 + if (val) 478 + rc = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 479 + else 480 + rc = ntb_link_disable(tc->ntb); 481 + 482 + if (rc) 483 + return rc; 484 + 485 + return size; 486 + } 487 + 488 + static TOOL_FOPS_RDWR(tool_link_fops, 489 + tool_link_read, 490 + tool_link_write); 491 + 492 + static ssize_t tool_link_event_write(struct file *filep, 493 + const char __user *ubuf, 494 + size_t size, loff_t *offp) 495 + { 496 + struct tool_ctx *tc = filep->private_data; 497 + char buf[32]; 498 + size_t buf_size; 499 + bool val; 500 + int rc; 501 + 502 + buf_size = min(size, (sizeof(buf) - 1)); 503 + if (copy_from_user(buf, ubuf, buf_size)) 504 + return -EFAULT; 505 + 506 + buf[buf_size] = '\0'; 507 + 508 + rc = strtobool(buf, &val); 509 + if (rc) 510 + return rc; 511 + 512 + if (wait_event_interruptible(tc->link_wq, 513 + ntb_link_is_up(tc->ntb, NULL, NULL) == val)) 514 + return -ERESTART; 515 + 516 + return size; 517 + } 518 + 519 + static TOOL_FOPS_RDWR(tool_link_event_fops, 520 + NULL, 521 + tool_link_event_write); 522 + 523 + static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, 524 + size_t size, loff_t *offp) 525 + { 526 + struct tool_mw *mw = filep->private_data; 527 + ssize_t rc; 528 + loff_t pos = *offp; 529 + void *buf; 530 + 531 + if (mw->local == NULL) 532 + return -EIO; 533 + if (pos < 0) 534 + return -EINVAL; 535 + if (pos >= mw->win_size || !size) 536 + return 0; 537 + if (size > mw->win_size - pos) 538 + size = mw->win_size - pos; 539 + 540 + buf = kmalloc(size, GFP_KERNEL); 541 + if (!buf) 542 + return -ENOMEM; 543 + 544 + memcpy_fromio(buf, mw->local + pos, size); 545 + rc = copy_to_user(ubuf, buf, size); 546 + if (rc == size) { 547 + rc = -EFAULT; 548 + goto err_free; 549 + } 550 + 551 + size -= rc; 552 + *offp = pos + size; 553 + rc = size; 554 + 555 + err_free: 556 + kfree(buf); 557 + 558 + return rc; 559 + } 560 + 561 + static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, 562 + size_t size, loff_t *offp) 563 + { 564 + struct tool_mw *mw = filep->private_data; 565 + ssize_t rc; 566 + loff_t pos = *offp; 567 + void *buf; 568 + 569 + if (pos < 0) 570 + return -EINVAL; 571 + if (pos >= mw->win_size || !size) 572 + return 0; 573 + if (size > mw->win_size - pos) 574 + size = mw->win_size - pos; 575 + 576 + buf = kmalloc(size, GFP_KERNEL); 577 + if (!buf) 578 + return -ENOMEM; 579 + 580 + rc = copy_from_user(buf, ubuf, size); 581 + if (rc == size) { 582 + rc = -EFAULT; 583 + goto err_free; 584 + } 585 + 586 + size -= rc; 587 + *offp = pos + size; 588 + rc = size; 589 + 590 + memcpy_toio(mw->local + pos, buf, size); 591 + 592 + err_free: 593 + kfree(buf); 594 + 595 + return rc; 596 + } 597 + 598 + static TOOL_FOPS_RDWR(tool_mw_fops, 599 + tool_mw_read, 600 + tool_mw_write); 601 + 602 + static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, 603 + size_t size, loff_t *offp) 604 + { 605 + struct tool_mw *mw = filep->private_data; 606 + 607 + if (!mw->peer) 608 + return -ENXIO; 609 + 610 + return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size); 611 + } 612 + 613 + static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, 614 + size_t size, loff_t *offp) 615 + { 616 + struct tool_mw *mw = filep->private_data; 617 + 618 + if (!mw->peer) 619 + return -ENXIO; 620 + 621 + return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size); 622 + } 623 + 624 + static TOOL_FOPS_RDWR(tool_peer_mw_fops, 625 + tool_peer_mw_read, 626 + tool_peer_mw_write); 627 + 628 + static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size) 629 + { 630 + int rc; 631 + struct tool_mw *mw = &tc->mws[idx]; 632 + phys_addr_t base; 633 + resource_size_t size, align, align_size; 634 + char buf[16]; 635 + 636 + if (mw->peer) 637 + return 0; 638 + 639 + rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align, 640 + &align_size); 641 + if (rc) 642 + return rc; 643 + 644 + mw->size = min_t(resource_size_t, req_size, size); 645 + mw->size = round_up(mw->size, align); 646 + mw->size = round_up(mw->size, align_size); 647 + mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size, 648 + &mw->peer_dma, GFP_KERNEL); 649 + 650 + if (!mw->peer) 651 + return -ENOMEM; 652 + 653 + rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size); 654 + if (rc) 655 + goto err_free_dma; 656 + 657 + snprintf(buf, sizeof(buf), "peer_mw%d", idx); 658 + mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR, 659 + mw->tc->dbgfs, mw, 660 + &tool_peer_mw_fops); 661 + 662 + return 0; 663 + 664 + err_free_dma: 665 + dma_free_coherent(&tc->ntb->pdev->dev, mw->size, 666 + mw->peer, 667 + mw->peer_dma); 668 + mw->peer = NULL; 669 + mw->peer_dma = 0; 670 + mw->size = 0; 671 + 672 + return rc; 673 + } 674 + 675 + static void tool_free_mw(struct tool_ctx *tc, int idx) 676 + { 677 + struct tool_mw *mw = &tc->mws[idx]; 678 + 679 + if (mw->peer) { 680 + ntb_mw_clear_trans(tc->ntb, idx); 681 + dma_free_coherent(&tc->ntb->pdev->dev, mw->size, 682 + mw->peer, 683 + mw->peer_dma); 684 + } 685 + 686 + mw->peer = NULL; 687 + mw->peer_dma = 0; 688 + 689 + debugfs_remove(mw->peer_dbg_file); 690 + 691 + mw->peer_dbg_file = NULL; 692 + } 693 + 694 + static ssize_t tool_peer_mw_trans_read(struct file *filep, 695 + char __user *ubuf, 696 + size_t size, loff_t *offp) 697 + { 698 + struct tool_mw *mw = filep->private_data; 699 + 700 + char *buf; 701 + size_t buf_size; 702 + ssize_t ret, off = 0; 703 + 704 + phys_addr_t base; 705 + resource_size_t mw_size; 706 + resource_size_t align; 707 + resource_size_t align_size; 708 + 709 + buf_size = min_t(size_t, size, 512); 710 + 711 + buf = kmalloc(buf_size, GFP_KERNEL); 712 + if (!buf) 713 + return -ENOMEM; 714 + 715 + ntb_mw_get_range(mw->tc->ntb, mw->idx, 716 + &base, &mw_size, &align, &align_size); 717 + 718 + off += scnprintf(buf + off, buf_size - off, 719 + "Peer MW %d Information:\n", mw->idx); 720 + 721 + off += scnprintf(buf + off, buf_size - off, 722 + "Physical Address \t%pa[p]\n", 723 + &base); 724 + 725 + off += scnprintf(buf + off, buf_size - off, 726 + "Window Size \t%lld\n", 727 + (unsigned long long)mw_size); 728 + 729 + off += scnprintf(buf + off, buf_size - off, 730 + "Alignment \t%lld\n", 731 + (unsigned long long)align); 732 + 733 + off += scnprintf(buf + off, buf_size - off, 734 + "Size Alignment \t%lld\n", 735 + (unsigned long long)align_size); 736 + 737 + off += scnprintf(buf + off, buf_size - off, 738 + "Ready \t%c\n", 739 + (mw->peer) ? 'Y' : 'N'); 740 + 741 + off += scnprintf(buf + off, buf_size - off, 742 + "Allocated Size \t%zd\n", 743 + (mw->peer) ? (size_t)mw->size : 0); 744 + 745 + ret = simple_read_from_buffer(ubuf, size, offp, buf, off); 746 + kfree(buf); 747 + return ret; 748 + } 749 + 750 + static ssize_t tool_peer_mw_trans_write(struct file *filep, 751 + const char __user *ubuf, 752 + size_t size, loff_t *offp) 753 + { 754 + struct tool_mw *mw = filep->private_data; 755 + 756 + char buf[32]; 757 + size_t buf_size; 758 + unsigned long long val; 759 + int rc; 760 + 761 + buf_size = min(size, (sizeof(buf) - 1)); 762 + if (copy_from_user(buf, ubuf, buf_size)) 763 + return -EFAULT; 764 + 765 + buf[buf_size] = '\0'; 766 + 767 + rc = kstrtoull(buf, 0, &val); 768 + if (rc) 769 + return rc; 770 + 771 + tool_free_mw(mw->tc, mw->idx); 772 + if (val) 773 + rc = tool_setup_mw(mw->tc, mw->idx, val); 774 + 775 + if (rc) 776 + return rc; 777 + 778 + return size; 779 + } 780 + 781 + static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops, 782 + tool_peer_mw_trans_read, 783 + tool_peer_mw_trans_write); 784 + 785 + static int tool_init_mw(struct tool_ctx *tc, int idx) 786 + { 787 + struct tool_mw *mw = &tc->mws[idx]; 788 + phys_addr_t base; 789 + int rc; 790 + 791 + rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size, 792 + NULL, NULL); 793 + if (rc) 794 + return rc; 795 + 796 + mw->tc = tc; 797 + mw->idx = idx; 798 + mw->local = ioremap_wc(base, mw->win_size); 799 + if (!mw->local) 800 + return -EFAULT; 801 + 802 + return 0; 803 + } 804 + 805 + static void tool_free_mws(struct tool_ctx *tc) 806 + { 807 + int i; 808 + 809 + for (i = 0; i < tc->mw_count; i++) { 810 + tool_free_mw(tc, i); 811 + 812 + if (tc->mws[i].local) 813 + iounmap(tc->mws[i].local); 814 + 815 + tc->mws[i].local = NULL; 816 + } 817 + } 818 + 484 819 static void tool_setup_dbgfs(struct tool_ctx *tc) 485 820 { 821 + int i; 822 + 486 823 /* This modules is useless without dbgfs... */ 487 824 if (!tool_dbgfs) { 488 825 tc->dbgfs = NULL; ··· 887 472 888 473 debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs, 889 474 tc, &tool_peer_spad_fops); 475 + 476 + debugfs_create_file("link", S_IRUSR | S_IWUSR, tc->dbgfs, 477 + tc, &tool_link_fops); 478 + 479 + debugfs_create_file("link_event", S_IWUSR, tc->dbgfs, 480 + tc, &tool_link_event_fops); 481 + 482 + for (i = 0; i < tc->mw_count; i++) { 483 + char buf[30]; 484 + 485 + snprintf(buf, sizeof(buf), "mw%d", i); 486 + debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 487 + &tc->mws[i], &tool_mw_fops); 488 + 489 + snprintf(buf, sizeof(buf), "peer_trans%d", i); 490 + debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 491 + &tc->mws[i], &tool_peer_mw_trans_fops); 492 + } 890 493 } 891 494 892 495 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) 893 496 { 894 497 struct tool_ctx *tc; 895 498 int rc; 499 + int i; 896 500 897 501 if (ntb_db_is_unsafe(ntb)) 898 502 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); ··· 919 485 if (ntb_spad_is_unsafe(ntb)) 920 486 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 921 487 922 - tc = kmalloc(sizeof(*tc), GFP_KERNEL); 488 + tc = kzalloc(sizeof(*tc), GFP_KERNEL); 923 489 if (!tc) { 924 490 rc = -ENOMEM; 925 491 goto err_tc; 926 492 } 927 493 928 494 tc->ntb = ntb; 495 + init_waitqueue_head(&tc->link_wq); 496 + 497 + tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS); 498 + for (i = 0; i < tc->mw_count; i++) { 499 + rc = tool_init_mw(tc, i); 500 + if (rc) 501 + goto err_ctx; 502 + } 929 503 930 504 tool_setup_dbgfs(tc); 931 505 ··· 947 505 return 0; 948 506 949 507 err_ctx: 508 + tool_free_mws(tc); 950 509 debugfs_remove_recursive(tc->dbgfs); 951 510 kfree(tc); 952 511 err_tc: ··· 957 514 static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) 958 515 { 959 516 struct tool_ctx *tc = ntb->ctx; 517 + 518 + tool_free_mws(tc); 960 519 961 520 ntb_clear_ctx(ntb); 962 521 ntb_link_disable(ntb);
+422
tools/testing/selftests/ntb/ntb_test.sh
··· 1 + #!/bin/bash 2 + # Copyright (c) 2016 Microsemi. All Rights Reserved. 3 + # 4 + # This program is free software; you can redistribute it and/or 5 + # modify it under the terms of the GNU General Public License as 6 + # published by the Free Software Foundation; either version 2 of 7 + # the License, or (at your option) any later version. 8 + # 9 + # This program is distributed in the hope that it would be useful, 10 + # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + # GNU General Public License for more details. 13 + # 14 + # Author: Logan Gunthorpe <logang@deltatee.com> 15 + 16 + REMOTE_HOST= 17 + LIST_DEVS=FALSE 18 + 19 + DEBUGFS=${DEBUGFS-/sys/kernel/debug} 20 + 21 + PERF_RUN_ORDER=32 22 + MAX_MW_SIZE=0 23 + RUN_DMA_TESTS= 24 + DONT_CLEANUP= 25 + MW_SIZE=65536 26 + 27 + function show_help() 28 + { 29 + echo "Usage: $0 [OPTIONS] LOCAL_DEV REMOTE_DEV" 30 + echo "Run tests on a pair of NTB endpoints." 31 + echo 32 + echo "If the NTB device loops back to the same host then," 33 + echo "just specifying the two PCI ids on the command line is" 34 + echo "sufficient. Otherwise, if the NTB link spans two hosts" 35 + echo "use the -r option to specify the hostname for the remote" 36 + echo "device. SSH will then be used to test the remote side." 37 + echo "An SSH key between the root users of the host would then" 38 + echo "be highly recommended." 39 + echo 40 + echo "Options:" 41 + echo " -C don't cleanup ntb modules on exit" 42 + echo " -d run dma tests" 43 + echo " -h show this help message" 44 + echo " -l list available local and remote PCI ids" 45 + echo " -r REMOTE_HOST specify the remote's hostname to connect" 46 + echo " to for the test (using ssh)" 47 + echo " -p NUM ntb_perf run order (default: $PERF_RUN_ORDER)" 48 + echo " -w max_mw_size maxmium memory window size" 49 + echo 50 + } 51 + 52 + function parse_args() 53 + { 54 + OPTIND=0 55 + while getopts "Cdhlm:r:p:w:" opt; do 56 + case "$opt" in 57 + C) DONT_CLEANUP=1 ;; 58 + d) RUN_DMA_TESTS=1 ;; 59 + h) show_help; exit 0 ;; 60 + l) LIST_DEVS=TRUE ;; 61 + m) MW_SIZE=${OPTARG} ;; 62 + r) REMOTE_HOST=${OPTARG} ;; 63 + p) PERF_RUN_ORDER=${OPTARG} ;; 64 + w) MAX_MW_SIZE=${OPTARG} ;; 65 + \?) 66 + echo "Invalid option: -$OPTARG" >&2 67 + exit 1 68 + ;; 69 + esac 70 + done 71 + } 72 + 73 + parse_args "$@" 74 + shift $((OPTIND-1)) 75 + LOCAL_DEV=$1 76 + shift 77 + parse_args "$@" 78 + shift $((OPTIND-1)) 79 + REMOTE_DEV=$1 80 + shift 81 + parse_args "$@" 82 + 83 + set -e 84 + 85 + function _modprobe() 86 + { 87 + modprobe "$@" 88 + } 89 + 90 + function split_remote() 91 + { 92 + VPATH=$1 93 + REMOTE= 94 + 95 + if [[ "$VPATH" == *":/"* ]]; then 96 + REMOTE=${VPATH%%:*} 97 + VPATH=${VPATH#*:} 98 + fi 99 + } 100 + 101 + function read_file() 102 + { 103 + split_remote $1 104 + if [[ "$REMOTE" != "" ]]; then 105 + ssh "$REMOTE" cat "$VPATH" 106 + else 107 + cat "$VPATH" 108 + fi 109 + } 110 + 111 + function write_file() 112 + { 113 + split_remote $2 114 + VALUE=$1 115 + 116 + if [[ "$REMOTE" != "" ]]; then 117 + ssh "$REMOTE" "echo \"$VALUE\" > \"$VPATH\"" 118 + else 119 + echo "$VALUE" > "$VPATH" 120 + fi 121 + } 122 + 123 + function link_test() 124 + { 125 + LOC=$1 126 + REM=$2 127 + EXP=0 128 + 129 + echo "Running link tests on: $(basename $LOC) / $(basename $REM)" 130 + 131 + if ! write_file "N" "$LOC/link" 2> /dev/null; then 132 + echo " Unsupported" 133 + return 134 + fi 135 + 136 + write_file "N" "$LOC/link_event" 137 + 138 + if [[ $(read_file "$REM/link") != "N" ]]; then 139 + echo "Expected remote link to be down in $REM/link" >&2 140 + exit -1 141 + fi 142 + 143 + write_file "Y" "$LOC/link" 144 + write_file "Y" "$LOC/link_event" 145 + 146 + echo " Passed" 147 + } 148 + 149 + function doorbell_test() 150 + { 151 + LOC=$1 152 + REM=$2 153 + EXP=0 154 + 155 + echo "Running db tests on: $(basename $LOC) / $(basename $REM)" 156 + 157 + write_file "c 0xFFFFFFFF" "$REM/db" 158 + 159 + for ((i=1; i <= 8; i++)); do 160 + let DB=$(read_file "$REM/db") || true 161 + if [[ "$DB" != "$EXP" ]]; then 162 + echo "Doorbell doesn't match expected value $EXP " \ 163 + "in $REM/db" >&2 164 + exit -1 165 + fi 166 + 167 + let "MASK=1 << ($i-1)" || true 168 + let "EXP=$EXP | $MASK" || true 169 + write_file "s $MASK" "$LOC/peer_db" 170 + done 171 + 172 + echo " Passed" 173 + } 174 + 175 + function read_spad() 176 + { 177 + VPATH=$1 178 + IDX=$2 179 + 180 + ROW=($(read_file "$VPATH" | grep -e "^$IDX")) 181 + let VAL=${ROW[1]} || true 182 + echo $VAL 183 + } 184 + 185 + function scratchpad_test() 186 + { 187 + LOC=$1 188 + REM=$2 189 + CNT=$(read_file "$LOC/spad" | wc -l) 190 + 191 + echo "Running spad tests on: $(basename $LOC) / $(basename $REM)" 192 + 193 + for ((i = 0; i < $CNT; i++)); do 194 + VAL=$RANDOM 195 + write_file "$i $VAL" "$LOC/peer_spad" 196 + RVAL=$(read_spad "$REM/spad" $i) 197 + 198 + if [[ "$VAL" != "$RVAL" ]]; then 199 + echo "Scratchpad doesn't match expected value $VAL " \ 200 + "in $REM/spad, got $RVAL" >&2 201 + exit -1 202 + fi 203 + 204 + done 205 + 206 + echo " Passed" 207 + } 208 + 209 + function write_mw() 210 + { 211 + split_remote $2 212 + 213 + if [[ "$REMOTE" != "" ]]; then 214 + ssh "$REMOTE" \ 215 + dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true 216 + else 217 + dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true 218 + fi 219 + } 220 + 221 + function mw_test() 222 + { 223 + IDX=$1 224 + LOC=$2 225 + REM=$3 226 + 227 + echo "Running $IDX tests on: $(basename $LOC) / $(basename $REM)" 228 + 229 + write_mw "$LOC/$IDX" 230 + 231 + split_remote "$LOC/$IDX" 232 + if [[ "$REMOTE" == "" ]]; then 233 + A=$VPATH 234 + else 235 + A=/tmp/ntb_test.$$.A 236 + ssh "$REMOTE" cat "$VPATH" > "$A" 237 + fi 238 + 239 + split_remote "$REM/peer_$IDX" 240 + if [[ "$REMOTE" == "" ]]; then 241 + B=$VPATH 242 + else 243 + B=/tmp/ntb_test.$$.B 244 + ssh "$REMOTE" cat "$VPATH" > "$B" 245 + fi 246 + 247 + cmp -n $MW_SIZE "$A" "$B" 248 + if [[ $? != 0 ]]; then 249 + echo "Memory window $MW did not match!" >&2 250 + fi 251 + 252 + if [[ "$A" == "/tmp/*" ]]; then 253 + rm "$A" 254 + fi 255 + 256 + if [[ "$B" == "/tmp/*" ]]; then 257 + rm "$B" 258 + fi 259 + 260 + echo " Passed" 261 + } 262 + 263 + function pingpong_test() 264 + { 265 + LOC=$1 266 + REM=$2 267 + 268 + echo "Running ping pong tests on: $(basename $LOC) / $(basename $REM)" 269 + 270 + LOC_START=$(read_file $LOC/count) 271 + REM_START=$(read_file $REM/count) 272 + 273 + sleep 7 274 + 275 + LOC_END=$(read_file $LOC/count) 276 + REM_END=$(read_file $REM/count) 277 + 278 + if [[ $LOC_START == $LOC_END ]] || [[ $REM_START == $REM_END ]]; then 279 + echo "Ping pong counter not incrementing!" >&2 280 + exit 1 281 + fi 282 + 283 + echo " Passed" 284 + } 285 + 286 + function perf_test() 287 + { 288 + USE_DMA=$1 289 + 290 + if [[ $USE_DMA == "1" ]]; then 291 + WITH="with" 292 + else 293 + WITH="without" 294 + fi 295 + 296 + _modprobe ntb_perf run_order=$PERF_RUN_ORDER \ 297 + max_mw_size=$MAX_MW_SIZE use_dma=$USE_DMA 298 + 299 + echo "Running local perf test $WITH DMA" 300 + write_file "" $LOCAL_PERF/run 301 + echo -n " " 302 + read_file $LOCAL_PERF/run 303 + echo " Passed" 304 + 305 + echo "Running remote perf test $WITH DMA" 306 + write_file "" $REMOTE_PERF/run 307 + echo -n " " 308 + read_file $LOCAL_PERF/run 309 + echo " Passed" 310 + 311 + _modprobe -r ntb_perf 312 + } 313 + 314 + function ntb_tool_tests() 315 + { 316 + LOCAL_TOOL=$DEBUGFS/ntb_tool/$LOCAL_DEV 317 + REMOTE_TOOL=$REMOTE_HOST:$DEBUGFS/ntb_tool/$REMOTE_DEV 318 + 319 + echo "Starting ntb_tool tests..." 320 + 321 + _modprobe ntb_tool 322 + 323 + write_file Y $LOCAL_TOOL/link_event 324 + write_file Y $REMOTE_TOOL/link_event 325 + 326 + link_test $LOCAL_TOOL $REMOTE_TOOL 327 + link_test $REMOTE_TOOL $LOCAL_TOOL 328 + 329 + for PEER_TRANS in $(ls $LOCAL_TOOL/peer_trans*); do 330 + PT=$(basename $PEER_TRANS) 331 + write_file $MW_SIZE $LOCAL_TOOL/$PT 332 + write_file $MW_SIZE $REMOTE_TOOL/$PT 333 + done 334 + 335 + doorbell_test $LOCAL_TOOL $REMOTE_TOOL 336 + doorbell_test $REMOTE_TOOL $LOCAL_TOOL 337 + scratchpad_test $LOCAL_TOOL $REMOTE_TOOL 338 + scratchpad_test $REMOTE_TOOL $LOCAL_TOOL 339 + 340 + for MW in $(ls $LOCAL_TOOL/mw*); do 341 + MW=$(basename $MW) 342 + 343 + mw_test $MW $LOCAL_TOOL $REMOTE_TOOL 344 + mw_test $MW $REMOTE_TOOL $LOCAL_TOOL 345 + done 346 + 347 + _modprobe -r ntb_tool 348 + } 349 + 350 + function ntb_pingpong_tests() 351 + { 352 + LOCAL_PP=$DEBUGFS/ntb_pingpong/$LOCAL_DEV 353 + REMOTE_PP=$REMOTE_HOST:$DEBUGFS/ntb_pingpong/$REMOTE_DEV 354 + 355 + echo "Starting ntb_pingpong tests..." 356 + 357 + _modprobe ntb_pingpong 358 + 359 + pingpong_test $LOCAL_PP $REMOTE_PP 360 + 361 + _modprobe -r ntb_pingpong 362 + } 363 + 364 + function ntb_perf_tests() 365 + { 366 + LOCAL_PERF=$DEBUGFS/ntb_perf/$LOCAL_DEV 367 + REMOTE_PERF=$REMOTE_HOST:$DEBUGFS/ntb_perf/$REMOTE_DEV 368 + 369 + echo "Starting ntb_perf tests..." 370 + 371 + perf_test 0 372 + 373 + if [[ $RUN_DMA_TESTS ]]; then 374 + perf_test 1 375 + fi 376 + } 377 + 378 + function cleanup() 379 + { 380 + set +e 381 + _modprobe -r ntb_tool 2> /dev/null 382 + _modprobe -r ntb_perf 2> /dev/null 383 + _modprobe -r ntb_pingpong 2> /dev/null 384 + _modprobe -r ntb_transport 2> /dev/null 385 + set -e 386 + } 387 + 388 + cleanup 389 + 390 + if ! [[ $$DONT_CLEANUP ]]; then 391 + trap cleanup EXIT 392 + fi 393 + 394 + if [ "$(id -u)" != "0" ]; then 395 + echo "This script must be run as root" 1>&2 396 + exit 1 397 + fi 398 + 399 + if [[ "$LIST_DEVS" == TRUE ]]; then 400 + echo "Local Devices:" 401 + ls -1 /sys/bus/ntb/devices 402 + echo 403 + 404 + if [[ "$REMOTE_HOST" != "" ]]; then 405 + echo "Remote Devices:" 406 + ssh $REMOTE_HOST ls -1 /sys/bus/ntb/devices 407 + fi 408 + 409 + exit 0 410 + fi 411 + 412 + if [[ "$LOCAL_DEV" == $"" ]] || [[ "$REMOTE_DEV" == $"" ]]; then 413 + show_help 414 + exit 1 415 + fi 416 + 417 + ntb_tool_tests 418 + echo 419 + ntb_pingpong_tests 420 + echo 421 + ntb_perf_tests 422 + echo