Blame view

net/rds/ib_send.c 30.3 KB
6a0979df3   Andy Grover   RDS/IB: Implement...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  /*
   * Copyright (c) 2006 Oracle.  All rights reserved.
   *
   * This software is available to you under a choice of one of two
   * licenses.  You may choose to be licensed under the terms of the GNU
   * General Public License (GPL) Version 2, available from the file
   * COPYING in the main directory of this source tree, or the
   * OpenIB.org BSD license below:
   *
   *     Redistribution and use in source and binary forms, with or
   *     without modification, are permitted provided that the following
   *     conditions are met:
   *
   *      - Redistributions of source code must retain the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer.
   *
   *      - Redistributions in binary form must reproduce the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer in the documentation and/or other materials
   *        provided with the distribution.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   *
   */
  #include <linux/kernel.h>
  #include <linux/in.h>
  #include <linux/device.h>
  #include <linux/dmapool.h>
cb0a60564   Manuel Zerpies   net/rds: use prin...
37
  #include <linux/ratelimit.h>
6a0979df3   Andy Grover   RDS/IB: Implement...
38
39
  
  #include "rds.h"
6a0979df3   Andy Grover   RDS/IB: Implement...
40
  #include "ib.h"
59f740a6a   Zach Brown   RDS/IB: print str...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  static char *rds_ib_wc_status_strings[] = {
  #define RDS_IB_WC_STATUS_STR(foo) \
  		[IB_WC_##foo] = __stringify(IB_WC_##foo)
  	RDS_IB_WC_STATUS_STR(SUCCESS),
  	RDS_IB_WC_STATUS_STR(LOC_LEN_ERR),
  	RDS_IB_WC_STATUS_STR(LOC_QP_OP_ERR),
  	RDS_IB_WC_STATUS_STR(LOC_EEC_OP_ERR),
  	RDS_IB_WC_STATUS_STR(LOC_PROT_ERR),
  	RDS_IB_WC_STATUS_STR(WR_FLUSH_ERR),
  	RDS_IB_WC_STATUS_STR(MW_BIND_ERR),
  	RDS_IB_WC_STATUS_STR(BAD_RESP_ERR),
  	RDS_IB_WC_STATUS_STR(LOC_ACCESS_ERR),
  	RDS_IB_WC_STATUS_STR(REM_INV_REQ_ERR),
  	RDS_IB_WC_STATUS_STR(REM_ACCESS_ERR),
  	RDS_IB_WC_STATUS_STR(REM_OP_ERR),
  	RDS_IB_WC_STATUS_STR(RETRY_EXC_ERR),
  	RDS_IB_WC_STATUS_STR(RNR_RETRY_EXC_ERR),
  	RDS_IB_WC_STATUS_STR(LOC_RDD_VIOL_ERR),
  	RDS_IB_WC_STATUS_STR(REM_INV_RD_REQ_ERR),
  	RDS_IB_WC_STATUS_STR(REM_ABORT_ERR),
  	RDS_IB_WC_STATUS_STR(INV_EECN_ERR),
  	RDS_IB_WC_STATUS_STR(INV_EEC_STATE_ERR),
  	RDS_IB_WC_STATUS_STR(FATAL_ERR),
  	RDS_IB_WC_STATUS_STR(RESP_TIMEOUT_ERR),
  	RDS_IB_WC_STATUS_STR(GENERAL_ERR),
  #undef RDS_IB_WC_STATUS_STR
  };
  
  char *rds_ib_wc_status_str(enum ib_wc_status status)
  {
  	return rds_str_array(rds_ib_wc_status_strings,
  			     ARRAY_SIZE(rds_ib_wc_status_strings), status);
  }
9c030391e   Andy Grover   RDS/IB: eliminate...
74
75
76
77
78
79
80
  /*
   * Convert IB-specific error message to RDS error message and call core
   * completion handler.
   */
  static void rds_ib_send_complete(struct rds_message *rm,
  				 int wc_status,
  				 void (*complete)(struct rds_message *rm, int status))
6a0979df3   Andy Grover   RDS/IB: Implement...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  {
  	int notify_status;
  
  	switch (wc_status) {
  	case IB_WC_WR_FLUSH_ERR:
  		return;
  
  	case IB_WC_SUCCESS:
  		notify_status = RDS_RDMA_SUCCESS;
  		break;
  
  	case IB_WC_REM_ACCESS_ERR:
  		notify_status = RDS_RDMA_REMOTE_ERROR;
  		break;
  
  	default:
  		notify_status = RDS_RDMA_OTHER_ERROR;
  		break;
  	}
9c030391e   Andy Grover   RDS/IB: eliminate...
100
  	complete(rm, notify_status);
6a0979df3   Andy Grover   RDS/IB: Implement...
101
  }
ff3d7d361   Andy Grover   RDS: Perform unma...
102
103
104
  static void rds_ib_send_unmap_data(struct rds_ib_connection *ic,
  				   struct rm_data_op *op,
  				   int wc_status)
6a0979df3   Andy Grover   RDS/IB: Implement...
105
  {
ff3d7d361   Andy Grover   RDS: Perform unma...
106
107
108
109
110
  	if (op->op_nents)
  		ib_dma_unmap_sg(ic->i_cm_id->device,
  				op->op_sg, op->op_nents,
  				DMA_TO_DEVICE);
  }
6a0979df3   Andy Grover   RDS/IB: Implement...
111

ff3d7d361   Andy Grover   RDS: Perform unma...
112
113
114
115
116
117
118
119
120
121
  static void rds_ib_send_unmap_rdma(struct rds_ib_connection *ic,
  				   struct rm_rdma_op *op,
  				   int wc_status)
  {
  	if (op->op_mapped) {
  		ib_dma_unmap_sg(ic->i_cm_id->device,
  				op->op_sg, op->op_nents,
  				op->op_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
  		op->op_mapped = 0;
  	}
15133f6e6   Andy Grover   RDS: Implement at...
122

ff3d7d361   Andy Grover   RDS: Perform unma...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  	/* If the user asked for a completion notification on this
  	 * message, we can implement three different semantics:
  	 *  1.	Notify when we received the ACK on the RDS message
  	 *	that was queued with the RDMA. This provides reliable
  	 *	notification of RDMA status at the expense of a one-way
  	 *	packet delay.
  	 *  2.	Notify when the IB stack gives us the completion event for
  	 *	the RDMA operation.
  	 *  3.	Notify when the IB stack gives us the completion event for
  	 *	the accompanying RDS messages.
  	 * Here, we implement approach #3. To implement approach #2,
  	 * we would need to take an event for the rdma WR. To implement #1,
  	 * don't call rds_rdma_send_complete at all, and fall back to the notify
  	 * handling in the ACK processing code.
  	 *
  	 * Note: There's no need to explicitly sync any RDMA buffers using
  	 * ib_dma_sync_sg_for_cpu - the completion for the RDMA
  	 * operation itself unmapped the RDMA buffers, which takes care
  	 * of synching.
  	 */
  	rds_ib_send_complete(container_of(op, struct rds_message, rdma),
  			     wc_status, rds_rdma_send_complete);
6a0979df3   Andy Grover   RDS/IB: Implement...
145

ff3d7d361   Andy Grover   RDS: Perform unma...
146
147
148
149
150
  	if (op->op_write)
  		rds_stats_add(s_send_rdma_bytes, op->op_bytes);
  	else
  		rds_stats_add(s_recv_rdma_bytes, op->op_bytes);
  }
6a0979df3   Andy Grover   RDS/IB: Implement...
151

ff3d7d361   Andy Grover   RDS: Perform unma...
152
153
154
155
156
157
158
159
160
  static void rds_ib_send_unmap_atomic(struct rds_ib_connection *ic,
  				     struct rm_atomic_op *op,
  				     int wc_status)
  {
  	/* unmap atomic recvbuf */
  	if (op->op_mapped) {
  		ib_dma_unmap_sg(ic->i_cm_id->device, op->op_sg, 1,
  				DMA_FROM_DEVICE);
  		op->op_mapped = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
161
  	}
ff3d7d361   Andy Grover   RDS: Perform unma...
162
163
  	rds_ib_send_complete(container_of(op, struct rds_message, atomic),
  			     wc_status, rds_atomic_send_complete);
15133f6e6   Andy Grover   RDS: Implement at...
164

ff3d7d361   Andy Grover   RDS: Perform unma...
165
  	if (op->op_type == RDS_ATOMIC_TYPE_CSWP)
51e2cba8b   Andy Grover   RDS: Move atomic ...
166
  		rds_ib_stats_inc(s_ib_atomic_cswp);
ff3d7d361   Andy Grover   RDS: Perform unma...
167
  	else
51e2cba8b   Andy Grover   RDS: Move atomic ...
168
  		rds_ib_stats_inc(s_ib_atomic_fadd);
ff3d7d361   Andy Grover   RDS: Perform unma...
169
  }
15133f6e6   Andy Grover   RDS: Implement at...
170

ff3d7d361   Andy Grover   RDS: Perform unma...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  /*
   * Unmap the resources associated with a struct send_work.
   *
   * Returns the rm for no good reason other than it is unobtainable
   * other than by switching on wr.opcode, currently, and the caller,
   * the event handler, needs it.
   */
  static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic,
  						struct rds_ib_send_work *send,
  						int wc_status)
  {
  	struct rds_message *rm = NULL;
  
  	/* In the error case, wc.opcode sometimes contains garbage */
  	switch (send->s_wr.opcode) {
  	case IB_WR_SEND:
  		if (send->s_op) {
  			rm = container_of(send->s_op, struct rds_message, data);
  			rds_ib_send_unmap_data(ic, send->s_op, wc_status);
  		}
  		break;
  	case IB_WR_RDMA_WRITE:
  	case IB_WR_RDMA_READ:
  		if (send->s_op) {
  			rm = container_of(send->s_op, struct rds_message, rdma);
  			rds_ib_send_unmap_rdma(ic, send->s_op, wc_status);
  		}
  		break;
  	case IB_WR_ATOMIC_FETCH_AND_ADD:
  	case IB_WR_ATOMIC_CMP_AND_SWP:
  		if (send->s_op) {
  			rm = container_of(send->s_op, struct rds_message, atomic);
  			rds_ib_send_unmap_atomic(ic, send->s_op, wc_status);
  		}
  		break;
  	default:
cb0a60564   Manuel Zerpies   net/rds: use prin...
207
  		printk_ratelimited(KERN_NOTICE
ff3d7d361   Andy Grover   RDS: Perform unma...
208
209
210
211
  			       "RDS/IB: %s: unexpected opcode 0x%x in WR!
  ",
  			       __func__, send->s_wr.opcode);
  		break;
15133f6e6   Andy Grover   RDS: Implement at...
212
  	}
ff3d7d361   Andy Grover   RDS: Perform unma...
213
  	send->s_wr.opcode = 0xdead;
6a0979df3   Andy Grover   RDS/IB: Implement...
214

ff3d7d361   Andy Grover   RDS: Perform unma...
215
  	return rm;
6a0979df3   Andy Grover   RDS/IB: Implement...
216
217
218
219
220
221
222
223
224
  }
  
  void rds_ib_send_init_ring(struct rds_ib_connection *ic)
  {
  	struct rds_ib_send_work *send;
  	u32 i;
  
  	for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
  		struct ib_sge *sge;
6a0979df3   Andy Grover   RDS/IB: Implement...
225
226
227
228
  		send->s_op = NULL;
  
  		send->s_wr.wr_id = i;
  		send->s_wr.sg_list = send->s_sge;
6a0979df3   Andy Grover   RDS/IB: Implement...
229
  		send->s_wr.ex.imm_data = 0;
919ced4ce   Andy Grover   RDS/IB: Remove ib...
230
  		sge = &send->s_sge[0];
6a0979df3   Andy Grover   RDS/IB: Implement...
231
232
233
  		sge->addr = ic->i_send_hdrs_dma + (i * sizeof(struct rds_header));
  		sge->length = sizeof(struct rds_header);
  		sge->lkey = ic->i_mr->lkey;
919ced4ce   Andy Grover   RDS/IB: Remove ib...
234
235
  
  		send->s_sge[1].lkey = ic->i_mr->lkey;
6a0979df3   Andy Grover   RDS/IB: Implement...
236
237
238
239
240
241
242
243
244
  	}
  }
  
  void rds_ib_send_clear_ring(struct rds_ib_connection *ic)
  {
  	struct rds_ib_send_work *send;
  	u32 i;
  
  	for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
ff3d7d361   Andy Grover   RDS: Perform unma...
245
246
  		if (send->s_op && send->s_wr.opcode != 0xdead)
  			rds_ib_send_unmap_op(ic, send, IB_WC_WR_FLUSH_ERR);
6a0979df3   Andy Grover   RDS/IB: Implement...
247
248
249
250
  	}
  }
  
  /*
f046011cd   Zach Brown   RDS/IB: track sig...
251
252
253
254
255
256
257
258
259
260
261
262
   * The only fast path caller always has a non-zero nr, so we don't
   * bother testing nr before performing the atomic sub.
   */
  static void rds_ib_sub_signaled(struct rds_ib_connection *ic, int nr)
  {
  	if ((atomic_sub_return(nr, &ic->i_signaled_sends) == 0) &&
  	    waitqueue_active(&rds_ib_ring_empty_wait))
  		wake_up(&rds_ib_ring_empty_wait);
  	BUG_ON(atomic_read(&ic->i_signaled_sends) < 0);
  }
  
  /*
6a0979df3   Andy Grover   RDS/IB: Implement...
263
264
265
266
267
268
269
270
271
   * The _oldest/_free ring operations here race cleanly with the alloc/unalloc
   * operations performed in the send path.  As the sender allocs and potentially
   * unallocs the next free entry in the ring it doesn't alter which is
   * the next to be freed, which is what this is concerned with.
   */
  void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
  {
  	struct rds_connection *conn = context;
  	struct rds_ib_connection *ic = conn->c_transport_data;
ff3d7d361   Andy Grover   RDS: Perform unma...
272
  	struct rds_message *rm = NULL;
6a0979df3   Andy Grover   RDS/IB: Implement...
273
274
275
276
277
278
  	struct ib_wc wc;
  	struct rds_ib_send_work *send;
  	u32 completed;
  	u32 oldest;
  	u32 i = 0;
  	int ret;
f046011cd   Zach Brown   RDS/IB: track sig...
279
  	int nr_sig = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
280
281
282
283
284
285
286
287
288
289
  
  	rdsdebug("cq %p conn %p
  ", cq, conn);
  	rds_ib_stats_inc(s_ib_tx_cq_call);
  	ret = ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
  	if (ret)
  		rdsdebug("ib_req_notify_cq send failed: %d
  ", ret);
  
  	while (ib_poll_cq(cq, 1, &wc) > 0) {
59f740a6a   Zach Brown   RDS/IB: print str...
290
291
292
293
  		rdsdebug("wc wr_id 0x%llx status %u (%s) byte_len %u imm_data %u
  ",
  			 (unsigned long long)wc.wr_id, wc.status,
  			 rds_ib_wc_status_str(wc.status), wc.byte_len,
6a0979df3   Andy Grover   RDS/IB: Implement...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  			 be32_to_cpu(wc.ex.imm_data));
  		rds_ib_stats_inc(s_ib_tx_cq_event);
  
  		if (wc.wr_id == RDS_IB_ACK_WR_ID) {
  			if (ic->i_ack_queued + HZ/2 < jiffies)
  				rds_ib_stats_inc(s_ib_tx_stalled);
  			rds_ib_ack_send_complete(ic);
  			continue;
  		}
  
  		oldest = rds_ib_ring_oldest(&ic->i_send_ring);
  
  		completed = rds_ib_ring_completed(&ic->i_send_ring, wc.wr_id, oldest);
  
  		for (i = 0; i < completed; i++) {
  			send = &ic->i_sends[oldest];
f046011cd   Zach Brown   RDS/IB: track sig...
310
311
  			if (send->s_wr.send_flags & IB_SEND_SIGNALED)
  				nr_sig++;
6a0979df3   Andy Grover   RDS/IB: Implement...
312

ff3d7d361   Andy Grover   RDS: Perform unma...
313
  			rm = rds_ib_send_unmap_op(ic, send, wc.status);
6a0979df3   Andy Grover   RDS/IB: Implement...
314

6a0979df3   Andy Grover   RDS/IB: Implement...
315
316
  			if (send->s_queued + HZ/2 < jiffies)
  				rds_ib_stats_inc(s_ib_tx_stalled);
c9e65383a   Chris Mason   rds: Fix RDMA mes...
317
318
319
320
321
322
  			if (send->s_op) {
  				if (send->s_op == rm->m_final_op) {
  					/* If anyone waited for this message to get flushed out, wake
  					 * them up now */
  					rds_message_unmapped(rm);
  				}
ff3d7d361   Andy Grover   RDS: Perform unma...
323
324
  				rds_message_put(rm);
  				send->s_op = NULL;
6a0979df3   Andy Grover   RDS/IB: Implement...
325
326
327
328
329
330
  			}
  
  			oldest = (oldest + 1) % ic->i_send_ring.w_nr;
  		}
  
  		rds_ib_ring_free(&ic->i_send_ring, completed);
f046011cd   Zach Brown   RDS/IB: track sig...
331
332
  		rds_ib_sub_signaled(ic, nr_sig);
  		nr_sig = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
333

f64f9e719   Joe Perches   net: Move && and ...
334
335
  		if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
  		    test_bit(0, &conn->c_map_queued))
6a0979df3   Andy Grover   RDS/IB: Implement...
336
337
338
339
  			queue_delayed_work(rds_wq, &conn->c_send_w, 0);
  
  		/* We expect errors as the qp is drained during shutdown */
  		if (wc.status != IB_WC_SUCCESS && rds_conn_up(conn)) {
59f740a6a   Zach Brown   RDS/IB: print str...
340
341
342
343
344
  			rds_ib_conn_error(conn, "send completion on %pI4 had status "
  					  "%u (%s), disconnecting and reconnecting
  ",
  					  &conn->c_faddr, wc.status,
  					  rds_ib_wc_status_str(wc.status));
6a0979df3   Andy Grover   RDS/IB: Implement...
345
346
347
348
349
350
351
352
353
354
  		}
  	}
  }
  
  /*
   * This is the main function for allocating credits when sending
   * messages.
   *
   * Conceptually, we have two counters:
   *  -	send credits: this tells us how many WRs we're allowed
25985edce   Lucas De Marchi   Fix common misspe...
355
   *	to submit without overruning the receiver's queue. For
6a0979df3   Andy Grover   RDS/IB: Implement...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
   *	each SEND WR we post, we decrement this by one.
   *
   *  -	posted credits: this tells us how many WRs we recently
   *	posted to the receive queue. This value is transferred
   *	to the peer as a "credit update" in a RDS header field.
   *	Every time we transmit credits to the peer, we subtract
   *	the amount of transferred credits from this counter.
   *
   * It is essential that we avoid situations where both sides have
   * exhausted their send credits, and are unable to send new credits
   * to the peer. We achieve this by requiring that we send at least
   * one credit update to the peer before exhausting our credits.
   * When new credits arrive, we subtract one credit that is withheld
   * until we've posted new buffers and are ready to transmit these
   * credits (see rds_ib_send_add_credits below).
   *
   * The RDS send code is essentially single-threaded; rds_send_xmit
0f4b1c7e8   Zach Brown   rds: fix rds_send...
373
   * sets RDS_IN_XMIT to ensure exclusive access to the send ring.
6a0979df3   Andy Grover   RDS/IB: Implement...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
   * However, the ACK sending code is independent and can race with
   * message SENDs.
   *
   * In the send path, we need to update the counters for send credits
   * and the counter of posted buffers atomically - when we use the
   * last available credit, we cannot allow another thread to race us
   * and grab the posted credits counter.  Hence, we have to use a
   * spinlock to protect the credit counter, or use atomics.
   *
   * Spinlocks shared between the send and the receive path are bad,
   * because they create unnecessary delays. An early implementation
   * using a spinlock showed a 5% degradation in throughput at some
   * loads.
   *
   * This implementation avoids spinlocks completely, putting both
   * counters into a single atomic, and updating that atomic using
   * atomic_add (in the receive path, when receiving fresh credits),
   * and using atomic_cmpxchg when updating the two counters.
   */
  int rds_ib_send_grab_credits(struct rds_ib_connection *ic,
7b70d0336   Steve Wise   RDS/IW+IB: Allow ...
394
  			     u32 wanted, u32 *adv_credits, int need_posted, int max_posted)
6a0979df3   Andy Grover   RDS/IB: Implement...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  {
  	unsigned int avail, posted, got = 0, advertise;
  	long oldval, newval;
  
  	*adv_credits = 0;
  	if (!ic->i_flowctl)
  		return wanted;
  
  try_again:
  	advertise = 0;
  	oldval = newval = atomic_read(&ic->i_credits);
  	posted = IB_GET_POST_CREDITS(oldval);
  	avail = IB_GET_SEND_CREDITS(oldval);
  
  	rdsdebug("rds_ib_send_grab_credits(%u): credits=%u posted=%u
  ",
  			wanted, avail, posted);
  
  	/* The last credit must be used to send a credit update. */
  	if (avail && !posted)
  		avail--;
  
  	if (avail < wanted) {
  		struct rds_connection *conn = ic->i_cm_id->context;
  
  		/* Oops, there aren't that many credits left! */
  		set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
  		got = avail;
  	} else {
  		/* Sometimes you get what you want, lalala. */
  		got = wanted;
  	}
  	newval -= IB_SET_SEND_CREDITS(got);
  
  	/*
  	 * If need_posted is non-zero, then the caller wants
  	 * the posted regardless of whether any send credits are
  	 * available.
  	 */
  	if (posted && (got || need_posted)) {
7b70d0336   Steve Wise   RDS/IW+IB: Allow ...
435
  		advertise = min_t(unsigned int, posted, max_posted);
6a0979df3   Andy Grover   RDS/IB: Implement...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  		newval -= IB_SET_POST_CREDITS(advertise);
  	}
  
  	/* Finally bill everything */
  	if (atomic_cmpxchg(&ic->i_credits, oldval, newval) != oldval)
  		goto try_again;
  
  	*adv_credits = advertise;
  	return got;
  }
  
  void rds_ib_send_add_credits(struct rds_connection *conn, unsigned int credits)
  {
  	struct rds_ib_connection *ic = conn->c_transport_data;
  
  	if (credits == 0)
  		return;
  
  	rdsdebug("rds_ib_send_add_credits(%u): current=%u%s
  ",
  			credits,
  			IB_GET_SEND_CREDITS(atomic_read(&ic->i_credits)),
  			test_bit(RDS_LL_SEND_FULL, &conn->c_flags) ? ", ll_send_full" : "");
  
  	atomic_add(IB_SET_SEND_CREDITS(credits), &ic->i_credits);
  	if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags))
  		queue_delayed_work(rds_wq, &conn->c_send_w, 0);
  
  	WARN_ON(IB_GET_SEND_CREDITS(credits) >= 16384);
  
  	rds_ib_stats_inc(s_ib_rx_credit_updates);
  }
  
  void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted)
  {
  	struct rds_ib_connection *ic = conn->c_transport_data;
  
  	if (posted == 0)
  		return;
  
  	atomic_add(IB_SET_POST_CREDITS(posted), &ic->i_credits);
  
  	/* Decide whether to send an update to the peer now.
  	 * If we would send a credit update for every single buffer we
  	 * post, we would end up with an ACK storm (ACK arrives,
  	 * consumes buffer, we refill the ring, send ACK to remote
  	 * advertising the newly posted buffer... ad inf)
  	 *
  	 * Performance pretty much depends on how often we send
  	 * credit updates - too frequent updates mean lots of ACKs.
  	 * Too infrequent updates, and the peer will run out of
  	 * credits and has to throttle.
  	 * For the time being, 16 seems to be a good compromise.
  	 */
  	if (IB_GET_POST_CREDITS(atomic_read(&ic->i_credits)) >= 16)
  		set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
  }
