xref: /openbmc/linux/net/smc/smc_cdc.h (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
25f08318fSUrsula Braun /*
35f08318fSUrsula Braun  * Shared Memory Communications over RDMA (SMC-R) and RoCE
45f08318fSUrsula Braun  *
55f08318fSUrsula Braun  * Connection Data Control (CDC)
65f08318fSUrsula Braun  *
75f08318fSUrsula Braun  * Copyright IBM Corp. 2016
85f08318fSUrsula Braun  *
95f08318fSUrsula Braun  * Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
105f08318fSUrsula Braun  */
115f08318fSUrsula Braun 
125f08318fSUrsula Braun #ifndef SMC_CDC_H
135f08318fSUrsula Braun #define SMC_CDC_H
145f08318fSUrsula Braun 
155f08318fSUrsula Braun #include <linux/kernel.h> /* max_t */
165f08318fSUrsula Braun #include <linux/atomic.h>
175f08318fSUrsula Braun #include <linux/in.h>
185f08318fSUrsula Braun #include <linux/compiler.h>
195f08318fSUrsula Braun 
205f08318fSUrsula Braun #include "smc.h"
215f08318fSUrsula Braun #include "smc_core.h"
225f08318fSUrsula Braun #include "smc_wr.h"
235f08318fSUrsula Braun 
245f08318fSUrsula Braun #define	SMC_CDC_MSG_TYPE		0xFE
255f08318fSUrsula Braun 
265f08318fSUrsula Braun /* in network byte order */
275f08318fSUrsula Braun union smc_cdc_cursor {		/* SMC cursor */
285f08318fSUrsula Braun 	struct {
295f08318fSUrsula Braun 		__be16	reserved;
305f08318fSUrsula Braun 		__be16	wrap;
315f08318fSUrsula Braun 		__be32	count;
325f08318fSUrsula Braun 	};
335f08318fSUrsula Braun #ifdef KERNEL_HAS_ATOMIC64
345f08318fSUrsula Braun 	atomic64_t	acurs;		/* for atomic processing */
355f08318fSUrsula Braun #else
365f08318fSUrsula Braun 	u64		acurs;		/* for atomic processing */
375f08318fSUrsula Braun #endif
385f08318fSUrsula Braun } __aligned(8);
395f08318fSUrsula Braun 
405f08318fSUrsula Braun /* in network byte order */
415f08318fSUrsula Braun struct smc_cdc_msg {
425f08318fSUrsula Braun 	struct smc_wr_rx_hdr		common; /* .type = 0xFE */
435f08318fSUrsula Braun 	u8				len;	/* 44 */
445f08318fSUrsula Braun 	__be16				seqno;
455f08318fSUrsula Braun 	__be32				token;
465f08318fSUrsula Braun 	union smc_cdc_cursor		prod;
475f08318fSUrsula Braun 	union smc_cdc_cursor		cons;	/* piggy backed "ack" */
485f08318fSUrsula Braun 	struct smc_cdc_producer_flags	prod_flags;
495f08318fSUrsula Braun 	struct smc_cdc_conn_state_flags	conn_state_flags;
505f08318fSUrsula Braun 	u8				reserved[18];
51b9a22dd9SUrsula Braun };
52b9a22dd9SUrsula Braun 
53b9a22dd9SUrsula Braun /* SMC-D cursor format */
54b9a22dd9SUrsula Braun union smcd_cdc_cursor {
55b9a22dd9SUrsula Braun 	struct {
56b9a22dd9SUrsula Braun 		u16	wrap;
57b9a22dd9SUrsula Braun 		u32	count;
58b9a22dd9SUrsula Braun 		struct smc_cdc_producer_flags	prod_flags;
59b9a22dd9SUrsula Braun 		struct smc_cdc_conn_state_flags	conn_state_flags;
60b9a22dd9SUrsula Braun 	} __packed;
61b9a22dd9SUrsula Braun #ifdef KERNEL_HAS_ATOMIC64
62b9a22dd9SUrsula Braun 	atomic64_t		acurs;		/* for atomic processing */
63b9a22dd9SUrsula Braun #else
64b9a22dd9SUrsula Braun 	u64			acurs;		/* for atomic processing */
65b9a22dd9SUrsula Braun #endif
66b9a22dd9SUrsula Braun } __aligned(8);
675f08318fSUrsula Braun 
68be244f28SHans Wippel /* CDC message for SMC-D */
69be244f28SHans Wippel struct smcd_cdc_msg {
70be244f28SHans Wippel 	struct smc_wr_rx_hdr common;	/* Type = 0xFE */
71be244f28SHans Wippel 	u8 res1[7];
72b9a22dd9SUrsula Braun 	union smcd_cdc_cursor	prod;
73b9a22dd9SUrsula Braun 	union smcd_cdc_cursor	cons;
74be244f28SHans Wippel 	u8 res3[8];
75b9a22dd9SUrsula Braun } __aligned(8);
76be244f28SHans Wippel 
smc_cdc_rxed_any_close(struct smc_connection * conn)775f08318fSUrsula Braun static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn)
785f08318fSUrsula Braun {
795f08318fSUrsula Braun 	return conn->local_rx_ctrl.conn_state_flags.peer_conn_abort ||
805f08318fSUrsula Braun 	       conn->local_rx_ctrl.conn_state_flags.peer_conn_closed;
815f08318fSUrsula Braun }
825f08318fSUrsula Braun 
smc_cdc_rxed_any_close_or_senddone(struct smc_connection * conn)835f08318fSUrsula Braun static inline bool smc_cdc_rxed_any_close_or_senddone(
845f08318fSUrsula Braun 	struct smc_connection *conn)
855f08318fSUrsula Braun {
865f08318fSUrsula Braun 	return smc_cdc_rxed_any_close(conn) ||
875f08318fSUrsula Braun 	       conn->local_rx_ctrl.conn_state_flags.peer_done_writing;
885f08318fSUrsula Braun }
895f08318fSUrsula Braun 
smc_curs_add(int size,union smc_host_cursor * curs,int value)905f08318fSUrsula Braun static inline void smc_curs_add(int size, union smc_host_cursor *curs,
915f08318fSUrsula Braun 				int value)
925f08318fSUrsula Braun {
935f08318fSUrsula Braun 	curs->count += value;
945f08318fSUrsula Braun 	if (curs->count >= size) {
955f08318fSUrsula Braun 		curs->wrap++;
965f08318fSUrsula Braun 		curs->count -= size;
975f08318fSUrsula Braun 	}
985f08318fSUrsula Braun }
995f08318fSUrsula Braun 
100bac6de7bSStefan Raspl /* Copy cursor src into tgt */
smc_curs_copy(union smc_host_cursor * tgt,union smc_host_cursor * src,struct smc_connection * conn)101bac6de7bSStefan Raspl static inline void smc_curs_copy(union smc_host_cursor *tgt,
102bac6de7bSStefan Raspl 				 union smc_host_cursor *src,
1035f08318fSUrsula Braun 				 struct smc_connection *conn)
1045f08318fSUrsula Braun {
1055f08318fSUrsula Braun #ifndef KERNEL_HAS_ATOMIC64
1065f08318fSUrsula Braun 	unsigned long flags;
1075f08318fSUrsula Braun 
1085f08318fSUrsula Braun 	spin_lock_irqsave(&conn->acurs_lock, flags);
109bac6de7bSStefan Raspl 	tgt->acurs = src->acurs;
1105f08318fSUrsula Braun 	spin_unlock_irqrestore(&conn->acurs_lock, flags);
1115f08318fSUrsula Braun #else
112bac6de7bSStefan Raspl 	atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
1135f08318fSUrsula Braun #endif
1145f08318fSUrsula Braun }
1155f08318fSUrsula Braun 
smc_curs_copy_net(union smc_cdc_cursor * tgt,union smc_cdc_cursor * src,struct smc_connection * conn)116bac6de7bSStefan Raspl static inline void smc_curs_copy_net(union smc_cdc_cursor *tgt,
117bac6de7bSStefan Raspl 				     union smc_cdc_cursor *src,
1185f08318fSUrsula Braun 				     struct smc_connection *conn)
1195f08318fSUrsula Braun {
1205f08318fSUrsula Braun #ifndef KERNEL_HAS_ATOMIC64
1215f08318fSUrsula Braun 	unsigned long flags;
1225f08318fSUrsula Braun 
1235f08318fSUrsula Braun 	spin_lock_irqsave(&conn->acurs_lock, flags);
124bac6de7bSStefan Raspl 	tgt->acurs = src->acurs;
1255f08318fSUrsula Braun 	spin_unlock_irqrestore(&conn->acurs_lock, flags);
1265f08318fSUrsula Braun #else
127bac6de7bSStefan Raspl 	atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
1285f08318fSUrsula Braun #endif
1295f08318fSUrsula Braun }
1305f08318fSUrsula Braun 
smcd_curs_copy(union smcd_cdc_cursor * tgt,union smcd_cdc_cursor * src,struct smc_connection * conn)131b9a22dd9SUrsula Braun static inline void smcd_curs_copy(union smcd_cdc_cursor *tgt,
132b9a22dd9SUrsula Braun 				  union smcd_cdc_cursor *src,
133b9a22dd9SUrsula Braun 				  struct smc_connection *conn)
134b9a22dd9SUrsula Braun {
135b9a22dd9SUrsula Braun #ifndef KERNEL_HAS_ATOMIC64
136b9a22dd9SUrsula Braun 	unsigned long flags;
137b9a22dd9SUrsula Braun 
138b9a22dd9SUrsula Braun 	spin_lock_irqsave(&conn->acurs_lock, flags);
139b9a22dd9SUrsula Braun 	tgt->acurs = src->acurs;
140b9a22dd9SUrsula Braun 	spin_unlock_irqrestore(&conn->acurs_lock, flags);
141b9a22dd9SUrsula Braun #else
142b9a22dd9SUrsula Braun 	atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
143b9a22dd9SUrsula Braun #endif
144b9a22dd9SUrsula Braun }
145b9a22dd9SUrsula Braun 
146b8649efaSUrsula Braun /* calculate cursor difference between old and new, where old <= new and
147b8649efaSUrsula Braun  * difference cannot exceed size
148b8649efaSUrsula Braun  */
smc_curs_diff(unsigned int size,union smc_host_cursor * old,union smc_host_cursor * new)1495f08318fSUrsula Braun static inline int smc_curs_diff(unsigned int size,
1505f08318fSUrsula Braun 				union smc_host_cursor *old,
1515f08318fSUrsula Braun 				union smc_host_cursor *new)
1525f08318fSUrsula Braun {
1535f08318fSUrsula Braun 	if (old->wrap != new->wrap)
1545f08318fSUrsula Braun 		return max_t(int, 0,
1555f08318fSUrsula Braun 			     ((size - old->count) + new->count));
1565f08318fSUrsula Braun 
1575f08318fSUrsula Braun 	return max_t(int, 0, (new->count - old->count));
1585f08318fSUrsula Braun }
1595f08318fSUrsula Braun 
160de8474ebSStefan Raspl /* calculate cursor difference between old and new - returns negative
161de8474ebSStefan Raspl  * value in case old > new
162de8474ebSStefan Raspl  */
smc_curs_comp(unsigned int size,union smc_host_cursor * old,union smc_host_cursor * new)163de8474ebSStefan Raspl static inline int smc_curs_comp(unsigned int size,
164de8474ebSStefan Raspl 				union smc_host_cursor *old,
165de8474ebSStefan Raspl 				union smc_host_cursor *new)
166de8474ebSStefan Raspl {
167de8474ebSStefan Raspl 	if (old->wrap > new->wrap ||
168de8474ebSStefan Raspl 	    (old->wrap == new->wrap && old->count > new->count))
169de8474ebSStefan Raspl 		return -smc_curs_diff(size, new, old);
170de8474ebSStefan Raspl 	return smc_curs_diff(size, old, new);
171de8474ebSStefan Raspl }
172de8474ebSStefan Raspl 
173b8649efaSUrsula Braun /* calculate cursor difference between old and new, where old <= new and
174b8649efaSUrsula Braun  * difference may exceed size
175b8649efaSUrsula Braun  */
smc_curs_diff_large(unsigned int size,union smc_host_cursor * old,union smc_host_cursor * new)176b8649efaSUrsula Braun static inline int smc_curs_diff_large(unsigned int size,
177b8649efaSUrsula Braun 				      union smc_host_cursor *old,
178b8649efaSUrsula Braun 				      union smc_host_cursor *new)
179b8649efaSUrsula Braun {
180b8649efaSUrsula Braun 	if (old->wrap < new->wrap)
181b8649efaSUrsula Braun 		return min_t(int,
182b8649efaSUrsula Braun 			     (size - old->count) + new->count +
183b8649efaSUrsula Braun 			     (new->wrap - old->wrap - 1) * size,
184b8649efaSUrsula Braun 			     size);
185b8649efaSUrsula Braun 
186b8649efaSUrsula Braun 	if (old->wrap > new->wrap) /* wrap has switched from 0xffff to 0x0000 */
187b8649efaSUrsula Braun 		return min_t(int,
188b8649efaSUrsula Braun 			     (size - old->count) + new->count +
189b8649efaSUrsula Braun 			     (new->wrap + 0xffff - old->wrap) * size,
190b8649efaSUrsula Braun 			     size);
191b8649efaSUrsula Braun 
192b8649efaSUrsula Braun 	return max_t(int, 0, (new->count - old->count));
193b8649efaSUrsula Braun }
194b8649efaSUrsula Braun 
smc_host_cursor_to_cdc(union smc_cdc_cursor * peer,union smc_host_cursor * local,union smc_host_cursor * save,struct smc_connection * conn)1955f08318fSUrsula Braun static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer,
1965f08318fSUrsula Braun 					  union smc_host_cursor *local,
197ccc8ca9bSUrsula Braun 					  union smc_host_cursor *save,
1985f08318fSUrsula Braun 					  struct smc_connection *conn)
1995f08318fSUrsula Braun {
200ccc8ca9bSUrsula Braun 	smc_curs_copy(save, local, conn);
201ccc8ca9bSUrsula Braun 	peer->count = htonl(save->count);
202ccc8ca9bSUrsula Braun 	peer->wrap = htons(save->wrap);
2035f08318fSUrsula Braun 	/* peer->reserved = htons(0); must be ensured by caller */
2045f08318fSUrsula Braun }
2055f08318fSUrsula Braun 
smc_host_msg_to_cdc(struct smc_cdc_msg * peer,struct smc_connection * conn,union smc_host_cursor * save)2065f08318fSUrsula Braun static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer,
207ccc8ca9bSUrsula Braun 				       struct smc_connection *conn,
208ccc8ca9bSUrsula Braun 				       union smc_host_cursor *save)
2095f08318fSUrsula Braun {
210ccc8ca9bSUrsula Braun 	struct smc_host_cdc_msg *local = &conn->local_tx_ctrl;
211ccc8ca9bSUrsula Braun 
2125f08318fSUrsula Braun 	peer->common.type = local->common.type;
2135f08318fSUrsula Braun 	peer->len = local->len;
2145f08318fSUrsula Braun 	peer->seqno = htons(local->seqno);
2155f08318fSUrsula Braun 	peer->token = htonl(local->token);
216ccc8ca9bSUrsula Braun 	smc_host_cursor_to_cdc(&peer->prod, &local->prod, save, conn);
217ccc8ca9bSUrsula Braun 	smc_host_cursor_to_cdc(&peer->cons, &local->cons, save, conn);
2185f08318fSUrsula Braun 	peer->prod_flags = local->prod_flags;
2195f08318fSUrsula Braun 	peer->conn_state_flags = local->conn_state_flags;
2205f08318fSUrsula Braun }
2215f08318fSUrsula Braun 
smc_cdc_cursor_to_host(union smc_host_cursor * local,union smc_cdc_cursor * peer,struct smc_connection * conn)2225f08318fSUrsula Braun static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
2235f08318fSUrsula Braun 					  union smc_cdc_cursor *peer,
2245f08318fSUrsula Braun 					  struct smc_connection *conn)
2255f08318fSUrsula Braun {
2265f08318fSUrsula Braun 	union smc_host_cursor temp, old;
2275f08318fSUrsula Braun 	union smc_cdc_cursor net;
2285f08318fSUrsula Braun 
229bac6de7bSStefan Raspl 	smc_curs_copy(&old, local, conn);
230bac6de7bSStefan Raspl 	smc_curs_copy_net(&net, peer, conn);
2315f08318fSUrsula Braun 	temp.count = ntohl(net.count);
2325f08318fSUrsula Braun 	temp.wrap = ntohs(net.wrap);
2335f08318fSUrsula Braun 	if ((old.wrap > temp.wrap) && temp.wrap)
2345f08318fSUrsula Braun 		return;
2355f08318fSUrsula Braun 	if ((old.wrap == temp.wrap) &&
2365f08318fSUrsula Braun 	    (old.count > temp.count))
2375f08318fSUrsula Braun 		return;
238bac6de7bSStefan Raspl 	smc_curs_copy(local, &temp, conn);
2395f08318fSUrsula Braun }
2405f08318fSUrsula Braun 
smcr_cdc_msg_to_host(struct smc_host_cdc_msg * local,struct smc_cdc_msg * peer,struct smc_connection * conn)241be244f28SHans Wippel static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
2425f08318fSUrsula Braun 					struct smc_cdc_msg *peer,
2435f08318fSUrsula Braun 					struct smc_connection *conn)
2445f08318fSUrsula Braun {
2455f08318fSUrsula Braun 	local->common.type = peer->common.type;
2465f08318fSUrsula Braun 	local->len = peer->len;
2475f08318fSUrsula Braun 	local->seqno = ntohs(peer->seqno);
2485f08318fSUrsula Braun 	local->token = ntohl(peer->token);
2495f08318fSUrsula Braun 	smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn);
2505f08318fSUrsula Braun 	smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn);
2515f08318fSUrsula Braun 	local->prod_flags = peer->prod_flags;
2525f08318fSUrsula Braun 	local->conn_state_flags = peer->conn_state_flags;
2535f08318fSUrsula Braun }
2545f08318fSUrsula Braun 
smcd_cdc_msg_to_host(struct smc_host_cdc_msg * local,struct smcd_cdc_msg * peer,struct smc_connection * conn)255be244f28SHans Wippel static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local,
256a225d2cdSUrsula Braun 					struct smcd_cdc_msg *peer,
257a225d2cdSUrsula Braun 					struct smc_connection *conn)
258be244f28SHans Wippel {
259b9a22dd9SUrsula Braun 	union smc_host_cursor temp;
260b9a22dd9SUrsula Braun 
261b9a22dd9SUrsula Braun 	temp.wrap = peer->prod.wrap;
262b9a22dd9SUrsula Braun 	temp.count = peer->prod.count;
263a225d2cdSUrsula Braun 	smc_curs_copy(&local->prod, &temp, conn);
264b9a22dd9SUrsula Braun 
265b9a22dd9SUrsula Braun 	temp.wrap = peer->cons.wrap;
266b9a22dd9SUrsula Braun 	temp.count = peer->cons.count;
267a225d2cdSUrsula Braun 	smc_curs_copy(&local->cons, &temp, conn);
268b9a22dd9SUrsula Braun 	local->prod_flags = peer->cons.prod_flags;
269b9a22dd9SUrsula Braun 	local->conn_state_flags = peer->cons.conn_state_flags;
270be244f28SHans Wippel }
271be244f28SHans Wippel 
smc_cdc_msg_to_host(struct smc_host_cdc_msg * local,struct smc_cdc_msg * peer,struct smc_connection * conn)272be244f28SHans Wippel static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local,
273be244f28SHans Wippel 				       struct smc_cdc_msg *peer,
274be244f28SHans Wippel 				       struct smc_connection *conn)
275be244f28SHans Wippel {
276be244f28SHans Wippel 	if (conn->lgr->is_smcd)
277a225d2cdSUrsula Braun 		smcd_cdc_msg_to_host(local, (struct smcd_cdc_msg *)peer, conn);
278be244f28SHans Wippel 	else
279be244f28SHans Wippel 		smcr_cdc_msg_to_host(local, peer, conn);
280be244f28SHans Wippel }
281be244f28SHans Wippel 
282ad6f317fSUrsula Braun struct smc_cdc_tx_pend {
283ad6f317fSUrsula Braun 	struct smc_connection	*conn;		/* socket connection */
284ad6f317fSUrsula Braun 	union smc_host_cursor	cursor;		/* tx sndbuf cursor sent */
285ad6f317fSUrsula Braun 	union smc_host_cursor	p_cursor;	/* rx RMBE cursor produced */
286ad6f317fSUrsula Braun 	u16			ctrl_seq;	/* conn. tx sequence # */
287ad6f317fSUrsula Braun };
2885f08318fSUrsula Braun 
28951957bc5SUrsula Braun int smc_cdc_get_free_slot(struct smc_connection *conn,
290c6f02ebeSKarsten Graul 			  struct smc_link *link,
29151957bc5SUrsula Braun 			  struct smc_wr_buf **wr_buf,
292ad6f317fSUrsula Braun 			  struct smc_rdma_wr **wr_rdma_buf,
2935f08318fSUrsula Braun 			  struct smc_cdc_tx_pend **pend);
294*349d4312SDust Li void smc_cdc_wait_pend_tx_wr(struct smc_connection *conn);
2955f08318fSUrsula Braun int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf,
2965f08318fSUrsula Braun 		     struct smc_cdc_tx_pend *pend);
2975f08318fSUrsula Braun int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn);
298be244f28SHans Wippel int smcd_cdc_msg_send(struct smc_connection *conn);
299b8ded9deSKarsten Graul int smcr_cdc_msg_send_validation(struct smc_connection *conn,
300b8ded9deSKarsten Graul 				 struct smc_cdc_tx_pend *pend,
301b8ded9deSKarsten Graul 				 struct smc_wr_buf *wr_buf);
3025f08318fSUrsula Braun int smc_cdc_init(void) __init;
303be244f28SHans Wippel void smcd_cdc_rx_init(struct smc_connection *conn);
3045f08318fSUrsula Braun 
3055f08318fSUrsula Braun #endif /* SMC_CDC_H */
306