aboutsummaryrefslogtreecommitdiffstats
path: root/net/smc/smc_cdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/smc/smc_cdc.c')
-rw-r--r--net/smc/smc_cdc.c86
1 files changed, 84 insertions, 2 deletions
diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c
index a7e8d63fc8ae..621d8cca570b 100644
--- a/net/smc/smc_cdc.c
+++ b/net/smc/smc_cdc.c
@@ -117,7 +117,7 @@ int smc_cdc_msg_send(struct smc_connection *conn,
117 return rc; 117 return rc;
118} 118}
119 119
120int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn) 120static int smcr_cdc_get_slot_and_msg_send(struct smc_connection *conn)
121{ 121{
122 struct smc_cdc_tx_pend *pend; 122 struct smc_cdc_tx_pend *pend;
123 struct smc_wr_buf *wr_buf; 123 struct smc_wr_buf *wr_buf;
@@ -130,6 +130,21 @@ int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn)
130 return smc_cdc_msg_send(conn, wr_buf, pend); 130 return smc_cdc_msg_send(conn, wr_buf, pend);
131} 131}
132 132
133int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn)
134{
135 int rc;
136
137 if (conn->lgr->is_smcd) {
138 spin_lock_bh(&conn->send_lock);
139 rc = smcd_cdc_msg_send(conn);
140 spin_unlock_bh(&conn->send_lock);
141 } else {
142 rc = smcr_cdc_get_slot_and_msg_send(conn);
143 }
144
145 return rc;
146}
147
133static bool smc_cdc_tx_filter(struct smc_wr_tx_pend_priv *tx_pend, 148static bool smc_cdc_tx_filter(struct smc_wr_tx_pend_priv *tx_pend,
134 unsigned long data) 149 unsigned long data)
135{ 150{
@@ -157,6 +172,45 @@ void smc_cdc_tx_dismiss_slots(struct smc_connection *conn)
157 (unsigned long)conn); 172 (unsigned long)conn);
158} 173}
159 174
175/* Send a SMC-D CDC header.
176 * This increments the free space available in our send buffer.
177 * Also update the confirmed receive buffer with what was sent to the peer.
178 */
179int smcd_cdc_msg_send(struct smc_connection *conn)
180{
181 struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
182 struct smcd_cdc_msg cdc;
183 int rc, diff;
184
185 memset(&cdc, 0, sizeof(cdc));
186 cdc.common.type = SMC_CDC_MSG_TYPE;
187 cdc.prod_wrap = conn->local_tx_ctrl.prod.wrap;
188 cdc.prod_count = conn->local_tx_ctrl.prod.count;
189
190 cdc.cons_wrap = conn->local_tx_ctrl.cons.wrap;
191 cdc.cons_count = conn->local_tx_ctrl.cons.count;
192 cdc.prod_flags = conn->local_tx_ctrl.prod_flags;
193 cdc.conn_state_flags = conn->local_tx_ctrl.conn_state_flags;
194 rc = smcd_tx_ism_write(conn, &cdc, sizeof(cdc), 0, 1);
195 if (rc)
196 return rc;
197 smc_curs_write(&conn->rx_curs_confirmed,
198 smc_curs_read(&conn->local_tx_ctrl.cons, conn), conn);
199 /* Calculate transmitted data and increment free send buffer space */
200 diff = smc_curs_diff(conn->sndbuf_desc->len, &conn->tx_curs_fin,
201 &conn->tx_curs_sent);
202 /* increased by confirmed number of bytes */
203 smp_mb__before_atomic();
204 atomic_add(diff, &conn->sndbuf_space);
205 /* guarantee 0 <= sndbuf_space <= sndbuf_desc->len */
206 smp_mb__after_atomic();
207 smc_curs_write(&conn->tx_curs_fin,
208 smc_curs_read(&conn->tx_curs_sent, conn), conn);
209
210 smc_tx_sndbuf_nonfull(smc);
211 return rc;
212}
213
160/********************************* receive ***********************************/ 214/********************************* receive ***********************************/
161 215
162static inline bool smc_cdc_before(u16 seq1, u16 seq2) 216static inline bool smc_cdc_before(u16 seq1, u16 seq2)
@@ -178,7 +232,7 @@ static void smc_cdc_handle_urg_data_arrival(struct smc_sock *smc,
178 if (!sock_flag(&smc->sk, SOCK_URGINLINE)) 232 if (!sock_flag(&smc->sk, SOCK_URGINLINE))
179 /* we'll skip the urgent byte, so don't account for it */ 233 /* we'll skip the urgent byte, so don't account for it */
180 (*diff_prod)--; 234 (*diff_prod)--;
181 base = (char *)conn->rmb_desc->cpu_addr; 235 base = (char *)conn->rmb_desc->cpu_addr + conn->rx_off;
182 if (conn->urg_curs.count) 236 if (conn->urg_curs.count)
183 conn->urg_rx_byte = *(base + conn->urg_curs.count - 1); 237 conn->urg_rx_byte = *(base + conn->urg_curs.count - 1);
184 else 238 else
@@ -276,6 +330,34 @@ static void smc_cdc_msg_recv(struct smc_sock *smc, struct smc_cdc_msg *cdc)
276 sock_put(&smc->sk); /* no free sk in softirq-context */ 330 sock_put(&smc->sk); /* no free sk in softirq-context */
277} 331}
278 332
333/* Schedule a tasklet for this connection. Triggered from the ISM device IRQ
334 * handler to indicate update in the DMBE.
335 *
336 * Context:
337 * - tasklet context
338 */
339static void smcd_cdc_rx_tsklet(unsigned long data)
340{
341 struct smc_connection *conn = (struct smc_connection *)data;
342 struct smcd_cdc_msg cdc;
343 struct smc_sock *smc;
344
345 if (!conn)
346 return;
347
348 memcpy(&cdc, conn->rmb_desc->cpu_addr, sizeof(cdc));
349 smc = container_of(conn, struct smc_sock, conn);
350 smc_cdc_msg_recv(smc, (struct smc_cdc_msg *)&cdc);
351}
352
353/* Initialize receive tasklet. Called from ISM device IRQ handler to start
354 * receiver side.
355 */
356void smcd_cdc_rx_init(struct smc_connection *conn)
357{
358 tasklet_init(&conn->rx_tsklet, smcd_cdc_rx_tsklet, (unsigned long)conn);
359}
360
279/***************************** init, exit, misc ******************************/ 361/***************************** init, exit, misc ******************************/
280 362
281static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) 363static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf)