xref: /OK3568_Linux_fs/kernel/net/smc/smc_cdc.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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