1 /* 2 * Shared Memory Communications over RDMA (SMC-R) and RoCE 3 * 4 * Connection Data Control (CDC) 5 * 6 * Copyright IBM Corp. 2016 7 * 8 * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> 9 */ 10 11 #ifndef SMC_CDC_H 12 #define SMC_CDC_H 13 14 #include <linux/kernel.h> /* max_t */ 15 #include <linux/atomic.h> 16 #include <linux/in.h> 17 #include <linux/compiler.h> 18 19 #include "smc.h" 20 #include "smc_core.h" 21 #include "smc_wr.h" 22 23 #define SMC_CDC_MSG_TYPE 0xFE 24 25 /* in network byte order */ 26 union smc_cdc_cursor { /* SMC cursor */ 27 struct { 28 __be16 reserved; 29 __be16 wrap; 30 __be32 count; 31 }; 32 #ifdef KERNEL_HAS_ATOMIC64 33 atomic64_t acurs; /* for atomic processing */ 34 #else 35 u64 acurs; /* for atomic processing */ 36 #endif 37 } __aligned(8); 38 39 /* in network byte order */ 40 struct smc_cdc_msg { 41 struct smc_wr_rx_hdr common; /* .type = 0xFE */ 42 u8 len; /* 44 */ 43 __be16 seqno; 44 __be32 token; 45 union smc_cdc_cursor prod; 46 union smc_cdc_cursor cons; /* piggy backed "ack" */ 47 struct smc_cdc_producer_flags prod_flags; 48 struct smc_cdc_conn_state_flags conn_state_flags; 49 u8 reserved[18]; 50 } __aligned(8); 51 52 static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn) 53 { 54 return conn->local_rx_ctrl.conn_state_flags.peer_conn_abort || 55 conn->local_rx_ctrl.conn_state_flags.peer_conn_closed; 56 } 57 58 static inline bool smc_cdc_rxed_any_close_or_senddone( 59 struct smc_connection *conn) 60 { 61 return smc_cdc_rxed_any_close(conn) || 62 conn->local_rx_ctrl.conn_state_flags.peer_done_writing; 63 } 64 65 static inline void smc_curs_add(int size, union smc_host_cursor *curs, 66 int value) 67 { 68 curs->count += value; 69 if (curs->count >= size) { 70 curs->wrap++; 71 curs->count -= size; 72 } 73 } 74 75 /* SMC cursors are 8 bytes long and require atomic reading and writing */ 76 static inline u64 smc_curs_read(union smc_host_cursor *curs, 77 struct smc_connection *conn) 78 { 79 #ifndef KERNEL_HAS_ATOMIC64 80 unsigned long flags; 81 u64 ret; 82 83 spin_lock_irqsave(&conn->acurs_lock, flags); 84 ret = curs->acurs; 85 spin_unlock_irqrestore(&conn->acurs_lock, flags); 86 return ret; 87 #else 88 return atomic64_read(&curs->acurs); 89 #endif 90 } 91 92 static inline u64 smc_curs_read_net(union smc_cdc_cursor *curs, 93 struct smc_connection *conn) 94 { 95 #ifndef KERNEL_HAS_ATOMIC64 96 unsigned long flags; 97 u64 ret; 98 99 spin_lock_irqsave(&conn->acurs_lock, flags); 100 ret = curs->acurs; 101 spin_unlock_irqrestore(&conn->acurs_lock, flags); 102 return ret; 103 #else 104 return atomic64_read(&curs->acurs); 105 #endif 106 } 107 108 static inline void smc_curs_write(union smc_host_cursor *curs, u64 val, 109 struct smc_connection *conn) 110 { 111 #ifndef KERNEL_HAS_ATOMIC64 112 unsigned long flags; 113 114 spin_lock_irqsave(&conn->acurs_lock, flags); 115 curs->acurs = val; 116 spin_unlock_irqrestore(&conn->acurs_lock, flags); 117 #else 118 atomic64_set(&curs->acurs, val); 119 #endif 120 } 121 122 static inline void smc_curs_write_net(union smc_cdc_cursor *curs, u64 val, 123 struct smc_connection *conn) 124 { 125 #ifndef KERNEL_HAS_ATOMIC64 126 unsigned long flags; 127 128 spin_lock_irqsave(&conn->acurs_lock, flags); 129 curs->acurs = val; 130 spin_unlock_irqrestore(&conn->acurs_lock, flags); 131 #else 132 atomic64_set(&curs->acurs, val); 133 #endif 134 } 135 136 /* calculate cursor difference between old and new, where old <= new */ 137 static inline int smc_curs_diff(unsigned int size, 138 union smc_host_cursor *old, 139 union smc_host_cursor *new) 140 { 141 if (old->wrap != new->wrap) 142 return max_t(int, 0, 143 ((size - old->count) + new->count)); 144 145 return max_t(int, 0, (new->count - old->count)); 146 } 147 148 static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer, 149 union smc_host_cursor *local, 150 struct smc_connection *conn) 151 { 152 union smc_host_cursor temp; 153 154 smc_curs_write(&temp, smc_curs_read(local, conn), conn); 155 peer->count = htonl(temp.count); 156 peer->wrap = htons(temp.wrap); 157 /* peer->reserved = htons(0); must be ensured by caller */ 158 } 159 160 static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer, 161 struct smc_host_cdc_msg *local, 162 struct smc_connection *conn) 163 { 164 peer->common.type = local->common.type; 165 peer->len = local->len; 166 peer->seqno = htons(local->seqno); 167 peer->token = htonl(local->token); 168 smc_host_cursor_to_cdc(&peer->prod, &local->prod, conn); 169 smc_host_cursor_to_cdc(&peer->cons, &local->cons, conn); 170 peer->prod_flags = local->prod_flags; 171 peer->conn_state_flags = local->conn_state_flags; 172 } 173 174 static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local, 175 union smc_cdc_cursor *peer, 176 struct smc_connection *conn) 177 { 178 union smc_host_cursor temp, old; 179 union smc_cdc_cursor net; 180 181 smc_curs_write(&old, smc_curs_read(local, conn), conn); 182 smc_curs_write_net(&net, smc_curs_read_net(peer, conn), conn); 183 temp.count = ntohl(net.count); 184 temp.wrap = ntohs(net.wrap); 185 if ((old.wrap > temp.wrap) && temp.wrap) 186 return; 187 if ((old.wrap == temp.wrap) && 188 (old.count > temp.count)) 189 return; 190 smc_curs_write(local, smc_curs_read(&temp, conn), conn); 191 } 192 193 static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local, 194 struct smc_cdc_msg *peer, 195 struct smc_connection *conn) 196 { 197 local->common.type = peer->common.type; 198 local->len = peer->len; 199 local->seqno = ntohs(peer->seqno); 200 local->token = ntohl(peer->token); 201 smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn); 202 smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn); 203 local->prod_flags = peer->prod_flags; 204 local->conn_state_flags = peer->conn_state_flags; 205 } 206 207 struct smc_cdc_tx_pend; 208 209 int smc_cdc_get_free_slot(struct smc_link *link, struct smc_wr_buf **wr_buf, 210 struct smc_cdc_tx_pend **pend); 211 void smc_cdc_tx_dismiss_slots(struct smc_connection *conn); 212 int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf, 213 struct smc_cdc_tx_pend *pend); 214 int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn); 215 bool smc_cdc_tx_has_pending(struct smc_connection *conn); 216 int smc_cdc_init(void) __init; 217 218 #endif /* SMC_CDC_H */ 219