Skip to content

Commit be244f2

Browse files
Hans Wippeldavem330
authored andcommitted
net/smc: add SMC-D support in data transfer
The data transfer and CDC message headers differ in SMC-R and SMC-D. This patch adds support for the SMC-D data transfer to the existing SMC code. It consists of the following: * SMC-D CDC support * SMC-D tx support * SMC-D rx support The CDC header is stored at the beginning of the receive buffer. Thus, a rx_offset variable is added for the CDC header offset within the buffer (0 for SMC-R). Signed-off-by: Hans Wippel <[email protected]> Signed-off-by: Ursula Braun <[email protected]> Suggested-by: Thomas Richter <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c758dfd commit be244f2

File tree

8 files changed

+308
-56
lines changed

8 files changed

+308
-56
lines changed

net/smc/smc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ struct smc_connection {
183183
spinlock_t acurs_lock; /* protect cursors */
184184
#endif
185185
struct work_struct close_work; /* peer sent some closing */
186+
struct tasklet_struct rx_tsklet; /* Receiver tasklet for SMC-D */
187+
u8 rx_off; /* receive offset:
188+
* 0 for SMC-R, 32 for SMC-D
189+
*/
190+
u64 peer_token; /* SMC-D token of peer */
186191
};
187192

188193
struct smc_sock { /* smc sock container */

net/smc/smc_cdc.c

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ int smc_cdc_msg_send(struct smc_connection *conn,
117117
return rc;
118118
}
119119

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)
121121
{
122122
struct smc_cdc_tx_pend *pend;
123123
struct smc_wr_buf *wr_buf;
@@ -130,6 +130,21 @@ int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn)
130130
return smc_cdc_msg_send(conn, wr_buf, pend);
131131
}
132132

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+
133148
static bool smc_cdc_tx_filter(struct smc_wr_tx_pend_priv *tx_pend,
134149
unsigned long data)
135150
{
@@ -157,6 +172,45 @@ void smc_cdc_tx_dismiss_slots(struct smc_connection *conn)
157172
(unsigned long)conn);
158173
}
159174

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+
160214
/********************************* receive ***********************************/
161215

162216
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,
178232
if (!sock_flag(&smc->sk, SOCK_URGINLINE))
179233
/* we'll skip the urgent byte, so don't account for it */
180234
(*diff_prod)--;
181-
base = (char *)conn->rmb_desc->cpu_addr;
235+
base = (char *)conn->rmb_desc->cpu_addr + conn->rx_off;
182236
if (conn->urg_curs.count)
183237
conn->urg_rx_byte = *(base + conn->urg_curs.count - 1);
184238
else
@@ -276,6 +330,34 @@ static void smc_cdc_msg_recv(struct smc_sock *smc, struct smc_cdc_msg *cdc)
276330
sock_put(&smc->sk); /* no free sk in softirq-context */
277331
}
278332

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+
279361
/***************************** init, exit, misc ******************************/
280362

281363
static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf)

net/smc/smc_cdc.h

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ struct smc_cdc_msg {
5050
u8 reserved[18];
5151
} __packed; /* format defined in RFC7609 */
5252

53+
/* CDC message for SMC-D */
54+
struct smcd_cdc_msg {
55+
struct smc_wr_rx_hdr common; /* Type = 0xFE */
56+
u8 res1[7];
57+
u16 prod_wrap;
58+
u32 prod_count;
59+
u8 res2[2];
60+
u16 cons_wrap;
61+
u32 cons_count;
62+
struct smc_cdc_producer_flags prod_flags;
63+
struct smc_cdc_conn_state_flags conn_state_flags;
64+
u8 res3[8];
65+
} __packed;
66+
5367
static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn)
5468
{
5569
return conn->local_rx_ctrl.conn_state_flags.peer_conn_abort ||
@@ -204,9 +218,9 @@ static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
204218
smc_curs_write(local, smc_curs_read(&temp, conn), conn);
205219
}
206220

207-
static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local,
208-
struct smc_cdc_msg *peer,
209-
struct smc_connection *conn)
221+
static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
222+
struct smc_cdc_msg *peer,
223+
struct smc_connection *conn)
210224
{
211225
local->common.type = peer->common.type;
212226
local->len = peer->len;
@@ -218,6 +232,27 @@ static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local,
218232
local->conn_state_flags = peer->conn_state_flags;
219233
}
220234

235+
static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local,
236+
struct smcd_cdc_msg *peer)
237+
{
238+
local->prod.wrap = peer->prod_wrap;
239+
local->prod.count = peer->prod_count;
240+
local->cons.wrap = peer->cons_wrap;
241+
local->cons.count = peer->cons_count;
242+
local->prod_flags = peer->prod_flags;
243+
local->conn_state_flags = peer->conn_state_flags;
244+
}
245+
246+
static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local,
247+
struct smc_cdc_msg *peer,
248+
struct smc_connection *conn)
249+
{
250+
if (conn->lgr->is_smcd)
251+
smcd_cdc_msg_to_host(local, (struct smcd_cdc_msg *)peer);
252+
else
253+
smcr_cdc_msg_to_host(local, peer, conn);
254+
}
255+
221256
struct smc_cdc_tx_pend;
222257

