9e0a556e40c8ce67411a40c68f72d5c691eeb38e
[platform/kernel/linux-rpi.git] / net / smc / smc_llc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Shared Memory Communications over RDMA (SMC-R) and RoCE
4  *
5  *  Link Layer Control (LLC)
6  *
7  *  For now, we only support the necessary "confirm link" functionality
8  *  which happens for the first RoCE link after successful CLC handshake.
9  *
10  *  Copyright IBM Corp. 2016
11  *
12  *  Author(s):  Klaus Wacker <Klaus.Wacker@de.ibm.com>
13  *              Ursula Braun <ubraun@linux.vnet.ibm.com>
14  */
15
16 #include <net/tcp.h>
17 #include <rdma/ib_verbs.h>
18
19 #include "smc.h"
20 #include "smc_core.h"
21 #include "smc_clc.h"
22 #include "smc_llc.h"
23
24 #define SMC_LLC_DATA_LEN                40
25
26 struct smc_llc_hdr {
27         struct smc_wr_rx_hdr common;
28         u8 length;      /* 44 */
29         u8 reserved;
30         u8 flags;
31 };
32
33 struct smc_llc_msg_confirm_link {       /* type 0x01 */
34         struct smc_llc_hdr hd;
35         u8 sender_mac[ETH_ALEN];
36         u8 sender_gid[SMC_GID_SIZE];
37         u8 sender_qp_num[3];
38         u8 link_num;
39         u8 link_uid[SMC_LGR_ID_SIZE];
40         u8 max_links;
41         u8 reserved[9];
42 };
43
44 struct smc_llc_msg_test_link {          /* type 0x07 */
45         struct smc_llc_hdr hd;
46         u8 user_data[16];
47         u8 reserved[24];
48 };
49
50 union smc_llc_msg {
51         struct smc_llc_msg_confirm_link confirm_link;
52         struct smc_llc_msg_test_link test_link;
53         struct {
54                 struct smc_llc_hdr hdr;
55                 u8 data[SMC_LLC_DATA_LEN];
56         } raw;
57 };
58
59 #define SMC_LLC_FLAG_RESP               0x80
60
61 /********************************** send *************************************/
62
63 struct smc_llc_tx_pend {
64 };
65
66 /* handler for send/transmission completion of an LLC msg */
67 static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend,
68                                struct smc_link *link,
69                                enum ib_wc_status wc_status)
70 {
71         /* future work: handle wc_status error for recovery and failover */
72 }
73
74 /**
75  * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits
76  * @link: Pointer to SMC link used for sending LLC control message.
77  * @wr_buf: Out variable returning pointer to work request payload buffer.
78  * @pend: Out variable returning pointer to private pending WR tracking.
79  *        It's the context the transmit complete handler will get.
80  *
81  * Reserves and pre-fills an entry for a pending work request send/tx.
82  * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx.
83  * Can sleep due to smc_get_ctrl_buf (if not in softirq context).
84  *
85  * Return: 0 on success, otherwise an error value.
86  */
87 static int smc_llc_add_pending_send(struct smc_link *link,
88                                     struct smc_wr_buf **wr_buf,
89                                     struct smc_wr_tx_pend_priv **pend)
90 {
91         int rc;
92
93         rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, pend);
94         if (rc < 0)
95                 return rc;
96         BUILD_BUG_ON_MSG(
97                 sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE,
98                 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)");
99         BUILD_BUG_ON_MSG(
100                 sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE,
101                 "must adapt SMC_WR_TX_SIZE to sizeof(struct smc_llc_msg); if not all smc_wr upper layer protocols use the same message size any more, must start to set link->wr_tx_sges[i].length on each individual smc_wr_tx_send()");
102         BUILD_BUG_ON_MSG(
103                 sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE,
104                 "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)");
105         return 0;
106 }
107
108 /* high-level API to send LLC confirm link */
109 int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[],
110                               union ib_gid *gid,
111                               enum smc_llc_reqresp reqresp)
112 {
113         struct smc_link_group *lgr = container_of(link, struct smc_link_group,
114                                                   lnk[SMC_SINGLE_LINK]);
115         struct smc_llc_msg_confirm_link *confllc;
116         struct smc_wr_tx_pend_priv *pend;
117         struct smc_wr_buf *wr_buf;
118         int rc;
119
120         rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
121         if (rc)
122                 return rc;
123         confllc = (struct smc_llc_msg_confirm_link *)wr_buf;
124         memset(confllc, 0, sizeof(*confllc));
125         confllc->hd.common.type = SMC_LLC_CONFIRM_LINK;
126         confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link);
127         if (reqresp == SMC_LLC_RESP)
128                 confllc->hd.flags |= SMC_LLC_FLAG_RESP;
129         memcpy(confllc->sender_mac, mac, ETH_ALEN);
130         memcpy(confllc->sender_gid, gid, SMC_GID_SIZE);
131         hton24(confllc->sender_qp_num, link->roce_qp->qp_num);
132         /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */
133         memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE);
134         confllc->max_links = SMC_LINKS_PER_LGR_MAX;
135         /* send llc message */
136         rc = smc_wr_tx_send(link, pend);
137         return rc;
138 }
139
140 /* send LLC test link request or response */
141 int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16],
142                            enum smc_llc_reqresp reqresp)
143 {
144         struct smc_llc_msg_test_link *testllc;
145         struct smc_wr_tx_pend_priv *pend;
146         struct smc_wr_buf *wr_buf;
147         int rc;
148
149         rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
150         if (rc)
151                 return rc;
152         testllc = (struct smc_llc_msg_test_link *)wr_buf;
153         memset(testllc, 0, sizeof(*testllc));
154         testllc->hd.common.type = SMC_LLC_TEST_LINK;
155         testllc->hd.length = sizeof(struct smc_llc_msg_test_link);
156         if (reqresp == SMC_LLC_RESP)
157                 testllc->hd.flags |= SMC_LLC_FLAG_RESP;
158         memcpy(testllc->user_data, user_data, sizeof(testllc->user_data));
159         /* send llc message */
160         rc = smc_wr_tx_send(link, pend);
161         return rc;
162 }
163
164 /********************************* receive ***********************************/
165
166 static void smc_llc_rx_confirm_link(struct smc_link *link,
167                                     struct smc_llc_msg_confirm_link *llc)
168 {
169         struct smc_link_group *lgr;
170
171         lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
172         if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
173                 if (lgr->role == SMC_SERV)
174                         complete(&link->llc_confirm_resp);
175         } else {
176                 if (lgr->role == SMC_CLNT) {
177                         link->link_id = llc->link_num;
178                         complete(&link->llc_confirm);
179                 }
180         }
181 }
182
183 static void smc_llc_rx_test_link(struct smc_link *link,
184                                  struct smc_llc_msg_test_link *llc)
185 {
186         if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
187                 /* unused as long as we don't send this type of msg */
188         } else {
189                 smc_llc_send_test_link(link, llc->user_data, SMC_LLC_RESP);
190         }
191 }
192
193 static void smc_llc_rx_handler(struct ib_wc *wc, void *buf)
194 {
195         struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
196         union smc_llc_msg *llc = buf;
197
198         if (wc->byte_len < sizeof(*llc))
199                 return; /* short message */
200         if (llc->raw.hdr.length != sizeof(*llc))
201                 return; /* invalid message */
202
203         switch (llc->raw.hdr.common.type) {
204         case SMC_LLC_TEST_LINK:
205                 smc_llc_rx_test_link(link, &llc->test_link);
206                 break;
207         case SMC_LLC_CONFIRM_LINK:
208                 smc_llc_rx_confirm_link(link, &llc->confirm_link);
209                 break;
210         }
211 }
212
213 /***************************** init, exit, misc ******************************/
214
215 static struct smc_wr_rx_handler smc_llc_rx_handlers[] = {
216         {
217                 .handler        = smc_llc_rx_handler,
218                 .type           = SMC_LLC_CONFIRM_LINK
219         },
220         {
221                 .handler        = smc_llc_rx_handler,
222                 .type           = SMC_LLC_TEST_LINK
223         },
224         {
225                 .handler        = NULL,
226         }
227 };
228
229 int __init smc_llc_init(void)
230 {
231         struct smc_wr_rx_handler *handler;
232         int rc = 0;
233
234         for (handler = smc_llc_rx_handlers; handler->handler; handler++) {
235                 INIT_HLIST_NODE(&handler->list);
236                 rc = smc_wr_rx_register_handler(handler);
237                 if (rc)
238                         break;
239         }
240         return rc;
241 }