summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/smc.h62
-rw-r--r--net/smc/Makefile2
-rw-r--r--net/smc/af_smc.c11
-rw-r--r--net/smc/smc_core.c270
-rw-r--r--net/smc/smc_core.h71
-rw-r--r--net/smc/smc_diag.c3
-rw-r--r--net/smc/smc_ism.c304
-rw-r--r--net/smc/smc_ism.h48
8 files changed, 679 insertions, 92 deletions
diff --git a/include/net/smc.h b/include/net/smc.h
index 2173932fab9d..824a7af8d654 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -20,4 +20,66 @@ struct smc_hashinfo {
20 20
21int smc_hash_sk(struct sock *sk); 21int smc_hash_sk(struct sock *sk);
22void smc_unhash_sk(struct sock *sk); 22void smc_unhash_sk(struct sock *sk);
23
24/* SMCD/ISM device driver interface */
25struct smcd_dmb {
26 u64 dmb_tok;
27 u64 rgid;
28 u32 dmb_len;
29 u32 sba_idx;
30 u32 vlan_valid;
31 u32 vlan_id;
32 void *cpu_addr;
33 dma_addr_t dma_addr;
34};
35
36#define ISM_EVENT_DMB 0
37#define ISM_EVENT_GID 1
38#define ISM_EVENT_SWR 2
39
40struct smcd_event {
41 u32 type;
42 u32 code;
43 u64 tok;
44 u64 time;
45 u64 info;
46};
47
48struct smcd_dev;
49
50struct smcd_ops {
51 int (*query_remote_gid)(struct smcd_dev *dev, u64 rgid, u32 vid_valid,
52 u32 vid);
53 int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
54 int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
55 int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
56 int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
57 int (*set_vlan_required)(struct smcd_dev *dev);
58 int (*reset_vlan_required)(struct smcd_dev *dev);
59 int (*signal_event)(struct smcd_dev *dev, u64 rgid, u32 trigger_irq,
60 u32 event_code, u64 info);
61 int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx,
62 bool sf, unsigned int offset, void *data,
63 unsigned int size);
64};
65
66struct smcd_dev {
67 const struct smcd_ops *ops;
68 struct device dev;
69 void *priv;
70 u64 local_gid;
71 struct list_head list;
72 spinlock_t lock;
73 struct smc_connection **conn;
74 struct list_head vlan;
75 struct workqueue_struct *event_wq;
76};
77
78struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
79 const struct smcd_ops *ops, int max_dmbs);
80int smcd_register_dev(struct smcd_dev *smcd);
81void smcd_unregister_dev(struct smcd_dev *smcd);
82void smcd_free_dev(struct smcd_dev *smcd);
83void smcd_handle_event(struct smcd_dev *dev, struct smcd_event *event);
84void smcd_handle_irq(struct smcd_dev *dev, unsigned int bit);
23#endif /* _SMC_H */ 85#endif /* _SMC_H */
diff --git a/net/smc/Makefile b/net/smc/Makefile
index 188104654b54..4df96b4b8130 100644
--- a/net/smc/Makefile
+++ b/net/smc/Makefile
@@ -1,4 +1,4 @@
1obj-$(CONFIG_SMC) += smc.o 1obj-$(CONFIG_SMC) += smc.o
2obj-$(CONFIG_SMC_DIAG) += smc_diag.o 2obj-$(CONFIG_SMC_DIAG) += smc_diag.o
3smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o smc_wr.o smc_llc.o 3smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o smc_wr.o smc_llc.o
4smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o 4smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index da7f02edcd37..8ce48799cf68 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -475,8 +475,8 @@ static int smc_connect_rdma(struct smc_sock *smc,
475 int reason_code = 0; 475 int reason_code = 0;
476 476
477 mutex_lock(&smc_create_lgr_pending); 477 mutex_lock(&smc_create_lgr_pending);
478 local_contact = smc_conn_create(smc, ibdev, ibport, &aclc->lcl, 478 local_contact = smc_conn_create(smc, false, aclc->hdr.flag, ibdev,
479 aclc->hdr.flag); 479 ibport, &aclc->lcl, NULL, 0);
480 if (local_contact < 0) { 480 if (local_contact < 0) {
481 if (local_contact == -ENOMEM) 481 if (local_contact == -ENOMEM)
482 reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/ 482 reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/
@@ -491,7 +491,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
491 smc_conn_save_peer_info(smc, aclc); 491 smc_conn_save_peer_info(smc, aclc);
492 492
493 /* create send buffer and rmb */ 493 /* create send buffer and rmb */
494 if (smc_buf_create(smc)) 494 if (smc_buf_create(smc, false))
495 return smc_connect_abort(smc, SMC_CLC_DECL_MEM, local_contact); 495 return smc_connect_abort(smc, SMC_CLC_DECL_MEM, local_contact);
496 496
497 if (local_contact == SMC_FIRST_CONTACT) 497 if (local_contact == SMC_FIRST_CONTACT)
@@ -894,7 +894,8 @@ static int smc_listen_rdma_init(struct smc_sock *new_smc,
894 int *local_contact) 894 int *local_contact)
895{ 895{
896 /* allocate connection / link group */ 896 /* allocate connection / link group */
897 *local_contact = smc_conn_create(new_smc, ibdev, ibport, &pclc->lcl, 0); 897 *local_contact = smc_conn_create(new_smc, false, 0, ibdev, ibport,
898 &pclc->lcl, NULL, 0);
898 if (*local_contact < 0) { 899 if (*local_contact < 0) {
899 if (*local_contact == -ENOMEM) 900 if (*local_contact == -ENOMEM)
900 return SMC_CLC_DECL_MEM;/* insufficient memory*/ 901 return SMC_CLC_DECL_MEM;/* insufficient memory*/
@@ -902,7 +903,7 @@ static int smc_listen_rdma_init(struct smc_sock *new_smc,
902 } 903 }
903 904
904 /* create send buffer and rmb */ 905 /* create send buffer and rmb */
905 if (smc_buf_create(new_smc)) 906 if (smc_buf_create(new_smc, false))
906 return SMC_CLC_DECL_MEM; 907 return SMC_CLC_DECL_MEM;
907 908
908 return 0; 909 return 0;
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index add82b0266f3..daa88db1841a 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -25,6 +25,7 @@
25#include "smc_llc.h" 25#include "smc_llc.h"
26#include "smc_cdc.h" 26#include "smc_cdc.h"
27#include "smc_close.h" 27#include "smc_close.h"
28#include "smc_ism.h"
28 29
29#define SMC_LGR_NUM_INCR 256 30#define SMC_LGR_NUM_INCR 256
30#define SMC_LGR_FREE_DELAY_SERV (600 * HZ) 31#define SMC_LGR_FREE_DELAY_SERV (600 * HZ)
@@ -46,8 +47,8 @@ static void smc_lgr_schedule_free_work(struct smc_link_group *lgr)
46 * otherwise there is a risk of out-of-sync link groups. 47 * otherwise there is a risk of out-of-sync link groups.
47 */ 48 */
48 mod_delayed_work(system_wq, &lgr->free_work, 49 mod_delayed_work(system_wq, &lgr->free_work,
49 lgr->role == SMC_CLNT ? SMC_LGR_FREE_DELAY_CLNT : 50 (!lgr->is_smcd && lgr->role == SMC_CLNT) ?
50 SMC_LGR_FREE_DELAY_SERV); 51 SMC_LGR_FREE_DELAY_CLNT : SMC_LGR_FREE_DELAY_SERV);
51} 52}
52 53
53/* Register connection's alert token in our lookup structure. 54/* Register connection's alert token in our lookup structure.
@@ -153,16 +154,18 @@ static void smc_lgr_free_work(struct work_struct *work)
153free: 154free:
154 spin_unlock_bh(&smc_lgr_list.lock); 155 spin_unlock_bh(&smc_lgr_list.lock);
155 if (!delayed_work_pending(&lgr->free_work)) { 156 if (!delayed_work_pending(&lgr->free_work)) {
156 if (lgr->lnk[SMC_SINGLE_LINK].state != SMC_LNK_INACTIVE) 157 if (!lgr->is_smcd &&
158 lgr->lnk[SMC_SINGLE_LINK].state != SMC_LNK_INACTIVE)
157 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]); 159 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]);
158 smc_lgr_free(lgr); 160 smc_lgr_free(lgr);
159 } 161 }
160} 162}
161 163
162/* create a new SMC link group */ 164/* create a new SMC link group */
163static int smc_lgr_create(struct smc_sock *smc, 165static int smc_lgr_create(struct smc_sock *smc, bool is_smcd,
164 struct smc_ib_device *smcibdev, u8 ibport, 166 struct smc_ib_device *smcibdev, u8 ibport,
165 char *peer_systemid, unsigned short vlan_id) 167 char *peer_systemid, unsigned short vlan_id,
168 struct smcd_dev *smcismdev, u64 peer_gid)
166{ 169{
167 struct smc_link_group *lgr; 170 struct smc_link_group *lgr;
168 struct smc_link *lnk; 171 struct smc_link *lnk;
@@ -170,17 +173,23 @@ static int smc_lgr_create(struct smc_sock *smc,
170 int rc = 0; 173 int rc = 0;
171 int i; 174 int i;
172 175
176 if (is_smcd && vlan_id) {
177 rc = smc_ism_get_vlan(smcismdev, vlan_id);
178 if (rc)
179 goto out;
180 }
181
173 lgr = kzalloc(sizeof(*lgr), GFP_KERNEL); 182 lgr = kzalloc(sizeof(*lgr), GFP_KERNEL);
174 if (!lgr) { 183 if (!lgr) {
175 rc = -ENOMEM; 184 rc = -ENOMEM;
176 goto out; 185 goto out;
177 } 186 }
178 lgr->role = smc->listen_smc ? SMC_SERV : SMC_CLNT; 187 lgr->is_smcd = is_smcd;
179 lgr->sync_err = 0; 188 lgr->sync_err = 0;
180 memcpy(lgr->peer_systemid, peer_systemid, SMC_SYSTEMID_LEN);
181 lgr->vlan_id = vlan_id; 189 lgr->vlan_id = vlan_id;
182 rwlock_init(&lgr->sndbufs_lock); 190 rwlock_init(&lgr->sndbufs_lock);
183 rwlock_init(&lgr->rmbs_lock); 191 rwlock_init(&lgr->rmbs_lock);
192 rwlock_init(&lgr->conns_lock);
184 for (i = 0; i < SMC_RMBE_SIZES; i++) { 193 for (i = 0; i < SMC_RMBE_SIZES; i++) {
185 INIT_LIST_HEAD(&lgr->sndbufs[i]); 194 INIT_LIST_HEAD(&lgr->sndbufs[i]);
186 INIT_LIST_HEAD(&lgr->rmbs[i]); 195 INIT_LIST_HEAD(&lgr->rmbs[i]);
@@ -189,36 +198,44 @@ static int smc_lgr_create(struct smc_sock *smc,
189 memcpy(&lgr->id, (u8 *)&smc_lgr_list.num, SMC_LGR_ID_SIZE); 198 memcpy(&lgr->id, (u8 *)&smc_lgr_list.num, SMC_LGR_ID_SIZE);
190 INIT_DELAYED_WORK(&lgr->free_work, smc_lgr_free_work); 199 INIT_DELAYED_WORK(&lgr->free_work, smc_lgr_free_work);
191 lgr->conns_all = RB_ROOT; 200 lgr->conns_all = RB_ROOT;
192 201 if (is_smcd) {
193 lnk = &lgr->lnk[SMC_SINGLE_LINK]; 202 /* SMC-D specific settings */
194 /* initialize link */ 203 lgr->peer_gid = peer_gid;
195 lnk->state = SMC_LNK_ACTIVATING; 204 lgr->smcd = smcismdev;
196 lnk->link_id = SMC_SINGLE_LINK; 205 } else {
197 lnk->smcibdev = smcibdev; 206 /* SMC-R specific settings */
198 lnk->ibport = ibport; 207 lgr->role = smc->listen_smc ? SMC_SERV : SMC_CLNT;
199 lnk->path_mtu = smcibdev->pattr[ibport - 1].active_mtu; 208 memcpy(lgr->peer_systemid, peer_systemid, SMC_SYSTEMID_LEN);
200 if (!smcibdev->initialized) 209
201 smc_ib_setup_per_ibdev(smcibdev); 210 lnk = &lgr->lnk[SMC_SINGLE_LINK];
202 get_random_bytes(rndvec, sizeof(rndvec)); 211 /* initialize link */
203 lnk->psn_initial = rndvec[0] + (rndvec[1] << 8) + (rndvec[2] << 16); 212 lnk->state = SMC_LNK_ACTIVATING;
204 rc = smc_llc_link_init(lnk); 213 lnk->link_id = SMC_SINGLE_LINK;
205 if (rc) 214 lnk->smcibdev = smcibdev;
206 goto free_lgr; 215 lnk->ibport = ibport;
207 rc = smc_wr_alloc_link_mem(lnk); 216 lnk->path_mtu = smcibdev->pattr[ibport - 1].active_mtu;
208 if (rc) 217 if (!smcibdev->initialized)
209 goto clear_llc_lnk; 218 smc_ib_setup_per_ibdev(smcibdev);
210 rc = smc_ib_create_protection_domain(lnk); 219 get_random_bytes(rndvec, sizeof(rndvec));
211 if (rc) 220 lnk->psn_initial = rndvec[0] + (rndvec[1] << 8) +
212 goto free_link_mem; 221 (rndvec[2] << 16);
213 rc = smc_ib_create_queue_pair(lnk); 222 rc = smc_llc_link_init(lnk);
214 if (rc) 223 if (rc)
215 goto dealloc_pd; 224 goto free_lgr;
216 rc = smc_wr_create_link(lnk); 225 rc = smc_wr_alloc_link_mem(lnk);
217 if (rc) 226 if (rc)
218 goto destroy_qp; 227 goto clear_llc_lnk;
219 228 rc = smc_ib_create_protection_domain(lnk);
229 if (rc)
230 goto free_link_mem;
231 rc = smc_ib_create_queue_pair(lnk);
232 if (rc)
233 goto dealloc_pd;
234 rc = smc_wr_create_link(lnk);
235 if (rc)
236 goto destroy_qp;
237 }
220 smc->conn.lgr = lgr; 238 smc->conn.lgr = lgr;
221 rwlock_init(&lgr->conns_lock);
222 spin_lock_bh(&smc_lgr_list.lock); 239 spin_lock_bh(&smc_lgr_list.lock);
223 list_add(&lgr->list, &smc_lgr_list.list); 240 list_add(&lgr->list, &smc_lgr_list.list);
224 spin_unlock_bh(&smc_lgr_list.lock); 241 spin_unlock_bh(&smc_lgr_list.lock);
@@ -264,7 +281,10 @@ void smc_conn_free(struct smc_connection *conn)
264{ 281{
265 if (!conn->lgr) 282 if (!conn->lgr)
266 return; 283 return;
267 smc_cdc_tx_dismiss_slots(conn); 284 if (conn->lgr->is_smcd)
285 smc_ism_unset_conn(conn);
286 else
287 smc_cdc_tx_dismiss_slots(conn);
268 smc_lgr_unregister_conn(conn); 288 smc_lgr_unregister_conn(conn);
269 smc_buf_unuse(conn); 289 smc_buf_unuse(conn);
270} 290}
@@ -280,8 +300,8 @@ static void smc_link_clear(struct smc_link *lnk)
280 smc_wr_free_link_mem(lnk); 300 smc_wr_free_link_mem(lnk);
281} 301}
282 302
283static void smc_buf_free(struct smc_link_group *lgr, bool is_rmb, 303static void smcr_buf_free(struct smc_link_group *lgr, bool is_rmb,
284 struct smc_buf_desc *buf_desc) 304 struct smc_buf_desc *buf_desc)
285{ 305{
286 struct smc_link *lnk = &lgr->lnk[SMC_SINGLE_LINK]; 306 struct smc_link *lnk = &lgr->lnk[SMC_SINGLE_LINK];
287 307
@@ -301,6 +321,25 @@ static void smc_buf_free(struct smc_link_group *lgr, bool is_rmb,
301 kfree(buf_desc); 321 kfree(buf_desc);
302} 322}
303 323
324static void smcd_buf_free(struct smc_link_group *lgr, bool is_dmb,
325 struct smc_buf_desc *buf_desc)
326{
327 if (is_dmb)
328 smc_ism_unregister_dmb(lgr->smcd, buf_desc);
329 else
330 kfree(buf_desc->cpu_addr);
331 kfree(buf_desc);
332}
333
334static void smc_buf_free(struct smc_link_group *lgr, bool is_rmb,
335 struct smc_buf_desc *buf_desc)
336{
337 if (lgr->is_smcd)
338 smcd_buf_free(lgr, is_rmb, buf_desc);
339 else
340 smcr_buf_free(lgr, is_rmb, buf_desc);
341}
342
304static void __smc_lgr_free_bufs(struct smc_link_group *lgr, bool is_rmb) 343static void __smc_lgr_free_bufs(struct smc_link_group *lgr, bool is_rmb)
305{ 344{
306 struct smc_buf_desc *buf_desc, *bf_desc; 345 struct smc_buf_desc *buf_desc, *bf_desc;
@@ -332,7 +371,10 @@ static void smc_lgr_free_bufs(struct smc_link_group *lgr)
332void smc_lgr_free(struct smc_link_group *lgr) 371void smc_lgr_free(struct smc_link_group *lgr)
333{ 372{
334 smc_lgr_free_bufs(lgr); 373 smc_lgr_free_bufs(lgr);
335 smc_link_clear(&lgr->lnk[SMC_SINGLE_LINK]); 374 if (lgr->is_smcd)
375 smc_ism_put_vlan(lgr->smcd, lgr->vlan_id);
376 else
377 smc_link_clear(&lgr->lnk[SMC_SINGLE_LINK]);
336 kfree(lgr); 378 kfree(lgr);
337} 379}
338 380
@@ -357,7 +399,8 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr)
357 lgr->terminating = 1; 399 lgr->terminating = 1;
358 if (!list_empty(&lgr->list)) /* forget lgr */ 400 if (!list_empty(&lgr->list)) /* forget lgr */
359 list_del_init(&lgr->list); 401 list_del_init(&lgr->list);
360 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]); 402 if (!lgr->is_smcd)
403 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]);
361 404
362 write_lock_bh(&lgr->conns_lock); 405 write_lock_bh(&lgr->conns_lock);
363 node = rb_first(&lgr->conns_all); 406 node = rb_first(&lgr->conns_all);
@@ -374,7 +417,8 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr)
374 node = rb_first(&lgr->conns_all); 417 node = rb_first(&lgr->conns_all);
375 } 418 }
376 write_unlock_bh(&lgr->conns_lock); 419 write_unlock_bh(&lgr->conns_lock);
377 wake_up(&lgr->lnk[SMC_SINGLE_LINK].wr_reg_wait); 420 if (!lgr->is_smcd)
421 wake_up(&lgr->lnk[SMC_SINGLE_LINK].wr_reg_wait);
378 smc_lgr_schedule_free_work(lgr); 422 smc_lgr_schedule_free_work(lgr);
379} 423}
380 424
@@ -392,13 +436,40 @@ void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport)
392 436
393 spin_lock_bh(&smc_lgr_list.lock); 437 spin_lock_bh(&smc_lgr_list.lock);
394 list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) { 438 list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) {
395 if (lgr->lnk[SMC_SINGLE_LINK].smcibdev == smcibdev && 439 if (!lgr->is_smcd &&
440 lgr->lnk[SMC_SINGLE_LINK].smcibdev == smcibdev &&
396 lgr->lnk[SMC_SINGLE_LINK].ibport == ibport) 441 lgr->lnk[SMC_SINGLE_LINK].ibport == ibport)
397 __smc_lgr_terminate(lgr); 442 __smc_lgr_terminate(lgr);
398 } 443 }
399 spin_unlock_bh(&smc_lgr_list.lock); 444 spin_unlock_bh(&smc_lgr_list.lock);
400} 445}
401 446
447/* Called when SMC-D device is terminated or peer is lost */
448void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid)
449{
450 struct smc_link_group *lgr, *l;
451 LIST_HEAD(lgr_free_list);
452
453 /* run common cleanup function and build free list */
454 spin_lock_bh(&smc_lgr_list.lock);
455 list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) {
456 if (lgr->is_smcd && lgr->smcd == dev &&
457 (!peer_gid || lgr->peer_gid == peer_gid) &&
458 !list_empty(&lgr->list)) {
459 __smc_lgr_terminate(lgr);
460 list_move(&lgr->list, &lgr_free_list);
461 }
462 }
463 spin_unlock_bh(&smc_lgr_list.lock);
464
465 /* cancel the regular free workers and actually free lgrs */
466 list_for_each_entry_safe(lgr, l, &lgr_free_list, list) {
467 list_del_init(&lgr->list);
468 cancel_delayed_work_sync(&lgr->free_work);
469 smc_lgr_free(lgr);
470 }
471}
472
402/* Determine vlan of internal TCP socket. 473/* Determine vlan of internal TCP socket.
403 * @vlan_id: address to store the determined vlan id into 474 * @vlan_id: address to store the determined vlan id into
404 */ 475 */
@@ -477,10 +548,30 @@ static int smc_link_determine_gid(struct smc_link_group *lgr)
477 return -ENODEV; 548 return -ENODEV;
478} 549}
479 550
551static bool smcr_lgr_match(struct smc_link_group *lgr,
552 struct smc_clc_msg_local *lcl,
553 enum smc_lgr_role role)
554{
555 return !memcmp(lgr->peer_systemid, lcl->id_for_peer,
556 SMC_SYSTEMID_LEN) &&
557 !memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_gid, &lcl->gid,
558 SMC_GID_SIZE) &&
559 !memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_mac, lcl->mac,
560 sizeof(lcl->mac)) &&
561 lgr->role == role;
562}
563
564static bool smcd_lgr_match(struct smc_link_group *lgr,
565 struct smcd_dev *smcismdev, u64 peer_gid)
566{
567 return lgr->peer_gid == peer_gid && lgr->smcd == smcismdev;
568}
569
480/* create a new SMC connection (and a new link group if necessary) */ 570/* create a new SMC connection (and a new link group if necessary) */
481int smc_conn_create(struct smc_sock *smc, 571int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
482 struct smc_ib_device *smcibdev, u8 ibport, 572 struct smc_ib_device *smcibdev, u8 ibport,
483 struct smc_clc_msg_local *lcl, int srv_first_contact) 573 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd,
574 u64 peer_gid)
484{ 575{
485 struct smc_connection *conn = &smc->conn; 576 struct smc_connection *conn = &smc->conn;
486 int local_contact = SMC_FIRST_CONTACT; 577 int local_contact = SMC_FIRST_CONTACT;
@@ -502,17 +593,12 @@ int smc_conn_create(struct smc_sock *smc,
502 spin_lock_bh(&smc_lgr_list.lock); 593 spin_lock_bh(&smc_lgr_list.lock);
503 list_for_each_entry(lgr, &smc_lgr_list.list, list) { 594 list_for_each_entry(lgr, &smc_lgr_list.list, list) {
504 write_lock_bh(&lgr->conns_lock); 595 write_lock_bh(&lgr->conns_lock);
505 if (!memcmp(lgr->peer_systemid, lcl->id_for_peer, 596 if ((is_smcd ? smcd_lgr_match(lgr, smcd, peer_gid) :
506 SMC_SYSTEMID_LEN) && 597 smcr_lgr_match(lgr, lcl, role)) &&
507 !memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_gid, &lcl->gid,
508 SMC_GID_SIZE) &&
509 !memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_mac, lcl->mac,
510 sizeof(lcl->mac)) &&
511 !lgr->sync_err && 598 !lgr->sync_err &&
512 (lgr->role == role) && 599 lgr->vlan_id == vlan_id &&
513 (lgr->vlan_id == vlan_id) && 600 (role == SMC_CLNT ||
514 ((role == SMC_CLNT) || 601 lgr->conns_num < SMC_RMBS_PER_LGR_MAX)) {
515 (lgr->conns_num < SMC_RMBS_PER_LGR_MAX))) {
516 /* link group found */ 602 /* link group found */
517 local_contact = SMC_REUSE_CONTACT; 603 local_contact = SMC_REUSE_CONTACT;
518 conn->lgr = lgr; 604 conn->lgr = lgr;
@@ -535,12 +621,13 @@ int smc_conn_create(struct smc_sock *smc,
535 621
536create: 622create:
537 if (local_contact == SMC_FIRST_CONTACT) { 623 if (local_contact == SMC_FIRST_CONTACT) {
538 rc = smc_lgr_create(smc, smcibdev, ibport, 624 rc = smc_lgr_create(smc, is_smcd, smcibdev, ibport,
539 lcl->id_for_peer, vlan_id); 625 lcl->id_for_peer, vlan_id, smcd, peer_gid);
540 if (rc) 626 if (rc)
541 goto out; 627 goto out;
542 smc_lgr_register_conn(conn); /* add smc conn to lgr */ 628 smc_lgr_register_conn(conn); /* add smc conn to lgr */
543 rc = smc_link_determine_gid(conn->lgr); 629 if (!is_smcd)
630 rc = smc_link_determine_gid(conn->lgr);
544 } 631 }
545 conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE; 632 conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
546 conn->local_tx_ctrl.len = SMC_WR_TX_SIZE; 633 conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
@@ -609,8 +696,8 @@ static inline int smc_rmb_wnd_update_limit(int rmbe_size)
609 return min_t(int, rmbe_size / 10, SOCK_MIN_SNDBUF / 2); 696 return min_t(int, rmbe_size / 10, SOCK_MIN_SNDBUF / 2);
610} 697}
611 698
612static struct smc_buf_desc *smc_new_buf_create(struct smc_link_group *lgr, 699static struct smc_buf_desc *smcr_new_buf_create(struct smc_link_group *lgr,
613 bool is_rmb, int bufsize) 700 bool is_rmb, int bufsize)
614{ 701{
615 struct smc_buf_desc *buf_desc; 702 struct smc_buf_desc *buf_desc;
616 struct smc_link *lnk; 703 struct smc_link *lnk;
@@ -668,7 +755,43 @@ static struct smc_buf_desc *smc_new_buf_create(struct smc_link_group *lgr,
668 return buf_desc; 755 return buf_desc;
669} 756}
670 757
671static int __smc_buf_create(struct smc_sock *smc, bool is_rmb) 758#define SMCD_DMBE_SIZES 7 /* 0 -> 16KB, 1 -> 32KB, .. 6 -> 1MB */
759
760static struct smc_buf_desc *smcd_new_buf_create(struct smc_link_group *lgr,
761 bool is_dmb, int bufsize)
762{
763 struct smc_buf_desc *buf_desc;
764 int rc;
765
766 if (smc_compress_bufsize(bufsize) > SMCD_DMBE_SIZES)
767 return ERR_PTR(-EAGAIN);
768
769 /* try to alloc a new DMB */
770 buf_desc = kzalloc(sizeof(*buf_desc), GFP_KERNEL);
771 if (!buf_desc)
772 return ERR_PTR(-ENOMEM);
773 if (is_dmb) {
774 rc = smc_ism_register_dmb(lgr, bufsize, buf_desc);
775 if (rc) {
776 kfree(buf_desc);
777 return ERR_PTR(-EAGAIN);
778 }
779 memset(buf_desc->cpu_addr, 0, bufsize);
780 buf_desc->len = bufsize;
781 } else {
782 buf_desc->cpu_addr = kzalloc(bufsize, GFP_KERNEL |
783 __GFP_NOWARN | __GFP_NORETRY |
784 __GFP_NOMEMALLOC);
785 if (!buf_desc->cpu_addr) {
786 kfree(buf_desc);
787 return ERR_PTR(-EAGAIN);
788 }
789 buf_desc->len = bufsize;
790 }
791 return buf_desc;
792}
793
794static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb)
672{ 795{
673 struct smc_buf_desc *buf_desc = ERR_PTR(-ENOMEM); 796 struct smc_buf_desc *buf_desc = ERR_PTR(-ENOMEM);
674 struct smc_connection *conn = &smc->conn; 797 struct smc_connection *conn = &smc->conn;
@@ -706,7 +829,11 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_rmb)
706 break; /* found reusable slot */ 829 break; /* found reusable slot */
707 } 830 }
708 831
709 buf_desc = smc_new_buf_create(lgr, is_rmb, bufsize); 832 if (is_smcd)
833 buf_desc = smcd_new_buf_create(lgr, is_rmb, bufsize);
834 else
835 buf_desc = smcr_new_buf_create(lgr, is_rmb, bufsize);
836
710 if (PTR_ERR(buf_desc) == -ENOMEM) 837 if (PTR_ERR(buf_desc) == -ENOMEM)
711 break; 838 break;
712 if (IS_ERR(buf_desc)) 839 if (IS_ERR(buf_desc))
@@ -728,6 +855,8 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_rmb)
728 smc->sk.sk_rcvbuf = bufsize * 2; 855 smc->sk.sk_rcvbuf = bufsize * 2;
729 atomic_set(&conn->bytes_to_rcv, 0); 856 atomic_set(&conn->bytes_to_rcv, 0);
730 conn->rmbe_update_limit = smc_rmb_wnd_update_limit(bufsize); 857 conn->rmbe_update_limit = smc_rmb_wnd_update_limit(bufsize);
858 if (is_smcd)
859 smc_ism_set_conn(conn); /* map RMB/smcd_dev to conn */
731 } else { 860 } else {
732 conn->sndbuf_desc = buf_desc; 861 conn->sndbuf_desc = buf_desc;
733 smc->sk.sk_sndbuf = bufsize * 2; 862 smc->sk.sk_sndbuf = bufsize * 2;
@@ -740,6 +869,8 @@ void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn)
740{ 869{
741 struct smc_link_group *lgr = conn->lgr; 870 struct smc_link_group *lgr = conn->lgr;
742 871
872 if (!conn->lgr || conn->lgr->is_smcd)
873 return;
743 smc_ib_sync_sg_for_cpu(lgr->lnk[SMC_SINGLE_LINK].smcibdev, 874 smc_ib_sync_sg_for_cpu(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
744 conn->sndbuf_desc, DMA_TO_DEVICE); 875 conn->sndbuf_desc, DMA_TO_DEVICE);
745} 876}
@@ -748,6 +879,8 @@ void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn)
748{ 879{
749 struct smc_link_group *lgr = conn->lgr; 880 struct smc_link_group *lgr = conn->lgr;
750 881
882 if (!conn->lgr || conn->lgr->is_smcd)
883 return;
751 smc_ib_sync_sg_for_device(lgr->lnk[SMC_SINGLE_LINK].smcibdev, 884 smc_ib_sync_sg_for_device(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
752 conn->sndbuf_desc, DMA_TO_DEVICE); 885 conn->sndbuf_desc, DMA_TO_DEVICE);
753} 886}
@@ -756,6 +889,8 @@ void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn)
756{ 889{
757 struct smc_link_group *lgr = conn->lgr; 890 struct smc_link_group *lgr = conn->lgr;
758 891
892 if (!conn->lgr || conn->lgr->is_smcd)
893 return;
759 smc_ib_sync_sg_for_cpu(lgr->lnk[SMC_SINGLE_LINK].smcibdev, 894 smc_ib_sync_sg_for_cpu(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
760 conn->rmb_desc, DMA_FROM_DEVICE); 895 conn->rmb_desc, DMA_FROM_DEVICE);
761} 896}
@@ -764,6 +899,8 @@ void smc_rmb_sync_sg_for_device(struct smc_connection *conn)
764{ 899{
765 struct smc_link_group *lgr = conn->lgr; 900 struct smc_link_group *lgr = conn->lgr;
766 901
902 if (!conn->lgr || conn->lgr->is_smcd)
903 return;
767 smc_ib_sync_sg_for_device(lgr->lnk[SMC_SINGLE_LINK].smcibdev, 904 smc_ib_sync_sg_for_device(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
768 conn->rmb_desc, DMA_FROM_DEVICE); 905 conn->rmb_desc, DMA_FROM_DEVICE);
769} 906}
@@ -774,16 +911,16 @@ void smc_rmb_sync_sg_for_device(struct smc_connection *conn)
774 * the Linux implementation uses just one RMB-element per RMB, i.e. uses an 911 * the Linux implementation uses just one RMB-element per RMB, i.e. uses an
775 * extra RMB for every connection in a link group 912 * extra RMB for every connection in a link group
776 */ 913 */
777int smc_buf_create(struct smc_sock *smc) 914int smc_buf_create(struct smc_sock *smc, bool is_smcd)
778{ 915{
779 int rc; 916 int rc;
780 917
781 /* create send buffer */ 918 /* create send buffer */
782 rc = __smc_buf_create(smc, false); 919 rc = __smc_buf_create(smc, is_smcd, false);
783 if (rc) 920 if (rc)
784 return rc; 921 return rc;
785 /* create rmb */ 922 /* create rmb */
786 rc = __smc_buf_create(smc, true); 923 rc = __smc_buf_create(smc, is_smcd, true);
787 if (rc) 924 if (rc)
788 smc_buf_free(smc->conn.lgr, false, smc->conn.sndbuf_desc); 925 smc_buf_free(smc->conn.lgr, false, smc->conn.sndbuf_desc);
789 return rc; 926 return rc;
@@ -865,7 +1002,8 @@ void smc_core_exit(void)
865 spin_unlock_bh(&smc_lgr_list.lock); 1002 spin_unlock_bh(&smc_lgr_list.lock);
866 list_for_each_entry_safe(lgr, lg, &lgr_freeing_list, list) { 1003 list_for_each_entry_safe(lgr, lg, &lgr_freeing_list, list) {
867 list_del_init(&lgr->list); 1004 list_del_init(&lgr->list);
868 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]); 1005 if (!lgr->is_smcd)
1006 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]);
869 cancel_delayed_work_sync(&lgr->free_work); 1007 cancel_delayed_work_sync(&lgr->free_work);
870 smc_lgr_free(lgr); /* free link group */ 1008 smc_lgr_free(lgr); /* free link group */
871 } 1009 }
diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
index 93cb3523bf50..cd9268a9570e 100644
--- a/net/smc/smc_core.h
+++ b/net/smc/smc_core.h
@@ -124,15 +124,28 @@ struct smc_buf_desc {
124 void *cpu_addr; /* virtual address of buffer */ 124 void *cpu_addr; /* virtual address of buffer */
125 struct page *pages; 125 struct page *pages;
126 int len; /* length of buffer */ 126 int len; /* length of buffer */
127 struct sg_table sgt[SMC_LINKS_PER_LGR_MAX];/* virtual buffer */
128 struct ib_mr *mr_rx[SMC_LINKS_PER_LGR_MAX];
129 /* for rmb only: memory region
130 * incl. rkey provided to peer
131 */
132 u32 order; /* allocation order */
133 u32 used; /* currently used / unused */ 127 u32 used; /* currently used / unused */
134 u8 reused : 1; /* new created / reused */ 128 u8 reused : 1; /* new created / reused */
135 u8 regerr : 1; /* err during registration */ 129 u8 regerr : 1; /* err during registration */
130 union {
131 struct { /* SMC-R */
132 struct sg_table sgt[SMC_LINKS_PER_LGR_MAX];
133 /* virtual buffer */
134 struct ib_mr *mr_rx[SMC_LINKS_PER_LGR_MAX];
135 /* for rmb only: memory region
136 * incl. rkey provided to peer
137 */
138 u32 order; /* allocation order */
139 };
140 struct { /* SMC-D */
141 unsigned short sba_idx;
142 /* SBA index number */
143 u64 token;
144 /* DMB token number */
145 dma_addr_t dma_addr;
146 /* DMA address */
147 };
148 };
136}; 149};
137 150
138struct smc_rtoken { /* address/key of remote RMB */ 151struct smc_rtoken { /* address/key of remote RMB */
@@ -148,12 +161,10 @@ struct smc_rtoken { /* address/key of remote RMB */
148 * struct smc_clc_msg_accept_confirm.rmbe_size being a 4 bit value (0..15) 161 * struct smc_clc_msg_accept_confirm.rmbe_size being a 4 bit value (0..15)
149 */ 162 */
150 163
164struct smcd_dev;
165
151struct smc_link_group { 166struct smc_link_group {
152 struct list_head list; 167 struct list_head list;
153 enum smc_lgr_role role; /* client or server */
154 struct smc_link lnk[SMC_LINKS_PER_LGR_MAX]; /* smc link */
155 char peer_systemid[SMC_SYSTEMID_LEN];
156 /* unique system_id of peer */
157 struct rb_root conns_all; /* connection tree */ 168 struct rb_root conns_all; /* connection tree */
158 rwlock_t conns_lock; /* protects conns_all */ 169 rwlock_t conns_lock; /* protects conns_all */
159 unsigned int conns_num; /* current # of connections */ 170 unsigned int conns_num; /* current # of connections */
@@ -163,17 +174,35 @@ struct smc_link_group {
163 rwlock_t sndbufs_lock; /* protects tx buffers */ 174 rwlock_t sndbufs_lock; /* protects tx buffers */
164 struct list_head rmbs[SMC_RMBE_SIZES]; /* rx buffers */ 175 struct list_head rmbs[SMC_RMBE_SIZES]; /* rx buffers */
165 rwlock_t rmbs_lock; /* protects rx buffers */ 176 rwlock_t rmbs_lock; /* protects rx buffers */
166 struct smc_rtoken rtokens[SMC_RMBS_PER_LGR_MAX]
167 [SMC_LINKS_PER_LGR_MAX];
168 /* remote addr/key pairs */
169 unsigned long rtokens_used_mask[BITS_TO_LONGS(
170 SMC_RMBS_PER_LGR_MAX)];
171 /* used rtoken elements */
172 177
173 u8 id[SMC_LGR_ID_SIZE]; /* unique lgr id */ 178 u8 id[SMC_LGR_ID_SIZE]; /* unique lgr id */
174 struct delayed_work free_work; /* delayed freeing of an lgr */ 179 struct delayed_work free_work; /* delayed freeing of an lgr */
175 u8 sync_err : 1; /* lgr no longer fits to peer */ 180 u8 sync_err : 1; /* lgr no longer fits to peer */
176 u8 terminating : 1;/* lgr is terminating */ 181 u8 terminating : 1;/* lgr is terminating */
182
183 bool is_smcd; /* SMC-R or SMC-D */
184 union {
185 struct { /* SMC-R */
186 enum smc_lgr_role role;
187 /* client or server */
188 struct smc_link lnk[SMC_LINKS_PER_LGR_MAX];
189 /* smc link */
190 char peer_systemid[SMC_SYSTEMID_LEN];
191 /* unique system_id of peer */
192 struct smc_rtoken rtokens[SMC_RMBS_PER_LGR_MAX]
193 [SMC_LINKS_PER_LGR_MAX];
194 /* remote addr/key pairs */
195 unsigned long rtokens_used_mask[BITS_TO_LONGS
196 (SMC_RMBS_PER_LGR_MAX)];
197 /* used rtoken elements */
198 };
199 struct { /* SMC-D */
200 u64 peer_gid;
201 /* Peer GID (remote) */
202 struct smcd_dev *smcd;
203 /* ISM device for VLAN reg. */
204 };
205 };
177}; 206};
178 207
179/* Find the connection associated with the given alert token in the link group. 208/* Find the connection associated with the given alert token in the link group.
@@ -217,7 +246,8 @@ void smc_lgr_free(struct smc_link_group *lgr);
217void smc_lgr_forget(struct smc_link_group *lgr); 246void smc_lgr_forget(struct smc_link_group *lgr);
218void smc_lgr_terminate(struct smc_link_group *lgr); 247void smc_lgr_terminate(struct smc_link_group *lgr);
219void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport); 248void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport);
220int smc_buf_create(struct smc_sock *smc); 249void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid);
250int smc_buf_create(struct smc_sock *smc, bool is_smcd);
221int smc_uncompress_bufsize(u8 compressed); 251int smc_uncompress_bufsize(u8 compressed);
222int smc_rmb_rtoken_handling(struct smc_connection *conn, 252int smc_rmb_rtoken_handling(struct smc_connection *conn,
223 struct smc_clc_msg_accept_confirm *clc); 253 struct smc_clc_msg_accept_confirm *clc);
@@ -227,9 +257,12 @@ void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn);
227void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn); 257void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn);
228void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn); 258void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn);
229void smc_rmb_sync_sg_for_device(struct smc_connection *conn); 259void smc_rmb_sync_sg_for_device(struct smc_connection *conn);
260
230void smc_conn_free(struct smc_connection *conn); 261void smc_conn_free(struct smc_connection *conn);
231int smc_conn_create(struct smc_sock *smc, 262int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
232 struct smc_ib_device *smcibdev, u8 ibport, 263 struct smc_ib_device *smcibdev, u8 ibport,
233 struct smc_clc_msg_local *lcl, int srv_first_contact); 264 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd,
265 u64 peer_gid);
266void smcd_conn_free(struct smc_connection *conn);
234void smc_core_exit(void); 267void smc_core_exit(void);
235#endif 268#endif
diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
index 839354402215..64ce107c24d9 100644
--- a/net/smc/smc_diag.c
+++ b/net/smc/smc_diag.c
@@ -136,7 +136,8 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
136 goto errout; 136 goto errout;
137 } 137 }
138 138
139 if ((req->diag_ext & (1 << (SMC_DIAG_LGRINFO - 1))) && smc->conn.lgr && 139 if (smc->conn.lgr && !smc->conn.lgr->is_smcd &&
140 (req->diag_ext & (1 << (SMC_DIAG_LGRINFO - 1))) &&
140 !list_empty(&smc->conn.lgr->list)) { 141 !list_empty(&smc->conn.lgr->list)) {
141 struct smc_diag_lgrinfo linfo = { 142 struct smc_diag_lgrinfo linfo = {
142 .role = smc->conn.lgr->role, 143 .role = smc->conn.lgr->role,
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
new file mode 100644
index 000000000000..ca1ce42fd49f
--- /dev/null
+++ b/net/smc/smc_ism.c
@@ -0,0 +1,304 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Shared Memory Communications Direct over ISM devices (SMC-D)
3 *
4 * Functions for ISM device.
5 *
6 * Copyright IBM Corp. 2018
7 */
8
9#include <linux/spinlock.h>
10#include <linux/slab.h>
11#include <asm/page.h>
12
13#include "smc.h"
14#include "smc_core.h"
15#include "smc_ism.h"
16
17struct smcd_dev_list smcd_dev_list = {
18 .list = LIST_HEAD_INIT(smcd_dev_list.list),
19 .lock = __SPIN_LOCK_UNLOCKED(smcd_dev_list.lock)
20};
21
22/* Test if an ISM communication is possible. */
23int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
24{
25 return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
26 vlan_id);
27}
28
29int smc_ism_write(struct smcd_dev *smcd, const struct smc_ism_position *pos,
30 void *data, size_t len)
31{
32 int rc;
33
34 rc = smcd->ops->move_data(smcd, pos->token, pos->index, pos->signal,
35 pos->offset, data, len);
36
37 return rc < 0 ? rc : 0;
38}
39
40/* Set a connection using this DMBE. */
41void smc_ism_set_conn(struct smc_connection *conn)
42{
43 unsigned long flags;
44
45 spin_lock_irqsave(&conn->lgr->smcd->lock, flags);
46 conn->lgr->smcd->conn[conn->rmb_desc->sba_idx] = conn;
47 spin_unlock_irqrestore(&conn->lgr->smcd->lock, flags);
48}
49
50/* Unset a connection using this DMBE. */
51void smc_ism_unset_conn(struct smc_connection *conn)
52{
53 unsigned long flags;
54
55 if (!conn->rmb_desc)
56 return;
57
58 spin_lock_irqsave(&conn->lgr->smcd->lock, flags);
59 conn->lgr->smcd->conn[conn->rmb_desc->sba_idx] = NULL;
60 spin_unlock_irqrestore(&conn->lgr->smcd->lock, flags);
61}
62
63/* Register a VLAN identifier with the ISM device. Use a reference count
64 * and add a VLAN identifier only when the first DMB using this VLAN is
65 * registered.
66 */
67int smc_ism_get_vlan(struct smcd_dev *smcd, unsigned short vlanid)
68{
69 struct smc_ism_vlanid *new_vlan, *vlan;
70 unsigned long flags;
71 int rc = 0;
72
73 if (!vlanid) /* No valid vlan id */
74 return -EINVAL;
75
76 /* create new vlan entry, in case we need it */
77 new_vlan = kzalloc(sizeof(*new_vlan), GFP_KERNEL);
78 if (!new_vlan)
79 return -ENOMEM;
80 new_vlan->vlanid = vlanid;
81 refcount_set(&new_vlan->refcnt, 1);
82
83 /* if there is an existing entry, increase count and return */
84 spin_lock_irqsave(&smcd->lock, flags);
85 list_for_each_entry(vlan, &smcd->vlan, list) {
86 if (vlan->vlanid == vlanid) {
87 refcount_inc(&vlan->refcnt);
88 kfree(new_vlan);
89 goto out;
90 }
91 }
92
93 /* no existing entry found.
94 * add new entry to device; might fail, e.g., if HW limit reached
95 */
96 if (smcd->ops->add_vlan_id(smcd, vlanid)) {
97 kfree(new_vlan);
98 rc = -EIO;
99 goto out;
100 }
101 list_add_tail(&new_vlan->list, &smcd->vlan);
102out:
103 spin_unlock_irqrestore(&smcd->lock, flags);
104 return rc;
105}
106
107/* Unregister a VLAN identifier with the ISM device. Use a reference count
108 * and remove a VLAN identifier only when the last DMB using this VLAN is
109 * unregistered.
110 */
111int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid)
112{
113 struct smc_ism_vlanid *vlan;
114 unsigned long flags;
115 bool found = false;
116 int rc = 0;
117
118 if (!vlanid) /* No valid vlan id */
119 return -EINVAL;
120
121 spin_lock_irqsave(&smcd->lock, flags);
122 list_for_each_entry(vlan, &smcd->vlan, list) {
123 if (vlan->vlanid == vlanid) {
124 if (!refcount_dec_and_test(&vlan->refcnt))
125 goto out;
126 found = true;
127 break;
128 }
129 }
130 if (!found) {
131 rc = -ENOENT;
132 goto out; /* VLAN id not in table */
133 }
134
135 /* Found and the last reference just gone */
136 if (smcd->ops->del_vlan_id(smcd, vlanid))
137 rc = -EIO;
138 list_del(&vlan->list);
139 kfree(vlan);
140out:
141 spin_unlock_irqrestore(&smcd->lock, flags);
142 return rc;
143}
144
145int smc_ism_unregister_dmb(struct smcd_dev *smcd, struct smc_buf_desc *dmb_desc)
146{
147 struct smcd_dmb dmb;
148
149 memset(&dmb, 0, sizeof(dmb));
150 dmb.dmb_tok = dmb_desc->token;
151 dmb.sba_idx = dmb_desc->sba_idx;
152 dmb.cpu_addr = dmb_desc->cpu_addr;
153 dmb.dma_addr = dmb_desc->dma_addr;
154 dmb.dmb_len = dmb_desc->len;
155 return smcd->ops->unregister_dmb(smcd, &dmb);
156}
157
158int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
159 struct smc_buf_desc *dmb_desc)
160{
161 struct smcd_dmb dmb;
162 int rc;
163
164 memset(&dmb, 0, sizeof(dmb));
165 dmb.dmb_len = dmb_len;
166 dmb.sba_idx = dmb_desc->sba_idx;
167 dmb.vlan_id = lgr->vlan_id;
168 dmb.rgid = lgr->peer_gid;
169 rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb);
170 if (!rc) {
171 dmb_desc->sba_idx = dmb.sba_idx;
172 dmb_desc->token = dmb.dmb_tok;
173 dmb_desc->cpu_addr = dmb.cpu_addr;
174 dmb_desc->dma_addr = dmb.dma_addr;
175 dmb_desc->len = dmb.dmb_len;
176 }
177 return rc;
178}
179
180struct smc_ism_event_work {
181 struct work_struct work;
182 struct smcd_dev *smcd;
183 struct smcd_event event;
184};
185
186/* worker for SMC-D events */
187static void smc_ism_event_work(struct work_struct *work)
188{
189 struct smc_ism_event_work *wrk =
190 container_of(work, struct smc_ism_event_work, work);
191
192 switch (wrk->event.type) {
193 case ISM_EVENT_GID: /* GID event, token is peer GID */
194 smc_smcd_terminate(wrk->smcd, wrk->event.tok);
195 break;
196 case ISM_EVENT_DMB:
197 break;
198 }
199 kfree(wrk);
200}
201
202static void smcd_release(struct device *dev)
203{
204 struct smcd_dev *smcd = container_of(dev, struct smcd_dev, dev);
205
206 kfree(smcd->conn);
207 kfree(smcd);
208}
209
210struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
211 const struct smcd_ops *ops, int max_dmbs)
212{
213 struct smcd_dev *smcd;
214
215 smcd = kzalloc(sizeof(*smcd), GFP_KERNEL);
216 if (!smcd)
217 return NULL;
218 smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *),
219 GFP_KERNEL);
220 if (!smcd->conn) {
221 kfree(smcd);
222 return NULL;
223 }
224
225 smcd->dev.parent = parent;
226 smcd->dev.release = smcd_release;
227 device_initialize(&smcd->dev);
228 dev_set_name(&smcd->dev, name);
229 smcd->ops = ops;
230
231 spin_lock_init(&smcd->lock);
232 INIT_LIST_HEAD(&smcd->vlan);
233 smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)",
234 WQ_MEM_RECLAIM, name);
235 return smcd;
236}
237EXPORT_SYMBOL_GPL(smcd_alloc_dev);
238
239int smcd_register_dev(struct smcd_dev *smcd)
240{
241 spin_lock(&smcd_dev_list.lock);
242 list_add_tail(&smcd->list, &smcd_dev_list.list);
243 spin_unlock(&smcd_dev_list.lock);
244
245 return device_add(&smcd->dev);
246}
247EXPORT_SYMBOL_GPL(smcd_register_dev);
248
249void smcd_unregister_dev(struct smcd_dev *smcd)
250{
251 spin_lock(&smcd_dev_list.lock);
252 list_del(&smcd->list);
253 spin_unlock(&smcd_dev_list.lock);
254 flush_workqueue(smcd->event_wq);
255 destroy_workqueue(smcd->event_wq);
256 smc_smcd_terminate(smcd, 0);
257
258 device_del(&smcd->dev);
259}
260EXPORT_SYMBOL_GPL(smcd_unregister_dev);
261
262void smcd_free_dev(struct smcd_dev *smcd)
263{
264 put_device(&smcd->dev);
265}
266EXPORT_SYMBOL_GPL(smcd_free_dev);
267
268/* SMCD Device event handler. Called from ISM device interrupt handler.
269 * Parameters are smcd device pointer,
270 * - event->type (0 --> DMB, 1 --> GID),
271 * - event->code (event code),
272 * - event->tok (either DMB token when event type 0, or GID when event type 1)
273 * - event->time (time of day)
274 * - event->info (debug info).
275 *
276 * Context:
277 * - Function called in IRQ context from ISM device driver event handler.
278 */
279void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event)
280{
281 struct smc_ism_event_work *wrk;
282
283 /* copy event to event work queue, and let it be handled there */
284 wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC);
285 if (!wrk)
286 return;
287 INIT_WORK(&wrk->work, smc_ism_event_work);
288 wrk->smcd = smcd;
289 wrk->event = *event;
290 queue_work(smcd->event_wq, &wrk->work);
291}
292EXPORT_SYMBOL_GPL(smcd_handle_event);
293
294/* SMCD Device interrupt handler. Called from ISM device interrupt handler.
295 * Parameters are smcd device pointer and DMB number. Find the connection and
296 * schedule the tasklet for this connection.
297 *
298 * Context:
299 * - Function called in IRQ context from ISM device driver IRQ handler.
300 */
301void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno)
302{
303}
304EXPORT_SYMBOL_GPL(smcd_handle_irq);
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
new file mode 100644
index 000000000000..aee45b860b79
--- /dev/null
+++ b/net/smc/smc_ism.h
@@ -0,0 +1,48 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/* Shared Memory Communications Direct over ISM devices (SMC-D)
3 *
4 * SMC-D ISM device structure definitions.
5 *
6 * Copyright IBM Corp. 2018
7 */
8
9#ifndef SMCD_ISM_H
10#define SMCD_ISM_H
11
12#include <linux/uio.h>
13
14#include "smc.h"
15
16struct smcd_dev_list { /* List of SMCD devices */
17 struct list_head list;
18 spinlock_t lock; /* Protects list of devices */
19};
20
21extern struct smcd_dev_list smcd_dev_list; /* list of smcd devices */
22
23struct smc_ism_vlanid { /* VLAN id set on ISM device */
24 struct list_head list;
25 unsigned short vlanid; /* Vlan id */
26 refcount_t refcnt; /* Reference count */
27};
28
29struct smc_ism_position { /* ISM device position to write to */
30 u64 token; /* Token of DMB */
31 u32 offset; /* Offset into DMBE */
32 u8 index; /* Index of DMBE */
33 u8 signal; /* Generate interrupt on owner side */
34};
35
36struct smcd_dev;
37
38int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *dev);
39void smc_ism_set_conn(struct smc_connection *conn);
40void smc_ism_unset_conn(struct smc_connection *conn);
41int smc_ism_get_vlan(struct smcd_dev *dev, unsigned short vlan_id);
42int smc_ism_put_vlan(struct smcd_dev *dev, unsigned short vlan_id);
43int smc_ism_register_dmb(struct smc_link_group *lgr, int buf_size,
44 struct smc_buf_desc *dmb_desc);
45int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc);
46int smc_ism_write(struct smcd_dev *dev, const struct smc_ism_position *pos,
47 void *data, size_t len);
48#endif