1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Shared Memory Communications over RDMA (SMC-R) and RoCE
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Connection Data Control (CDC)
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright IBM Corp. 2016
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com>
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #ifndef SMC_CDC_H
13*4882a593Smuzhiyun #define SMC_CDC_H
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/kernel.h> /* max_t */
16*4882a593Smuzhiyun #include <linux/atomic.h>
17*4882a593Smuzhiyun #include <linux/in.h>
18*4882a593Smuzhiyun #include <linux/compiler.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "smc.h"
21*4882a593Smuzhiyun #include "smc_core.h"
22*4882a593Smuzhiyun #include "smc_wr.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define SMC_CDC_MSG_TYPE 0xFE
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* in network byte order */
27*4882a593Smuzhiyun union smc_cdc_cursor { /* SMC cursor */
28*4882a593Smuzhiyun struct {
29*4882a593Smuzhiyun __be16 reserved;
30*4882a593Smuzhiyun __be16 wrap;
31*4882a593Smuzhiyun __be32 count;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun #ifdef KERNEL_HAS_ATOMIC64
34*4882a593Smuzhiyun atomic64_t acurs; /* for atomic processing */
35*4882a593Smuzhiyun #else
36*4882a593Smuzhiyun u64 acurs; /* for atomic processing */
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun } __aligned(8);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* in network byte order */
41*4882a593Smuzhiyun struct smc_cdc_msg {
42*4882a593Smuzhiyun struct smc_wr_rx_hdr common; /* .type = 0xFE */
43*4882a593Smuzhiyun u8 len; /* 44 */
44*4882a593Smuzhiyun __be16 seqno;
45*4882a593Smuzhiyun __be32 token;
46*4882a593Smuzhiyun union smc_cdc_cursor prod;
47*4882a593Smuzhiyun union smc_cdc_cursor cons; /* piggy backed "ack" */
48*4882a593Smuzhiyun struct smc_cdc_producer_flags prod_flags;
49*4882a593Smuzhiyun struct smc_cdc_conn_state_flags conn_state_flags;
50*4882a593Smuzhiyun u8 reserved[18];
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* SMC-D cursor format */
54*4882a593Smuzhiyun union smcd_cdc_cursor {
55*4882a593Smuzhiyun struct {
56*4882a593Smuzhiyun u16 wrap;
57*4882a593Smuzhiyun u32 count;
58*4882a593Smuzhiyun struct smc_cdc_producer_flags prod_flags;
59*4882a593Smuzhiyun struct smc_cdc_conn_state_flags conn_state_flags;
60*4882a593Smuzhiyun } __packed;
61*4882a593Smuzhiyun #ifdef KERNEL_HAS_ATOMIC64
62*4882a593Smuzhiyun atomic64_t acurs; /* for atomic processing */
63*4882a593Smuzhiyun #else
64*4882a593Smuzhiyun u64 acurs; /* for atomic processing */
65*4882a593Smuzhiyun #endif
66*4882a593Smuzhiyun } __aligned(8);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* CDC message for SMC-D */
69*4882a593Smuzhiyun struct smcd_cdc_msg {
70*4882a593Smuzhiyun struct smc_wr_rx_hdr common; /* Type = 0xFE */
71*4882a593Smuzhiyun u8 res1[7];
72*4882a593Smuzhiyun union smcd_cdc_cursor prod;
73*4882a593Smuzhiyun union smcd_cdc_cursor cons;
74*4882a593Smuzhiyun u8 res3[8];
75*4882a593Smuzhiyun } __aligned(8);
76*4882a593Smuzhiyun
smc_cdc_rxed_any_close(struct smc_connection * conn)77*4882a593Smuzhiyun static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun return conn->local_rx_ctrl.conn_state_flags.peer_conn_abort ||
80*4882a593Smuzhiyun conn->local_rx_ctrl.conn_state_flags.peer_conn_closed;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
smc_cdc_rxed_any_close_or_senddone(struct smc_connection * conn)83*4882a593Smuzhiyun static inline bool smc_cdc_rxed_any_close_or_senddone(
84*4882a593Smuzhiyun struct smc_connection *conn)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun return smc_cdc_rxed_any_close(conn) ||
87*4882a593Smuzhiyun conn->local_rx_ctrl.conn_state_flags.peer_done_writing;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
smc_curs_add(int size,union smc_host_cursor * curs,int value)90*4882a593Smuzhiyun static inline void smc_curs_add(int size, union smc_host_cursor *curs,
91*4882a593Smuzhiyun int value)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun curs->count += value;
94*4882a593Smuzhiyun if (curs->count >= size) {
95*4882a593Smuzhiyun curs->wrap++;
96*4882a593Smuzhiyun curs->count -= size;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* Copy cursor src into tgt */
smc_curs_copy(union smc_host_cursor * tgt,union smc_host_cursor * src,struct smc_connection * conn)101*4882a593Smuzhiyun static inline void smc_curs_copy(union smc_host_cursor *tgt,
102*4882a593Smuzhiyun union smc_host_cursor *src,
103*4882a593Smuzhiyun struct smc_connection *conn)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun #ifndef KERNEL_HAS_ATOMIC64
106*4882a593Smuzhiyun unsigned long flags;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun spin_lock_irqsave(&conn->acurs_lock, flags);
109*4882a593Smuzhiyun tgt->acurs = src->acurs;
110*4882a593Smuzhiyun spin_unlock_irqrestore(&conn->acurs_lock, flags);
111*4882a593Smuzhiyun #else
112*4882a593Smuzhiyun atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
113*4882a593Smuzhiyun #endif
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
smc_curs_copy_net(union smc_cdc_cursor * tgt,union smc_cdc_cursor * src,struct smc_connection * conn)116*4882a593Smuzhiyun static inline void smc_curs_copy_net(union smc_cdc_cursor *tgt,
117*4882a593Smuzhiyun union smc_cdc_cursor *src,
118*4882a593Smuzhiyun struct smc_connection *conn)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun #ifndef KERNEL_HAS_ATOMIC64
121*4882a593Smuzhiyun unsigned long flags;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun spin_lock_irqsave(&conn->acurs_lock, flags);
124*4882a593Smuzhiyun tgt->acurs = src->acurs;
125*4882a593Smuzhiyun spin_unlock_irqrestore(&conn->acurs_lock, flags);
126*4882a593Smuzhiyun #else
127*4882a593Smuzhiyun atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
128*4882a593Smuzhiyun #endif
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
smcd_curs_copy(union smcd_cdc_cursor * tgt,union smcd_cdc_cursor * src,struct smc_connection * conn)131*4882a593Smuzhiyun static inline void smcd_curs_copy(union smcd_cdc_cursor *tgt,
132*4882a593Smuzhiyun union smcd_cdc_cursor *src,
133*4882a593Smuzhiyun struct smc_connection *conn)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun #ifndef KERNEL_HAS_ATOMIC64
136*4882a593Smuzhiyun unsigned long flags;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun spin_lock_irqsave(&conn->acurs_lock, flags);
139*4882a593Smuzhiyun tgt->acurs = src->acurs;
140*4882a593Smuzhiyun spin_unlock_irqrestore(&conn->acurs_lock, flags);
141*4882a593Smuzhiyun #else
142*4882a593Smuzhiyun atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
143*4882a593Smuzhiyun #endif
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* calculate cursor difference between old and new, where old <= new and
147*4882a593Smuzhiyun * difference cannot exceed size
148*4882a593Smuzhiyun */
smc_curs_diff(unsigned int size,union smc_host_cursor * old,union smc_host_cursor * new)149*4882a593Smuzhiyun static inline int smc_curs_diff(unsigned int size,
150*4882a593Smuzhiyun union smc_host_cursor *old,
151*4882a593Smuzhiyun union smc_host_cursor *new)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun if (old->wrap != new->wrap)
154*4882a593Smuzhiyun return max_t(int, 0,
155*4882a593Smuzhiyun ((size - old->count) + new->count));
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return max_t(int, 0, (new->count - old->count));
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* calculate cursor difference between old and new - returns negative
161*4882a593Smuzhiyun * value in case old > new
162*4882a593Smuzhiyun */
smc_curs_comp(unsigned int size,union smc_host_cursor * old,union smc_host_cursor * new)163*4882a593Smuzhiyun static inline int smc_curs_comp(unsigned int size,
164*4882a593Smuzhiyun union smc_host_cursor *old,
165*4882a593Smuzhiyun union smc_host_cursor *new)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun if (old->wrap > new->wrap ||
168*4882a593Smuzhiyun (old->wrap == new->wrap && old->count > new->count))
169*4882a593Smuzhiyun return -smc_curs_diff(size, new, old);
170*4882a593Smuzhiyun return smc_curs_diff(size, old, new);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /* calculate cursor difference between old and new, where old <= new and
174*4882a593Smuzhiyun * difference may exceed size
175*4882a593Smuzhiyun */
smc_curs_diff_large(unsigned int size,union smc_host_cursor * old,union smc_host_cursor * new)176*4882a593Smuzhiyun static inline int smc_curs_diff_large(unsigned int size,
177*4882a593Smuzhiyun union smc_host_cursor *old,
178*4882a593Smuzhiyun union smc_host_cursor *new)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun if (old->wrap < new->wrap)
181*4882a593Smuzhiyun return min_t(int,
182*4882a593Smuzhiyun (size - old->count) + new->count +
183*4882a593Smuzhiyun (new->wrap - old->wrap - 1) * size,
184*4882a593Smuzhiyun size);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun if (old->wrap > new->wrap) /* wrap has switched from 0xffff to 0x0000 */
187*4882a593Smuzhiyun return min_t(int,
188*4882a593Smuzhiyun (size - old->count) + new->count +
189*4882a593Smuzhiyun (new->wrap + 0xffff - old->wrap) * size,
190*4882a593Smuzhiyun size);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun return max_t(int, 0, (new->count - old->count));
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
smc_host_cursor_to_cdc(union smc_cdc_cursor * peer,union smc_host_cursor * local,union smc_host_cursor * save,struct smc_connection * conn)195*4882a593Smuzhiyun static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer,
196*4882a593Smuzhiyun union smc_host_cursor *local,
197*4882a593Smuzhiyun union smc_host_cursor *save,
198*4882a593Smuzhiyun struct smc_connection *conn)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun smc_curs_copy(save, local, conn);
201*4882a593Smuzhiyun peer->count = htonl(save->count);
202*4882a593Smuzhiyun peer->wrap = htons(save->wrap);
203*4882a593Smuzhiyun /* peer->reserved = htons(0); must be ensured by caller */
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
smc_host_msg_to_cdc(struct smc_cdc_msg * peer,struct smc_connection * conn,union smc_host_cursor * save)206*4882a593Smuzhiyun static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer,
207*4882a593Smuzhiyun struct smc_connection *conn,
208*4882a593Smuzhiyun union smc_host_cursor *save)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun struct smc_host_cdc_msg *local = &conn->local_tx_ctrl;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun peer->common.type = local->common.type;
213*4882a593Smuzhiyun peer->len = local->len;
214*4882a593Smuzhiyun peer->seqno = htons(local->seqno);
215*4882a593Smuzhiyun peer->token = htonl(local->token);
216*4882a593Smuzhiyun smc_host_cursor_to_cdc(&peer->prod, &local->prod, save, conn);
217*4882a593Smuzhiyun smc_host_cursor_to_cdc(&peer->cons, &local->cons, save, conn);
218*4882a593Smuzhiyun peer->prod_flags = local->prod_flags;
219*4882a593Smuzhiyun peer->conn_state_flags = local->conn_state_flags;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
smc_cdc_cursor_to_host(union smc_host_cursor * local,union smc_cdc_cursor * peer,struct smc_connection * conn)222*4882a593Smuzhiyun static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
223*4882a593Smuzhiyun union smc_cdc_cursor *peer,
224*4882a593Smuzhiyun struct smc_connection *conn)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun union smc_host_cursor temp, old;
227*4882a593Smuzhiyun union smc_cdc_cursor net;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun smc_curs_copy(&old, local, conn);
230*4882a593Smuzhiyun smc_curs_copy_net(&net, peer, conn);
231*4882a593Smuzhiyun temp.count = ntohl(net.count);
232*4882a593Smuzhiyun temp.wrap = ntohs(net.wrap);
233*4882a593Smuzhiyun if ((old.wrap > temp.wrap) && temp.wrap)
234*4882a593Smuzhiyun return;
235*4882a593Smuzhiyun if ((old.wrap == temp.wrap) &&
236*4882a593Smuzhiyun (old.count > temp.count))
237*4882a593Smuzhiyun return;
238*4882a593Smuzhiyun smc_curs_copy(local, &temp, conn);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
smcr_cdc_msg_to_host(struct smc_host_cdc_msg * local,struct smc_cdc_msg * peer,struct smc_connection * conn)241*4882a593Smuzhiyun static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
242*4882a593Smuzhiyun struct smc_cdc_msg *peer,
243*4882a593Smuzhiyun struct smc_connection *conn)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun local->common.type = peer->common.type;
246*4882a593Smuzhiyun local->len = peer->len;
247*4882a593Smuzhiyun local->seqno = ntohs(peer->seqno);
248*4882a593Smuzhiyun local->token = ntohl(peer->token);
249*4882a593Smuzhiyun smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn);
250*4882a593Smuzhiyun smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn);
251*4882a593Smuzhiyun local->prod_flags = peer->prod_flags;
252*4882a593Smuzhiyun local->conn_state_flags = peer->conn_state_flags;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
smcd_cdc_msg_to_host(struct smc_host_cdc_msg * local,struct smcd_cdc_msg * peer,struct smc_connection * conn)255*4882a593Smuzhiyun static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local,
256*4882a593Smuzhiyun struct smcd_cdc_msg *peer,
257*4882a593Smuzhiyun struct smc_connection *conn)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun union smc_host_cursor temp;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun temp.wrap = peer->prod.wrap;
262*4882a593Smuzhiyun temp.count = peer->prod.count;
263*4882a593Smuzhiyun smc_curs_copy(&local->prod, &temp, conn);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun temp.wrap = peer->cons.wrap;
266*4882a593Smuzhiyun temp.count = peer->cons.count;
267*4882a593Smuzhiyun smc_curs_copy(&local->cons, &temp, conn);
268*4882a593Smuzhiyun local->prod_flags = peer->cons.prod_flags;
269*4882a593Smuzhiyun local->conn_state_flags = peer->cons.conn_state_flags;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
smc_cdc_msg_to_host(struct smc_host_cdc_msg * local,struct smc_cdc_msg * peer,struct smc_connection * conn)272*4882a593Smuzhiyun static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local,
273*4882a593Smuzhiyun struct smc_cdc_msg *peer,
274*4882a593Smuzhiyun struct smc_connection *conn)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun if (conn->lgr->is_smcd)
277*4882a593Smuzhiyun smcd_cdc_msg_to_host(local, (struct smcd_cdc_msg *)peer, conn);
278*4882a593Smuzhiyun else
279*4882a593Smuzhiyun smcr_cdc_msg_to_host(local, peer, conn);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun struct smc_cdc_tx_pend {
283*4882a593Smuzhiyun struct smc_connection *conn; /* socket connection */
284*4882a593Smuzhiyun union smc_host_cursor cursor; /* tx sndbuf cursor sent */
285*4882a593Smuzhiyun union smc_host_cursor p_cursor; /* rx RMBE cursor produced */
286*4882a593Smuzhiyun u16 ctrl_seq; /* conn. tx sequence # */
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun int smc_cdc_get_free_slot(struct smc_connection *conn,
290*4882a593Smuzhiyun struct smc_link *link,
291*4882a593Smuzhiyun struct smc_wr_buf **wr_buf,
292*4882a593Smuzhiyun struct smc_rdma_wr **wr_rdma_buf,
293*4882a593Smuzhiyun struct smc_cdc_tx_pend **pend);
294*4882a593Smuzhiyun void smc_cdc_wait_pend_tx_wr(struct smc_connection *conn);
295*4882a593Smuzhiyun int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf,
296*4882a593Smuzhiyun struct smc_cdc_tx_pend *pend);
297*4882a593Smuzhiyun int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn);
298*4882a593Smuzhiyun int smcd_cdc_msg_send(struct smc_connection *conn);
299*4882a593Smuzhiyun int smcr_cdc_msg_send_validation(struct smc_connection *conn,
300*4882a593Smuzhiyun struct smc_cdc_tx_pend *pend,
301*4882a593Smuzhiyun struct smc_wr_buf *wr_buf);
302*4882a593Smuzhiyun int smc_cdc_init(void) __init;
303*4882a593Smuzhiyun void smcd_cdc_rx_init(struct smc_connection *conn);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun #endif /* SMC_CDC_H */
306