aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2017-12-06 09:31:57 -0500
committerJon Mason <jdmason@kudzu.us>2018-01-28 22:17:24 -0500
commit5648e56d03fa0c153fccd089efd903f1f6af559f (patch)
tree38ca84143d74f9a8b1e738236645077e3f0c3e54
parent7f46c8b3a5523a28cb81c2c12bc3dcc76ed52d59 (diff)
NTB: ntb_perf: Add full multi-port NTB API support
Former NTB Performance driver could only work with NTB devices, which got Scratchpads available and had just two ports. Since there are devices, which don't have Scratchpads and got more than two peer ports, the performance measuring tool needs to be rewritten. This patch adds the ability to test any available NTB peer. Additionally it allows to set NTB memory windows up using any available data exchange interface: Scratchpad or Message registers. Some cleanups are also added here. Signed-off-by: Serge Semin <fancer.lancer@gmail.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
-rw-r--r--drivers/ntb/test/ntb_perf.c1820
1 files changed, 1219 insertions, 601 deletions
diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c
index 6f6c602d04af..8de72f3fba4d 100644
--- a/drivers/ntb/test/ntb_perf.c
+++ b/drivers/ntb/test/ntb_perf.c
@@ -5,6 +5,7 @@
5 * GPL LICENSE SUMMARY 5 * GPL LICENSE SUMMARY
6 * 6 *
7 * Copyright(c) 2015 Intel Corporation. All rights reserved. 7 * Copyright(c) 2015 Intel Corporation. All rights reserved.
8 * Copyright(c) 2017 T-Platforms. All Rights Reserved.
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify 10 * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
13 * BSD LICENSE 14 * BSD LICENSE
14 * 15 *
15 * Copyright(c) 2015 Intel Corporation. All rights reserved. 16 * Copyright(c) 2015 Intel Corporation. All rights reserved.
17 * Copyright(c) 2017 T-Platforms. All Rights Reserved.
16 * 18 *
17 * Redistribution and use in source and binary forms, with or without 19 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions 20 * modification, are permitted provided that the following conditions
@@ -40,859 +42,1475 @@
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 42 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * 44 *
43 * PCIe NTB Perf Linux driver 45 * PCIe NTB Perf Linux driver
46 */
47
48/*
49 * How to use this tool, by example.
50 *
51 * Assuming $DBG_DIR is something like:
52 * '/sys/kernel/debug/ntb_perf/0000:00:03.0'
53 * Suppose aside from local device there is at least one remote device
54 * connected to NTB with index 0.
55 *-----------------------------------------------------------------------------
56 * Eg: install driver with specified chunk/total orders and dma-enabled flag
57 *
58 * root@self# insmod ntb_perf.ko chunk_order=19 total_order=28 use_dma
59 *-----------------------------------------------------------------------------
60 * Eg: check NTB ports (index) and MW mapping information
61 *
62 * root@self# cat $DBG_DIR/info
63 *-----------------------------------------------------------------------------
64 * Eg: start performance test with peer (index 0) and get the test metrics
65 *
66 * root@self# echo 0 > $DBG_DIR/run
67 * root@self# cat $DBG_DIR/run
44 */ 68 */
45 69
46#include <linux/init.h> 70#include <linux/init.h>
47#include <linux/kernel.h> 71#include <linux/kernel.h>
48#include <linux/module.h> 72#include <linux/module.h>
49#include <linux/kthread.h> 73#include <linux/sched.h>
50#include <linux/time.h> 74#include <linux/wait.h>
51#include <linux/timer.h>
52#include <linux/dma-mapping.h> 75#include <linux/dma-mapping.h>
76#include <linux/dmaengine.h>
53#include <linux/pci.h> 77#include <linux/pci.h>
78#include <linux/ktime.h>
54#include <linux/slab.h> 79#include <linux/slab.h>
55#include <linux/spinlock.h>
56#include <linux/debugfs.h>
57#include <linux/dmaengine.h>
58#include <linux/delay.h> 80#include <linux/delay.h>
59#include <linux/sizes.h> 81#include <linux/sizes.h>
82#include <linux/workqueue.h>
83#include <linux/debugfs.h>
84#include <linux/random.h>
60#include <linux/ntb.h> 85#include <linux/ntb.h>
61#include <linux/mutex.h>
62 86
63#define DRIVER_NAME "ntb_perf" 87#define DRIVER_NAME "ntb_perf"
64#define DRIVER_DESCRIPTION "PCIe NTB Performance Measurement Tool" 88#define DRIVER_VERSION "2.0"
65
66#define DRIVER_VERSION "1.0"
67#define DRIVER_AUTHOR "Dave Jiang <dave.jiang@intel.com>"
68
69#define PERF_LINK_DOWN_TIMEOUT 10
70#define PERF_VERSION 0xffff0001
71#define MAX_THREADS 32
72#define MAX_TEST_SIZE SZ_1M
73#define MAX_SRCS 32
74#define DMA_OUT_RESOURCE_TO msecs_to_jiffies(50)
75#define DMA_RETRIES 20
76#define SZ_4G (1ULL << 32)
77#define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */
78#define PIDX NTB_DEF_PEER_IDX
79 89
80MODULE_LICENSE("Dual BSD/GPL"); 90MODULE_LICENSE("Dual BSD/GPL");
81MODULE_VERSION(DRIVER_VERSION); 91MODULE_VERSION(DRIVER_VERSION);
82MODULE_AUTHOR(DRIVER_AUTHOR); 92MODULE_AUTHOR("Dave Jiang <dave.jiang@intel.com>");
83MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 93MODULE_DESCRIPTION("PCIe NTB Performance Measurement Tool");
94
95#define MAX_THREADS_CNT 32
96#define DEF_THREADS_CNT 1
97#define MAX_CHUNK_SIZE SZ_1M
98#define MAX_CHUNK_ORDER 20 /* no larger than 1M */
99
100#define DMA_TRIES 100
101#define DMA_MDELAY 10
84 102
85static struct dentry *perf_debugfs_dir; 103#define MSG_TRIES 500
104#define MSG_UDELAY_LOW 1000
105#define MSG_UDELAY_HIGH 2000
106
107#define PERF_BUF_LEN 1024
86 108
87static unsigned long max_mw_size; 109static unsigned long max_mw_size;
88module_param(max_mw_size, ulong, 0644); 110module_param(max_mw_size, ulong, 0644);
89MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows"); 111MODULE_PARM_DESC(max_mw_size, "Upper limit of memory window size");
90 112
91static unsigned int seg_order = 19; /* 512K */ 113static unsigned char chunk_order = 19; /* 512K */
92module_param(seg_order, uint, 0644); 114module_param(chunk_order, byte, 0644);
93MODULE_PARM_DESC(seg_order, "size order [2^n] of buffer segment for testing"); 115MODULE_PARM_DESC(chunk_order, "Data chunk order [2^n] to transfer");
94 116
95static unsigned int run_order = 32; /* 4G */ 117static unsigned char total_order = 30; /* 1G */
96module_param(run_order, uint, 0644); 118module_param(total_order, byte, 0644);
97MODULE_PARM_DESC(run_order, "size order [2^n] of total data to transfer"); 119MODULE_PARM_DESC(total_order, "Total data order [2^n] to transfer");
98 120
99static bool use_dma; /* default to 0 */ 121static bool use_dma; /* default to 0 */
100module_param(use_dma, bool, 0644); 122module_param(use_dma, bool, 0644);
101MODULE_PARM_DESC(use_dma, "Using DMA engine to measure performance"); 123MODULE_PARM_DESC(use_dma, "Use DMA engine to measure performance");
102 124
103static bool on_node = true; /* default to 1 */ 125/*==============================================================================
104module_param(on_node, bool, 0644); 126 * Perf driver data definition
105MODULE_PARM_DESC(on_node, "Run threads only on NTB device node (default: true)"); 127 *==============================================================================
106 128 */
107struct perf_mw { 129
108 phys_addr_t phys_addr; 130enum perf_cmd {
109 resource_size_t phys_size; 131 PERF_CMD_INVAL = -1,/* invalid spad command */
110 void __iomem *vbase; 132 PERF_CMD_SSIZE = 0, /* send out buffer size */
111 size_t xlat_size; 133 PERF_CMD_RSIZE = 1, /* recv in buffer size */
112 size_t buf_size; 134 PERF_CMD_SXLAT = 2, /* send in buffer xlat */
113 void *virt_addr; 135 PERF_CMD_RXLAT = 3, /* recv out buffer xlat */
114 dma_addr_t dma_addr; 136 PERF_CMD_CLEAR = 4, /* clear allocated memory */
137 PERF_STS_DONE = 5, /* init is done */
138 PERF_STS_LNKUP = 6, /* link up state flag */
115}; 139};
116 140
117struct perf_ctx; 141struct perf_ctx;
118 142
119struct pthr_ctx { 143struct perf_peer {
120 struct task_struct *thread; 144 struct perf_ctx *perf;
121 struct perf_ctx *perf; 145 int pidx;
122 atomic_t dma_sync; 146 int gidx;
123 struct dma_chan *dma_chan; 147
124 int dma_prep_err; 148 /* Outbound MW params */
125 int src_idx; 149 u64 outbuf_xlat;
126 void *srcs[MAX_SRCS]; 150 resource_size_t outbuf_size;
127 wait_queue_head_t *wq; 151 void __iomem *outbuf;
128 int status; 152
129 u64 copied; 153 /* Inbound MW params */
130 u64 diff_us; 154 dma_addr_t inbuf_xlat;
155 resource_size_t inbuf_size;
156 void *inbuf;
157
158 /* NTB connection setup service */
159 struct work_struct service;
160 unsigned long sts;
131}; 161};
162#define to_peer_service(__work) \
163 container_of(__work, struct perf_peer, service)
132 164
133struct perf_ctx { 165struct perf_thread {
134 struct ntb_dev *ntb; 166 struct perf_ctx *perf;
135 spinlock_t db_lock; 167 int tidx;
136 struct perf_mw mw; 168
137 bool link_is_up; 169 /* DMA-based test sync parameters */
138 struct delayed_work link_work; 170 atomic_t dma_sync;
139 wait_queue_head_t link_wq; 171 wait_queue_head_t dma_wait;
140 u8 perf_threads; 172 struct dma_chan *dma_chan;
141 /* mutex ensures only one set of threads run at once */ 173
142 struct mutex run_mutex; 174 /* Data source and measured statistics */
143 struct pthr_ctx pthr_ctx[MAX_THREADS]; 175 void *src;
144 atomic_t tsync; 176 u64 copied;
145 atomic_t tdone; 177 ktime_t duration;
178 int status;
179 struct work_struct work;
146}; 180};
181#define to_thread_work(__work) \
182 container_of(__work, struct perf_thread, work)
147 183
148enum { 184struct perf_ctx {
149 VERSION = 0, 185 struct ntb_dev *ntb;
150 MW_SZ_HIGH, 186
151 MW_SZ_LOW, 187 /* Global device index and peers descriptors */
152 MAX_SPAD 188 int gidx;
189 int pcnt;
190 struct perf_peer *peers;
191
192 /* Performance measuring work-threads interface */
193 unsigned long busy_flag;
194 wait_queue_head_t twait;
195 atomic_t tsync;
196 u8 tcnt;
197 struct perf_peer *test_peer;
198 struct perf_thread threads[MAX_THREADS_CNT];
199
200 /* Scratchpad/Message IO operations */
201 int (*cmd_send)(struct perf_peer *peer, enum perf_cmd cmd, u64 data);
202 int (*cmd_recv)(struct perf_ctx *perf, int *pidx, enum perf_cmd *cmd,
203 u64 *data);
204
205 struct dentry *dbgfs_dir;
153}; 206};
154 207
208/*
209 * Scratchpads-base commands interface
210 */
211#define PERF_SPAD_CNT(_pcnt) \
212 (3*((_pcnt) + 1))
213#define PERF_SPAD_CMD(_gidx) \
214 (3*(_gidx))
215#define PERF_SPAD_LDATA(_gidx) \
216 (3*(_gidx) + 1)
217#define PERF_SPAD_HDATA(_gidx) \
218 (3*(_gidx) + 2)
219#define PERF_SPAD_NOTIFY(_gidx) \
220 (BIT_ULL(_gidx))
221
222/*
223 * Messages-base commands interface
224 */
225#define PERF_MSG_CNT 3
226#define PERF_MSG_CMD 0
227#define PERF_MSG_LDATA 1
228#define PERF_MSG_HDATA 2
229
230/*==============================================================================
231 * Static data declarations
232 *==============================================================================
233 */
234
235static struct dentry *perf_dbgfs_topdir;
236
237static struct workqueue_struct *perf_wq __read_mostly;
238
239/*==============================================================================
240 * NTB cross-link commands execution service
241 *==============================================================================
242 */
243
244static void perf_terminate_test(struct perf_ctx *perf);
245
246static inline bool perf_link_is_up(struct perf_peer *peer)
247{
248 u64 link;
249
250 link = ntb_link_is_up(peer->perf->ntb, NULL, NULL);
251 return !!(link & BIT_ULL_MASK(peer->pidx));
252}
253
254static int perf_spad_cmd_send(struct perf_peer *peer, enum perf_cmd cmd,
255 u64 data)
256{
257 struct perf_ctx *perf = peer->perf;
258 int try;
259 u32 sts;
260
261 dev_dbg(&perf->ntb->dev, "CMD send: %d 0x%llx\n", cmd, data);
262
263 /*
264 * Perform predefined number of attempts before give up.
265 * We are sending the data to the port specific scratchpad, so
266 * to prevent a multi-port access race-condition. Additionally
267 * there is no need in local locking since only thread-safe
268 * service work is using this method.
269 */
270 for (try = 0; try < MSG_TRIES; try++) {
271 if (!perf_link_is_up(peer))
272 return -ENOLINK;
273
274 sts = ntb_peer_spad_read(perf->ntb, peer->pidx,
275 PERF_SPAD_CMD(perf->gidx));
276 if (le32_to_cpu(sts) != PERF_CMD_INVAL) {
277 usleep_range(MSG_UDELAY_LOW, MSG_UDELAY_HIGH);
278 continue;
279 }
280
281 ntb_peer_spad_write(perf->ntb, peer->pidx,
282 PERF_SPAD_LDATA(perf->gidx),
283 cpu_to_le32(lower_32_bits(data)));
284 ntb_peer_spad_write(perf->ntb, peer->pidx,
285 PERF_SPAD_HDATA(perf->gidx),
286 cpu_to_le32(upper_32_bits(data)));
287 mmiowb();
288 ntb_peer_spad_write(perf->ntb, peer->pidx,
289 PERF_SPAD_CMD(perf->gidx),
290 cpu_to_le32(cmd));
291 mmiowb();
292 ntb_peer_db_set(perf->ntb, PERF_SPAD_NOTIFY(peer->gidx));
293
294 dev_dbg(&perf->ntb->dev, "DB ring peer %#llx\n",
295 PERF_SPAD_NOTIFY(peer->gidx));
296
297 break;
298 }
299
300 return try < MSG_TRIES ? 0 : -EAGAIN;
301}
302
303static int perf_spad_cmd_recv(struct perf_ctx *perf, int *pidx,
304 enum perf_cmd *cmd, u64 *data)
305{
306 struct perf_peer *peer;
307 u32 val;
308
309 ntb_db_clear(perf->ntb, PERF_SPAD_NOTIFY(perf->gidx));
310
311 /*
312 * We start scanning all over, since cleared DB may have been set
313 * by any peer. Yes, it makes peer with smaller index being
314 * serviced with greater priority, but it's convenient for spad
315 * and message code unification and simplicity.
316 */
317 for (*pidx = 0; *pidx < perf->pcnt; (*pidx)++) {
318 peer = &perf->peers[*pidx];
319
320 if (!perf_link_is_up(peer))
321 continue;
322
323 val = ntb_spad_read(perf->ntb, PERF_SPAD_CMD(peer->gidx));
324 val = le32_to_cpu(val);
325 if (val == PERF_CMD_INVAL)
326 continue;
327
328 *cmd = val;
329
330 val = ntb_spad_read(perf->ntb, PERF_SPAD_LDATA(peer->gidx));
331 *data = le32_to_cpu(val);
332
333 val = ntb_spad_read(perf->ntb, PERF_SPAD_HDATA(peer->gidx));
334 *data |= (u64)le32_to_cpu(val) << 32;
335
336 /* Next command can be retrieved from now */
337 ntb_spad_write(perf->ntb, PERF_SPAD_CMD(peer->gidx),
338 cpu_to_le32(PERF_CMD_INVAL));
339
340 dev_dbg(&perf->ntb->dev, "CMD recv: %d 0x%llx\n", *cmd, *data);
341
342 return 0;
343 }
344
345 return -ENODATA;
346}
347
348static int perf_msg_cmd_send(struct perf_peer *peer, enum perf_cmd cmd,
349 u64 data)
350{
351 struct perf_ctx *perf = peer->perf;
352 int try, ret;
353 u64 outbits;
354
355 dev_dbg(&perf->ntb->dev, "CMD send: %d 0x%llx\n", cmd, data);
356
357 /*
358 * Perform predefined number of attempts before give up. Message
359 * registers are free of race-condition problem when accessed
360 * from different ports, so we don't need splitting registers
361 * by global device index. We also won't have local locking,
362 * since the method is used from service work only.
363 */
364 outbits = ntb_msg_outbits(perf->ntb);
365 for (try = 0; try < MSG_TRIES; try++) {
366 if (!perf_link_is_up(peer))
367 return -ENOLINK;
368
369 ret = ntb_msg_clear_sts(perf->ntb, outbits);
370 if (ret)
371 return ret;
372
373 ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_LDATA,
374 cpu_to_le32(lower_32_bits(data)));
375
376 if (ntb_msg_read_sts(perf->ntb) & outbits) {
377 usleep_range(MSG_UDELAY_LOW, MSG_UDELAY_HIGH);
378 continue;
379 }
380
381 ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_HDATA,
382 cpu_to_le32(upper_32_bits(data)));
383 mmiowb();
384
385 /* This call shall trigger peer message event */
386 ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_CMD,
387 cpu_to_le32(cmd));
388
389 break;
390 }
391
392 return try < MSG_TRIES ? 0 : -EAGAIN;
393}
394
395static int perf_msg_cmd_recv(struct perf_ctx *perf, int *pidx,
396 enum perf_cmd *cmd, u64 *data)
397{
398 u64 inbits;
399 u32 val;
400
401 inbits = ntb_msg_inbits(perf->ntb);
402
403 if (hweight64(ntb_msg_read_sts(perf->ntb) & inbits) < 3)
404 return -ENODATA;
405
406 val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_CMD);
407 *cmd = le32_to_cpu(val);
408
409 val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_LDATA);
410 *data = le32_to_cpu(val);
411
412 val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_HDATA);
413 *data |= (u64)le32_to_cpu(val) << 32;
414
415 /* Next command can be retrieved from now */
416 ntb_msg_clear_sts(perf->ntb, inbits);
417
418 dev_dbg(&perf->ntb->dev, "CMD recv: %d 0x%llx\n", *cmd, *data);
419
420 return 0;
421}
422
423static int perf_cmd_send(struct perf_peer *peer, enum perf_cmd cmd, u64 data)
424{
425 struct perf_ctx *perf = peer->perf;
426
427 if (cmd == PERF_CMD_SSIZE || cmd == PERF_CMD_SXLAT)
428 return perf->cmd_send(peer, cmd, data);
429
430 dev_err(&perf->ntb->dev, "Send invalid command\n");
431 return -EINVAL;
432}
433
434static int perf_cmd_exec(struct perf_peer *peer, enum perf_cmd cmd)
435{
436 switch (cmd) {
437 case PERF_CMD_SSIZE:
438 case PERF_CMD_RSIZE:
439 case PERF_CMD_SXLAT:
440 case PERF_CMD_RXLAT:
441 case PERF_CMD_CLEAR:
442 break;
443 default:
444 dev_err(&peer->perf->ntb->dev, "Exec invalid command\n");
445 return -EINVAL;
446 }
447
448 /* No need of memory barrier, since bit ops have invernal lock */
449 set_bit(cmd, &peer->sts);
450
451 dev_dbg(&peer->perf->ntb->dev, "CMD exec: %d\n", cmd);
452
453 (void)queue_work(system_highpri_wq, &peer->service);
454
455 return 0;
456}
457
458static int perf_cmd_recv(struct perf_ctx *perf)
459{
460 struct perf_peer *peer;
461 int ret, pidx, cmd;
462 u64 data;
463
464 while (!(ret = perf->cmd_recv(perf, &pidx, &cmd, &data))) {
465 peer = &perf->peers[pidx];
466
467 switch (cmd) {
468 case PERF_CMD_SSIZE:
469 peer->inbuf_size = data;
470 return perf_cmd_exec(peer, PERF_CMD_RSIZE);
471 case PERF_CMD_SXLAT:
472 peer->outbuf_xlat = data;
473 return perf_cmd_exec(peer, PERF_CMD_RXLAT);
474 default:
475 dev_err(&perf->ntb->dev, "Recv invalid command\n");
476 return -EINVAL;
477 }
478 }
479
480 /* Return 0 if no data left to process, otherwise an error */
481 return ret == -ENODATA ? 0 : ret;
482}
483
155static void perf_link_event(void *ctx) 484static void perf_link_event(void *ctx)
156{ 485{
157 struct perf_ctx *perf = ctx; 486 struct perf_ctx *perf = ctx;
487 struct perf_peer *peer;
488 bool lnk_up;
489 int pidx;
158 490
159 if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) { 491 for (pidx = 0; pidx < perf->pcnt; pidx++) {
160 schedule_delayed_work(&perf->link_work, 2*HZ); 492 peer = &perf->peers[pidx];
161 } else {
162 dev_dbg(&perf->ntb->pdev->dev, "link down\n");
163 493
164 if (!perf->link_is_up) 494 lnk_up = perf_link_is_up(peer);
165 cancel_delayed_work_sync(&perf->link_work);
166 495
167 perf->link_is_up = false; 496 if (lnk_up &&
497 !test_and_set_bit(PERF_STS_LNKUP, &peer->sts)) {
498 perf_cmd_exec(peer, PERF_CMD_SSIZE);
499 } else if (!lnk_up &&
500 test_and_clear_bit(PERF_STS_LNKUP, &peer->sts)) {
501 perf_cmd_exec(peer, PERF_CMD_CLEAR);
502 }
168 } 503 }
169} 504}
170 505
171static void perf_db_event(void *ctx, int vec) 506static void perf_db_event(void *ctx, int vec)
172{ 507{
173 struct perf_ctx *perf = ctx; 508 struct perf_ctx *perf = ctx;
174 u64 db_bits, db_mask;
175 509
176 db_mask = ntb_db_vector_mask(perf->ntb, vec); 510 dev_dbg(&perf->ntb->dev, "DB vec %d mask %#llx bits %#llx\n", vec,
177 db_bits = ntb_db_read(perf->ntb); 511 ntb_db_vector_mask(perf->ntb, vec), ntb_db_read(perf->ntb));
512
513 /* Just receive all available commands */
514 (void)perf_cmd_recv(perf);
515}
516
517static void perf_msg_event(void *ctx)
518{
519 struct perf_ctx *perf = ctx;
520
521 dev_dbg(&perf->ntb->dev, "Msg status bits %#llx\n",
522 ntb_msg_read_sts(perf->ntb));
178 523
179 dev_dbg(&perf->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", 524 /* Messages are only sent one-by-one */
180 vec, db_mask, db_bits); 525 (void)perf_cmd_recv(perf);
181} 526}
182 527
183static const struct ntb_ctx_ops perf_ops = { 528static const struct ntb_ctx_ops perf_ops = {
184 .link_event = perf_link_event, 529 .link_event = perf_link_event,
185 .db_event = perf_db_event, 530 .db_event = perf_db_event,
531 .msg_event = perf_msg_event
186}; 532};
187 533
188static void perf_copy_callback(void *data) 534static void perf_free_outbuf(struct perf_peer *peer)
535{
536 (void)ntb_peer_mw_clear_trans(peer->perf->ntb, peer->pidx, peer->gidx);
537}
538
539static int perf_setup_outbuf(struct perf_peer *peer)
189{ 540{
190 struct pthr_ctx *pctx = data; 541 struct perf_ctx *perf = peer->perf;
542 int ret;
543
544 /* Outbuf size can be unaligned due to custom max_mw_size */
545 ret = ntb_peer_mw_set_trans(perf->ntb, peer->pidx, peer->gidx,
546 peer->outbuf_xlat, peer->outbuf_size);
547 if (ret) {
548 dev_err(&perf->ntb->dev, "Failed to set outbuf translation\n");
549 return ret;
550 }
551
552 /* Initialization is finally done */
553 set_bit(PERF_STS_DONE, &peer->sts);
191 554
192 atomic_dec(&pctx->dma_sync); 555 return 0;
193} 556}
194 557
195static ssize_t perf_copy(struct pthr_ctx *pctx, char __iomem *dst, 558static void perf_free_inbuf(struct perf_peer *peer)
196 char *src, size_t size)
197{ 559{
198 struct perf_ctx *perf = pctx->perf; 560 if (!peer->inbuf)
199 struct dma_async_tx_descriptor *txd; 561 return;
200 struct dma_chan *chan = pctx->dma_chan;
201 struct dma_device *device;
202 struct dmaengine_unmap_data *unmap;
203 dma_cookie_t cookie;
204 size_t src_off, dst_off;
205 struct perf_mw *mw = &perf->mw;
206 void __iomem *vbase;
207 void __iomem *dst_vaddr;
208 dma_addr_t dst_phys;
209 int retries = 0;
210 562
211 if (!use_dma) { 563 (void)ntb_mw_clear_trans(peer->perf->ntb, peer->pidx, peer->gidx);
212 memcpy_toio(dst, src, size); 564 dma_free_coherent(&peer->perf->ntb->dev, peer->inbuf_size,
213 return size; 565 peer->inbuf, peer->inbuf_xlat);
566 peer->inbuf = NULL;
567}
568
569static int perf_setup_inbuf(struct perf_peer *peer)
570{
571 resource_size_t xlat_align, size_align, size_max;
572 struct perf_ctx *perf = peer->perf;
573 int ret;
574
575 /* Get inbound MW parameters */
576 ret = ntb_mw_get_align(perf->ntb, peer->pidx, perf->gidx,
577 &xlat_align, &size_align, &size_max);
578 if (ret) {
579 dev_err(&perf->ntb->dev, "Couldn't get inbuf restrictions\n");
580 return ret;
214 } 581 }
215 582
216 if (!chan) { 583 if (peer->inbuf_size > size_max) {
217 dev_err(&perf->ntb->dev, "DMA engine does not exist\n"); 584 dev_err(&perf->ntb->dev, "Too big inbuf size %pa > %pa\n",
585 &peer->inbuf_size, &size_max);
218 return -EINVAL; 586 return -EINVAL;
219 } 587 }
220 588
221 device = chan->device; 589 peer->inbuf_size = round_up(peer->inbuf_size, size_align);
222 src_off = (uintptr_t)src & ~PAGE_MASK;
223 dst_off = (uintptr_t __force)dst & ~PAGE_MASK;
224 590
225 if (!is_dma_copy_aligned(device, src_off, dst_off, size)) 591 perf_free_inbuf(peer);
226 return -ENODEV;
227
228 vbase = mw->vbase;
229 dst_vaddr = dst;
230 dst_phys = mw->phys_addr + (dst_vaddr - vbase);
231 592
232 unmap = dmaengine_get_unmap_data(device->dev, 1, GFP_NOWAIT); 593 peer->inbuf = dma_alloc_coherent(&perf->ntb->dev, peer->inbuf_size,
233 if (!unmap) 594 &peer->inbuf_xlat, GFP_KERNEL);
595 if (!peer->inbuf) {
596 dev_err(&perf->ntb->dev, "Failed to alloc inbuf of %pa\n",
597 &peer->inbuf_size);
234 return -ENOMEM; 598 return -ENOMEM;
599 }
600 if (!IS_ALIGNED(peer->inbuf_xlat, xlat_align)) {
601 dev_err(&perf->ntb->dev, "Unaligned inbuf allocated\n");
602 goto err_free_inbuf;
603 }
235 604
236 unmap->len = size; 605 ret = ntb_mw_set_trans(perf->ntb, peer->pidx, peer->gidx,
237 unmap->addr[0] = dma_map_page(device->dev, virt_to_page(src), 606 peer->inbuf_xlat, peer->inbuf_size);
238 src_off, size, DMA_TO_DEVICE); 607 if (ret) {
239 if (dma_mapping_error(device->dev, unmap->addr[0])) 608 dev_err(&perf->ntb->dev, "Failed to set inbuf translation\n");
240 goto err_get_unmap; 609 goto err_free_inbuf;
610 }
241 611
242 unmap->to_cnt = 1; 612 /*
613 * We submit inbuf xlat transmission cmd for execution here to follow
614 * the code architecture, even though this method is called from service
615 * work itself so the command will be executed right after it returns.
616 */
617 (void)perf_cmd_exec(peer, PERF_CMD_SXLAT);
243 618
244 do { 619 return 0;
245 txd = device->device_prep_dma_memcpy(chan, dst_phys,
246 unmap->addr[0],
247 size, DMA_PREP_INTERRUPT);
248 if (!txd) {
249 set_current_state(TASK_INTERRUPTIBLE);
250 schedule_timeout(DMA_OUT_RESOURCE_TO);
251 }
252 } while (!txd && (++retries < DMA_RETRIES));
253 620
254 if (!txd) { 621err_free_inbuf:
255 pctx->dma_prep_err++; 622 perf_free_inbuf(peer);
256 goto err_get_unmap;
257 }
258 623
259 txd->callback = perf_copy_callback; 624 return ret;
260 txd->callback_param = pctx; 625}
261 dma_set_unmap(txd, unmap);
262 626
263 cookie = dmaengine_submit(txd); 627static void perf_service_work(struct work_struct *work)
264 if (dma_submit_error(cookie)) 628{
265 goto err_set_unmap; 629 struct perf_peer *peer = to_peer_service(work);
266 630
267 dmaengine_unmap_put(unmap); 631 if (test_and_clear_bit(PERF_CMD_SSIZE, &peer->sts))
632 perf_cmd_send(peer, PERF_CMD_SSIZE, peer->outbuf_size);
268 633
269 atomic_inc(&pctx->dma_sync); 634 if (test_and_clear_bit(PERF_CMD_RSIZE, &peer->sts))
270 dma_async_issue_pending(chan); 635 perf_setup_inbuf(peer);
271 636
272 return size; 637 if (test_and_clear_bit(PERF_CMD_SXLAT, &peer->sts))
638 perf_cmd_send(peer, PERF_CMD_SXLAT, peer->inbuf_xlat);
273 639
274err_set_unmap: 640 if (test_and_clear_bit(PERF_CMD_RXLAT, &peer->sts))
275 dmaengine_unmap_put(unmap); 641 perf_setup_outbuf(peer);
276err_get_unmap:
277 dmaengine_unmap_put(unmap);
278 return 0;
279}
280 642
281static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src, 643 if (test_and_clear_bit(PERF_CMD_CLEAR, &peer->sts)) {
282 u64 buf_size, u64 win_size, u64 total) 644 clear_bit(PERF_STS_DONE, &peer->sts);
283{ 645 if (test_bit(0, &peer->perf->busy_flag) &&
284 int chunks, total_chunks, i; 646 peer == peer->perf->test_peer) {
285 int copied_chunks = 0; 647 dev_warn(&peer->perf->ntb->dev,
286 u64 copied = 0, result; 648 "Freeing while test on-fly\n");
287 char __iomem *tmp = dst; 649 perf_terminate_test(peer->perf);
288 u64 perf, diff_us;
289 ktime_t kstart, kstop, kdiff;
290 unsigned long last_sleep = jiffies;
291
292 chunks = div64_u64(win_size, buf_size);
293 total_chunks = div64_u64(total, buf_size);
294 kstart = ktime_get();
295
296 for (i = 0; i < total_chunks; i++) {
297 result = perf_copy(pctx, tmp, src, buf_size);
298 copied += result;
299 copied_chunks++;
300 if (copied_chunks == chunks) {
301 tmp = dst;
302 copied_chunks = 0;
303 } else
304 tmp += buf_size;
305
306 /* Probably should schedule every 5s to prevent soft hang. */
307 if (unlikely((jiffies - last_sleep) > 5 * HZ)) {
308 last_sleep = jiffies;
309 set_current_state(TASK_INTERRUPTIBLE);
310 schedule_timeout(1);
311 } 650 }
651 perf_free_outbuf(peer);
652 perf_free_inbuf(peer);
653 }
654}
312 655
313 if (unlikely(kthread_should_stop())) 656static int perf_init_service(struct perf_ctx *perf)
314 break; 657{
658 u64 mask;
659
660 if (ntb_peer_mw_count(perf->ntb) < perf->pcnt + 1) {
661 dev_err(&perf->ntb->dev, "Not enough memory windows\n");
662 return -EINVAL;
315 } 663 }
316 664
317 if (use_dma) { 665 if (ntb_msg_count(perf->ntb) >= PERF_MSG_CNT) {
318 pr_debug("%s: All DMA descriptors submitted\n", current->comm); 666 perf->cmd_send = perf_msg_cmd_send;
319 while (atomic_read(&pctx->dma_sync) != 0) { 667 perf->cmd_recv = perf_msg_cmd_recv;
320 if (kthread_should_stop()) 668
321 break; 669 dev_dbg(&perf->ntb->dev, "Message service initialized\n");
322 msleep(20); 670
323 } 671 return 0;
324 } 672 }
325 673
326 kstop = ktime_get(); 674 dev_dbg(&perf->ntb->dev, "Message service unsupported\n");
327 kdiff = ktime_sub(kstop, kstart);
328 diff_us = ktime_to_us(kdiff);
329 675
330 pr_debug("%s: copied %llu bytes\n", current->comm, copied); 676 mask = GENMASK_ULL(perf->pcnt, 0);
677 if (ntb_spad_count(perf->ntb) >= PERF_SPAD_CNT(perf->pcnt) &&
678 (ntb_db_valid_mask(perf->ntb) & mask) == mask) {
679 perf->cmd_send = perf_spad_cmd_send;
680 perf->cmd_recv = perf_spad_cmd_recv;
331 681
332 pr_debug("%s: lasted %llu usecs\n", current->comm, diff_us); 682 dev_dbg(&perf->ntb->dev, "Scratchpad service initialized\n");
333 683
334 perf = div64_u64(copied, diff_us); 684 return 0;
685 }
335 686
336 pr_debug("%s: MBytes/s: %llu\n", current->comm, perf); 687 dev_dbg(&perf->ntb->dev, "Scratchpad service unsupported\n");
337 688
338 pctx->copied = copied; 689 dev_err(&perf->ntb->dev, "Command services unsupported\n");
339 pctx->diff_us = diff_us;
340 690
341 return 0; 691 return -EINVAL;
342} 692}
343 693
344static bool perf_dma_filter_fn(struct dma_chan *chan, void *node) 694static int perf_enable_service(struct perf_ctx *perf)
345{ 695{
346 /* Is the channel required to be on the same node as the device? */ 696 u64 mask, incmd_bit;
347 if (!on_node) 697 int ret, sidx, scnt;
348 return true;
349 698
350 return dev_to_node(&chan->dev->device) == (int)(unsigned long)node; 699 mask = ntb_db_valid_mask(perf->ntb);
351} 700 (void)ntb_db_set_mask(perf->ntb, mask);
352 701
353static int ntb_perf_thread(void *data) 702 ret = ntb_set_ctx(perf->ntb, perf, &perf_ops);
354{ 703 if (ret)
355 struct pthr_ctx *pctx = data; 704 return ret;
356 struct perf_ctx *perf = pctx->perf;
357 struct pci_dev *pdev = perf->ntb->pdev;
358 struct perf_mw *mw = &perf->mw;
359 char __iomem *dst;
360 u64 win_size, buf_size, total;
361 void *src;
362 int rc, node, i;
363 struct dma_chan *dma_chan = NULL;
364 705
365 pr_debug("kthread %s starting...\n", current->comm); 706 if (perf->cmd_send == perf_msg_cmd_send) {
707 u64 inbits, outbits;
366 708
367 node = on_node ? dev_to_node(&pdev->dev) : NUMA_NO_NODE; 709 inbits = ntb_msg_inbits(perf->ntb);
710 outbits = ntb_msg_outbits(perf->ntb);
711 (void)ntb_msg_set_mask(perf->ntb, inbits | outbits);
368 712
369 if (use_dma && !pctx->dma_chan) { 713 incmd_bit = BIT_ULL(__ffs64(inbits));
370 dma_cap_mask_t dma_mask; 714 ret = ntb_msg_clear_mask(perf->ntb, incmd_bit);
371 715
372 dma_cap_zero(dma_mask); 716 dev_dbg(&perf->ntb->dev, "MSG sts unmasked %#llx\n", incmd_bit);
373 dma_cap_set(DMA_MEMCPY, dma_mask); 717 } else {
374 dma_chan = dma_request_channel(dma_mask, perf_dma_filter_fn, 718 scnt = ntb_spad_count(perf->ntb);
375 (void *)(unsigned long)node); 719 for (sidx = 0; sidx < scnt; sidx++)
376 if (!dma_chan) { 720 ntb_spad_write(perf->ntb, sidx, PERF_CMD_INVAL);
377 pr_warn("%s: cannot acquire DMA channel, quitting\n", 721 incmd_bit = PERF_SPAD_NOTIFY(perf->gidx);
378 current->comm); 722 ret = ntb_db_clear_mask(perf->ntb, incmd_bit);
379 return -ENODEV; 723
380 } 724 dev_dbg(&perf->ntb->dev, "DB bits unmasked %#llx\n", incmd_bit);
381 pctx->dma_chan = dma_chan; 725 }
726 if (ret) {
727 ntb_clear_ctx(perf->ntb);
728 return ret;
382 } 729 }
383 730
384 for (i = 0; i < MAX_SRCS; i++) { 731 ntb_link_enable(perf->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
385 pctx->srcs[i] = kmalloc_node(MAX_TEST_SIZE, GFP_KERNEL, node); 732 /* Might be not necessary */
386 if (!pctx->srcs[i]) { 733 ntb_link_event(perf->ntb);
387 rc = -ENOMEM; 734
388 goto err; 735 return 0;
389 } 736}
737
738static void perf_disable_service(struct perf_ctx *perf)
739{
740 int pidx;
741
742 ntb_link_disable(perf->ntb);
743
744 if (perf->cmd_send == perf_msg_cmd_send) {
745 u64 inbits;
746
747 inbits = ntb_msg_inbits(perf->ntb);
748 (void)ntb_msg_set_mask(perf->ntb, inbits);
749 } else {
750 (void)ntb_db_set_mask(perf->ntb, PERF_SPAD_NOTIFY(perf->gidx));
390 } 751 }
391 752
392 win_size = mw->phys_size; 753 ntb_clear_ctx(perf->ntb);
393 buf_size = 1ULL << seg_order;
394 total = 1ULL << run_order;
395 754
396 if (buf_size > MAX_TEST_SIZE) 755 for (pidx = 0; pidx < perf->pcnt; pidx++)
397 buf_size = MAX_TEST_SIZE; 756 perf_cmd_exec(&perf->peers[pidx], PERF_CMD_CLEAR);
398 757
399 dst = (char __iomem *)mw->vbase; 758 for (pidx = 0; pidx < perf->pcnt; pidx++)
759 flush_work(&perf->peers[pidx].service);
760}
400 761
401 atomic_inc(&perf->tsync); 762/*==============================================================================
402 while (atomic_read(&perf->tsync) != perf->perf_threads) 763 * Performance measuring work-thread
403 schedule(); 764 *==============================================================================
765 */
404 766
405 src = pctx->srcs[pctx->src_idx]; 767static void perf_dma_copy_callback(void *data)
406 pctx->src_idx = (pctx->src_idx + 1) & (MAX_SRCS - 1); 768{
769 struct perf_thread *pthr = data;
407 770
408 rc = perf_move_data(pctx, dst, src, buf_size, win_size, total); 771 atomic_dec(&pthr->dma_sync);
772 wake_up(&pthr->dma_wait);
773}
409 774
410 atomic_dec(&perf->tsync); 775static int perf_copy_chunk(struct perf_thread *pthr,
776 void __iomem *dst, void *src, size_t len)
777{
778 struct dma_async_tx_descriptor *tx;
779 struct dmaengine_unmap_data *unmap;
780 struct device *dma_dev;
781 int try = 0, ret = 0;
411 782
412 if (rc < 0) { 783 if (!use_dma) {
413 pr_err("%s: failed\n", current->comm); 784 memcpy_toio(dst, src, len);
414 rc = -ENXIO; 785 goto ret_check_tsync;
415 goto err;
416 } 786 }
417 787
418 for (i = 0; i < MAX_SRCS; i++) { 788 dma_dev = pthr->dma_chan->device->dev;
419 kfree(pctx->srcs[i]); 789
420 pctx->srcs[i] = NULL; 790 if (!is_dma_copy_aligned(pthr->dma_chan->device, offset_in_page(src),
791 offset_in_page(dst), len))
792 return -EIO;
793
794 unmap = dmaengine_get_unmap_data(dma_dev, 2, GFP_NOWAIT);
795 if (!unmap)
796 return -ENOMEM;
797
798 unmap->len = len;
799 unmap->addr[0] = dma_map_page(dma_dev, virt_to_page(src),
800 offset_in_page(src), len, DMA_TO_DEVICE);
801 if (dma_mapping_error(dma_dev, unmap->addr[0])) {
802 ret = -EIO;
803 goto err_free_resource;
421 } 804 }
805 unmap->to_cnt = 1;
422 806
423 atomic_inc(&perf->tdone); 807 unmap->addr[1] = dma_map_page(dma_dev, virt_to_page(dst),
424 wake_up(pctx->wq); 808 offset_in_page(dst), len, DMA_FROM_DEVICE);
425 rc = 0; 809 if (dma_mapping_error(dma_dev, unmap->addr[1])) {
426 goto done; 810 ret = -EIO;
811 goto err_free_resource;
812 }
813 unmap->from_cnt = 1;
427 814
428err: 815 do {
429 for (i = 0; i < MAX_SRCS; i++) { 816 tx = dmaengine_prep_dma_memcpy(pthr->dma_chan, unmap->addr[1],
430 kfree(pctx->srcs[i]); 817 unmap->addr[0], len, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
431 pctx->srcs[i] = NULL; 818 if (!tx)
819 msleep(DMA_MDELAY);
820 } while (!tx && (try++ < DMA_TRIES));
821
822 if (!tx) {
823 ret = -EIO;
824 goto err_free_resource;
432 } 825 }
433 826
434 if (dma_chan) { 827 tx->callback = perf_dma_copy_callback;
435 dma_release_channel(dma_chan); 828 tx->callback_param = pthr;
436 pctx->dma_chan = NULL; 829 dma_set_unmap(tx, unmap);
830
831 if (dma_submit_error(dmaengine_submit(tx))) {
832 dmaengine_unmap_put(unmap);
833 goto err_free_resource;
437 } 834 }
438 835
439done: 836 dmaengine_unmap_put(unmap);
440 /* Wait until we are told to stop */ 837
441 for (;;) { 838 atomic_inc(&pthr->dma_sync);
442 set_current_state(TASK_INTERRUPTIBLE); 839 dma_async_issue_pending(pthr->dma_chan);
443 if (kthread_should_stop()) 840
444 break; 841ret_check_tsync:
445 schedule(); 842 return likely(atomic_read(&pthr->perf->tsync) > 0) ? 0 : -EINTR;
843
844err_free_resource:
845 dmaengine_unmap_put(unmap);
846
847 return ret;
848}
849
850static bool perf_dma_filter(struct dma_chan *chan, void *data)
851{
852 struct perf_ctx *perf = data;
853 int node;
854
855 node = dev_to_node(&perf->ntb->dev);
856
857 return node == NUMA_NO_NODE || node == dev_to_node(chan->device->dev);
858}
859
860static int perf_init_test(struct perf_thread *pthr)
861{
862 struct perf_ctx *perf = pthr->perf;
863 dma_cap_mask_t dma_mask;
864
865 pthr->src = kmalloc_node(perf->test_peer->outbuf_size, GFP_KERNEL,
866 dev_to_node(&perf->ntb->dev));
867 if (!pthr->src)
868 return -ENOMEM;
869
870 get_random_bytes(pthr->src, perf->test_peer->outbuf_size);
871
872 if (!use_dma)
873 return 0;
874
875 dma_cap_zero(dma_mask);
876 dma_cap_set(DMA_MEMCPY, dma_mask);
877 pthr->dma_chan = dma_request_channel(dma_mask, perf_dma_filter, perf);
878 if (!pthr->dma_chan) {
879 dev_err(&perf->ntb->dev, "%d: Failed to get DMA channel\n",
880 pthr->tidx);
881 atomic_dec(&perf->tsync);
882 wake_up(&perf->twait);
883 kfree(pthr->src);
884 return -ENODEV;
446 } 885 }
447 __set_current_state(TASK_RUNNING);
448 886
449 return rc; 887 atomic_set(&pthr->dma_sync, 0);
888
889 return 0;
450} 890}
451 891
452static void perf_free_mw(struct perf_ctx *perf) 892static int perf_run_test(struct perf_thread *pthr)
453{ 893{
454 struct perf_mw *mw = &perf->mw; 894 struct perf_peer *peer = pthr->perf->test_peer;
455 struct pci_dev *pdev = perf->ntb->pdev; 895 struct perf_ctx *perf = pthr->perf;
896 void __iomem *flt_dst, *bnd_dst;
897 u64 total_size, chunk_size;
898 void *flt_src;
899 int ret = 0;
900
901 total_size = 1ULL << total_order;
902 chunk_size = 1ULL << chunk_order;
903 chunk_size = min_t(u64, peer->outbuf_size, chunk_size);
904
905 flt_src = pthr->src;
906 bnd_dst = peer->outbuf + peer->outbuf_size;
907 flt_dst = peer->outbuf;
908
909 pthr->duration = ktime_get();
910
911 /* Copied field is cleared on test launch stage */
912 while (pthr->copied < total_size) {
913 ret = perf_copy_chunk(pthr, flt_dst, flt_src, chunk_size);
914 if (ret) {
915 dev_err(&perf->ntb->dev, "%d: Got error %d on test\n",
916 pthr->tidx, ret);
917 return ret;
918 }
456 919
457 if (!mw->virt_addr) 920 pthr->copied += chunk_size;
458 return; 921
922 flt_dst += chunk_size;
923 flt_src += chunk_size;
924 if (flt_dst >= bnd_dst || flt_dst < peer->outbuf) {
925 flt_dst = peer->outbuf;
926 flt_src = pthr->src;
927 }
459 928
460 ntb_mw_clear_trans(perf->ntb, PIDX, 0); 929 /* Give up CPU to give a chance for other threads to use it */
461 dma_free_coherent(&pdev->dev, mw->buf_size, 930 schedule();
462 mw->virt_addr, mw->dma_addr); 931 }
463 mw->xlat_size = 0; 932
464 mw->buf_size = 0; 933 return 0;
465 mw->virt_addr = NULL;
466} 934}
467 935
468static int perf_set_mw(struct perf_ctx *perf, resource_size_t size) 936static int perf_sync_test(struct perf_thread *pthr)
469{ 937{
470 struct perf_mw *mw = &perf->mw; 938 struct perf_ctx *perf = pthr->perf;
471 size_t xlat_size, buf_size;
472 resource_size_t xlat_align;
473 resource_size_t xlat_align_size;
474 int rc;
475 939
476 if (!size) 940 if (!use_dma)
477 return -EINVAL; 941 goto no_dma_ret;
478 942
479 rc = ntb_mw_get_align(perf->ntb, PIDX, 0, &xlat_align, 943 wait_event(pthr->dma_wait,
480 &xlat_align_size, NULL); 944 (atomic_read(&pthr->dma_sync) == 0 ||
481 if (rc) 945 atomic_read(&perf->tsync) < 0));
482 return rc;
483 946
484 xlat_size = round_up(size, xlat_align_size); 947 if (atomic_read(&perf->tsync) < 0)
485 buf_size = round_up(size, xlat_align); 948 return -EINTR;
486 949
487 if (mw->xlat_size == xlat_size) 950no_dma_ret:
488 return 0; 951 pthr->duration = ktime_sub(ktime_get(), pthr->duration);
489 952
490 if (mw->buf_size) 953 dev_dbg(&perf->ntb->dev, "%d: copied %llu bytes\n",
491 perf_free_mw(perf); 954 pthr->tidx, pthr->copied);
492 955
493 mw->xlat_size = xlat_size; 956 dev_dbg(&perf->ntb->dev, "%d: lasted %llu usecs\n",
494 mw->buf_size = buf_size; 957 pthr->tidx, ktime_to_us(pthr->duration));
958
959 dev_dbg(&perf->ntb->dev, "%d: %llu MBytes/s\n", pthr->tidx,
960 div64_u64(pthr->copied, ktime_to_us(pthr->duration)));
961
962 return 0;
963}
964
965static void perf_clear_test(struct perf_thread *pthr)
966{
967 struct perf_ctx *perf = pthr->perf;
968
969 if (!use_dma)
970 goto no_dma_notify;
971
972 /*
973 * If test finished without errors, termination isn't needed.
974 * We call it anyway just to be sure of the transfers completion.
975 */
976 (void)dmaengine_terminate_sync(pthr->dma_chan);
977
978 dma_release_channel(pthr->dma_chan);
979
980no_dma_notify:
981 atomic_dec(&perf->tsync);
982 wake_up(&perf->twait);
983 kfree(pthr->src);
984}
495 985
496 mw->virt_addr = dma_alloc_coherent(&perf->ntb->pdev->dev, buf_size, 986static void perf_thread_work(struct work_struct *work)
497 &mw->dma_addr, GFP_KERNEL); 987{
498 if (!mw->virt_addr) { 988 struct perf_thread *pthr = to_thread_work(work);
499 mw->xlat_size = 0; 989 int ret;
500 mw->buf_size = 0; 990
991 /*
992 * Perform stages in compliance with use_dma flag value.
993 * Test status is changed only if error happened, otherwise
994 * status -ENODATA is kept while test is on-fly. Results
995 * synchronization is performed only if test fininshed
996 * without an error or interruption.
997 */
998 ret = perf_init_test(pthr);
999 if (ret) {
1000 pthr->status = ret;
1001 return;
501 } 1002 }
502 1003
503 rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size); 1004 ret = perf_run_test(pthr);
504 if (rc) { 1005 if (ret) {
505 dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n"); 1006 pthr->status = ret;
506 perf_free_mw(perf); 1007 goto err_clear_test;
507 return -EIO;
508 } 1008 }
509 1009
510 return 0; 1010 pthr->status = perf_sync_test(pthr);
1011
1012err_clear_test:
1013 perf_clear_test(pthr);
511} 1014}
512 1015
513static void perf_link_work(struct work_struct *work) 1016static int perf_set_tcnt(struct perf_ctx *perf, u8 tcnt)
514{ 1017{
515 struct perf_ctx *perf = 1018 if (tcnt == 0 || tcnt > MAX_THREADS_CNT)
516 container_of(work, struct perf_ctx, link_work.work); 1019 return -EINVAL;
517 struct ntb_dev *ndev = perf->ntb;
518 struct pci_dev *pdev = ndev->pdev;
519 u32 val;
520 u64 size;
521 int rc;
522 1020
523 dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__); 1021 if (test_and_set_bit_lock(0, &perf->busy_flag))
1022 return -EBUSY;
1023
1024 perf->tcnt = tcnt;
1025
1026 clear_bit_unlock(0, &perf->busy_flag);
524 1027
525 size = perf->mw.phys_size; 1028 return 0;
1029}
526 1030
527 if (max_mw_size && size > max_mw_size) 1031static void perf_terminate_test(struct perf_ctx *perf)
528 size = max_mw_size; 1032{
1033 int tidx;
529 1034
530 ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size)); 1035 atomic_set(&perf->tsync, -1);
531 ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size)); 1036 wake_up(&perf->twait);
532 ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION);
533 1037
534 /* now read what peer wrote */ 1038 for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) {
535 val = ntb_spad_read(ndev, VERSION); 1039 wake_up(&perf->threads[tidx].dma_wait);
536 if (val != PERF_VERSION) { 1040 cancel_work_sync(&perf->threads[tidx].work);
537 dev_dbg(&pdev->dev, "Remote version = %#x\n", val);
538 goto out;
539 } 1041 }
1042}
1043
1044static int perf_submit_test(struct perf_peer *peer)
1045{
1046 struct perf_ctx *perf = peer->perf;
1047 struct perf_thread *pthr;
1048 int tidx, ret;
540 1049
541 val = ntb_spad_read(ndev, MW_SZ_HIGH); 1050 if (!test_bit(PERF_STS_DONE, &peer->sts))
542 size = (u64)val << 32; 1051 return -ENOLINK;
543 1052
544 val = ntb_spad_read(ndev, MW_SZ_LOW); 1053 if (test_and_set_bit_lock(0, &perf->busy_flag))
545 size |= val; 1054 return -EBUSY;
546 1055
547 dev_dbg(&pdev->dev, "Remote MW size = %#llx\n", size); 1056 perf->test_peer = peer;
1057 atomic_set(&perf->tsync, perf->tcnt);
548 1058
549 rc = perf_set_mw(perf, size); 1059 for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) {
550 if (rc) 1060 pthr = &perf->threads[tidx];
551 goto out1;
552 1061
553 perf->link_is_up = true; 1062 pthr->status = -ENODATA;
554 wake_up(&perf->link_wq); 1063 pthr->copied = 0;
1064 pthr->duration = ktime_set(0, 0);
1065 if (tidx < perf->tcnt)
1066 (void)queue_work(perf_wq, &pthr->work);
1067 }
555 1068
556 return; 1069 ret = wait_event_interruptible(perf->twait,
1070 atomic_read(&perf->tsync) <= 0);
1071 if (ret == -ERESTARTSYS) {
1072 perf_terminate_test(perf);
1073 ret = -EINTR;
1074 }
557 1075
558out1: 1076 clear_bit_unlock(0, &perf->busy_flag);
559 perf_free_mw(perf);
560 1077
561out: 1078 return ret;
562 if (ntb_link_is_up(ndev, NULL, NULL) == 1)
563 schedule_delayed_work(&perf->link_work,
564 msecs_to_jiffies(PERF_LINK_DOWN_TIMEOUT));
565} 1079}
566 1080
567static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf) 1081static int perf_read_stats(struct perf_ctx *perf, char *buf,
1082 size_t size, ssize_t *pos)
568{ 1083{
569 struct perf_mw *mw; 1084 struct perf_thread *pthr;
570 int rc; 1085 int tidx;
1086
1087 if (test_and_set_bit_lock(0, &perf->busy_flag))
1088 return -EBUSY;
571 1089
572 mw = &perf->mw; 1090 (*pos) += scnprintf(buf + *pos, size - *pos,
1091 " Peer %d test statistics:\n", perf->test_peer->pidx);
573 1092
574 rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size); 1093 for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) {
575 if (rc) 1094 pthr = &perf->threads[tidx];
576 return rc;
577 1095
578 perf->mw.vbase = ioremap_wc(mw->phys_addr, mw->phys_size); 1096 if (pthr->status == -ENODATA)
579 if (!mw->vbase) 1097 continue;
580 return -ENOMEM; 1098
1099 if (pthr->status) {
1100 (*pos) += scnprintf(buf + *pos, size - *pos,
1101 "%d: error status %d\n", tidx, pthr->status);
1102 continue;
1103 }
1104
1105 (*pos) += scnprintf(buf + *pos, size - *pos,
1106 "%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n",
1107 tidx, pthr->copied, ktime_to_us(pthr->duration),
1108 div64_u64(pthr->copied, ktime_to_us(pthr->duration)));
1109 }
1110
1111 clear_bit_unlock(0, &perf->busy_flag);
581 1112
582 return 0; 1113 return 0;
583} 1114}
584 1115
585static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf, 1116static void perf_init_threads(struct perf_ctx *perf)
586 size_t count, loff_t *offp)
587{ 1117{
588 struct perf_ctx *perf = filp->private_data; 1118 struct perf_thread *pthr;
1119 int tidx;
1120
1121 perf->tcnt = DEF_THREADS_CNT;
1122 perf->test_peer = &perf->peers[0];
1123 init_waitqueue_head(&perf->twait);
1124
1125 for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) {
1126 pthr = &perf->threads[tidx];
1127
1128 pthr->perf = perf;
1129 pthr->tidx = tidx;
1130 pthr->status = -ENODATA;
1131 init_waitqueue_head(&pthr->dma_wait);
1132 INIT_WORK(&pthr->work, perf_thread_work);
1133 }
1134}
1135
1136static void perf_clear_threads(struct perf_ctx *perf)
1137{
1138 perf_terminate_test(perf);
1139}
1140
1141/*==============================================================================
1142 * DebugFS nodes
1143 *==============================================================================
1144 */
1145
1146static ssize_t perf_dbgfs_read_info(struct file *filep, char __user *ubuf,
1147 size_t size, loff_t *offp)
1148{
1149 struct perf_ctx *perf = filep->private_data;
1150 struct perf_peer *peer;
1151 size_t buf_size;
1152 ssize_t pos = 0;
1153 int ret, pidx;
589 char *buf; 1154 char *buf;
590 ssize_t ret, out_off = 0;
591 struct pthr_ctx *pctx;
592 int i;
593 u64 rate;
594 1155
595 if (!perf) 1156 buf_size = min_t(size_t, size, 0x1000U);
596 return 0;
597 1157
598 buf = kmalloc(1024, GFP_KERNEL); 1158 buf = kmalloc(buf_size, GFP_KERNEL);
599 if (!buf) 1159 if (!buf)
600 return -ENOMEM; 1160 return -ENOMEM;
601 1161
602 if (mutex_is_locked(&perf->run_mutex)) { 1162 pos += scnprintf(buf + pos, buf_size - pos,
603 out_off = scnprintf(buf, 64, "running\n"); 1163 " Performance measuring tool info:\n\n");
604 goto read_from_buf; 1164
1165 pos += scnprintf(buf + pos, buf_size - pos,
1166 "Local port %d, Global index %d\n", ntb_port_number(perf->ntb),
1167 perf->gidx);
1168 pos += scnprintf(buf + pos, buf_size - pos, "Test status: ");
1169 if (test_bit(0, &perf->busy_flag)) {
1170 pos += scnprintf(buf + pos, buf_size - pos,
1171 "on-fly with port %d (%d)\n",
1172 ntb_peer_port_number(perf->ntb, perf->test_peer->pidx),
1173 perf->test_peer->pidx);
1174 } else {
1175 pos += scnprintf(buf + pos, buf_size - pos, "idle\n");
605 } 1176 }
606 1177
607 for (i = 0; i < MAX_THREADS; i++) { 1178 for (pidx = 0; pidx < perf->pcnt; pidx++) {
608 pctx = &perf->pthr_ctx[i]; 1179 peer = &perf->peers[pidx];
1180
1181 pos += scnprintf(buf + pos, buf_size - pos,
1182 "Port %d (%d), Global index %d:\n",
1183 ntb_peer_port_number(perf->ntb, peer->pidx), peer->pidx,
1184 peer->gidx);
1185
1186 pos += scnprintf(buf + pos, buf_size - pos,
1187 "\tLink status: %s\n",
1188 test_bit(PERF_STS_LNKUP, &peer->sts) ? "up" : "down");
1189
1190 pos += scnprintf(buf + pos, buf_size - pos,
1191 "\tOut buffer addr 0x%pK\n", peer->outbuf);
609 1192
610 if (pctx->status == -ENODATA) 1193 pos += scnprintf(buf + pos, buf_size - pos,
611 break; 1194 "\tOut buffer size %pa\n", &peer->outbuf_size);
612 1195
613 if (pctx->status) { 1196 pos += scnprintf(buf + pos, buf_size - pos,
614 out_off += scnprintf(buf + out_off, 1024 - out_off, 1197 "\tOut buffer xlat 0x%016llx[p]\n", peer->outbuf_xlat);
615 "%d: error %d\n", i, 1198
616 pctx->status); 1199 if (!peer->inbuf) {
1200 pos += scnprintf(buf + pos, buf_size - pos,
1201 "\tIn buffer addr: unallocated\n");
617 continue; 1202 continue;
618 } 1203 }
619 1204
620 rate = div64_u64(pctx->copied, pctx->diff_us); 1205 pos += scnprintf(buf + pos, buf_size - pos,
621 out_off += scnprintf(buf + out_off, 1024 - out_off, 1206 "\tIn buffer addr 0x%pK\n", peer->inbuf);
622 "%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n", 1207
623 i, pctx->copied, pctx->diff_us, rate); 1208 pos += scnprintf(buf + pos, buf_size - pos,
1209 "\tIn buffer size %pa\n", &peer->inbuf_size);
1210
1211 pos += scnprintf(buf + pos, buf_size - pos,
1212 "\tIn buffer xlat %pad[p]\n", &peer->inbuf_xlat);
624 } 1213 }
625 1214
626read_from_buf: 1215 ret = simple_read_from_buffer(ubuf, size, offp, buf, pos);
627 ret = simple_read_from_buffer(ubuf, count, offp, buf, out_off);
628 kfree(buf); 1216 kfree(buf);
629 1217
630 return ret; 1218 return ret;
631} 1219}
632 1220
633static void threads_cleanup(struct perf_ctx *perf) 1221static const struct file_operations perf_dbgfs_info = {
1222 .open = simple_open,
1223 .read = perf_dbgfs_read_info
1224};
1225
1226static ssize_t perf_dbgfs_read_run(struct file *filep, char __user *ubuf,
1227 size_t size, loff_t *offp)
634{ 1228{
635 struct pthr_ctx *pctx; 1229 struct perf_ctx *perf = filep->private_data;
636 int i; 1230 ssize_t ret, pos = 0;
1231 char *buf;
637 1232
638 for (i = 0; i < MAX_THREADS; i++) { 1233 buf = kmalloc(PERF_BUF_LEN, GFP_KERNEL);
639 pctx = &perf->pthr_ctx[i]; 1234 if (!buf)
640 if (pctx->thread) { 1235 return -ENOMEM;
641 pctx->status = kthread_stop(pctx->thread);
642 pctx->thread = NULL;
643 }
644 }
645}
646 1236
647static void perf_clear_thread_status(struct perf_ctx *perf) 1237 ret = perf_read_stats(perf, buf, PERF_BUF_LEN, &pos);
648{ 1238 if (ret)
649 int i; 1239 goto err_free;
1240
1241 ret = simple_read_from_buffer(ubuf, size, offp, buf, pos);
1242err_free:
1243 kfree(buf);
650 1244
651 for (i = 0; i < MAX_THREADS; i++) 1245 return ret;
652 perf->pthr_ctx[i].status = -ENODATA;
653} 1246}
654 1247
655static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf, 1248static ssize_t perf_dbgfs_write_run(struct file *filep, const char __user *ubuf,
656 size_t count, loff_t *offp) 1249 size_t size, loff_t *offp)
657{ 1250{
658 struct perf_ctx *perf = filp->private_data; 1251 struct perf_ctx *perf = filep->private_data;
659 int node, i; 1252 struct perf_peer *peer;
660 DECLARE_WAIT_QUEUE_HEAD(wq); 1253 int pidx, ret;
661 1254
662 if (wait_event_interruptible(perf->link_wq, perf->link_is_up)) 1255 ret = kstrtoint_from_user(ubuf, size, 0, &pidx);
663 return -ENOLINK; 1256 if (ret)
1257 return ret;
664 1258
665 if (perf->perf_threads == 0) 1259 if (pidx < 0 || pidx >= perf->pcnt)
666 return -EINVAL; 1260 return -EINVAL;
667 1261
668 if (!mutex_trylock(&perf->run_mutex)) 1262 peer = &perf->peers[pidx];
669 return -EBUSY;
670 1263
671 perf_clear_thread_status(perf); 1264 ret = perf_submit_test(peer);
1265 if (ret)
1266 return ret;
672 1267
673 if (perf->perf_threads > MAX_THREADS) { 1268 return size;
674 perf->perf_threads = MAX_THREADS; 1269}
675 pr_info("Reset total threads to: %u\n", MAX_THREADS);
676 }
677 1270
678 /* no greater than 1M */ 1271static const struct file_operations perf_dbgfs_run = {
679 if (seg_order > MAX_SEG_ORDER) { 1272 .open = simple_open,
680 seg_order = MAX_SEG_ORDER; 1273 .read = perf_dbgfs_read_run,
681 pr_info("Fix seg_order to %u\n", seg_order); 1274 .write = perf_dbgfs_write_run
682 } 1275};
683 1276
684 if (run_order < seg_order) { 1277static ssize_t perf_dbgfs_read_tcnt(struct file *filep, char __user *ubuf,
685 run_order = seg_order; 1278 size_t size, loff_t *offp)
686 pr_info("Fix run_order to %u\n", run_order); 1279{
687 } 1280 struct perf_ctx *perf = filep->private_data;
1281 char buf[8];
1282 ssize_t pos;
688 1283
689 node = on_node ? dev_to_node(&perf->ntb->pdev->dev) 1284 pos = scnprintf(buf, sizeof(buf), "%hhu\n", perf->tcnt);
690 : NUMA_NO_NODE;
691 atomic_set(&perf->tdone, 0);
692 1285
693 /* launch kernel thread */ 1286 return simple_read_from_buffer(ubuf, size, offp, buf, pos);
694 for (i = 0; i < perf->perf_threads; i++) { 1287}
695 struct pthr_ctx *pctx;
696 1288
697 pctx = &perf->pthr_ctx[i]; 1289static ssize_t perf_dbgfs_write_tcnt(struct file *filep,
698 atomic_set(&pctx->dma_sync, 0); 1290 const char __user *ubuf,
699 pctx->perf = perf; 1291 size_t size, loff_t *offp)
700 pctx->wq = &wq; 1292{
701 pctx->thread = 1293 struct perf_ctx *perf = filep->private_data;
702 kthread_create_on_node(ntb_perf_thread, 1294 int ret;
703 (void *)pctx, 1295 u8 val;
704 node, "ntb_perf %d", i);
705 if (IS_ERR(pctx->thread)) {
706 pctx->thread = NULL;
707 goto err;
708 } else {
709 wake_up_process(pctx->thread);
710 }
711 }
712 1296
713 wait_event_interruptible(wq, 1297 ret = kstrtou8_from_user(ubuf, size, 0, &val);
714 atomic_read(&perf->tdone) == perf->perf_threads); 1298 if (ret)
1299 return ret;
715 1300
716 threads_cleanup(perf); 1301 ret = perf_set_tcnt(perf, val);
717 mutex_unlock(&perf->run_mutex); 1302 if (ret)
718 return count; 1303 return ret;
719 1304
720err: 1305 return size;
721 threads_cleanup(perf);
722 mutex_unlock(&perf->run_mutex);
723 return -ENXIO;
724} 1306}
725 1307
726static const struct file_operations ntb_perf_debugfs_run = { 1308static const struct file_operations perf_dbgfs_tcnt = {
727 .owner = THIS_MODULE,
728 .open = simple_open, 1309 .open = simple_open,
729 .read = debugfs_run_read, 1310 .read = perf_dbgfs_read_tcnt,
730 .write = debugfs_run_write, 1311 .write = perf_dbgfs_write_tcnt
731}; 1312};
732 1313
733static int perf_debugfs_setup(struct perf_ctx *perf) 1314static void perf_setup_dbgfs(struct perf_ctx *perf)
734{ 1315{
735 struct pci_dev *pdev = perf->ntb->pdev; 1316 struct pci_dev *pdev = perf->ntb->pdev;
736 struct dentry *debugfs_node_dir;
737 struct dentry *debugfs_run;
738 struct dentry *debugfs_threads;
739 struct dentry *debugfs_seg_order;
740 struct dentry *debugfs_run_order;
741 struct dentry *debugfs_use_dma;
742 struct dentry *debugfs_on_node;
743
744 if (!debugfs_initialized())
745 return -ENODEV;
746 1317
747 /* Assumpion: only one NTB device in the system */ 1318 perf->dbgfs_dir = debugfs_create_dir(pci_name(pdev), perf_dbgfs_topdir);
748 if (!perf_debugfs_dir) { 1319 if (!perf->dbgfs_dir) {
749 perf_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 1320 dev_warn(&perf->ntb->dev, "DebugFS unsupported\n");
750 if (!perf_debugfs_dir) 1321 return;
751 return -ENODEV; 1322 }
752 } 1323
753 1324 debugfs_create_file("info", 0600, perf->dbgfs_dir, perf,
754 debugfs_node_dir = debugfs_create_dir(pci_name(pdev), 1325 &perf_dbgfs_info);
755 perf_debugfs_dir);
756 if (!debugfs_node_dir)
757 goto err;
758
759 debugfs_run = debugfs_create_file("run", S_IRUSR | S_IWUSR,
760 debugfs_node_dir, perf,
761 &ntb_perf_debugfs_run);
762 if (!debugfs_run)
763 goto err;
764
765 debugfs_threads = debugfs_create_u8("threads", S_IRUSR | S_IWUSR,
766 debugfs_node_dir,
767 &perf->perf_threads);
768 if (!debugfs_threads)
769 goto err;
770
771 debugfs_seg_order = debugfs_create_u32("seg_order", 0600,
772 debugfs_node_dir,
773 &seg_order);
774 if (!debugfs_seg_order)
775 goto err;
776
777 debugfs_run_order = debugfs_create_u32("run_order", 0600,
778 debugfs_node_dir,
779 &run_order);
780 if (!debugfs_run_order)
781 goto err;
782
783 debugfs_use_dma = debugfs_create_bool("use_dma", 0600,
784 debugfs_node_dir,
785 &use_dma);
786 if (!debugfs_use_dma)
787 goto err;
788
789 debugfs_on_node = debugfs_create_bool("on_node", 0600,
790 debugfs_node_dir,
791 &on_node);
792 if (!debugfs_on_node)
793 goto err;
794 1326
795 return 0; 1327 debugfs_create_file("run", 0600, perf->dbgfs_dir, perf,
1328 &perf_dbgfs_run);
796 1329
797err: 1330 debugfs_create_file("threads_count", 0600, perf->dbgfs_dir, perf,
798 debugfs_remove_recursive(perf_debugfs_dir); 1331 &perf_dbgfs_tcnt);
799 perf_debugfs_dir = NULL; 1332
800 return -ENODEV; 1333 /* They are made read-only for test exec safety and integrity */
1334 debugfs_create_u8("chunk_order", 0500, perf->dbgfs_dir, &chunk_order);
1335
1336 debugfs_create_u8("total_order", 0500, perf->dbgfs_dir, &total_order);
1337
1338 debugfs_create_bool("use_dma", 0500, perf->dbgfs_dir, &use_dma);
801} 1339}
802 1340
803static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb) 1341static void perf_clear_dbgfs(struct perf_ctx *perf)
1342{
1343 debugfs_remove_recursive(perf->dbgfs_dir);
1344}
1345
1346/*==============================================================================
1347 * Basic driver initialization
1348 *==============================================================================
1349 */
1350
1351static struct perf_ctx *perf_create_data(struct ntb_dev *ntb)
804{ 1352{
805 struct pci_dev *pdev = ntb->pdev;
806 struct perf_ctx *perf; 1353 struct perf_ctx *perf;
807 int node;
808 int rc = 0;
809 1354
810 if (ntb_spad_count(ntb) < MAX_SPAD) { 1355 perf = devm_kzalloc(&ntb->dev, sizeof(*perf), GFP_KERNEL);
811 dev_err(&ntb->dev, "Not enough scratch pad registers for %s", 1356 if (!perf)
812 DRIVER_NAME); 1357 return ERR_PTR(-ENOMEM);
813 return -EIO;
814 }
815 1358
816 if (!ntb->ops->mw_set_trans) { 1359 perf->pcnt = ntb_peer_port_count(ntb);
817 dev_err(&ntb->dev, "Need inbound MW based NTB API\n"); 1360 perf->peers = devm_kcalloc(&ntb->dev, perf->pcnt, sizeof(*perf->peers),
818 return -EINVAL; 1361 GFP_KERNEL);
1362 if (!perf->peers)
1363 return ERR_PTR(-ENOMEM);
1364
1365 perf->ntb = ntb;
1366
1367 return perf;
1368}
1369
1370static int perf_setup_peer_mw(struct perf_peer *peer)
1371{
1372 struct perf_ctx *perf = peer->perf;
1373 phys_addr_t phys_addr;
1374 int ret;
1375
1376 /* Get outbound MW parameters and map it */
1377 ret = ntb_peer_mw_get_addr(perf->ntb, peer->gidx, &phys_addr,
1378 &peer->outbuf_size);
1379 if (ret)
1380 return ret;
1381
1382 peer->outbuf = devm_ioremap_wc(&perf->ntb->dev, phys_addr,
1383 peer->outbuf_size);
1384 if (!peer->outbuf)
1385 return -ENOMEM;
1386
1387 if (max_mw_size && peer->outbuf_size > max_mw_size) {
1388 peer->outbuf_size = max_mw_size;
1389 dev_warn(&peer->perf->ntb->dev,
1390 "Peer %d outbuf reduced to %#llx\n", peer->pidx,
1391 peer->outbuf_size);
819 } 1392 }
820 1393
821 if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) 1394 return 0;
822 dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n"); 1395}
823 1396
824 node = on_node ? dev_to_node(&pdev->dev) : NUMA_NO_NODE; 1397static int perf_init_peers(struct perf_ctx *perf)
825 perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node); 1398{
826 if (!perf) { 1399 struct perf_peer *peer;
827 rc = -ENOMEM; 1400 int pidx, lport, ret;
828 goto err_perf; 1401
1402 lport = ntb_port_number(perf->ntb);
1403 perf->gidx = -1;
1404 for (pidx = 0; pidx < perf->pcnt; pidx++) {
1405 peer = &perf->peers[pidx];
1406
1407 peer->perf = perf;
1408 peer->pidx = pidx;
1409 if (lport < ntb_peer_port_number(perf->ntb, pidx)) {
1410 if (perf->gidx == -1)
1411 perf->gidx = pidx;
1412 peer->gidx = pidx + 1;
1413 } else {
1414 peer->gidx = pidx;
1415 }
1416 INIT_WORK(&peer->service, perf_service_work);
829 } 1417 }
1418 if (perf->gidx == -1)
1419 perf->gidx = pidx;
830 1420
831 perf->ntb = ntb; 1421 for (pidx = 0; pidx < perf->pcnt; pidx++) {
832 perf->perf_threads = 1; 1422 ret = perf_setup_peer_mw(&perf->peers[pidx]);
833 atomic_set(&perf->tsync, 0); 1423 if (ret)
834 mutex_init(&perf->run_mutex); 1424 return ret;
835 spin_lock_init(&perf->db_lock); 1425 }
836 perf_setup_mw(ntb, perf); 1426
837 init_waitqueue_head(&perf->link_wq); 1427 dev_dbg(&perf->ntb->dev, "Global port index %d\n", perf->gidx);
838 INIT_DELAYED_WORK(&perf->link_work, perf_link_work); 1428
1429 return 0;
1430}
839 1431
840 rc = ntb_set_ctx(ntb, perf, &perf_ops); 1432static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
841 if (rc) 1433{
842 goto err_ctx; 1434 struct perf_ctx *perf;
1435 int ret;
843 1436
844 perf->link_is_up = false; 1437 perf = perf_create_data(ntb);
845 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 1438 if (IS_ERR(perf))
846 ntb_link_event(ntb); 1439 return PTR_ERR(perf);
847 1440
848 rc = perf_debugfs_setup(perf); 1441 ret = perf_init_peers(perf);
849 if (rc) 1442 if (ret)
850 goto err_ctx; 1443 return ret;
851 1444
852 perf_clear_thread_status(perf); 1445 perf_init_threads(perf);
853 1446
854 return 0; 1447 ret = perf_init_service(perf);
1448 if (ret)
1449 return ret;
855 1450
856err_ctx: 1451 ret = perf_enable_service(perf);
857 cancel_delayed_work_sync(&perf->link_work); 1452 if (ret)
858 kfree(perf); 1453 return ret;
859err_perf: 1454
860 return rc; 1455 perf_setup_dbgfs(perf);
1456
1457 return 0;
861} 1458}
862 1459
863static void perf_remove(struct ntb_client *client, struct ntb_dev *ntb) 1460static void perf_remove(struct ntb_client *client, struct ntb_dev *ntb)
864{ 1461{
865 struct perf_ctx *perf = ntb->ctx; 1462 struct perf_ctx *perf = ntb->ctx;
866 int i;
867 1463
868 dev_dbg(&perf->ntb->dev, "%s called\n", __func__); 1464 perf_clear_dbgfs(perf);
869 1465
870 mutex_lock(&perf->run_mutex); 1466 perf_disable_service(perf);
871 1467
872 cancel_delayed_work_sync(&perf->link_work); 1468 perf_clear_threads(perf);
1469}
873 1470
874 ntb_clear_ctx(ntb); 1471static struct ntb_client perf_client = {
875 ntb_link_disable(ntb); 1472 .ops = {
1473 .probe = perf_probe,
1474 .remove = perf_remove
1475 }
1476};
876 1477
877 debugfs_remove_recursive(perf_debugfs_dir); 1478static int __init perf_init(void)
878 perf_debugfs_dir = NULL; 1479{
1480 int ret;
879 1481
880 if (use_dma) { 1482 if (chunk_order > MAX_CHUNK_ORDER) {
881 for (i = 0; i < MAX_THREADS; i++) { 1483 chunk_order = MAX_CHUNK_ORDER;
882 struct pthr_ctx *pctx = &perf->pthr_ctx[i]; 1484 pr_info("Chunk order reduced to %hhu\n", chunk_order);
1485 }
883 1486
884 if (pctx->dma_chan) 1487 if (total_order < chunk_order) {
885 dma_release_channel(pctx->dma_chan); 1488 total_order = chunk_order;
886 } 1489 pr_info("Total data order reduced to %hhu\n", total_order);
887 } 1490 }
888 1491
889 kfree(perf); 1492 perf_wq = alloc_workqueue("perf_wq", WQ_UNBOUND | WQ_SYSFS, 0);
1493 if (!perf_wq)
1494 return -ENOMEM;
1495
1496 if (debugfs_initialized())
1497 perf_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
1498
1499 ret = ntb_register_client(&perf_client);
1500 if (ret) {
1501 debugfs_remove_recursive(perf_dbgfs_topdir);
1502 destroy_workqueue(perf_wq);
1503 }
1504
1505 return ret;
890} 1506}
1507module_init(perf_init);
1508
1509static void __exit perf_exit(void)
1510{
1511 ntb_unregister_client(&perf_client);
1512 debugfs_remove_recursive(perf_dbgfs_topdir);
1513 destroy_workqueue(perf_wq);
1514}
1515module_exit(perf_exit);
891 1516
892static struct ntb_client perf_client = {
893 .ops = {
894 .probe = perf_probe,
895 .remove = perf_remove,
896 },
897};
898module_ntb_client(perf_client);