blob: 619dd89fbac08e135a341728dd4d974090f23f17 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Ursula Braunf38ba1792017-01-09 16:55:19 +01002/*
3 * Shared Memory Communications over RDMA (SMC-R) and RoCE
4 *
5 * Work Requests exploiting Infiniband API
6 *
7 * Work requests (WR) of type ib_post_send or ib_post_recv respectively
8 * are submitted to either RC SQ or RC RQ respectively
9 * (reliably connected send/receive queue)
10 * and become work queue entries (WQEs).
11 * While an SQ WR/WQE is pending, we track it until transmission completion.
12 * Through a send or receive completion queue (CQ) respectively,
13 * we get completion queue entries (CQEs) [aka work completions (WCs)].
14 * Since the CQ callback is called from IRQ context, we split work by using
15 * bottom halves implemented by tasklets.
16 *
17 * SMC uses this to exchange LLC (link layer control)
18 * and CDC (connection data control) messages.
19 *
20 * Copyright IBM Corp. 2016
21 *
22 * Author(s): Steffen Maier <maier@linux.vnet.ibm.com>
23 */
24
25#include <linux/atomic.h>
26#include <linux/hashtable.h>
27#include <linux/wait.h>
28#include <rdma/ib_verbs.h>
29#include <asm/div64.h>
30
31#include "smc.h"
32#include "smc_wr.h"
33
34#define SMC_WR_MAX_POLL_CQE 10 /* max. # of compl. queue elements in 1 poll */
35
36#define SMC_WR_RX_HASH_BITS 4
37static DEFINE_HASHTABLE(smc_wr_rx_hash, SMC_WR_RX_HASH_BITS);
38static DEFINE_SPINLOCK(smc_wr_rx_hash_lock);
39
40struct smc_wr_tx_pend { /* control data for a pending send request */
41 u64 wr_id; /* work request id sent */
42 smc_wr_tx_handler handler;
43 enum ib_wc_status wc_status; /* CQE status */
44 struct smc_link *link;
45 u32 idx;
46 struct smc_wr_tx_pend_priv priv;
47};
48
49/******************************** send queue *********************************/
50
51/*------------------------------- completion --------------------------------*/
52
53static inline int smc_wr_tx_find_pending_index(struct smc_link *link, u64 wr_id)
54{
55 u32 i;
56
57 for (i = 0; i < link->wr_tx_cnt; i++) {
58 if (link->wr_tx_pends[i].wr_id == wr_id)
59 return i;
60 }
61 return link->wr_tx_cnt;
62}
63
64static inline void smc_wr_tx_process_cqe(struct ib_wc *wc)
65{
66 struct smc_wr_tx_pend pnd_snd;
67 struct smc_link *link;
68 u32 pnd_snd_idx;
69 int i;
70
71 link = wc->qp->qp_context;
Ursula Braun652a1e42017-07-28 13:56:17 +020072
73 if (wc->opcode == IB_WC_REG_MR) {
74 if (wc->status)
75 link->wr_reg_state = FAILED;
76 else
77 link->wr_reg_state = CONFIRMED;
Ursula Braun15e1b992019-11-14 13:02:44 +010078 smc_wr_wakeup_reg_wait(link);
Ursula Braun652a1e42017-07-28 13:56:17 +020079 return;
80 }
81
Ursula Braunf38ba1792017-01-09 16:55:19 +010082 pnd_snd_idx = smc_wr_tx_find_pending_index(link, wc->wr_id);
83 if (pnd_snd_idx == link->wr_tx_cnt)
84 return;
85 link->wr_tx_pends[pnd_snd_idx].wc_status = wc->status;
86 memcpy(&pnd_snd, &link->wr_tx_pends[pnd_snd_idx], sizeof(pnd_snd));
87 /* clear the full struct smc_wr_tx_pend including .priv */
88 memset(&link->wr_tx_pends[pnd_snd_idx], 0,
89 sizeof(link->wr_tx_pends[pnd_snd_idx]));
90 memset(&link->wr_tx_bufs[pnd_snd_idx], 0,
91 sizeof(link->wr_tx_bufs[pnd_snd_idx]));
92 if (!test_and_clear_bit(pnd_snd_idx, link->wr_tx_mask))
93 return;
94 if (wc->status) {
95 for_each_set_bit(i, link->wr_tx_mask, link->wr_tx_cnt) {
96 /* clear full struct smc_wr_tx_pend including .priv */
97 memset(&link->wr_tx_pends[i], 0,
98 sizeof(link->wr_tx_pends[i]));
99 memset(&link->wr_tx_bufs[i], 0,
100 sizeof(link->wr_tx_bufs[i]));
101 clear_bit(i, link->wr_tx_mask);
102 }
Ursula Braunb38d7322017-01-09 16:55:25 +0100103 /* terminate connections of this link group abnormally */
Ursula Braunf528ba22019-10-21 16:13:14 +0200104 smc_lgr_terminate_sched(smc_get_lgr(link));
Ursula Braunf38ba1792017-01-09 16:55:19 +0100105 }
106 if (pnd_snd.handler)
107 pnd_snd.handler(&pnd_snd.priv, link, wc->status);
108 wake_up(&link->wr_tx_wait);
109}
110
111static void smc_wr_tx_tasklet_fn(unsigned long data)
112{
113 struct smc_ib_device *dev = (struct smc_ib_device *)data;
114 struct ib_wc wc[SMC_WR_MAX_POLL_CQE];
115 int i = 0, rc;
116 int polled = 0;
117
118again:
119 polled++;
120 do {
Ursula Braun86e780d2018-01-24 10:28:15 +0100121 memset(&wc, 0, sizeof(wc));
Ursula Braunf38ba1792017-01-09 16:55:19 +0100122 rc = ib_poll_cq(dev->roce_cq_send, SMC_WR_MAX_POLL_CQE, wc);
123 if (polled == 1) {
124 ib_req_notify_cq(dev->roce_cq_send,
125 IB_CQ_NEXT_COMP |
126 IB_CQ_REPORT_MISSED_EVENTS);
127 }
128 if (!rc)
129 break;
130 for (i = 0; i < rc; i++)
131 smc_wr_tx_process_cqe(&wc[i]);
132 } while (rc > 0);
133 if (polled == 1)
134 goto again;
135}
136
137void smc_wr_tx_cq_handler(struct ib_cq *ib_cq, void *cq_context)
138{
139 struct smc_ib_device *dev = (struct smc_ib_device *)cq_context;
140
141 tasklet_schedule(&dev->send_tasklet);
142}
143
144/*---------------------------- request submission ---------------------------*/
145
146static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx)
147{
148 *idx = link->wr_tx_cnt;
149 for_each_clear_bit(*idx, link->wr_tx_mask, link->wr_tx_cnt) {
150 if (!test_and_set_bit(*idx, link->wr_tx_mask))
151 return 0;
152 }
153 *idx = link->wr_tx_cnt;
154 return -EBUSY;
155}
156
157/**
158 * smc_wr_tx_get_free_slot() - returns buffer for message assembly,
159 * and sets info for pending transmit tracking
160 * @link: Pointer to smc_link used to later send the message.
161 * @handler: Send completion handler function pointer.
162 * @wr_buf: Out value returns pointer to message buffer.
Ursula Braunad6f3172019-02-04 13:44:44 +0100163 * @wr_rdma_buf: Out value returns pointer to rdma work request.
Ursula Braunf38ba1792017-01-09 16:55:19 +0100164 * @wr_pend_priv: Out value returns pointer serving as handler context.
165 *
166 * Return: 0 on success, or -errno on error.
167 */
168int smc_wr_tx_get_free_slot(struct smc_link *link,
169 smc_wr_tx_handler handler,
170 struct smc_wr_buf **wr_buf,
Ursula Braunad6f3172019-02-04 13:44:44 +0100171 struct smc_rdma_wr **wr_rdma_buf,
Ursula Braunf38ba1792017-01-09 16:55:19 +0100172 struct smc_wr_tx_pend_priv **wr_pend_priv)
173{
Ursula Braun15e1b992019-11-14 13:02:44 +0100174 struct smc_link_group *lgr = smc_get_lgr(link);
Ursula Braunf38ba1792017-01-09 16:55:19 +0100175 struct smc_wr_tx_pend *wr_pend;
Ursula Braun1a0a04c2018-01-25 11:15:36 +0100176 u32 idx = link->wr_tx_cnt;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100177 struct ib_send_wr *wr_ib;
178 u64 wr_id;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100179 int rc;
180
181 *wr_buf = NULL;
182 *wr_pend_priv = NULL;
Ursula Braun15e1b992019-11-14 13:02:44 +0100183 if (in_softirq() || lgr->terminating) {
Ursula Braunf38ba1792017-01-09 16:55:19 +0100184 rc = smc_wr_tx_get_free_slot_index(link, &idx);
185 if (rc)
186 return rc;
187 } else {
Ursula Braun15e1b992019-11-14 13:02:44 +0100188 rc = wait_event_interruptible_timeout(
Ursula Braunf38ba1792017-01-09 16:55:19 +0100189 link->wr_tx_wait,
Karsten Graul0d18a0cb2018-07-25 16:35:33 +0200190 link->state == SMC_LNK_INACTIVE ||
Ursula Braun15e1b992019-11-14 13:02:44 +0100191 lgr->terminating ||
Ursula Braunf38ba1792017-01-09 16:55:19 +0100192 (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
193 SMC_WR_TX_WAIT_FREE_SLOT_TIME);
194 if (!rc) {
Ursula Braunb38d7322017-01-09 16:55:25 +0100195 /* timeout - terminate connections */
Ursula Braun15e1b992019-11-14 13:02:44 +0100196 smc_lgr_terminate_sched(lgr);
Ursula Braunf38ba1792017-01-09 16:55:19 +0100197 return -EPIPE;
198 }
Ursula Braunf38ba1792017-01-09 16:55:19 +0100199 if (idx == link->wr_tx_cnt)
200 return -EPIPE;
201 }
202 wr_id = smc_wr_tx_get_next_wr_id(link);
203 wr_pend = &link->wr_tx_pends[idx];
204 wr_pend->wr_id = wr_id;
205 wr_pend->handler = handler;
206 wr_pend->link = link;
207 wr_pend->idx = idx;
208 wr_ib = &link->wr_tx_ibs[idx];
209 wr_ib->wr_id = wr_id;
210 *wr_buf = &link->wr_tx_bufs[idx];
Ursula Braunad6f3172019-02-04 13:44:44 +0100211 if (wr_rdma_buf)
212 *wr_rdma_buf = &link->wr_tx_rdmas[idx];
Ursula Braunf38ba1792017-01-09 16:55:19 +0100213 *wr_pend_priv = &wr_pend->priv;
214 return 0;
215}
216
217int smc_wr_tx_put_slot(struct smc_link *link,
218 struct smc_wr_tx_pend_priv *wr_pend_priv)
219{
220 struct smc_wr_tx_pend *pend;
221
222 pend = container_of(wr_pend_priv, struct smc_wr_tx_pend, priv);
223 if (pend->idx < link->wr_tx_cnt) {
Ursula Braune438bae2018-11-20 16:46:43 +0100224 u32 idx = pend->idx;
225
Ursula Braunf38ba1792017-01-09 16:55:19 +0100226 /* clear the full struct smc_wr_tx_pend including .priv */
Karsten Graul46ad0222019-01-30 18:51:08 +0100227 memset(&link->wr_tx_pends[idx], 0,
228 sizeof(link->wr_tx_pends[idx]));
229 memset(&link->wr_tx_bufs[idx], 0,
230 sizeof(link->wr_tx_bufs[idx]));
Ursula Braune438bae2018-11-20 16:46:43 +0100231 test_and_clear_bit(idx, link->wr_tx_mask);
Ursula Braunf38ba1792017-01-09 16:55:19 +0100232 return 1;
233 }
234
235 return 0;
236}
237
238/* Send prepared WR slot via ib_post_send.
239 * @priv: pointer to smc_wr_tx_pend_priv identifying prepared message buffer
240 */
241int smc_wr_tx_send(struct smc_link *link, struct smc_wr_tx_pend_priv *priv)
242{
Ursula Braunf38ba1792017-01-09 16:55:19 +0100243 struct smc_wr_tx_pend *pend;
244 int rc;
245
246 ib_req_notify_cq(link->smcibdev->roce_cq_send,
Ursula Braun8301fa42017-09-21 09:16:30 +0200247 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
Ursula Braunf38ba1792017-01-09 16:55:19 +0100248 pend = container_of(priv, struct smc_wr_tx_pend, priv);
Bart Van Assche2e3bbe42018-07-18 09:25:30 -0700249 rc = ib_post_send(link->roce_qp, &link->wr_tx_ibs[pend->idx], NULL);
Ursula Braunb4772b32018-01-25 11:15:33 +0100250 if (rc) {
Ursula Braunf38ba1792017-01-09 16:55:19 +0100251 smc_wr_tx_put_slot(link, priv);
Ursula Braunf528ba22019-10-21 16:13:14 +0200252 smc_lgr_terminate_sched(smc_get_lgr(link));
Ursula Braunb4772b32018-01-25 11:15:33 +0100253 }
Ursula Braunf38ba1792017-01-09 16:55:19 +0100254 return rc;
255}
256
Ursula Braun652a1e42017-07-28 13:56:17 +0200257/* Register a memory region and wait for result. */
258int smc_wr_reg_send(struct smc_link *link, struct ib_mr *mr)
259{
Ursula Braun652a1e42017-07-28 13:56:17 +0200260 int rc;
261
262 ib_req_notify_cq(link->smcibdev->roce_cq_send,
263 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
264 link->wr_reg_state = POSTED;
265 link->wr_reg.wr.wr_id = (u64)(uintptr_t)mr;
266 link->wr_reg.mr = mr;
267 link->wr_reg.key = mr->rkey;
Bart Van Assche2e3bbe42018-07-18 09:25:30 -0700268 rc = ib_post_send(link->roce_qp, &link->wr_reg.wr, NULL);
Ursula Braun652a1e42017-07-28 13:56:17 +0200269 if (rc)
270 return rc;
271
272 rc = wait_event_interruptible_timeout(link->wr_reg_wait,
273 (link->wr_reg_state != POSTED),
274 SMC_WR_REG_MR_WAIT_TIME);
275 if (!rc) {
276 /* timeout - terminate connections */
Ursula Braunf528ba22019-10-21 16:13:14 +0200277 smc_lgr_terminate_sched(smc_get_lgr(link));
Ursula Braun652a1e42017-07-28 13:56:17 +0200278 return -EPIPE;
279 }
280 if (rc == -ERESTARTSYS)
281 return -EINTR;
282 switch (link->wr_reg_state) {
283 case CONFIRMED:
284 rc = 0;
285 break;
286 case FAILED:
287 rc = -EIO;
288 break;
289 case POSTED:
290 rc = -EPIPE;
291 break;
292 }
293 return rc;
294}
295
Ursula Braun86e780d2018-01-24 10:28:15 +0100296void smc_wr_tx_dismiss_slots(struct smc_link *link, u8 wr_tx_hdr_type,
Ursula Braun5f083182017-01-09 16:55:22 +0100297 smc_wr_tx_filter filter,
298 smc_wr_tx_dismisser dismisser,
299 unsigned long data)
300{
301 struct smc_wr_tx_pend_priv *tx_pend;
Ursula Braun86e780d2018-01-24 10:28:15 +0100302 struct smc_wr_rx_hdr *wr_tx;
Ursula Braun5f083182017-01-09 16:55:22 +0100303 int i;
304
305 for_each_set_bit(i, link->wr_tx_mask, link->wr_tx_cnt) {
Ursula Braun86e780d2018-01-24 10:28:15 +0100306 wr_tx = (struct smc_wr_rx_hdr *)&link->wr_tx_bufs[i];
307 if (wr_tx->type != wr_tx_hdr_type)
Ursula Braun5f083182017-01-09 16:55:22 +0100308 continue;
309 tx_pend = &link->wr_tx_pends[i].priv;
310 if (filter(tx_pend, data))
311 dismisser(tx_pend);
312 }
313}
314
Ursula Braunf38ba1792017-01-09 16:55:19 +0100315/****************************** receive queue ********************************/
316
317int smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler)
318{
319 struct smc_wr_rx_handler *h_iter;
320 int rc = 0;
321
322 spin_lock(&smc_wr_rx_hash_lock);
323 hash_for_each_possible(smc_wr_rx_hash, h_iter, list, handler->type) {
324 if (h_iter->type == handler->type) {
325 rc = -EEXIST;
326 goto out_unlock;
327 }
328 }
329 hash_add(smc_wr_rx_hash, &handler->list, handler->type);
330out_unlock:
331 spin_unlock(&smc_wr_rx_hash_lock);
332 return rc;
333}
334
335/* Demultiplex a received work request based on the message type to its handler.
336 * Relies on smc_wr_rx_hash having been completely filled before any IB WRs,
337 * and not being modified any more afterwards so we don't need to lock it.
338 */
339static inline void smc_wr_rx_demultiplex(struct ib_wc *wc)
340{
341 struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
342 struct smc_wr_rx_handler *handler;
343 struct smc_wr_rx_hdr *wr_rx;
344 u64 temp_wr_id;
345 u32 index;
346
347 if (wc->byte_len < sizeof(*wr_rx))
348 return; /* short message */
349 temp_wr_id = wc->wr_id;
350 index = do_div(temp_wr_id, link->wr_rx_cnt);
351 wr_rx = (struct smc_wr_rx_hdr *)&link->wr_rx_bufs[index];
352 hash_for_each_possible(smc_wr_rx_hash, handler, list, wr_rx->type) {
353 if (handler->type == wr_rx->type)
354 handler->handler(wc, wr_rx);
355 }
356}
357
358static inline void smc_wr_rx_process_cqes(struct ib_wc wc[], int num)
359{
360 struct smc_link *link;
361 int i;
362
363 for (i = 0; i < num; i++) {
364 link = wc[i].qp->qp_context;
365 if (wc[i].status == IB_WC_SUCCESS) {
Karsten Graul877ae5b2018-05-02 16:56:44 +0200366 link->wr_rx_tstamp = jiffies;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100367 smc_wr_rx_demultiplex(&wc[i]);
368 smc_wr_rx_post(link); /* refill WR RX */
369 } else {
370 /* handle status errors */
371 switch (wc[i].status) {
372 case IB_WC_RETRY_EXC_ERR:
373 case IB_WC_RNR_RETRY_EXC_ERR:
374 case IB_WC_WR_FLUSH_ERR:
Ursula Braunb38d7322017-01-09 16:55:25 +0100375 /* terminate connections of this link group
376 * abnormally
377 */
Ursula Braunf528ba22019-10-21 16:13:14 +0200378 smc_lgr_terminate_sched(smc_get_lgr(link));
Ursula Braunf38ba1792017-01-09 16:55:19 +0100379 break;
380 default:
381 smc_wr_rx_post(link); /* refill WR RX */
382 break;
383 }
384 }
385 }
386}
387
388static void smc_wr_rx_tasklet_fn(unsigned long data)
389{
390 struct smc_ib_device *dev = (struct smc_ib_device *)data;
391 struct ib_wc wc[SMC_WR_MAX_POLL_CQE];
392 int polled = 0;
393 int rc;
394
395again:
396 polled++;
397 do {
398 memset(&wc, 0, sizeof(wc));
399 rc = ib_poll_cq(dev->roce_cq_recv, SMC_WR_MAX_POLL_CQE, wc);
400 if (polled == 1) {
401 ib_req_notify_cq(dev->roce_cq_recv,
402 IB_CQ_SOLICITED_MASK
403 | IB_CQ_REPORT_MISSED_EVENTS);
404 }
405 if (!rc)
406 break;
407 smc_wr_rx_process_cqes(&wc[0], rc);
408 } while (rc > 0);
409 if (polled == 1)
410 goto again;
411}
412
413void smc_wr_rx_cq_handler(struct ib_cq *ib_cq, void *cq_context)
414{
415 struct smc_ib_device *dev = (struct smc_ib_device *)cq_context;
416
417 tasklet_schedule(&dev->recv_tasklet);
418}
419
420int smc_wr_rx_post_init(struct smc_link *link)
421{
422 u32 i;
423 int rc = 0;
424
425 for (i = 0; i < link->wr_rx_cnt; i++)
426 rc = smc_wr_rx_post(link);
427 return rc;
428}
429
430/***************************** init, exit, misc ******************************/
431
432void smc_wr_remember_qp_attr(struct smc_link *lnk)
433{
434 struct ib_qp_attr *attr = &lnk->qp_attr;
435 struct ib_qp_init_attr init_attr;
436
437 memset(attr, 0, sizeof(*attr));
438 memset(&init_attr, 0, sizeof(init_attr));
439 ib_query_qp(lnk->roce_qp, attr,
440 IB_QP_STATE |
441 IB_QP_CUR_STATE |
442 IB_QP_PKEY_INDEX |
443 IB_QP_PORT |
444 IB_QP_QKEY |
445 IB_QP_AV |
446 IB_QP_PATH_MTU |
447 IB_QP_TIMEOUT |
448 IB_QP_RETRY_CNT |
449 IB_QP_RNR_RETRY |
450 IB_QP_RQ_PSN |
451 IB_QP_ALT_PATH |
452 IB_QP_MIN_RNR_TIMER |
453 IB_QP_SQ_PSN |
454 IB_QP_PATH_MIG_STATE |
455 IB_QP_CAP |
456 IB_QP_DEST_QPN,
457 &init_attr);
458
459 lnk->wr_tx_cnt = min_t(size_t, SMC_WR_BUF_CNT,
460 lnk->qp_attr.cap.max_send_wr);
461 lnk->wr_rx_cnt = min_t(size_t, SMC_WR_BUF_CNT * 3,
462 lnk->qp_attr.cap.max_recv_wr);
463}
464
465static void smc_wr_init_sge(struct smc_link *lnk)
466{
467 u32 i;
468
469 for (i = 0; i < lnk->wr_tx_cnt; i++) {
470 lnk->wr_tx_sges[i].addr =
471 lnk->wr_tx_dma_addr + i * SMC_WR_BUF_SIZE;
472 lnk->wr_tx_sges[i].length = SMC_WR_TX_SIZE;
Ursula Braunbd4ad572017-01-09 16:55:20 +0100473 lnk->wr_tx_sges[i].lkey = lnk->roce_pd->local_dma_lkey;
Ursula Braunad6f3172019-02-04 13:44:44 +0100474 lnk->wr_tx_rdma_sges[i].tx_rdma_sge[0].wr_tx_rdma_sge[0].lkey =
475 lnk->roce_pd->local_dma_lkey;
476 lnk->wr_tx_rdma_sges[i].tx_rdma_sge[0].wr_tx_rdma_sge[1].lkey =
477 lnk->roce_pd->local_dma_lkey;
478 lnk->wr_tx_rdma_sges[i].tx_rdma_sge[1].wr_tx_rdma_sge[0].lkey =
479 lnk->roce_pd->local_dma_lkey;
480 lnk->wr_tx_rdma_sges[i].tx_rdma_sge[1].wr_tx_rdma_sge[1].lkey =
481 lnk->roce_pd->local_dma_lkey;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100482 lnk->wr_tx_ibs[i].next = NULL;
483 lnk->wr_tx_ibs[i].sg_list = &lnk->wr_tx_sges[i];
484 lnk->wr_tx_ibs[i].num_sge = 1;
485 lnk->wr_tx_ibs[i].opcode = IB_WR_SEND;
486 lnk->wr_tx_ibs[i].send_flags =
Ursula Braun2c9c1682017-04-10 14:58:05 +0200487 IB_SEND_SIGNALED | IB_SEND_SOLICITED;
Ursula Braunad6f3172019-02-04 13:44:44 +0100488 lnk->wr_tx_rdmas[i].wr_tx_rdma[0].wr.opcode = IB_WR_RDMA_WRITE;
489 lnk->wr_tx_rdmas[i].wr_tx_rdma[1].wr.opcode = IB_WR_RDMA_WRITE;
490 lnk->wr_tx_rdmas[i].wr_tx_rdma[0].wr.sg_list =
491 lnk->wr_tx_rdma_sges[i].tx_rdma_sge[0].wr_tx_rdma_sge;
492 lnk->wr_tx_rdmas[i].wr_tx_rdma[1].wr.sg_list =
493 lnk->wr_tx_rdma_sges[i].tx_rdma_sge[1].wr_tx_rdma_sge;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100494 }
495 for (i = 0; i < lnk->wr_rx_cnt; i++) {
496 lnk->wr_rx_sges[i].addr =
497 lnk->wr_rx_dma_addr + i * SMC_WR_BUF_SIZE;
498 lnk->wr_rx_sges[i].length = SMC_WR_BUF_SIZE;
Ursula Braunbd4ad572017-01-09 16:55:20 +0100499 lnk->wr_rx_sges[i].lkey = lnk->roce_pd->local_dma_lkey;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100500 lnk->wr_rx_ibs[i].next = NULL;
501 lnk->wr_rx_ibs[i].sg_list = &lnk->wr_rx_sges[i];
502 lnk->wr_rx_ibs[i].num_sge = 1;
503 }
Ursula Braun652a1e42017-07-28 13:56:17 +0200504 lnk->wr_reg.wr.next = NULL;
505 lnk->wr_reg.wr.num_sge = 0;
506 lnk->wr_reg.wr.send_flags = IB_SEND_SIGNALED;
507 lnk->wr_reg.wr.opcode = IB_WR_REG_MR;
508 lnk->wr_reg.access = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100509}
510
511void smc_wr_free_link(struct smc_link *lnk)
512{
513 struct ib_device *ibdev;
514
515 memset(lnk->wr_tx_mask, 0,
516 BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*lnk->wr_tx_mask));
517
518 if (!lnk->smcibdev)
519 return;
520 ibdev = lnk->smcibdev->ibdev;
521
522 if (lnk->wr_rx_dma_addr) {
523 ib_dma_unmap_single(ibdev, lnk->wr_rx_dma_addr,
524 SMC_WR_BUF_SIZE * lnk->wr_rx_cnt,
525 DMA_FROM_DEVICE);
526 lnk->wr_rx_dma_addr = 0;
527 }
528 if (lnk->wr_tx_dma_addr) {
529 ib_dma_unmap_single(ibdev, lnk->wr_tx_dma_addr,
530 SMC_WR_BUF_SIZE * lnk->wr_tx_cnt,
531 DMA_TO_DEVICE);
532 lnk->wr_tx_dma_addr = 0;
533 }
534}
535
536void smc_wr_free_link_mem(struct smc_link *lnk)
537{
538 kfree(lnk->wr_tx_pends);
539 lnk->wr_tx_pends = NULL;
540 kfree(lnk->wr_tx_mask);
541 lnk->wr_tx_mask = NULL;
542 kfree(lnk->wr_tx_sges);
543 lnk->wr_tx_sges = NULL;
Ursula Braunad6f3172019-02-04 13:44:44 +0100544 kfree(lnk->wr_tx_rdma_sges);
545 lnk->wr_tx_rdma_sges = NULL;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100546 kfree(lnk->wr_rx_sges);
547 lnk->wr_rx_sges = NULL;
Ursula Braunad6f3172019-02-04 13:44:44 +0100548 kfree(lnk->wr_tx_rdmas);
549 lnk->wr_tx_rdmas = NULL;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100550 kfree(lnk->wr_rx_ibs);
551 lnk->wr_rx_ibs = NULL;
552 kfree(lnk->wr_tx_ibs);
553 lnk->wr_tx_ibs = NULL;
554 kfree(lnk->wr_tx_bufs);
555 lnk->wr_tx_bufs = NULL;
556 kfree(lnk->wr_rx_bufs);
557 lnk->wr_rx_bufs = NULL;
558}
559
560int smc_wr_alloc_link_mem(struct smc_link *link)
561{
562 /* allocate link related memory */
563 link->wr_tx_bufs = kcalloc(SMC_WR_BUF_CNT, SMC_WR_BUF_SIZE, GFP_KERNEL);
564 if (!link->wr_tx_bufs)
565 goto no_mem;
566 link->wr_rx_bufs = kcalloc(SMC_WR_BUF_CNT * 3, SMC_WR_BUF_SIZE,
567 GFP_KERNEL);
568 if (!link->wr_rx_bufs)
569 goto no_mem_wr_tx_bufs;
570 link->wr_tx_ibs = kcalloc(SMC_WR_BUF_CNT, sizeof(link->wr_tx_ibs[0]),
571 GFP_KERNEL);
572 if (!link->wr_tx_ibs)
573 goto no_mem_wr_rx_bufs;
574 link->wr_rx_ibs = kcalloc(SMC_WR_BUF_CNT * 3,
575 sizeof(link->wr_rx_ibs[0]),
576 GFP_KERNEL);
577 if (!link->wr_rx_ibs)
578 goto no_mem_wr_tx_ibs;
Ursula Braunad6f3172019-02-04 13:44:44 +0100579 link->wr_tx_rdmas = kcalloc(SMC_WR_BUF_CNT,
580 sizeof(link->wr_tx_rdmas[0]),
581 GFP_KERNEL);
582 if (!link->wr_tx_rdmas)
583 goto no_mem_wr_rx_ibs;
584 link->wr_tx_rdma_sges = kcalloc(SMC_WR_BUF_CNT,
585 sizeof(link->wr_tx_rdma_sges[0]),
586 GFP_KERNEL);
587 if (!link->wr_tx_rdma_sges)
588 goto no_mem_wr_tx_rdmas;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100589 link->wr_tx_sges = kcalloc(SMC_WR_BUF_CNT, sizeof(link->wr_tx_sges[0]),
590 GFP_KERNEL);
591 if (!link->wr_tx_sges)
Ursula Braunad6f3172019-02-04 13:44:44 +0100592 goto no_mem_wr_tx_rdma_sges;
Ursula Braunf38ba1792017-01-09 16:55:19 +0100593 link->wr_rx_sges = kcalloc(SMC_WR_BUF_CNT * 3,
594 sizeof(link->wr_rx_sges[0]),
595 GFP_KERNEL);
596 if (!link->wr_rx_sges)
597 goto no_mem_wr_tx_sges;
Kees Cook6396bb22018-06-12 14:03:40 -0700598 link->wr_tx_mask = kcalloc(BITS_TO_LONGS(SMC_WR_BUF_CNT),
599 sizeof(*link->wr_tx_mask),
600 GFP_KERNEL);
Ursula Braunf38ba1792017-01-09 16:55:19 +0100601 if (!link->wr_tx_mask)
602 goto no_mem_wr_rx_sges;
603 link->wr_tx_pends = kcalloc(SMC_WR_BUF_CNT,
604 sizeof(link->wr_tx_pends[0]),
605 GFP_KERNEL);
606 if (!link->wr_tx_pends)
607 goto no_mem_wr_tx_mask;
608 return 0;
609
610no_mem_wr_tx_mask:
611 kfree(link->wr_tx_mask);
612no_mem_wr_rx_sges:
613 kfree(link->wr_rx_sges);
614no_mem_wr_tx_sges:
615 kfree(link->wr_tx_sges);
Ursula Braunad6f3172019-02-04 13:44:44 +0100616no_mem_wr_tx_rdma_sges:
617 kfree(link->wr_tx_rdma_sges);
618no_mem_wr_tx_rdmas:
619 kfree(link->wr_tx_rdmas);
Ursula Braunf38ba1792017-01-09 16:55:19 +0100620no_mem_wr_rx_ibs:
621 kfree(link->wr_rx_ibs);
622no_mem_wr_tx_ibs:
623 kfree(link->wr_tx_ibs);
624no_mem_wr_rx_bufs:
625 kfree(link->wr_rx_bufs);
626no_mem_wr_tx_bufs:
627 kfree(link->wr_tx_bufs);
628no_mem:
629 return -ENOMEM;
630}
631
632void smc_wr_remove_dev(struct smc_ib_device *smcibdev)
633{
634 tasklet_kill(&smcibdev->recv_tasklet);
635 tasklet_kill(&smcibdev->send_tasklet);
636}
637
638void smc_wr_add_dev(struct smc_ib_device *smcibdev)
639{
640 tasklet_init(&smcibdev->recv_tasklet, smc_wr_rx_tasklet_fn,
641 (unsigned long)smcibdev);
642 tasklet_init(&smcibdev->send_tasklet, smc_wr_tx_tasklet_fn,
643 (unsigned long)smcibdev);
644}
645
646int smc_wr_create_link(struct smc_link *lnk)
647{
648 struct ib_device *ibdev = lnk->smcibdev->ibdev;
649 int rc = 0;
650
651 smc_wr_tx_set_wr_id(&lnk->wr_tx_id, 0);
652 lnk->wr_rx_id = 0;
653 lnk->wr_rx_dma_addr = ib_dma_map_single(
654 ibdev, lnk->wr_rx_bufs, SMC_WR_BUF_SIZE * lnk->wr_rx_cnt,
655 DMA_FROM_DEVICE);
656 if (ib_dma_mapping_error(ibdev, lnk->wr_rx_dma_addr)) {
657 lnk->wr_rx_dma_addr = 0;
658 rc = -EIO;
659 goto out;
660 }
661 lnk->wr_tx_dma_addr = ib_dma_map_single(
662 ibdev, lnk->wr_tx_bufs, SMC_WR_BUF_SIZE * lnk->wr_tx_cnt,
663 DMA_TO_DEVICE);
664 if (ib_dma_mapping_error(ibdev, lnk->wr_tx_dma_addr)) {
665 rc = -EIO;
666 goto dma_unmap;
667 }
668 smc_wr_init_sge(lnk);
669 memset(lnk->wr_tx_mask, 0,
670 BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*lnk->wr_tx_mask));
Ursula Braun652a1e42017-07-28 13:56:17 +0200671 init_waitqueue_head(&lnk->wr_tx_wait);
672 init_waitqueue_head(&lnk->wr_reg_wait);
Ursula Braunf38ba1792017-01-09 16:55:19 +0100673 return rc;
674
675dma_unmap:
676 ib_dma_unmap_single(ibdev, lnk->wr_rx_dma_addr,
677 SMC_WR_BUF_SIZE * lnk->wr_rx_cnt,
678 DMA_FROM_DEVICE);
679 lnk->wr_rx_dma_addr = 0;
680out:
681 return rc;
682}