]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - net/smc/smc_wr.c
KVM: SVM: Move spec control call after restore of GS
[mirror_ubuntu-artful-kernel.git] / net / smc / smc_wr.c
CommitLineData
f38ba179
UB
1/*
2 * Shared Memory Communications over RDMA (SMC-R) and RoCE
3 *
4 * Work Requests exploiting Infiniband API
5 *
6 * Work requests (WR) of type ib_post_send or ib_post_recv respectively
7 * are submitted to either RC SQ or RC RQ respectively
8 * (reliably connected send/receive queue)
9 * and become work queue entries (WQEs).
10 * While an SQ WR/WQE is pending, we track it until transmission completion.
11 * Through a send or receive completion queue (CQ) respectively,
12 * we get completion queue entries (CQEs) [aka work completions (WCs)].
13 * Since the CQ callback is called from IRQ context, we split work by using
14 * bottom halves implemented by tasklets.
15 *
16 * SMC uses this to exchange LLC (link layer control)
17 * and CDC (connection data control) messages.
18 *
19 * Copyright IBM Corp. 2016
20 *
21 * Author(s): Steffen Maier <maier@linux.vnet.ibm.com>
22 */
23
24#include <linux/atomic.h>
25#include <linux/hashtable.h>
26#include <linux/wait.h>
27#include <rdma/ib_verbs.h>
28#include <asm/div64.h>
29
30#include "smc.h"
31#include "smc_wr.h"
32
33#define SMC_WR_MAX_POLL_CQE 10 /* max. # of compl. queue elements in 1 poll */
34
35#define SMC_WR_RX_HASH_BITS 4
36static DEFINE_HASHTABLE(smc_wr_rx_hash, SMC_WR_RX_HASH_BITS);
37static DEFINE_SPINLOCK(smc_wr_rx_hash_lock);
38
39struct smc_wr_tx_pend { /* control data for a pending send request */
40 u64 wr_id; /* work request id sent */
41 smc_wr_tx_handler handler;
42 enum ib_wc_status wc_status; /* CQE status */
43 struct smc_link *link;
44 u32 idx;
45 struct smc_wr_tx_pend_priv priv;
46};
47
48/******************************** send queue *********************************/
49
50/*------------------------------- completion --------------------------------*/
51
52static inline int smc_wr_tx_find_pending_index(struct smc_link *link, u64 wr_id)
53{
54 u32 i;
55
56 for (i = 0; i < link->wr_tx_cnt; i++) {
57 if (link->wr_tx_pends[i].wr_id == wr_id)
58 return i;
59 }
60 return link->wr_tx_cnt;
61}
62
63static inline void smc_wr_tx_process_cqe(struct ib_wc *wc)
64{
65 struct smc_wr_tx_pend pnd_snd;
66 struct smc_link *link;
67 u32 pnd_snd_idx;
68 int i;
69
70 link = wc->qp->qp_context;
71 pnd_snd_idx = smc_wr_tx_find_pending_index(link, wc->wr_id);
72 if (pnd_snd_idx == link->wr_tx_cnt)
73 return;
74 link->wr_tx_pends[pnd_snd_idx].wc_status = wc->status;
75 memcpy(&pnd_snd, &link->wr_tx_pends[pnd_snd_idx], sizeof(pnd_snd));
76 /* clear the full struct smc_wr_tx_pend including .priv */
77 memset(&link->wr_tx_pends[pnd_snd_idx], 0,
78 sizeof(link->wr_tx_pends[pnd_snd_idx]));
79 memset(&link->wr_tx_bufs[pnd_snd_idx], 0,
80 sizeof(link->wr_tx_bufs[pnd_snd_idx]));
81 if (!test_and_clear_bit(pnd_snd_idx, link->wr_tx_mask))
82 return;
83 if (wc->status) {
b38d7324
UB
84 struct smc_link_group *lgr;
85
f38ba179
UB
86 for_each_set_bit(i, link->wr_tx_mask, link->wr_tx_cnt) {
87 /* clear full struct smc_wr_tx_pend including .priv */
88 memset(&link->wr_tx_pends[i], 0,
89 sizeof(link->wr_tx_pends[i]));
90 memset(&link->wr_tx_bufs[i], 0,
91 sizeof(link->wr_tx_bufs[i]));
92 clear_bit(i, link->wr_tx_mask);
93 }
b38d7324
UB
94 /* terminate connections of this link group abnormally */
95 lgr = container_of(link, struct smc_link_group,
96 lnk[SMC_SINGLE_LINK]);
97 smc_lgr_terminate(lgr);
f38ba179
UB
98 }
99 if (pnd_snd.handler)
100 pnd_snd.handler(&pnd_snd.priv, link, wc->status);
101 wake_up(&link->wr_tx_wait);
102}
103
104static void smc_wr_tx_tasklet_fn(unsigned long data)
105{
106 struct smc_ib_device *dev = (struct smc_ib_device *)data;
107 struct ib_wc wc[SMC_WR_MAX_POLL_CQE];
108 int i = 0, rc;
109 int polled = 0;
110
111again:
112 polled++;
113 do {
114 rc = ib_poll_cq(dev->roce_cq_send, SMC_WR_MAX_POLL_CQE, wc);
115 if (polled == 1) {
116 ib_req_notify_cq(dev->roce_cq_send,
117 IB_CQ_NEXT_COMP |
118 IB_CQ_REPORT_MISSED_EVENTS);
119 }
120 if (!rc)
121 break;
122 for (i = 0; i < rc; i++)
123 smc_wr_tx_process_cqe(&wc[i]);
124 } while (rc > 0);
125 if (polled == 1)
126 goto again;
127}
128
129void smc_wr_tx_cq_handler(struct ib_cq *ib_cq, void *cq_context)
130{
131 struct smc_ib_device *dev = (struct smc_ib_device *)cq_context;
132
133 tasklet_schedule(&dev->send_tasklet);
134}
135
136/*---------------------------- request submission ---------------------------*/
137
138static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx)
139{
140 *idx = link->wr_tx_cnt;
141 for_each_clear_bit(*idx, link->wr_tx_mask, link->wr_tx_cnt) {
142 if (!test_and_set_bit(*idx, link->wr_tx_mask))
143 return 0;
144 }
145 *idx = link->wr_tx_cnt;
146 return -EBUSY;
147}
148
149/**
150 * smc_wr_tx_get_free_slot() - returns buffer for message assembly,
151 * and sets info for pending transmit tracking
152 * @link: Pointer to smc_link used to later send the message.
153 * @handler: Send completion handler function pointer.
154 * @wr_buf: Out value returns pointer to message buffer.
155 * @wr_pend_priv: Out value returns pointer serving as handler context.
156 *
157 * Return: 0 on success, or -errno on error.
158 */
159int smc_wr_tx_get_free_slot(struct smc_link *link,
160 smc_wr_tx_handler handler,
161 struct smc_wr_buf **wr_buf,
162 struct smc_wr_tx_pend_priv **wr_pend_priv)
163{
164 struct smc_wr_tx_pend *wr_pend;
165 struct ib_send_wr *wr_ib;
166 u64 wr_id;
167 u32 idx;
168 int rc;
169
170 *wr_buf = NULL;
171 *wr_pend_priv = NULL;
172 if (in_softirq()) {
173 rc = smc_wr_tx_get_free_slot_index(link, &idx);
174 if (rc)
175 return rc;
176 } else {
177 rc = wait_event_interruptible_timeout(
178 link->wr_tx_wait,
179 (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
180 SMC_WR_TX_WAIT_FREE_SLOT_TIME);
181 if (!rc) {
b38d7324
UB
182 /* timeout - terminate connections */
183 struct smc_link_group *lgr;
184
185 lgr = container_of(link, struct smc_link_group,
186 lnk[SMC_SINGLE_LINK]);
187 smc_lgr_terminate(lgr);
f38ba179
UB
188 return -EPIPE;
189 }
190 if (rc == -ERESTARTSYS)
191 return -EINTR;
192 if (idx == link->wr_tx_cnt)
193 return -EPIPE;
194 }
195 wr_id = smc_wr_tx_get_next_wr_id(link);
196 wr_pend = &link->wr_tx_pends[idx];
197 wr_pend->wr_id = wr_id;
198 wr_pend->handler = handler;
199 wr_pend->link = link;
200 wr_pend->idx = idx;
201 wr_ib = &link->wr_tx_ibs[idx];
202 wr_ib->wr_id = wr_id;
203 *wr_buf = &link->wr_tx_bufs[idx];
204 *wr_pend_priv = &wr_pend->priv;
205 return 0;
206}
207
208int smc_wr_tx_put_slot(struct smc_link *link,
209 struct smc_wr_tx_pend_priv *wr_pend_priv)
210{
211 struct smc_wr_tx_pend *pend;
212
213 pend = container_of(wr_pend_priv, struct smc_wr_tx_pend, priv);
214 if (pend->idx < link->wr_tx_cnt) {
215 /* clear the full struct smc_wr_tx_pend including .priv */
216 memset(&link->wr_tx_pends[pend->idx], 0,
217 sizeof(link->wr_tx_pends[pend->idx]));
218 memset(&link->wr_tx_bufs[pend->idx], 0,
219 sizeof(link->wr_tx_bufs[pend->idx]));
220 test_and_clear_bit(pend->idx, link->wr_tx_mask);
221 return 1;
222 }
223
224 return 0;
225}
226
227/* Send prepared WR slot via ib_post_send.
228 * @priv: pointer to smc_wr_tx_pend_priv identifying prepared message buffer
229 */
230int smc_wr_tx_send(struct smc_link *link, struct smc_wr_tx_pend_priv *priv)
231{
232 struct ib_send_wr *failed_wr = NULL;
233 struct smc_wr_tx_pend *pend;
234 int rc;
235
236 ib_req_notify_cq(link->smcibdev->roce_cq_send,
237 IB_CQ_SOLICITED_MASK | IB_CQ_REPORT_MISSED_EVENTS);
238 pend = container_of(priv, struct smc_wr_tx_pend, priv);
239 rc = ib_post_send(link->roce_qp, &link->wr_tx_ibs[pend->idx],
240 &failed_wr);
241 if (rc)
242 smc_wr_tx_put_slot(link, priv);
243 return rc;
244}
245
5f08318f
UB
246void smc_wr_tx_dismiss_slots(struct smc_link *link, u8 wr_rx_hdr_type,
247 smc_wr_tx_filter filter,
248 smc_wr_tx_dismisser dismisser,
249 unsigned long data)
250{
251 struct smc_wr_tx_pend_priv *tx_pend;
252 struct smc_wr_rx_hdr *wr_rx;
253 int i;
254
255 for_each_set_bit(i, link->wr_tx_mask, link->wr_tx_cnt) {
256 wr_rx = (struct smc_wr_rx_hdr *)&link->wr_rx_bufs[i];
257 if (wr_rx->type != wr_rx_hdr_type)
258 continue;
259 tx_pend = &link->wr_tx_pends[i].priv;
260 if (filter(tx_pend, data))
261 dismisser(tx_pend);
262 }
263}
264
b38d7324
UB
265bool smc_wr_tx_has_pending(struct smc_link *link, u8 wr_rx_hdr_type,
266 smc_wr_tx_filter filter, unsigned long data)
267{
268 struct smc_wr_tx_pend_priv *tx_pend;
269 struct smc_wr_rx_hdr *wr_rx;
270 int i;
271
272 for_each_set_bit(i, link->wr_tx_mask, link->wr_tx_cnt) {
273 wr_rx = (struct smc_wr_rx_hdr *)&link->wr_rx_bufs[i];
274 if (wr_rx->type != wr_rx_hdr_type)
275 continue;
276 tx_pend = &link->wr_tx_pends[i].priv;
277 if (filter(tx_pend, data))
278 return true;
279 }
280 return false;
281}
282
f38ba179
UB
283/****************************** receive queue ********************************/
284
285int smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler)
286{
287 struct smc_wr_rx_handler *h_iter;
288 int rc = 0;
289
290 spin_lock(&smc_wr_rx_hash_lock);
291 hash_for_each_possible(smc_wr_rx_hash, h_iter, list, handler->type) {
292 if (h_iter->type == handler->type) {
293 rc = -EEXIST;
294 goto out_unlock;
295 }
296 }
297 hash_add(smc_wr_rx_hash, &handler->list, handler->type);
298out_unlock:
299 spin_unlock(&smc_wr_rx_hash_lock);
300 return rc;
301}
302
303/* Demultiplex a received work request based on the message type to its handler.
304 * Relies on smc_wr_rx_hash having been completely filled before any IB WRs,
305 * and not being modified any more afterwards so we don't need to lock it.
306 */
307static inline void smc_wr_rx_demultiplex(struct ib_wc *wc)
308{
309 struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
310 struct smc_wr_rx_handler *handler;
311 struct smc_wr_rx_hdr *wr_rx;
312 u64 temp_wr_id;
313 u32 index;
314
315 if (wc->byte_len < sizeof(*wr_rx))
316 return; /* short message */
317 temp_wr_id = wc->wr_id;
318 index = do_div(temp_wr_id, link->wr_rx_cnt);
319 wr_rx = (struct smc_wr_rx_hdr *)&link->wr_rx_bufs[index];
320 hash_for_each_possible(smc_wr_rx_hash, handler, list, wr_rx->type) {
321 if (handler->type == wr_rx->type)
322 handler->handler(wc, wr_rx);
323 }
324}
325
326static inline void smc_wr_rx_process_cqes(struct ib_wc wc[], int num)
327{
328 struct smc_link *link;
329 int i;
330
331 for (i = 0; i < num; i++) {
332 link = wc[i].qp->qp_context;
333 if (wc[i].status == IB_WC_SUCCESS) {
334 smc_wr_rx_demultiplex(&wc[i]);
335 smc_wr_rx_post(link); /* refill WR RX */
336 } else {
b38d7324
UB
337 struct smc_link_group *lgr;
338
f38ba179
UB
339 /* handle status errors */
340 switch (wc[i].status) {
341 case IB_WC_RETRY_EXC_ERR:
342 case IB_WC_RNR_RETRY_EXC_ERR:
343 case IB_WC_WR_FLUSH_ERR:
b38d7324
UB
344 /* terminate connections of this link group
345 * abnormally
346 */
347 lgr = container_of(link, struct smc_link_group,
348 lnk[SMC_SINGLE_LINK]);
349 smc_lgr_terminate(lgr);
f38ba179
UB
350 break;
351 default:
352 smc_wr_rx_post(link); /* refill WR RX */
353 break;
354 }
355 }
356 }
357}
358
359static void smc_wr_rx_tasklet_fn(unsigned long data)
360{
361 struct smc_ib_device *dev = (struct smc_ib_device *)data;
362 struct ib_wc wc[SMC_WR_MAX_POLL_CQE];
363 int polled = 0;
364 int rc;
365
366again:
367 polled++;
368 do {
369 memset(&wc, 0, sizeof(wc));
370 rc = ib_poll_cq(dev->roce_cq_recv, SMC_WR_MAX_POLL_CQE, wc);
371 if (polled == 1) {
372 ib_req_notify_cq(dev->roce_cq_recv,
373 IB_CQ_SOLICITED_MASK
374 | IB_CQ_REPORT_MISSED_EVENTS);
375 }
376 if (!rc)
377 break;
378 smc_wr_rx_process_cqes(&wc[0], rc);
379 } while (rc > 0);
380 if (polled == 1)
381 goto again;
382}
383
384void smc_wr_rx_cq_handler(struct ib_cq *ib_cq, void *cq_context)
385{
386 struct smc_ib_device *dev = (struct smc_ib_device *)cq_context;
387
388 tasklet_schedule(&dev->recv_tasklet);
389}
390
391int smc_wr_rx_post_init(struct smc_link *link)
392{
393 u32 i;
394 int rc = 0;
395
396 for (i = 0; i < link->wr_rx_cnt; i++)
397 rc = smc_wr_rx_post(link);
398 return rc;
399}
400
401/***************************** init, exit, misc ******************************/
402
403void smc_wr_remember_qp_attr(struct smc_link *lnk)
404{
405 struct ib_qp_attr *attr = &lnk->qp_attr;
406 struct ib_qp_init_attr init_attr;
407
408 memset(attr, 0, sizeof(*attr));
409 memset(&init_attr, 0, sizeof(init_attr));
410 ib_query_qp(lnk->roce_qp, attr,
411 IB_QP_STATE |
412 IB_QP_CUR_STATE |
413 IB_QP_PKEY_INDEX |
414 IB_QP_PORT |
415 IB_QP_QKEY |
416 IB_QP_AV |
417 IB_QP_PATH_MTU |
418 IB_QP_TIMEOUT |
419 IB_QP_RETRY_CNT |
420 IB_QP_RNR_RETRY |
421 IB_QP_RQ_PSN |
422 IB_QP_ALT_PATH |
423 IB_QP_MIN_RNR_TIMER |
424 IB_QP_SQ_PSN |
425 IB_QP_PATH_MIG_STATE |
426 IB_QP_CAP |
427 IB_QP_DEST_QPN,
428 &init_attr);
429
430 lnk->wr_tx_cnt = min_t(size_t, SMC_WR_BUF_CNT,
431 lnk->qp_attr.cap.max_send_wr);
432 lnk->wr_rx_cnt = min_t(size_t, SMC_WR_BUF_CNT * 3,
433 lnk->qp_attr.cap.max_recv_wr);
434}
435
436static void smc_wr_init_sge(struct smc_link *lnk)
437{
438 u32 i;
439
440 for (i = 0; i < lnk->wr_tx_cnt; i++) {
441 lnk->wr_tx_sges[i].addr =
442 lnk->wr_tx_dma_addr + i * SMC_WR_BUF_SIZE;
443 lnk->wr_tx_sges[i].length = SMC_WR_TX_SIZE;
bd4ad577 444 lnk->wr_tx_sges[i].lkey = lnk->roce_pd->local_dma_lkey;
f38ba179
UB
445 lnk->wr_tx_ibs[i].next = NULL;
446 lnk->wr_tx_ibs[i].sg_list = &lnk->wr_tx_sges[i];
447 lnk->wr_tx_ibs[i].num_sge = 1;
448 lnk->wr_tx_ibs[i].opcode = IB_WR_SEND;
449 lnk->wr_tx_ibs[i].send_flags =
2c9c1682 450 IB_SEND_SIGNALED | IB_SEND_SOLICITED;
f38ba179
UB
451 }
452 for (i = 0; i < lnk->wr_rx_cnt; i++) {
453 lnk->wr_rx_sges[i].addr =
454 lnk->wr_rx_dma_addr + i * SMC_WR_BUF_SIZE;
455 lnk->wr_rx_sges[i].length = SMC_WR_BUF_SIZE;
bd4ad577 456 lnk->wr_rx_sges[i].lkey = lnk->roce_pd->local_dma_lkey;
f38ba179
UB
457 lnk->wr_rx_ibs[i].next = NULL;
458 lnk->wr_rx_ibs[i].sg_list = &lnk->wr_rx_sges[i];
459 lnk->wr_rx_ibs[i].num_sge = 1;
460 }
461}
462
463void smc_wr_free_link(struct smc_link *lnk)
464{
465 struct ib_device *ibdev;
466
467 memset(lnk->wr_tx_mask, 0,
468 BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*lnk->wr_tx_mask));
469
470 if (!lnk->smcibdev)
471 return;
472 ibdev = lnk->smcibdev->ibdev;
473
474 if (lnk->wr_rx_dma_addr) {
475 ib_dma_unmap_single(ibdev, lnk->wr_rx_dma_addr,
476 SMC_WR_BUF_SIZE * lnk->wr_rx_cnt,
477 DMA_FROM_DEVICE);
478 lnk->wr_rx_dma_addr = 0;
479 }
480 if (lnk->wr_tx_dma_addr) {
481 ib_dma_unmap_single(ibdev, lnk->wr_tx_dma_addr,
482 SMC_WR_BUF_SIZE * lnk->wr_tx_cnt,
483 DMA_TO_DEVICE);
484 lnk->wr_tx_dma_addr = 0;
485 }
486}
487
488void smc_wr_free_link_mem(struct smc_link *lnk)
489{
490 kfree(lnk->wr_tx_pends);
491 lnk->wr_tx_pends = NULL;
492 kfree(lnk->wr_tx_mask);
493 lnk->wr_tx_mask = NULL;
494 kfree(lnk->wr_tx_sges);
495 lnk->wr_tx_sges = NULL;
496 kfree(lnk->wr_rx_sges);
497 lnk->wr_rx_sges = NULL;
498 kfree(lnk->wr_rx_ibs);
499 lnk->wr_rx_ibs = NULL;
500 kfree(lnk->wr_tx_ibs);
501 lnk->wr_tx_ibs = NULL;
502 kfree(lnk->wr_tx_bufs);
503 lnk->wr_tx_bufs = NULL;
504 kfree(lnk->wr_rx_bufs);
505 lnk->wr_rx_bufs = NULL;
506}
507
508int smc_wr_alloc_link_mem(struct smc_link *link)
509{
510 /* allocate link related memory */
511 link->wr_tx_bufs = kcalloc(SMC_WR_BUF_CNT, SMC_WR_BUF_SIZE, GFP_KERNEL);
512 if (!link->wr_tx_bufs)
513 goto no_mem;
514 link->wr_rx_bufs = kcalloc(SMC_WR_BUF_CNT * 3, SMC_WR_BUF_SIZE,
515 GFP_KERNEL);
516 if (!link->wr_rx_bufs)
517 goto no_mem_wr_tx_bufs;
518 link->wr_tx_ibs = kcalloc(SMC_WR_BUF_CNT, sizeof(link->wr_tx_ibs[0]),
519 GFP_KERNEL);
520 if (!link->wr_tx_ibs)
521 goto no_mem_wr_rx_bufs;
522 link->wr_rx_ibs = kcalloc(SMC_WR_BUF_CNT * 3,
523 sizeof(link->wr_rx_ibs[0]),
524 GFP_KERNEL);
525 if (!link->wr_rx_ibs)
526 goto no_mem_wr_tx_ibs;
527 link->wr_tx_sges = kcalloc(SMC_WR_BUF_CNT, sizeof(link->wr_tx_sges[0]),
528 GFP_KERNEL);
529 if (!link->wr_tx_sges)
530 goto no_mem_wr_rx_ibs;
531 link->wr_rx_sges = kcalloc(SMC_WR_BUF_CNT * 3,
532 sizeof(link->wr_rx_sges[0]),
533 GFP_KERNEL);
534 if (!link->wr_rx_sges)
535 goto no_mem_wr_tx_sges;
536 link->wr_tx_mask = kzalloc(
537 BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*link->wr_tx_mask),
538 GFP_KERNEL);
539 if (!link->wr_tx_mask)
540 goto no_mem_wr_rx_sges;
541 link->wr_tx_pends = kcalloc(SMC_WR_BUF_CNT,
542 sizeof(link->wr_tx_pends[0]),
543 GFP_KERNEL);
544 if (!link->wr_tx_pends)
545 goto no_mem_wr_tx_mask;
546 return 0;
547
548no_mem_wr_tx_mask:
549 kfree(link->wr_tx_mask);
550no_mem_wr_rx_sges:
551 kfree(link->wr_rx_sges);
552no_mem_wr_tx_sges:
553 kfree(link->wr_tx_sges);
554no_mem_wr_rx_ibs:
555 kfree(link->wr_rx_ibs);
556no_mem_wr_tx_ibs:
557 kfree(link->wr_tx_ibs);
558no_mem_wr_rx_bufs:
559 kfree(link->wr_rx_bufs);
560no_mem_wr_tx_bufs:
561 kfree(link->wr_tx_bufs);
562no_mem:
563 return -ENOMEM;
564}
565
566void smc_wr_remove_dev(struct smc_ib_device *smcibdev)
567{
568 tasklet_kill(&smcibdev->recv_tasklet);
569 tasklet_kill(&smcibdev->send_tasklet);
570}
571
572void smc_wr_add_dev(struct smc_ib_device *smcibdev)
573{
574 tasklet_init(&smcibdev->recv_tasklet, smc_wr_rx_tasklet_fn,
575 (unsigned long)smcibdev);
576 tasklet_init(&smcibdev->send_tasklet, smc_wr_tx_tasklet_fn,
577 (unsigned long)smcibdev);
578}
579
580int smc_wr_create_link(struct smc_link *lnk)
581{
582 struct ib_device *ibdev = lnk->smcibdev->ibdev;
583 int rc = 0;
584
585 smc_wr_tx_set_wr_id(&lnk->wr_tx_id, 0);
586 lnk->wr_rx_id = 0;
587 lnk->wr_rx_dma_addr = ib_dma_map_single(
588 ibdev, lnk->wr_rx_bufs, SMC_WR_BUF_SIZE * lnk->wr_rx_cnt,
589 DMA_FROM_DEVICE);
590 if (ib_dma_mapping_error(ibdev, lnk->wr_rx_dma_addr)) {
591 lnk->wr_rx_dma_addr = 0;
592 rc = -EIO;
593 goto out;
594 }
595 lnk->wr_tx_dma_addr = ib_dma_map_single(
596 ibdev, lnk->wr_tx_bufs, SMC_WR_BUF_SIZE * lnk->wr_tx_cnt,
597 DMA_TO_DEVICE);
598 if (ib_dma_mapping_error(ibdev, lnk->wr_tx_dma_addr)) {
599 rc = -EIO;
600 goto dma_unmap;
601 }
602 smc_wr_init_sge(lnk);
603 memset(lnk->wr_tx_mask, 0,
604 BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*lnk->wr_tx_mask));
605 return rc;
606
607dma_unmap:
608 ib_dma_unmap_single(ibdev, lnk->wr_rx_dma_addr,
609 SMC_WR_BUF_SIZE * lnk->wr_rx_cnt,
610 DMA_FROM_DEVICE);
611 lnk->wr_rx_dma_addr = 0;
612out:
613 return rc;
614}