summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wippel <hwippel@linux.ibm.com>2018-06-28 13:05:07 -0400
committerDavid S. Miller <davem@davemloft.net>2018-06-30 07:42:25 -0400
commitc6ba7c9ba43de1b57e9a53946e7ff988554c84ed (patch)
treef33c624945a384089b599be4550c98735c674ff8
parente82f2e31f5597a3de44bd27b7427f577f637c552 (diff)
net/smc: add base infrastructure for SMC-D and ISM
SMC supports two variants: SMC-R and SMC-D. For data transport, SMC-R uses RDMA devices, SMC-D uses so-called Internal Shared Memory (ISM) devices. An ISM device only allows shared memory communication between SMC instances on the same machine. For example, this allows virtual machines on the same host to communicate via SMC without RDMA devices. This patch adds the base infrastructure for SMC-D and ISM devices to the existing SMC code. It contains the following: * ISM driver interface: This interface allows an ISM driver to register ISM devices in SMC. In the process, the driver provides a set of device ops for each device. SMC uses these ops to execute SMC specific operations on or transfer data over the device. * Core SMC-D link group, connection, and buffer support: Link groups, SMC connections and SMC buffers (in smc_core) are extended to support SMC-D. * SMC type checks: Some type checks are added to prevent using SMC-R specific code for SMC-D and vice versa. To actually use SMC-D, additional changes to pnetid, CLC, CDC, etc. are required. These are added in follow-up patches. Signed-off-by: Hans Wippel <hwippel@linux.ibm.com> Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Suggested-by: Thomas Richter <tmricht@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-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