Commit 32199ec3 authored by Linus Torvalds's avatar Linus Torvalds

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
parents a02040d8 95f1464f
...@@ -8341,6 +8341,7 @@ F: drivers/ntb/ ...@@ -8341,6 +8341,7 @@ F: drivers/ntb/
F: drivers/net/ntb_netdev.c F: drivers/net/ntb_netdev.c
F: include/linux/ntb.h F: include/linux/ntb.h
F: include/linux/ntb_transport.h F: include/linux/ntb_transport.h
F: tools/testing/selftests/ntb/
NTB INTEL DRIVER NTB INTEL DRIVER
M: Jon Mason <jdmason@kudzu.us> M: Jon Mason <jdmason@kudzu.us>
......
...@@ -551,13 +551,15 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, ...@@ -551,13 +551,15 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *offp) size_t count, loff_t *offp)
{ {
struct intel_ntb_dev *ndev; struct intel_ntb_dev *ndev;
struct pci_dev *pdev;
void __iomem *mmio; void __iomem *mmio;
char *buf; char *buf;
size_t buf_size; size_t buf_size;
ssize_t ret, off; ssize_t ret, off;
union { u64 v64; u32 v32; u16 v16; } u; union { u64 v64; u32 v32; u16 v16; u8 v8; } u;
ndev = filp->private_data; ndev = filp->private_data;
pdev = ndev_pdev(ndev);
mmio = ndev->self_mmio; mmio = ndev->self_mmio;
buf_size = min(count, 0x800ul); buf_size = min(count, 0x800ul);
...@@ -631,6 +633,41 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, ...@@ -631,6 +633,41 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"Doorbell Bell -\t\t%#llx\n", u.v64); "Doorbell Bell -\t\t%#llx\n", u.v64);
off += scnprintf(buf + off, buf_size - off,
"\nNTB Window Size:\n");
pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"PBAR23SZ %hhu\n", u.v8);
if (!ndev->bar4_split) {
pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"PBAR45SZ %hhu\n", u.v8);
} else {
pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"PBAR4SZ %hhu\n", u.v8);
pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"PBAR5SZ %hhu\n", u.v8);
}
pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"SBAR23SZ %hhu\n", u.v8);
if (!ndev->bar4_split) {
pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"SBAR45SZ %hhu\n", u.v8);
} else {
pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"SBAR4SZ %hhu\n", u.v8);
pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &u.v8);
off += scnprintf(buf + off, buf_size - off,
"SBAR5SZ %hhu\n", u.v8);
}
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"\nNTB Incoming XLAT:\n"); "\nNTB Incoming XLAT:\n");
...@@ -669,7 +706,7 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, ...@@ -669,7 +706,7 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
"LMT45 -\t\t\t%#018llx\n", u.v64); "LMT45 -\t\t\t%#018llx\n", u.v64);
} }
if (pdev_is_xeon(ndev->ntb.pdev)) { if (pdev_is_xeon(pdev)) {
if (ntb_topo_is_b2b(ndev->ntb.topo)) { if (ntb_topo_is_b2b(ndev->ntb.topo)) {
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"\nNTB Outgoing B2B XLAT:\n"); "\nNTB Outgoing B2B XLAT:\n");
...@@ -750,22 +787,22 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, ...@@ -750,22 +787,22 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"\nXEON NTB Hardware Errors:\n"); "\nXEON NTB Hardware Errors:\n");
if (!pci_read_config_word(ndev->ntb.pdev, if (!pci_read_config_word(pdev,
XEON_DEVSTS_OFFSET, &u.v16)) XEON_DEVSTS_OFFSET, &u.v16))
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"DEVSTS -\t\t%#06x\n", u.v16); "DEVSTS -\t\t%#06x\n", u.v16);
if (!pci_read_config_word(ndev->ntb.pdev, if (!pci_read_config_word(pdev,
XEON_LINK_STATUS_OFFSET, &u.v16)) XEON_LINK_STATUS_OFFSET, &u.v16))
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"LNKSTS -\t\t%#06x\n", u.v16); "LNKSTS -\t\t%#06x\n", u.v16);
if (!pci_read_config_dword(ndev->ntb.pdev, if (!pci_read_config_dword(pdev,
XEON_UNCERRSTS_OFFSET, &u.v32)) XEON_UNCERRSTS_OFFSET, &u.v32))
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"UNCERRSTS -\t\t%#06x\n", u.v32); "UNCERRSTS -\t\t%#06x\n", u.v32);
if (!pci_read_config_dword(ndev->ntb.pdev, if (!pci_read_config_dword(pdev,
XEON_CORERRSTS_OFFSET, &u.v32)) XEON_CORERRSTS_OFFSET, &u.v32))
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"CORERRSTS -\t\t%#06x\n", u.v32); "CORERRSTS -\t\t%#06x\n", u.v32);
......
...@@ -153,6 +153,7 @@ struct ntb_transport_qp { ...@@ -153,6 +153,7 @@ struct ntb_transport_qp {
unsigned int rx_index; unsigned int rx_index;
unsigned int rx_max_entry; unsigned int rx_max_entry;
unsigned int rx_max_frame; unsigned int rx_max_frame;
unsigned int rx_alloc_entry;
dma_cookie_t last_cookie; dma_cookie_t last_cookie;
struct tasklet_struct rxc_db_work; struct tasklet_struct rxc_db_work;
...@@ -480,7 +481,9 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, ...@@ -480,7 +481,9 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
out_offset += snprintf(buf + out_offset, out_count - out_offset, out_offset += snprintf(buf + out_offset, out_count - out_offset,
"rx_index - \t%u\n", qp->rx_index); "rx_index - \t%u\n", qp->rx_index);
out_offset += snprintf(buf + out_offset, out_count - out_offset, out_offset += snprintf(buf + out_offset, out_count - out_offset,
"rx_max_entry - \t%u\n\n", qp->rx_max_entry); "rx_max_entry - \t%u\n", qp->rx_max_entry);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"rx_alloc_entry - \t%u\n\n", qp->rx_alloc_entry);
out_offset += snprintf(buf + out_offset, out_count - out_offset, out_offset += snprintf(buf + out_offset, out_count - out_offset,
"tx_bytes - \t%llu\n", qp->tx_bytes); "tx_bytes - \t%llu\n", qp->tx_bytes);
...@@ -597,9 +600,12 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, ...@@ -597,9 +600,12 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
{ {
struct ntb_transport_qp *qp = &nt->qp_vec[qp_num]; struct ntb_transport_qp *qp = &nt->qp_vec[qp_num];
struct ntb_transport_mw *mw; struct ntb_transport_mw *mw;
struct ntb_dev *ndev = nt->ndev;
struct ntb_queue_entry *entry;
unsigned int rx_size, num_qps_mw; unsigned int rx_size, num_qps_mw;
unsigned int mw_num, mw_count, qp_count; unsigned int mw_num, mw_count, qp_count;
unsigned int i; unsigned int i;
int node;
mw_count = nt->mw_count; mw_count = nt->mw_count;
qp_count = nt->qp_count; qp_count = nt->qp_count;
...@@ -626,6 +632,23 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, ...@@ -626,6 +632,23 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
qp->rx_max_entry = rx_size / qp->rx_max_frame; qp->rx_max_entry = rx_size / qp->rx_max_frame;
qp->rx_index = 0; qp->rx_index = 0;
/*
* Checking to see if we have more entries than the default.
* We should add additional entries if that is the case so we
* can be in sync with the transport frames.
*/
node = dev_to_node(&ndev->dev);
for (i = qp->rx_alloc_entry; i < qp->rx_max_entry; i++) {
entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
if (!entry)
return -ENOMEM;
entry->qp = qp;
ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry,
&qp->rx_free_q);
qp->rx_alloc_entry++;
}
qp->remote_rx_info->entry = qp->rx_max_entry - 1; qp->remote_rx_info->entry = qp->rx_max_entry - 1;
/* setup the hdr offsets with 0's */ /* setup the hdr offsets with 0's */
...@@ -1037,6 +1060,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) ...@@ -1037,6 +1060,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
int node; int node;
int rc, i; int rc, i;
mw_count = ntb_mw_count(ndev);
if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) {
dev_err(&ndev->dev, "Not enough scratch pad registers for %s",
NTB_TRANSPORT_NAME);
return -EIO;
}
if (ntb_db_is_unsafe(ndev)) if (ntb_db_is_unsafe(ndev))
dev_dbg(&ndev->dev, dev_dbg(&ndev->dev,
"doorbell is unsafe, proceed anyway...\n"); "doorbell is unsafe, proceed anyway...\n");
...@@ -1052,8 +1082,6 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) ...@@ -1052,8 +1082,6 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
nt->ndev = ndev; nt->ndev = ndev;
mw_count = ntb_mw_count(ndev);
nt->mw_count = mw_count; nt->mw_count = mw_count;
nt->mw_vec = kzalloc_node(mw_count * sizeof(*nt->mw_vec), nt->mw_vec = kzalloc_node(mw_count * sizeof(*nt->mw_vec),
...@@ -1722,8 +1750,9 @@ ntb_transport_create_queue(void *data, struct device *client_dev, ...@@ -1722,8 +1750,9 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry,
&qp->rx_free_q); &qp->rx_free_q);
} }
qp->rx_alloc_entry = NTB_QP_DEF_NUM_ENTRIES;
for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { for (i = 0; i < qp->tx_max_entry; i++) {
entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
if (!entry) if (!entry)
goto err2; goto err2;
...@@ -1744,6 +1773,7 @@ err2: ...@@ -1744,6 +1773,7 @@ err2:
while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
kfree(entry); kfree(entry);
err1: err1:
qp->rx_alloc_entry = 0;
while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q))) while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
kfree(entry); kfree(entry);
if (qp->tx_dma_chan) if (qp->tx_dma_chan)
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/ntb.h> #include <linux/ntb.h>
#include <linux/mutex.h>
#define DRIVER_NAME "ntb_perf" #define DRIVER_NAME "ntb_perf"
#define DRIVER_DESCRIPTION "PCIe NTB Performance Measurement Tool" #define DRIVER_DESCRIPTION "PCIe NTB Performance Measurement Tool"
...@@ -83,6 +84,10 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION); ...@@ -83,6 +84,10 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
static struct dentry *perf_debugfs_dir; static struct dentry *perf_debugfs_dir;
static unsigned long max_mw_size;
module_param(max_mw_size, ulong, 0644);
MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows");
static unsigned int seg_order = 19; /* 512K */ static unsigned int seg_order = 19; /* 512K */
module_param(seg_order, uint, 0644); module_param(seg_order, uint, 0644);
MODULE_PARM_DESC(seg_order, "size order [n^2] of buffer segment for testing"); MODULE_PARM_DESC(seg_order, "size order [n^2] of buffer segment for testing");
...@@ -117,6 +122,10 @@ struct pthr_ctx { ...@@ -117,6 +122,10 @@ struct pthr_ctx {
int dma_prep_err; int dma_prep_err;
int src_idx; int src_idx;
void *srcs[MAX_SRCS]; void *srcs[MAX_SRCS];
wait_queue_head_t *wq;
int status;
u64 copied;
u64 diff_us;
}; };
struct perf_ctx { struct perf_ctx {
...@@ -124,23 +133,23 @@ struct perf_ctx { ...@@ -124,23 +133,23 @@ struct perf_ctx {
spinlock_t db_lock; spinlock_t db_lock;
struct perf_mw mw; struct perf_mw mw;
bool link_is_up; bool link_is_up;
struct work_struct link_cleanup;
struct delayed_work link_work; struct delayed_work link_work;
wait_queue_head_t link_wq;
struct dentry *debugfs_node_dir; struct dentry *debugfs_node_dir;
struct dentry *debugfs_run; struct dentry *debugfs_run;
struct dentry *debugfs_threads; struct dentry *debugfs_threads;
u8 perf_threads; u8 perf_threads;
bool run; /* mutex ensures only one set of threads run at once */
struct mutex run_mutex;
struct pthr_ctx pthr_ctx[MAX_THREADS]; struct pthr_ctx pthr_ctx[MAX_THREADS];
atomic_t tsync; atomic_t tsync;
atomic_t tdone;
}; };
enum { enum {
VERSION = 0, VERSION = 0,
MW_SZ_HIGH, MW_SZ_HIGH,
MW_SZ_LOW, MW_SZ_LOW,
SPAD_MSG,
SPAD_ACK,
MAX_SPAD MAX_SPAD
}; };
...@@ -148,10 +157,16 @@ static void perf_link_event(void *ctx) ...@@ -148,10 +157,16 @@ static void perf_link_event(void *ctx)
{ {
struct perf_ctx *perf = ctx; struct perf_ctx *perf = ctx;
if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) {
schedule_delayed_work(&perf->link_work, 2*HZ); schedule_delayed_work(&perf->link_work, 2*HZ);
else } else {
schedule_work(&perf->link_cleanup); dev_dbg(&perf->ntb->pdev->dev, "link down\n");
if (!perf->link_is_up)
cancel_delayed_work_sync(&perf->link_work);
perf->link_is_up = false;
}
} }
static void perf_db_event(void *ctx, int vec) static void perf_db_event(void *ctx, int vec)
...@@ -271,6 +286,7 @@ static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src, ...@@ -271,6 +286,7 @@ static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src,
char __iomem *tmp = dst; char __iomem *tmp = dst;
u64 perf, diff_us; u64 perf, diff_us;
ktime_t kstart, kstop, kdiff; ktime_t kstart, kstop, kdiff;
unsigned long last_sleep = jiffies;
chunks = div64_u64(win_size, buf_size); chunks = div64_u64(win_size, buf_size);
total_chunks = div64_u64(total, buf_size); total_chunks = div64_u64(total, buf_size);
...@@ -286,30 +302,40 @@ static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src, ...@@ -286,30 +302,40 @@ static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src,
} else } else
tmp += buf_size; tmp += buf_size;
/* Probably should schedule every 4GB to prevent soft hang. */ /* Probably should schedule every 5s to prevent soft hang. */
if (((copied % SZ_4G) == 0) && !use_dma) { if (unlikely((jiffies - last_sleep) > 5 * HZ)) {
last_sleep = jiffies;
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1); schedule_timeout(1);
} }
if (unlikely(kthread_should_stop()))
break;
} }
if (use_dma) { if (use_dma) {
pr_info("%s: All DMA descriptors submitted\n", current->comm); pr_debug("%s: All DMA descriptors submitted\n", current->comm);
while (atomic_read(&pctx->dma_sync) != 0) while (atomic_read(&pctx->dma_sync) != 0) {
if (kthread_should_stop())
break;
msleep(20); msleep(20);
}
} }
kstop = ktime_get(); kstop = ktime_get();
kdiff = ktime_sub(kstop, kstart); kdiff = ktime_sub(kstop, kstart);
diff_us = ktime_to_us(kdiff); diff_us = ktime_to_us(kdiff);
pr_info("%s: copied %llu bytes\n", current->comm, copied); pr_debug("%s: copied %llu bytes\n", current->comm, copied);
pr_info("%s: lasted %llu usecs\n", current->comm, diff_us); pr_debug("%s: lasted %llu usecs\n", current->comm, diff_us);
perf = div64_u64(copied, diff_us); perf = div64_u64(copied, diff_us);
pr_info("%s: MBytes/s: %llu\n", current->comm, perf); pr_debug("%s: MBytes/s: %llu\n", current->comm, perf);
pctx->copied = copied;
pctx->diff_us = diff_us;
return 0; return 0;
} }
...@@ -331,7 +357,7 @@ static int ntb_perf_thread(void *data) ...@@ -331,7 +357,7 @@ static int ntb_perf_thread(void *data)
int rc, node, i; int rc, node, i;
struct dma_chan *dma_chan = NULL; struct dma_chan *dma_chan = NULL;
pr_info("kthread %s starting...\n", current->comm); pr_debug("kthread %s starting...\n", current->comm);
node = dev_to_node(&pdev->dev); node = dev_to_node(&pdev->dev);
...@@ -389,7 +415,10 @@ static int ntb_perf_thread(void *data) ...@@ -389,7 +415,10 @@ static int ntb_perf_thread(void *data)
pctx->srcs[i] = NULL; pctx->srcs[i] = NULL;
} }
return 0; atomic_inc(&perf->tdone);
wake_up(pctx->wq);
rc = 0;
goto done;
err: err:
for (i = 0; i < MAX_SRCS; i++) { for (i = 0; i < MAX_SRCS; i++) {
...@@ -402,6 +431,16 @@ err: ...@@ -402,6 +431,16 @@ err:
pctx->dma_chan = NULL; pctx->dma_chan = NULL;
} }
done:
/* Wait until we are told to stop */
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
break;
schedule();
}
__set_current_state(TASK_RUNNING);
return rc; return rc;
} }
...@@ -472,6 +511,10 @@ static void perf_link_work(struct work_struct *work) ...@@ -472,6 +511,10 @@ static void perf_link_work(struct work_struct *work)
dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__); dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__);
size = perf->mw.phys_size; size = perf->mw.phys_size;
if (max_mw_size && size > max_mw_size)
size = max_mw_size;
ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size)); ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size)); ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
ntb_peer_spad_write(ndev, VERSION, PERF_VERSION); ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
...@@ -496,6 +539,7 @@ static void perf_link_work(struct work_struct *work) ...@@ -496,6 +539,7 @@ static void perf_link_work(struct work_struct *work)
goto out1; goto out1;
perf->link_is_up = true; perf->link_is_up = true;
wake_up(&perf->link_wq);
return; return;
...@@ -508,18 +552,6 @@ out: ...@@ -508,18 +552,6 @@ out:
msecs_to_jiffies(PERF_LINK_DOWN_TIMEOUT)); msecs_to_jiffies(PERF_LINK_DOWN_TIMEOUT));
} }
static void perf_link_cleanup(struct work_struct *work)
{
struct perf_ctx *perf = container_of(work,
struct perf_ctx,
link_cleanup);
dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__);
if (!perf->link_is_up)
cancel_delayed_work_sync(&perf->link_work);
}
static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf) static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)
{ {
struct perf_mw *mw; struct perf_mw *mw;
...@@ -544,16 +576,44 @@ static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf, ...@@ -544,16 +576,44 @@ static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf,
{ {
struct perf_ctx *perf = filp->private_data; struct perf_ctx *perf = filp->private_data;
char *buf; char *buf;
ssize_t ret, out_offset; ssize_t ret, out_off = 0;
struct pthr_ctx *pctx;
int i;
u64 rate;
if (!perf) if (!perf)
return 0; return 0;
buf = kmalloc(64, GFP_KERNEL); buf = kmalloc(1024, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
out_offset = snprintf(buf, 64, "%d\n", perf->run);
ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); if (mutex_is_locked(&perf->run_mutex)) {
out_off = snprintf(buf, 64, "running\n");
goto read_from_buf;
}
for (i = 0; i < MAX_THREADS; i++) {
pctx = &perf->pthr_ctx[i];
if (pctx->status == -ENODATA)
break;
if (pctx->status) {
out_off += snprintf(buf + out_off, 1024 - out_off,
"%d: error %d\n", i,
pctx->status);
continue;
}
rate = div64_u64(pctx->copied, pctx->diff_us);
out_off += snprintf(buf + out_off, 1024 - out_off,
"%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n",
i, pctx->copied, pctx->diff_us, rate);
}
read_from_buf:
ret = simple_read_from_buffer(ubuf, count, offp, buf, out_off);
kfree(buf); kfree(buf);
return ret; return ret;
...@@ -564,80 +624,90 @@ static void threads_cleanup(struct perf_ctx *perf) ...@@ -564,80 +624,90 @@ static void threads_cleanup(struct perf_ctx *perf)
struct pthr_ctx *pctx; struct pthr_ctx *pctx;
int i; int i;
perf->run = false;
for (i = 0; i < MAX_THREADS; i++) { for (i = 0; i < MAX_THREADS; i++) {
pctx = &perf->pthr_ctx[i]; pctx = &perf->pthr_ctx[i];
if (pctx->thread) {