f046011cd   Zach Brown   RDS/IB: track sig...
493
494
495
  static inline int rds_ib_set_wr_signal_state(struct rds_ib_connection *ic,
  					     struct rds_ib_send_work *send,
  					     bool notify)
241eef3e2   Andy Grover   RDS: Implement si...
496
497
498
499
500
501
502
503
504
  {
  	/*
  	 * We want to delay signaling completions just enough to get
  	 * the batching benefits but not so much that we create dead time
  	 * on the wire.
  	 */
  	if (ic->i_unsignaled_wrs-- == 0 || notify) {
  		ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
  		send->s_wr.send_flags |= IB_SEND_SIGNALED;
f046011cd   Zach Brown   RDS/IB: track sig...
505
  		return 1;
241eef3e2   Andy Grover   RDS: Implement si...
506
  	}
f046011cd   Zach Brown   RDS/IB: track sig...
507
  	return 0;
241eef3e2   Andy Grover   RDS: Implement si...
508
  }
6a0979df3   Andy Grover   RDS/IB: Implement...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  /*
   * This can be called multiple times for a given message.  The first time
   * we see a message we map its scatterlist into the IB device so that
   * we can provide that mapped address to the IB scatter gather entries
   * in the IB work requests.  We translate the scatterlist into a series
   * of work requests that fragment the message.  These work requests complete
   * in order so we pass ownership of the message to the completion handler
   * once we send the final fragment.
   *
   * The RDS core uses the c_send_lock to only enter this function once
   * per connection.  This makes sure that the tx ring alloc/unalloc pairs
   * don't get out of sync and confuse the ring.
   */
  int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
  		unsigned int hdr_off, unsigned int sg, unsigned int off)
  {
  	struct rds_ib_connection *ic = conn->c_transport_data;
  	struct ib_device *dev = ic->i_cm_id->device;
  	struct rds_ib_send_work *send = NULL;
  	struct rds_ib_send_work *first;
  	struct rds_ib_send_work *prev;
  	struct ib_send_wr *failed_wr;
  	struct scatterlist *scat;
  	u32 pos;
  	u32 i;
  	u32 work_alloc;
da5a06cef   Andy Grover   RDS: rewrite rds_...
535
  	u32 credit_alloc = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
536
537
538
  	u32 posted;
  	u32 adv_credits = 0;
  	int send_flags = 0;
da5a06cef   Andy Grover   RDS: rewrite rds_...
539
  	int bytes_sent = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
540
541
  	int ret;
  	int flow_controlled = 0;
f046011cd   Zach Brown   RDS/IB: track sig...
542
  	int nr_sig = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
543
544
545
  
  	BUG_ON(off % RDS_FRAG_SIZE);
  	BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header));