223258
int smc_cdc_get_free_slot(struct smc_connection *conn,
@@ -227,6 +262,8 @@ void smc_cdc_tx_dismiss_slots(struct smc_connection *conn);
227262
int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf,
228263
struct smc_cdc_tx_pend *pend);
229264
int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn);
265+
int smcd_cdc_msg_send(struct smc_connection *conn);
230266
int smc_cdc_init(void) __init;
267+
void smcd_cdc_rx_init(struct smc_connection *conn);
231268

232269
#endif /* SMC_CDC_H */

net/smc/smc_core.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,12 @@ void smc_conn_free(struct smc_connection *conn)
281281
{
282282
if (!conn->lgr)
283283
return;
284-
if (conn->lgr->is_smcd)
284+
if (conn->lgr->is_smcd) {
285285
smc_ism_unset_conn(conn);
286-
else
286+
tasklet_kill(&conn->rx_tsklet);
287+
} else {
287288
smc_cdc_tx_dismiss_slots(conn);
289+
}
288290
smc_lgr_unregister_conn(conn);
289291
smc_buf_unuse(conn);
290292
}
@@ -324,10 +326,13 @@ static void smcr_buf_free(struct smc_link_group *lgr, bool is_rmb,
324326
static void smcd_buf_free(struct smc_link_group *lgr, bool is_dmb,
325327
struct smc_buf_desc *buf_desc)
326328
{
327-
if (is_dmb)
329+
if (is_dmb) {
330+
/* restore original buf len */
331+
buf_desc->len += sizeof(struct smcd_cdc_msg);
328332
smc_ism_unregister_dmb(lgr->smcd, buf_desc);
329-
else
333+
} else {
330334
kfree(buf_desc->cpu_addr);
335+
}
331336
kfree(buf_desc);
332337
}
333338

@@ -632,6 +637,10 @@ int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
632637
conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
633638
conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
634639
conn->urg_state = SMC_URG_READ;
640+
if (is_smcd) {
641+
conn->rx_off = sizeof(struct smcd_cdc_msg);
642+
smcd_cdc_rx_init(conn); /* init tasklet for this conn */
643+
}
635644
#ifndef KERNEL_HAS_ATOMIC64
636645
spin_lock_init(&conn->acurs_lock);
637646
#endif
@@ -776,8 +785,9 @@ static struct smc_buf_desc *smcd_new_buf_create(struct smc_link_group *lgr,
776785
kfree(buf_desc);
777786
return ERR_PTR(-EAGAIN);
778787
}
779-
memset(buf_desc->cpu_addr, 0, bufsize);
780-
buf_desc->len = bufsize;
788+
buf_desc->pages = virt_to_page(buf_desc->cpu_addr);
789+
/* CDC header stored in buf. So, pretend it was smaller */
790+
buf_desc->len = bufsize - sizeof(struct smcd_cdc_msg);
781791
} else {
782792
buf_desc->cpu_addr = kzalloc(bufsize, GFP_KERNEL |
783793
__GFP_NOWARN | __GFP_NORETRY |
@@ -854,7 +864,8 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb)
854864
conn->rmbe_size_short = bufsize_short;
855865
smc->sk.sk_rcvbuf = bufsize * 2;
856866
atomic_set(&conn->bytes_to_rcv, 0);
857-
conn->rmbe_update_limit = smc_rmb_wnd_update_limit(bufsize);
867+
conn->rmbe_update_limit =
868+
smc_rmb_wnd_update_limit(buf_desc->len);
858869
if (is_smcd)
859870
smc_ism_set_conn(conn); /* map RMB/smcd_dev to conn */
860871
} else {

net/smc/smc_ism.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,5 +302,13 @@ EXPORT_SYMBOL_GPL(smcd_handle_event);
302302
*/
303303
void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno)
304304
{
305+
struct smc_connection *conn = NULL;
306+
unsigned long flags;
307+
308+
spin_lock_irqsave(&smcd->lock, flags);
309+
conn = smcd->conn[dmbno];
310+
if (conn)
311+
tasklet_schedule(&conn->rx_tsklet);
312+
spin_unlock_irqrestore(&smcd->lock, flags);
305313
}
306314
EXPORT_SYMBOL_GPL(smcd_handle_irq);

net/smc/smc_rx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
305305
target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
306306

307307
/* we currently use 1 RMBE per RMB, so RMBE == RMB base addr */
308-
rcvbuf_base = conn->rmb_desc->cpu_addr;
308+
rcvbuf_base = conn->rx_off + conn->rmb_desc->cpu_addr;
309309

310310
do { /* while (read_remaining) */
311311
if (read_done >= target || (pipe && read_done))

0 commit comments

Comments
 (0)