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