2e7b3b994   Andy Grover   RDS: Fix congesti...
546
547
548
549
  	/* Do not send cong updates to IB loopback */
  	if (conn->c_loopback
  	    && rm->m_inc.i_hdr.h_flags & RDS_FLAG_CONG_BITMAP) {
  		rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
6094628bf   Neil Horman   rds: prevent BUG_...
550
551
552
553
  		scat = &rm->data.op_sg[sg];
  		ret = sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
  		ret = min_t(int, ret, scat->length - conn->c_xmit_data_off);
  		return ret;
2e7b3b994   Andy Grover   RDS: Fix congesti...
554
  	}
6a0979df3   Andy Grover   RDS/IB: Implement...
555
556
557
558
559
560
561
562
563
564
565
566
567
  	/* FIXME we may overallocate here */
  	if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0)
  		i = 1;
  	else
  		i = ceil(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE);
  
  	work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos);
  	if (work_alloc == 0) {
  		set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
  		rds_ib_stats_inc(s_ib_tx_ring_full);
  		ret = -ENOMEM;
  		goto out;
  	}
6a0979df3   Andy Grover   RDS/IB: Implement...
568
  	if (ic->i_flowctl) {
7b70d0336   Steve Wise   RDS/IW+IB: Allow ...
569
  		credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT);
