diff options
Diffstat (limited to 'net/smc/smc_cdc.c')
-rw-r--r-- | net/smc/smc_cdc.c | 86 |
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 | ||
120 | int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn) | 120 | static 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 | ||
133 | int 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 | |||
133 | static bool smc_cdc_tx_filter(struct smc_wr_tx_pend_priv *tx_pend, | 148 | static 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 | */ | ||
179 | int 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 | ||
162 | static inline bool smc_cdc_before(u16 seq1, u16 seq2) | 216 | static 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 | */ | ||
339 | static 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 | */ | ||
356 | void 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 | ||
281 | static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) | 363 | static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) |