6a0979df3   Andy Grover   RDS/IB: Implement...
570
571
572
573
  		adv_credits += posted;
  		if (credit_alloc < work_alloc) {
  			rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc);
  			work_alloc = credit_alloc;
c8de3f100   Andy Grover   RDS/IB: Make all ...
574
  			flow_controlled = 1;
6a0979df3   Andy Grover   RDS/IB: Implement...
575
576
  		}
  		if (work_alloc == 0) {
d39e0602b   Steve Wise   RDS/IW+IB: Set th...
577
  			set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
6a0979df3   Andy Grover   RDS/IB: Implement...
578
579
580
581
582
583
584
  			rds_ib_stats_inc(s_ib_tx_throttle);
  			ret = -ENOMEM;
  			goto out;
  		}
  	}
  
  	/* map the message the first time we see it */
ff3d7d361   Andy Grover   RDS: Perform unma...
585
  	if (!ic->i_data_op) {
6c7cc6e46   Andy Grover   RDS: Rename data ...
586
587
588
589
590
591
592
593
  		if (rm->data.op_nents) {
  			rm->data.op_count = ib_dma_map_sg(dev,
  							  rm->data.op_sg,
  							  rm->data.op_nents,
  							  DMA_TO_DEVICE);
  			rdsdebug("ic %p mapping rm %p: %d
  ", ic, rm, rm->data.op_count);
  			if (rm->data.op_count == 0) {
6a0979df3   Andy Grover   RDS/IB: Implement...
594
595
596
597
598
599
  				rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
  				rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
  				ret = -ENOMEM; /* XXX ? */
  				goto out;
  			}
  		} else {
6c7cc6e46   Andy Grover   RDS: Rename data ...
600
  			rm->data.op_count = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
601
  		}
6a0979df3   Andy Grover   RDS/IB: Implement...
602
  		rds_message_addref(rm);
ff3d7d361   Andy Grover   RDS: Perform unma...
603
  		ic->i_data_op = &rm->data;
6a0979df3   Andy Grover   RDS/IB: Implement...
604
605
606
607
608
609
610
611
612
  
  		/* Finalize the header */
  		if (test_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags))
  			rm->m_inc.i_hdr.h_flags |= RDS_FLAG_ACK_REQUIRED;
  		if (test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags))
  			rm->m_inc.i_hdr.h_flags |= RDS_FLAG_RETRANSMITTED;
  
  		/* If it has a RDMA op, tell the peer we did it. This is
  		 * used by the peer to release use-once RDMA MRs. */
f8b3aaf2b   Andy Grover   RDS: Remove struc...
613
  		if (rm->rdma.op_active) {
6a0979df3   Andy Grover   RDS/IB: Implement...
614
  			struct rds_ext_header_rdma ext_hdr;
f8b3aaf2b   Andy Grover   RDS: Remove struc...
615
  			ext_hdr.h_rdma_rkey = cpu_to_be32(rm->rdma.op_rkey);
6a0979df3   Andy Grover   RDS/IB: Implement...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  			rds_message_add_extension(&rm->m_inc.i_hdr,
  					RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
  		}
  		if (rm->m_rdma_cookie) {
  			rds_message_add_rdma_dest_extension(&rm->m_inc.i_hdr,
  					rds_rdma_cookie_key(rm->m_rdma_cookie),
  					rds_rdma_cookie_offset(rm->m_rdma_cookie));
  		}
  
  		/* Note - rds_ib_piggyb_ack clears the ACK_REQUIRED bit, so
  		 * we should not do this unless we have a chance of at least
  		 * sticking the header into the send ring. Which is why we
  		 * should call rds_ib_ring_alloc first. */
  		rm->m_inc.i_hdr.h_ack = cpu_to_be64(rds_ib_piggyb_ack(ic));
  		rds_message_make_checksum(&rm->m_inc.i_hdr);
  
  		/*
  		 * Update adv_credits since we reset the ACK_REQUIRED bit.
  		 */
c8de3f100   Andy Grover   RDS/IB: Make all ...
635
636
637
638
639
  		if (ic->i_flowctl) {
  			rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
  			adv_credits += posted;
  			BUG_ON(adv_credits > 255);
  		}
735f61e62   Andy Grover   RDS: Do not BUG()...
640
  	}
6a0979df3   Andy Grover   RDS/IB: Implement...
641

6a0979df3   Andy Grover   RDS/IB: Implement...
642
643
644
645
646
647
  	/* Sometimes you want to put a fence between an RDMA
  	 * READ and the following SEND.
  	 * We could either do this all the time
  	 * or when requested by the user. Right now, we let
  	 * the application choose.
  	 */
f8b3aaf2b   Andy Grover   RDS: Remove struc...
648
  	if (rm->rdma.op_active && rm->rdma.op_fence)
6a0979df3   Andy Grover   RDS/IB: Implement...
649
  		send_flags = IB_SEND_FENCE;
da5a06cef   Andy Grover   RDS: rewrite rds_...
650
651
652
653
  	/* Each frag gets a header. Msgs may be 0 bytes */
  	send = &ic->i_sends[pos];
  	first = send;
  	prev = NULL;
ff3d7d361   Andy Grover   RDS: Perform unma...
654
  	scat = &ic->i_data_op->op_sg[sg];
da5a06cef   Andy Grover   RDS: rewrite rds_...
655
656
657
658
659
660
661
662
663
664
665
  	i = 0;
  	do {
  		unsigned int len = 0;
  
  		/* Set up the header */
  		send->s_wr.send_flags = send_flags;
  		send->s_wr.opcode = IB_WR_SEND;
  		send->s_wr.num_sge = 1;
  		send->s_wr.next = NULL;
  		send->s_queued = jiffies;
  		send->s_op = NULL;
6a0979df3   Andy Grover   RDS/IB: Implement...
666

da5a06cef   Andy Grover   RDS: rewrite rds_...
667
668
669
670
671
  		send->s_sge[0].addr = ic->i_send_hdrs_dma
  			+ (pos * sizeof(struct rds_header));
  		send->s_sge[0].length = sizeof(struct rds_header);
  
  		memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
6a0979df3   Andy Grover   RDS/IB: Implement...
672

da5a06cef   Andy Grover   RDS: rewrite rds_...
673
674
  		/* Set up the data, if present */
  		if (i < work_alloc
6c7cc6e46   Andy Grover   RDS: Rename data ...
675
  		    && scat != &rm->data.op_sg[rm->data.op_count]) {
da5a06cef   Andy Grover   RDS: rewrite rds_...
676
677
  			len = min(RDS_FRAG_SIZE, ib_sg_dma_len(dev, scat) - off);
  			send->s_wr.num_sge = 2;
6a0979df3   Andy Grover   RDS/IB: Implement...
678

da5a06cef   Andy Grover   RDS: rewrite rds_...
679
680
  			send->s_sge[1].addr = ib_sg_dma_address(dev, scat) + off;
  			send->s_sge[1].length = len;
6a0979df3   Andy Grover   RDS/IB: Implement...
681

da5a06cef   Andy Grover   RDS: rewrite rds_...
682
683
684
685
686
687
688
  			bytes_sent += len;
  			off += len;
  			if (off == ib_sg_dma_len(dev, scat)) {
  				scat++;
  				off = 0;
  			}
  		}
6a0979df3   Andy Grover   RDS/IB: Implement...
689

241eef3e2   Andy Grover   RDS: Implement si...
690
  		rds_ib_set_wr_signal_state(ic, send, 0);
6a0979df3   Andy Grover   RDS/IB: Implement...
691

6a0979df3   Andy Grover   RDS/IB: Implement...
692
693
694
  		/*
  		 * Always signal the last one if we're stopping due to flow control.
  		 */
c8de3f100   Andy Grover   RDS/IB: Make all ...
695
  		if (ic->i_flowctl && flow_controlled && i == (work_alloc-1))
6a0979df3   Andy Grover   RDS/IB: Implement...
696
  			send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
f046011cd   Zach Brown   RDS/IB: track sig...
697
698
  		if (send->s_wr.send_flags & IB_SEND_SIGNALED)
  			nr_sig++;
6a0979df3   Andy Grover   RDS/IB: Implement...
699
700
701
  		rdsdebug("send %p wr %p num_sge %u next %p
  ", send,
  			 &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
c8de3f100   Andy Grover   RDS/IB: Make all ...
702
  		if (ic->i_flowctl && adv_credits) {
6a0979df3   Andy Grover   RDS/IB: Implement...
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  			struct rds_header *hdr = &ic->i_send_hdrs[pos];
  
  			/* add credit and redo the header checksum */
  			hdr->h_credit = adv_credits;
  			rds_message_make_checksum(hdr);
  			adv_credits = 0;
  			rds_ib_stats_inc(s_ib_tx_credit_updates);
  		}
  
  		if (prev)
  			prev->s_wr.next = &send->s_wr;
  		prev = send;
  
  		pos = (pos + 1) % ic->i_send_ring.w_nr;
da5a06cef   Andy Grover   RDS: rewrite rds_...
717
718
719
720
  		send = &ic->i_sends[pos];
  		i++;
  
  	} while (i < work_alloc
6c7cc6e46   Andy Grover   RDS: Rename data ...
721
  		 && scat != &rm->data.op_sg[rm->data.op_count]);
6a0979df3   Andy Grover   RDS/IB: Implement...
722
723
724
725
  
  	/* Account the RDS header in the number of bytes we sent, but just once.
  	 * The caller has no concept of fragmentation. */
  	if (hdr_off == 0)
da5a06cef   Andy Grover   RDS: rewrite rds_...
726
  		bytes_sent += sizeof(struct rds_header);
6a0979df3   Andy Grover   RDS/IB: Implement...
727
728
  
  	/* if we finished the message then send completion owns it */
6c7cc6e46   Andy Grover   RDS: Rename data ...
729
  	if (scat == &rm->data.op_sg[rm->data.op_count]) {
ff3d7d361   Andy Grover   RDS: Perform unma...
730
  		prev->s_op = ic->i_data_op;
241eef3e2   Andy Grover   RDS: Implement si...
731
  		prev->s_wr.send_flags |= IB_SEND_SOLICITED;
ff3d7d361   Andy Grover   RDS: Perform unma...
732
  		ic->i_data_op = NULL;
6a0979df3   Andy Grover   RDS/IB: Implement...
733
  	}
da5a06cef   Andy Grover   RDS: rewrite rds_...
734
  	/* Put back wrs & credits we didn't use */
6a0979df3   Andy Grover   RDS/IB: Implement...
735
736
737
738
739
740
  	if (i < work_alloc) {
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
  		work_alloc = i;
  	}
  	if (ic->i_flowctl && i < credit_alloc)
  		rds_ib_send_add_credits(conn, credit_alloc - i);
f046011cd   Zach Brown   RDS/IB: track sig...
741
742
  	if (nr_sig)
  		atomic_add(nr_sig, &ic->i_signaled_sends);
6a0979df3   Andy Grover   RDS/IB: Implement...
743
744
745
746
747
748
749
750
751
752
753
754
  	/* XXX need to worry about failed_wr and partial sends. */
  	failed_wr = &first->s_wr;
  	ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
  	rdsdebug("ic %p first %p (wr %p) ret %d wr %p
  ", ic,
  		 first, &first->s_wr, ret, failed_wr);
  	BUG_ON(failed_wr != &first->s_wr);
  	if (ret) {
  		printk(KERN_WARNING "RDS/IB: ib_post_send to %pI4 "
  		       "returned %d
  ", &conn->c_faddr, ret);
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
f046011cd   Zach Brown   RDS/IB: track sig...
755
  		rds_ib_sub_signaled(ic, nr_sig);
ff3d7d361   Andy Grover   RDS: Perform unma...
756
757
758
  		if (prev->s_op) {
  			ic->i_data_op = prev->s_op;
  			prev->s_op = NULL;
6a0979df3   Andy Grover   RDS/IB: Implement...
759
  		}
735f61e62   Andy Grover   RDS: Do not BUG()...
760
761
762
  
  		rds_ib_conn_error(ic->conn, "ib_post_send failed
  ");
6a0979df3   Andy Grover   RDS/IB: Implement...
763
764
  		goto out;
  	}
da5a06cef   Andy Grover   RDS: rewrite rds_...
765
  	ret = bytes_sent;
6a0979df3   Andy Grover   RDS/IB: Implement...
766
767
768
769
  out:
  	BUG_ON(adv_credits);
  	return ret;
  }
15133f6e6   Andy Grover   RDS: Implement at...
770
771
772
773
774
  /*
   * Issue atomic operation.
   * A simplified version of the rdma case, we always map 1 SG, and
   * only 8 bytes, for the return value from the atomic operation.
   */
ff3d7d361   Andy Grover   RDS: Perform unma...
775
  int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op)
15133f6e6   Andy Grover   RDS: Implement at...
776
777
778
779
780
781
782
783
  {
  	struct rds_ib_connection *ic = conn->c_transport_data;
  	struct rds_ib_send_work *send = NULL;
  	struct ib_send_wr *failed_wr;
  	struct rds_ib_device *rds_ibdev;
  	u32 pos;
  	u32 work_alloc;
  	int ret;
f046011cd   Zach Brown   RDS/IB: track sig...
784
  	int nr_sig = 0;
15133f6e6   Andy Grover   RDS: Implement at...
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
  
  	rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
  
  	work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, 1, &pos);
  	if (work_alloc != 1) {
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
  		rds_ib_stats_inc(s_ib_tx_ring_full);
  		ret = -ENOMEM;
  		goto out;
  	}
  
  	/* address of send request in ring */
  	send = &ic->i_sends[pos];
  	send->s_queued = jiffies;
  
  	if (op->op_type == RDS_ATOMIC_TYPE_CSWP) {
20c72bd5f   Andy Grover   RDS: Implement ma...
801
802
803
804
805
  		send->s_wr.opcode = IB_WR_MASKED_ATOMIC_CMP_AND_SWP;
  		send->s_wr.wr.atomic.compare_add = op->op_m_cswp.compare;
  		send->s_wr.wr.atomic.swap = op->op_m_cswp.swap;
  		send->s_wr.wr.atomic.compare_add_mask = op->op_m_cswp.compare_mask;
  		send->s_wr.wr.atomic.swap_mask = op->op_m_cswp.swap_mask;
15133f6e6   Andy Grover   RDS: Implement at...
806
  	} else { /* FADD */
20c72bd5f   Andy Grover   RDS: Implement ma...
807
808
  		send->s_wr.opcode = IB_WR_MASKED_ATOMIC_FETCH_AND_ADD;
  		send->s_wr.wr.atomic.compare_add = op->op_m_fadd.add;
15133f6e6   Andy Grover   RDS: Implement at...
809
  		send->s_wr.wr.atomic.swap = 0;
20c72bd5f   Andy Grover   RDS: Implement ma...
810
811
  		send->s_wr.wr.atomic.compare_add_mask = op->op_m_fadd.nocarry_mask;
  		send->s_wr.wr.atomic.swap_mask = 0;
15133f6e6   Andy Grover   RDS: Implement at...
812
  	}
f046011cd   Zach Brown   RDS/IB: track sig...
813
  	nr_sig = rds_ib_set_wr_signal_state(ic, send, op->op_notify);
15133f6e6   Andy Grover   RDS: Implement at...
814
815
816
817
  	send->s_wr.num_sge = 1;
  	send->s_wr.next = NULL;
  	send->s_wr.wr.atomic.remote_addr = op->op_remote_addr;
  	send->s_wr.wr.atomic.rkey = op->op_rkey;
1cc2228c5   Chris Mason   rds: Fix referenc...
818
819
  	send->s_op = op;
  	rds_message_addref(container_of(send->s_op, struct rds_message, atomic));
15133f6e6   Andy Grover   RDS: Implement at...
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  
  	/* map 8 byte retval buffer to the device */
  	ret = ib_dma_map_sg(ic->i_cm_id->device, op->op_sg, 1, DMA_FROM_DEVICE);
  	rdsdebug("ic %p mapping atomic op %p. mapped %d pg
  ", ic, op, ret);
  	if (ret != 1) {
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
  		rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
  		ret = -ENOMEM; /* XXX ? */
  		goto out;
  	}
  
  	/* Convert our struct scatterlist to struct ib_sge */
  	send->s_sge[0].addr = ib_sg_dma_address(ic->i_cm_id->device, op->op_sg);
  	send->s_sge[0].length = ib_sg_dma_len(ic->i_cm_id->device, op->op_sg);
  	send->s_sge[0].lkey = ic->i_mr->lkey;
  
  	rdsdebug("rva %Lx rpa %Lx len %u
  ", op->op_remote_addr,
  		 send->s_sge[0].addr, send->s_sge[0].length);
f046011cd   Zach Brown   RDS/IB: track sig...
840
841
  	if (nr_sig)
  		atomic_add(nr_sig, &ic->i_signaled_sends);
15133f6e6   Andy Grover   RDS: Implement at...
842
843
844
845
846
847
848
849
850
851
852
  	failed_wr = &send->s_wr;
  	ret = ib_post_send(ic->i_cm_id->qp, &send->s_wr, &failed_wr);
  	rdsdebug("ic %p send %p (wr %p) ret %d wr %p
  ", ic,
  		 send, &send->s_wr, ret, failed_wr);
  	BUG_ON(failed_wr != &send->s_wr);
  	if (ret) {
  		printk(KERN_WARNING "RDS/IB: atomic ib_post_send to %pI4 "
  		       "returned %d
  ", &conn->c_faddr, ret);
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
f046011cd   Zach Brown   RDS/IB: track sig...
853
  		rds_ib_sub_signaled(ic, nr_sig);
15133f6e6   Andy Grover   RDS: Implement at...
854
855
856
857
858
859
860
861
862
863
864
865
  		goto out;
  	}
  
  	if (unlikely(failed_wr != &send->s_wr)) {
  		printk(KERN_WARNING "RDS/IB: atomic ib_post_send() rc=%d, but failed_wqe updated!
  ", ret);
  		BUG_ON(failed_wr != &send->s_wr);
  	}
  
  out:
  	return ret;
  }
f8b3aaf2b   Andy Grover   RDS: Remove struc...
866
  int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
6a0979df3   Andy Grover   RDS/IB: Implement...
867
868
869
870
871
872
  {
  	struct rds_ib_connection *ic = conn->c_transport_data;
  	struct rds_ib_send_work *send = NULL;
  	struct rds_ib_send_work *first;
  	struct rds_ib_send_work *prev;
  	struct ib_send_wr *failed_wr;
6a0979df3   Andy Grover   RDS/IB: Implement...
873
874
  	struct scatterlist *scat;
  	unsigned long len;
f8b3aaf2b   Andy Grover   RDS: Remove struc...
875
  	u64 remote_addr = op->op_remote_addr;
89bf9d415   Zach Brown   RDS/IB: get the x...
876
  	u32 max_sge = ic->rds_ibdev->max_sge;
6a0979df3   Andy Grover   RDS/IB: Implement...
877
878
879
880
881
882
883
  	u32 pos;
  	u32 work_alloc;
  	u32 i;
  	u32 j;
  	int sent;
  	int ret;
  	int num_sge;
f046011cd   Zach Brown   RDS/IB: track sig...
884
  	int nr_sig = 0;
6a0979df3   Andy Grover   RDS/IB: Implement...
885

ff3d7d361   Andy Grover   RDS: Perform unma...
886
  	/* map the op the first time we see it */
f8b3aaf2b   Andy Grover   RDS: Remove struc...
887
888
889
890
891
892
893
  	if (!op->op_mapped) {
  		op->op_count = ib_dma_map_sg(ic->i_cm_id->device,
  					     op->op_sg, op->op_nents, (op->op_write) ?
  					     DMA_TO_DEVICE : DMA_FROM_DEVICE);
  		rdsdebug("ic %p mapping op %p: %d
  ", ic, op, op->op_count);
  		if (op->op_count == 0) {
6a0979df3   Andy Grover   RDS/IB: Implement...
894
895
896
897
  			rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
  			ret = -ENOMEM; /* XXX ? */
  			goto out;
  		}
f8b3aaf2b   Andy Grover   RDS: Remove struc...
898
  		op->op_mapped = 1;
6a0979df3   Andy Grover   RDS/IB: Implement...
899
900
901
902
903
904
  	}
  
  	/*
  	 * Instead of knowing how to return a partial rdma read/write we insist that there
  	 * be enough work requests to send the entire message.
  	 */
89bf9d415   Zach Brown   RDS/IB: get the x...
905
  	i = ceil(op->op_count, max_sge);
6a0979df3   Andy Grover   RDS/IB: Implement...
906
907
908
909
910
911
912
913
914
915
916
917
  
  	work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos);
  	if (work_alloc != i) {
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
  		rds_ib_stats_inc(s_ib_tx_ring_full);
  		ret = -ENOMEM;
  		goto out;
  	}
  
  	send = &ic->i_sends[pos];
  	first = send;
  	prev = NULL;
f8b3aaf2b   Andy Grover   RDS: Remove struc...
918
  	scat = &op->op_sg[0];
6a0979df3   Andy Grover   RDS/IB: Implement...
919
  	sent = 0;
f8b3aaf2b   Andy Grover   RDS: Remove struc...
920
  	num_sge = op->op_count;
6a0979df3   Andy Grover   RDS/IB: Implement...
921

f8b3aaf2b   Andy Grover   RDS: Remove struc...
922
  	for (i = 0; i < work_alloc && scat != &op->op_sg[op->op_count]; i++) {
6a0979df3   Andy Grover   RDS/IB: Implement...
923
924
  		send->s_wr.send_flags = 0;
  		send->s_queued = jiffies;
1cc2228c5   Chris Mason   rds: Fix referenc...
925
  		send->s_op = NULL;
241eef3e2   Andy Grover   RDS: Implement si...
926

f046011cd   Zach Brown   RDS/IB: track sig...
927
  		nr_sig += rds_ib_set_wr_signal_state(ic, send, op->op_notify);
6a0979df3   Andy Grover   RDS/IB: Implement...
928

f8b3aaf2b   Andy Grover   RDS: Remove struc...
929
  		send->s_wr.opcode = op->op_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
6a0979df3   Andy Grover   RDS/IB: Implement...
930
  		send->s_wr.wr.rdma.remote_addr = remote_addr;
f8b3aaf2b   Andy Grover   RDS: Remove struc...
931
  		send->s_wr.wr.rdma.rkey = op->op_rkey;
6a0979df3   Andy Grover   RDS/IB: Implement...
932

89bf9d415   Zach Brown   RDS/IB: get the x...
933
934
935
  		if (num_sge > max_sge) {
  			send->s_wr.num_sge = max_sge;
  			num_sge -= max_sge;
6a0979df3   Andy Grover   RDS/IB: Implement...
936
937
938
939
940
941
942
943
  		} else {
  			send->s_wr.num_sge = num_sge;
  		}
  
  		send->s_wr.next = NULL;
  
  		if (prev)
  			prev->s_wr.next = &send->s_wr;
f8b3aaf2b   Andy Grover   RDS: Remove struc...
944
  		for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
6a0979df3   Andy Grover   RDS/IB: Implement...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  			len = ib_sg_dma_len(ic->i_cm_id->device, scat);
  			send->s_sge[j].addr =
  				 ib_sg_dma_address(ic->i_cm_id->device, scat);
  			send->s_sge[j].length = len;
  			send->s_sge[j].lkey = ic->i_mr->lkey;
  
  			sent += len;
  			rdsdebug("ic %p sent %d remote_addr %llu
  ", ic, sent, remote_addr);
  
  			remote_addr += len;
  			scat++;
  		}
  
  		rdsdebug("send %p wr %p num_sge %u next %p
  ", send,
  			&send->s_wr, send->s_wr.num_sge, send->s_wr.next);
  
  		prev = send;
  		if (++send == &ic->i_sends[ic->i_send_ring.w_nr])
  			send = ic->i_sends;
  	}
1cc2228c5   Chris Mason   rds: Fix referenc...
967
968
969
970
971
  	/* give a reference to the last op */
  	if (scat == &op->op_sg[op->op_count]) {
  		prev->s_op = op;
  		rds_message_addref(container_of(op, struct rds_message, rdma));
  	}
6a0979df3   Andy Grover   RDS/IB: Implement...
972
973
974
975
  	if (i < work_alloc) {
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
  		work_alloc = i;
  	}
f046011cd   Zach Brown   RDS/IB: track sig...
976
977
  	if (nr_sig)
  		atomic_add(nr_sig, &ic->i_signaled_sends);
6a0979df3   Andy Grover   RDS/IB: Implement...
978
979
980
981
982
983
984
985
986
987
988
  	failed_wr = &first->s_wr;
  	ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
  	rdsdebug("ic %p first %p (wr %p) ret %d wr %p
  ", ic,
  		 first, &first->s_wr, ret, failed_wr);
  	BUG_ON(failed_wr != &first->s_wr);
  	if (ret) {
  		printk(KERN_WARNING "RDS/IB: rdma ib_post_send to %pI4 "
  		       "returned %d
  ", &conn->c_faddr, ret);
  		rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
f046011cd   Zach Brown   RDS/IB: track sig...
989
  		rds_ib_sub_signaled(ic, nr_sig);
6a0979df3   Andy Grover   RDS/IB: Implement...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  		goto out;
  	}
  
  	if (unlikely(failed_wr != &first->s_wr)) {
  		printk(KERN_WARNING "RDS/IB: ib_post_send() rc=%d, but failed_wqe updated!
  ", ret);
  		BUG_ON(failed_wr != &first->s_wr);
  	}
  
  
  out:
  	return ret;
  }
  
  void rds_ib_xmit_complete(struct rds_connection *conn)
  {
  	struct rds_ib_connection *ic = conn->c_transport_data;
  
  	/* We may have a pending ACK or window update we were unable
  	 * to send previously (due to flow control). Try again. */
  	rds_ib_attempt_ack(ic);
  }