Commit b9247544 authored by Karsten Graul's avatar Karsten Graul Committed by David S. Miller

net/smc: convert static link ID instances to support multiple links

As a preparation for the support of multiple links remove the usage of
a static link id (SMC_SINGLE_LINK) and allow dynamic link ids.
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Reviewed-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 387707fd
...@@ -338,28 +338,48 @@ static void smc_copy_sock_settings_to_smc(struct smc_sock *smc) ...@@ -338,28 +338,48 @@ static void smc_copy_sock_settings_to_smc(struct smc_sock *smc)
} }
/* register a new rmb, send confirm_rkey msg to register with peer */ /* register a new rmb, send confirm_rkey msg to register with peer */
static int smc_reg_rmb(struct smc_link *link, struct smc_buf_desc *rmb_desc, static int smcr_link_reg_rmb(struct smc_link *link,
bool conf_rkey) struct smc_buf_desc *rmb_desc, bool conf_rkey)
{ {
if (!rmb_desc->wr_reg) { if (!rmb_desc->is_reg_mr[link->link_idx]) {
/* register memory region for new rmb */ /* register memory region for new rmb */
if (smc_wr_reg_send(link, rmb_desc->mr_rx[link->link_idx])) { if (smc_wr_reg_send(link, rmb_desc->mr_rx[link->link_idx])) {
rmb_desc->regerr = 1; rmb_desc->is_reg_err = true;
return -EFAULT; return -EFAULT;
} }
rmb_desc->wr_reg = 1; rmb_desc->is_reg_mr[link->link_idx] = true;
} }
if (!conf_rkey) if (!conf_rkey)
return 0; return 0;
/* exchange confirm_rkey msg with peer */ /* exchange confirm_rkey msg with peer */
if (smc_llc_do_confirm_rkey(link, rmb_desc)) { if (!rmb_desc->is_conf_rkey) {
rmb_desc->regerr = 1; if (smc_llc_do_confirm_rkey(link, rmb_desc)) {
return -EFAULT; rmb_desc->is_reg_err = true;
return -EFAULT;
}
rmb_desc->is_conf_rkey = true;
}
return 0;
}
/* register the new rmb on all links */
static int smcr_lgr_reg_rmbs(struct smc_link_group *lgr,
struct smc_buf_desc *rmb_desc)
{
int i, rc;
for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
if (lgr->lnk[i].state != SMC_LNK_ACTIVE)
continue;
rc = smcr_link_reg_rmb(&lgr->lnk[i], rmb_desc, true);
if (rc)
return rc;
} }
return 0; return 0;
} }
static int smc_clnt_conf_first_link(struct smc_sock *smc) static int smcr_clnt_conf_first_link(struct smc_sock *smc)
{ {
struct net *net = sock_net(smc->clcsock->sk); struct net *net = sock_net(smc->clcsock->sk);
struct smc_link *link = smc->conn.lnk; struct smc_link *link = smc->conn.lnk;
...@@ -387,7 +407,7 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc) ...@@ -387,7 +407,7 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc)
smc_wr_remember_qp_attr(link); smc_wr_remember_qp_attr(link);
if (smc_reg_rmb(link, smc->conn.rmb_desc, false)) if (smcr_link_reg_rmb(link, smc->conn.rmb_desc, false))
return SMC_CLC_DECL_ERR_REGRMB; return SMC_CLC_DECL_ERR_REGRMB;
/* send CONFIRM LINK response over RoCE fabric */ /* send CONFIRM LINK response over RoCE fabric */
...@@ -632,7 +652,7 @@ static int smc_connect_rdma(struct smc_sock *smc, ...@@ -632,7 +652,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RDYLNK, return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RDYLNK,
ini->cln_first_contact); ini->cln_first_contact);
} else { } else {
if (smc_reg_rmb(link, smc->conn.rmb_desc, true)) if (smcr_lgr_reg_rmbs(smc->conn.lgr, smc->conn.rmb_desc))
return smc_connect_abort(smc, SMC_CLC_DECL_ERR_REGRMB, return smc_connect_abort(smc, SMC_CLC_DECL_ERR_REGRMB,
ini->cln_first_contact); ini->cln_first_contact);
} }
...@@ -647,7 +667,7 @@ static int smc_connect_rdma(struct smc_sock *smc, ...@@ -647,7 +667,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
if (ini->cln_first_contact == SMC_FIRST_CONTACT) { if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
/* QP confirmation over RoCE fabric */ /* QP confirmation over RoCE fabric */
reason_code = smc_clnt_conf_first_link(smc); reason_code = smcr_clnt_conf_first_link(smc);
if (reason_code) if (reason_code)
return smc_connect_abort(smc, reason_code, return smc_connect_abort(smc, reason_code,
ini->cln_first_contact); ini->cln_first_contact);
...@@ -997,14 +1017,14 @@ void smc_close_non_accepted(struct sock *sk) ...@@ -997,14 +1017,14 @@ void smc_close_non_accepted(struct sock *sk)
sock_put(sk); /* final sock_put */ sock_put(sk); /* final sock_put */
} }
static int smc_serv_conf_first_link(struct smc_sock *smc) static int smcr_serv_conf_first_link(struct smc_sock *smc)
{ {
struct net *net = sock_net(smc->clcsock->sk); struct net *net = sock_net(smc->clcsock->sk);
struct smc_link *link = smc->conn.lnk; struct smc_link *link = smc->conn.lnk;
int rest; int rest;
int rc; int rc;
if (smc_reg_rmb(link, smc->conn.rmb_desc, false)) if (smcr_link_reg_rmb(link, smc->conn.rmb_desc, false))
return SMC_CLC_DECL_ERR_REGRMB; return SMC_CLC_DECL_ERR_REGRMB;
/* send CONFIRM LINK request to client over the RoCE fabric */ /* send CONFIRM LINK request to client over the RoCE fabric */
...@@ -1189,10 +1209,10 @@ static int smc_listen_ism_init(struct smc_sock *new_smc, ...@@ -1189,10 +1209,10 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
/* listen worker: register buffers */ /* listen worker: register buffers */
static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact) static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact)
{ {
struct smc_link *link = new_smc->conn.lnk; struct smc_connection *conn = &new_smc->conn;
if (local_contact != SMC_FIRST_CONTACT) { if (local_contact != SMC_FIRST_CONTACT) {
if (smc_reg_rmb(link, new_smc->conn.rmb_desc, true)) if (smcr_lgr_reg_rmbs(conn->lgr, conn->rmb_desc))
return SMC_CLC_DECL_ERR_REGRMB; return SMC_CLC_DECL_ERR_REGRMB;
} }
smc_rmb_sync_sg_for_device(&new_smc->conn); smc_rmb_sync_sg_for_device(&new_smc->conn);
...@@ -1222,7 +1242,7 @@ static int smc_listen_rdma_finish(struct smc_sock *new_smc, ...@@ -1222,7 +1242,7 @@ static int smc_listen_rdma_finish(struct smc_sock *new_smc,
goto decline; goto decline;
} }
/* QP confirmation over RoCE fabric */ /* QP confirmation over RoCE fabric */
reason_code = smc_serv_conf_first_link(new_smc); reason_code = smcr_serv_conf_first_link(new_smc);
if (reason_code) if (reason_code)
goto decline; goto decline;
} }
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#define SMC_CLC_DECL_DIFFPREFIX 0x03070000 /* IP prefix / subnet mismatch */ #define SMC_CLC_DECL_DIFFPREFIX 0x03070000 /* IP prefix / subnet mismatch */
#define SMC_CLC_DECL_GETVLANERR 0x03080000 /* err to get vlan id of ip device*/ #define SMC_CLC_DECL_GETVLANERR 0x03080000 /* err to get vlan id of ip device*/
#define SMC_CLC_DECL_ISMVLANERR 0x03090000 /* err to reg vlan id on ism dev */ #define SMC_CLC_DECL_ISMVLANERR 0x03090000 /* err to reg vlan id on ism dev */
#define SMC_CLC_DECL_NOACTLINK 0x030a0000 /* no active smc-r link in lgr */
#define SMC_CLC_DECL_SYNCERR 0x04000000 /* synchronization error */ #define SMC_CLC_DECL_SYNCERR 0x04000000 /* synchronization error */
#define SMC_CLC_DECL_PEERDECL 0x05000000 /* peer declined during handshake */ #define SMC_CLC_DECL_PEERDECL 0x05000000 /* peer declined during handshake */
#define SMC_CLC_DECL_INTERR 0x09990000 /* internal error */ #define SMC_CLC_DECL_INTERR 0x09990000 /* internal error */
......
...@@ -116,7 +116,7 @@ static void smc_lgr_add_alert_token(struct smc_connection *conn) ...@@ -116,7 +116,7 @@ static void smc_lgr_add_alert_token(struct smc_connection *conn)
* Requires @conns_lock * Requires @conns_lock
* Note that '0' is a reserved value and not assigned. * Note that '0' is a reserved value and not assigned.
*/ */
static void smc_lgr_register_conn(struct smc_connection *conn) static int smc_lgr_register_conn(struct smc_connection *conn)
{ {
struct smc_sock *smc = container_of(conn, struct smc_sock, conn); struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
static atomic_t nexttoken = ATOMIC_INIT(0); static atomic_t nexttoken = ATOMIC_INIT(0);
...@@ -133,10 +133,22 @@ static void smc_lgr_register_conn(struct smc_connection *conn) ...@@ -133,10 +133,22 @@ static void smc_lgr_register_conn(struct smc_connection *conn)
smc_lgr_add_alert_token(conn); smc_lgr_add_alert_token(conn);
/* assign the new connection to a link */ /* assign the new connection to a link */
if (!conn->lgr->is_smcd) if (!conn->lgr->is_smcd) {
conn->lnk = &conn->lgr->lnk[SMC_SINGLE_LINK]; struct smc_link *lnk;
int i;
/* tbd - link balancing */
for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
lnk = &conn->lgr->lnk[i];
if (lnk->state == SMC_LNK_ACTIVATING ||
lnk->state == SMC_LNK_ACTIVE)
conn->lnk = lnk;
}
if (!conn->lnk)
return SMC_CLC_DECL_NOACTLINK;
}
conn->lgr->conns_num++; conn->lgr->conns_num++;
return 0;
} }
/* Unregister connection and reset the alert token of the given connection< /* Unregister connection and reset the alert token of the given connection<
...@@ -202,8 +214,8 @@ static void smc_lgr_free_work(struct work_struct *work) ...@@ -202,8 +214,8 @@ static void smc_lgr_free_work(struct work_struct *work)
struct smc_link_group, struct smc_link_group,
free_work); free_work);
spinlock_t *lgr_lock; spinlock_t *lgr_lock;
struct smc_link *lnk;
bool conns; bool conns;
int i;
smc_lgr_list_head(lgr, &lgr_lock); smc_lgr_list_head(lgr, &lgr_lock);
spin_lock_bh(lgr_lock); spin_lock_bh(lgr_lock);
...@@ -220,25 +232,38 @@ static void smc_lgr_free_work(struct work_struct *work) ...@@ -220,25 +232,38 @@ static void smc_lgr_free_work(struct work_struct *work)
} }
list_del_init(&lgr->list); /* remove from smc_lgr_list */ list_del_init(&lgr->list); /* remove from smc_lgr_list */
lnk = &lgr->lnk[SMC_SINGLE_LINK];
if (!lgr->is_smcd && !lgr->terminating) { if (!lgr->is_smcd && !lgr->terminating) {
/* try to send del link msg, on error free lgr immediately */ bool do_wait = false;
if (lnk->state == SMC_LNK_ACTIVE &&
!smcr_link_send_delete(lnk, true)) { for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
/* reschedule in case we never receive a response */ struct smc_link *lnk = &lgr->lnk[i];
smc_lgr_schedule_free_work(lgr); /* try to send del link msg, on err free immediately */
if (lnk->state == SMC_LNK_ACTIVE &&
!smcr_link_send_delete(lnk, true)) {
/* reschedule in case we never receive a resp */
smc_lgr_schedule_free_work(lgr);
do_wait = true;
}
}
if (do_wait) {
spin_unlock_bh(lgr_lock); spin_unlock_bh(lgr_lock);
return; return; /* wait for resp, see smc_llc_rx_delete_link */
} }
} }
lgr->freeing = 1; /* this instance does the freeing, no new schedule */ lgr->freeing = 1; /* this instance does the freeing, no new schedule */
spin_unlock_bh(lgr_lock); spin_unlock_bh(lgr_lock);
cancel_delayed_work(&lgr->free_work); cancel_delayed_work(&lgr->free_work);
if (!lgr->is_smcd && lnk->state != SMC_LNK_INACTIVE)
smc_llc_link_inactive(lnk);
if (lgr->is_smcd && !lgr->terminating) if (lgr->is_smcd && !lgr->terminating)
smc_ism_signal_shutdown(lgr); smc_ism_signal_shutdown(lgr);
if (!lgr->is_smcd) {
for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
struct smc_link *lnk = &lgr->lnk[i];
if (lnk->state != SMC_LNK_INACTIVE)
smc_llc_link_inactive(lnk);
}
}
smc_lgr_free(lgr); smc_lgr_free(lgr);
} }
...@@ -417,29 +442,37 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -417,29 +442,37 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
return rc; return rc;
} }
static void smcr_buf_unuse(struct smc_buf_desc *rmb_desc,
struct smc_link *lnk)
{
struct smc_link_group *lgr = lnk->lgr;
if (rmb_desc->is_conf_rkey && !list_empty(&lgr->list)) {
/* unregister rmb with peer */
smc_llc_do_delete_rkey(lnk, rmb_desc);
rmb_desc->is_conf_rkey = false;
}
if (rmb_desc->is_reg_err) {
/* buf registration failed, reuse not possible */
write_lock_bh(&lgr->rmbs_lock);
list_del(&rmb_desc->list);
write_unlock_bh(&lgr->rmbs_lock);
smc_buf_free(lgr, true, rmb_desc);
} else {
rmb_desc->used = 0;
}
}
static void smc_buf_unuse(struct smc_connection *conn, static void smc_buf_unuse(struct smc_connection *conn,
struct smc_link_group *lgr) struct smc_link_group *lgr)
{ {
if (conn->sndbuf_desc) if (conn->sndbuf_desc)
conn->sndbuf_desc->used = 0; conn->sndbuf_desc->used = 0;
if (conn->rmb_desc) { if (conn->rmb_desc && lgr->is_smcd)
if (!conn->rmb_desc->regerr) { conn->rmb_desc->used = 0;
if (!lgr->is_smcd && !list_empty(&lgr->list)) { else if (conn->rmb_desc)
/* unregister rmb with peer */ smcr_buf_unuse(conn->rmb_desc, conn->lnk);
smc_llc_do_delete_rkey(
conn->lnk,
conn->rmb_desc);
}
conn->rmb_desc->used = 0;
} else {
/* buf registration failed, reuse not possible */
write_lock_bh(&lgr->rmbs_lock);
list_del(&conn->rmb_desc->list);
write_unlock_bh(&lgr->rmbs_lock);
smc_buf_free(lgr, true, conn->rmb_desc);
}
}
} }
/* remove a finished connection from its link group */ /* remove a finished connection from its link group */
...@@ -467,6 +500,8 @@ void smc_conn_free(struct smc_connection *conn) ...@@ -467,6 +500,8 @@ void smc_conn_free(struct smc_connection *conn)
static void smcr_link_clear(struct smc_link *lnk) static void smcr_link_clear(struct smc_link *lnk)
{ {
if (lnk->peer_qpn == 0)
return;
lnk->peer_qpn = 0; lnk->peer_qpn = 0;
smc_llc_link_clear(lnk); smc_llc_link_clear(lnk);
smc_ib_modify_qp_reset(lnk); smc_ib_modify_qp_reset(lnk);
...@@ -482,17 +517,23 @@ static void smcr_link_clear(struct smc_link *lnk) ...@@ -482,17 +517,23 @@ static void smcr_link_clear(struct smc_link *lnk)
static void smcr_buf_free(struct smc_link_group *lgr, bool is_rmb, static void smcr_buf_free(struct smc_link_group *lgr, bool is_rmb,
struct smc_buf_desc *buf_desc) struct smc_buf_desc *buf_desc)
{ {
struct smc_link *lnk = &lgr->lnk[SMC_SINGLE_LINK]; struct smc_link *lnk;
int i;
if (is_rmb) { for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
if (buf_desc->mr_rx[lnk->link_idx]) lnk = &lgr->lnk[i];
smc_ib_put_memory_region( if (!buf_desc->is_map_ib[lnk->link_idx])
buf_desc->mr_rx[lnk->link_idx]); continue;
smc_ib_buf_unmap_sg(lnk, buf_desc, DMA_FROM_DEVICE); if (is_rmb) {
} else { if (buf_desc->mr_rx[lnk->link_idx])
smc_ib_buf_unmap_sg(lnk, buf_desc, DMA_TO_DEVICE); smc_ib_put_memory_region(
buf_desc->mr_rx[lnk->link_idx]);
smc_ib_buf_unmap_sg(lnk, buf_desc, DMA_FROM_DEVICE);
} else {
smc_ib_buf_unmap_sg(lnk, buf_desc, DMA_TO_DEVICE);
}
sg_free_table(&buf_desc->sgt[lnk->link_idx]);
} }
sg_free_table(&buf_desc->sgt[lnk->link_idx]);
if (buf_desc->pages) if (buf_desc->pages)
__free_pages(buf_desc->pages, buf_desc->order); __free_pages(buf_desc->pages, buf_desc->order);
...@@ -551,6 +592,8 @@ static void smc_lgr_free_bufs(struct smc_link_group *lgr) ...@@ -551,6 +592,8 @@ static void smc_lgr_free_bufs(struct smc_link_group *lgr)
/* remove a link group */ /* remove a link group */
static void smc_lgr_free(struct smc_link_group *lgr) static void smc_lgr_free(struct smc_link_group *lgr)
{ {
int i;
smc_lgr_free_bufs(lgr); smc_lgr_free_bufs(lgr);
if (lgr->is_smcd) { if (lgr->is_smcd) {
if (!lgr->terminating) { if (!lgr->terminating) {
...@@ -560,7 +603,11 @@ static void smc_lgr_free(struct smc_link_group *lgr) ...@@ -560,7 +603,11 @@ static void smc_lgr_free(struct smc_link_group *lgr)
if (!atomic_dec_return(&lgr->smcd->lgr_cnt)) if (!atomic_dec_return(&lgr->smcd->lgr_cnt))
wake_up(&lgr->smcd->lgrs_deleted); wake_up(&lgr->smcd->lgrs_deleted);
} else { } else {
smcr_link_clear(&lgr->lnk[SMC_SINGLE_LINK]); for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
if (lgr->lnk[i].state == SMC_LNK_INACTIVE)
continue;
smcr_link_clear(&lgr->lnk[i]);
}
if (!atomic_dec_return(&lgr_cnt)) if (!atomic_dec_return(&lgr_cnt))
wake_up(&lgrs_deleted); wake_up(&lgrs_deleted);
} }
...@@ -628,16 +675,20 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft) ...@@ -628,16 +675,20 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft)
static void smc_lgr_cleanup(struct smc_link_group *lgr) static void smc_lgr_cleanup(struct smc_link_group *lgr)
{ {
int i;
if (lgr->is_smcd) { if (lgr->is_smcd) {
smc_ism_signal_shutdown(lgr); smc_ism_signal_shutdown(lgr);
smcd_unregister_all_dmbs(lgr); smcd_unregister_all_dmbs(lgr);
smc_ism_put_vlan(lgr->smcd, lgr->vlan_id); smc_ism_put_vlan(lgr->smcd, lgr->vlan_id);
put_device(&lgr->smcd->dev); put_device(&lgr->smcd->dev);
} else { } else {
struct smc_link *lnk = &lgr->lnk[SMC_SINGLE_LINK]; for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
struct smc_link *lnk = &lgr->lnk[i];
if (lnk->state != SMC_LNK_INACTIVE) if (lnk->state != SMC_LNK_INACTIVE)
smc_llc_link_inactive(lnk); smc_llc_link_inactive(lnk);
}
} }
} }
...@@ -650,6 +701,7 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr, bool soft) ...@@ -650,6 +701,7 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr, bool soft)
struct smc_connection *conn; struct smc_connection *conn;
struct smc_sock *smc; struct smc_sock *smc;
struct rb_node *node; struct rb_node *node;
int i;
if (lgr->terminating) if (lgr->terminating)
return; /* lgr already terminating */ return; /* lgr already terminating */
...@@ -657,7 +709,8 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr, bool soft) ...@@ -657,7 +709,8 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr, bool soft)
cancel_delayed_work_sync(&lgr->free_work); cancel_delayed_work_sync(&lgr->free_work);
lgr->terminating = 1; lgr->terminating = 1;
if (!lgr->is_smcd) if (!lgr->is_smcd)
smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]); for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++)
smc_llc_link_inactive(&lgr->lnk[i]);
/* kill remaining link group connections */ /* kill remaining link group connections */
read_lock_bh(&lgr->conns_lock); read_lock_bh(&lgr->conns_lock);
...@@ -703,14 +756,22 @@ void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport) ...@@ -703,14 +756,22 @@ void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport)
{ {
struct smc_link_group *lgr, *l; struct smc_link_group *lgr, *l;
LIST_HEAD(lgr_free_list); LIST_HEAD(lgr_free_list);
int i;
spin_lock_bh(&smc_lgr_list.lock); spin_lock_bh(&smc_lgr_list.lock);
list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) { list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) {
if (!lgr->is_smcd && if (lgr->is_smcd)
lgr->lnk[SMC_SINGLE_LINK].smcibdev == smcibdev && continue;
lgr->lnk[SMC_SINGLE_LINK].ibport == ibport) { /* tbd - terminate only when no more links are active */
list_move(&lgr->list, &lgr_free_list); for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
lgr->freeing = 1; if (lgr->lnk[i].state == SMC_LNK_INACTIVE ||
lgr->lnk[i].state == SMC_LNK_DELETING)
continue;
if (lgr->lnk[i].smcibdev == smcibdev &&
lgr->lnk[i].ibport == ibport) {
list_move(&lgr->list, &lgr_free_list);
lgr->freeing = 1;
}
} }
} }
spin_unlock_bh(&smc_lgr_list.lock); spin_unlock_bh(&smc_lgr_list.lock);
...@@ -775,6 +836,7 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev) ...@@ -775,6 +836,7 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev)
{ {
struct smc_link_group *lgr, *lg; struct smc_link_group *lgr, *lg;
LIST_HEAD(lgr_free_list); LIST_HEAD(lgr_free_list);
int i;
spin_lock_bh(&smc_lgr_list.lock); spin_lock_bh(&smc_lgr_list.lock);
if (!smcibdev) { if (!smcibdev) {
...@@ -783,9 +845,12 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev) ...@@ -783,9 +845,12 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev)
lgr->freeing = 1; lgr->freeing = 1;
} else { } else {
list_for_each_entry_safe(lgr, lg, &smc_lgr_list.list, list) { list_for_each_entry_safe(lgr, lg, &smc_lgr_list.list, list) {
if (lgr->lnk[SMC_SINGLE_LINK].smcibdev == smcibdev) { for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
list_move(&lgr->list, &lgr_free_list); if (lgr->lnk[i].smcibdev == smcibdev) {
lgr->freeing = 1; list_move(&lgr->list, &lgr_free_list);
lgr->freeing = 1;
break;
}
} }
} }
} }
...@@ -857,15 +922,21 @@ static bool smcr_lgr_match(struct smc_link_group *lgr, ...@@ -857,15 +922,21 @@ static bool smcr_lgr_match(struct smc_link_group *lgr,
struct smc_clc_msg_local *lcl, struct smc_clc_msg_local *lcl,
enum smc_lgr_role role, u32 clcqpn) enum smc_lgr_role role, u32 clcqpn)
{ {
return !memcmp(lgr->peer_systemid, lcl->id_for_peer, int i;
SMC_SYSTEMID_LEN) &&
!memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_gid, &lcl->gid, if (memcmp(lgr->peer_systemid, lcl->id_for_peer, SMC_SYSTEMID_LEN) ||
SMC_GID_SIZE) && lgr->role != role)
!memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_mac, lcl->mac, return false;
sizeof(lcl->mac)) &&
lgr->role == role && for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
(lgr->role == SMC_SERV || if (lgr->lnk[i].state != SMC_LNK_ACTIVE)
lgr->lnk[SMC_SINGLE_LINK].peer_qpn == clcqpn); continue;
if ((lgr->role == SMC_SERV || lgr->lnk[i].peer_qpn == clcqpn) &&
!memcmp(lgr->lnk[i].peer_gid, &lcl->gid, SMC_GID_SIZE) &&
!memcmp(lgr->lnk[i].peer_mac, lcl->mac, sizeof(lcl->mac)))
return true;
}
return false;
} }
static bool smcd_lgr_match(struct smc_link_group *lgr, static bool smcd_lgr_match(struct smc_link_group *lgr,
...@@ -906,15 +977,17 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -906,15 +977,17 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
/* link group found */ /* link group found */
ini->cln_first_contact = SMC_REUSE_CONTACT; ini->cln_first_contact = SMC_REUSE_CONTACT;
conn->lgr = lgr; conn->lgr = lgr;
smc_lgr_register_conn(conn); /* add smc conn to lgr */ rc = smc_lgr_register_conn(conn); /* add conn to lgr */
if (delayed_work_pending(&lgr->free_work))
cancel_delayed_work(&lgr->free_work);
write_unlock_bh(&lgr->conns_lock); write_unlock_bh(&lgr->conns_lock);
if (!rc && delayed_work_pending(&lgr->free_work))
cancel_delayed_work(&lgr->free_work);
break; break;
} }
write_unlock_bh(&lgr->conns_lock); write_unlock_bh(&lgr->conns_lock);
} }
spin_unlock_bh(lgr_lock); spin_unlock_bh(lgr_lock);
if (rc)
return rc;
if (role == SMC_CLNT && !ini->srv_first_contact && if (role == SMC_CLNT && !ini->srv_first_contact &&
ini->cln_first_contact == SMC_FIRST_CONTACT) { ini->cln_first_contact == SMC_FIRST_CONTACT) {
...@@ -932,8 +1005,10 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -932,8 +1005,10 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
goto out; goto out;
lgr = conn->lgr; lgr = conn->lgr;
write_lock_bh(&lgr->conns_lock); write_lock_bh(&lgr->conns_lock);
smc_lgr_register_conn(conn); /* add smc conn to lgr */ rc = smc_lgr_register_conn(conn); /* add smc conn to lgr */
write_unlock_bh(&lgr->conns_lock); write_unlock_bh(&lgr->conns_lock);
if (rc)
goto out;
} }
conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE; conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
conn->local_tx_ctrl.len = SMC_WR_TX_SIZE; conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
...@@ -1006,12 +1081,55 @@ static inline int smc_rmb_wnd_update_limit(int rmbe_size) ...@@ -1006,12 +1081,55 @@ static inline int smc_rmb_wnd_update_limit(int rmbe_size)
return min_t(int, rmbe_size / 10, SOCK_MIN_SNDBUF / 2); return min_t(int, rmbe_size / 10, SOCK_MIN_SNDBUF / 2);
} }
/* map an rmb buf to a link */
static int smcr_buf_map_link(struct smc_buf_desc *buf_desc, bool is_rmb,
struct smc_link *lnk)
{
int rc;
if (buf_desc->is_map_ib[lnk->link_idx])
return 0;
rc = sg_alloc_table(&buf_desc->sgt[lnk->link_idx], 1, GFP_KERNEL);
if (rc)
return rc;
sg_set_buf(buf_desc->sgt[lnk->link_idx].sgl,
buf_desc->cpu_addr, buf_desc->len);
/* map sg table to DMA address */
rc = smc_ib_buf_map_sg(lnk, buf_desc,
is_rmb ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
/* SMC protocol depends on mapping to one DMA address only */
if (rc != 1) {
rc = -EAGAIN;
goto free_table;
}
/* create a new memory region for the RMB */
if (is_rmb) {
rc = smc_ib_get_memory_region(lnk->roce_pd,
IB_ACCESS_REMOTE_WRITE |
IB_ACCESS_LOCAL_WRITE,
buf_desc, lnk->link_idx);
if (rc)
goto buf_unmap;
smc_ib_sync_sg_for_device(lnk, buf_desc, DMA_FROM_DEVICE);
}
buf_desc->is_map_ib[lnk->link_idx] = true;
return 0;
buf_unmap:
smc_ib_buf_unmap_sg(lnk, buf_desc,
is_rmb ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
free_table:
sg_free_table(&buf_desc->sgt[lnk->link_idx]);
return rc;
}
static struct smc_buf_desc *smcr_new_buf_create(struct smc_link_group *lgr, static struct smc_buf_desc *smcr_new_buf_create(struct smc_link_group *lgr,
bool is_rmb, int bufsize) bool is_rmb, int bufsize)
{ {
struct smc_buf_desc *buf_desc; struct smc_buf_desc *buf_desc;
struct smc_link *lnk;
int rc;
/* try to alloc a new buffer */ /* try to alloc a new buffer */
buf_desc = kzalloc(sizeof(*buf_desc), GFP_KERNEL); buf_desc = kzalloc(sizeof(*buf_desc), GFP_KERNEL);
...@@ -1028,40 +1146,32 @@ static struct smc_buf_desc *smcr_new_buf_create(struct smc_link_group *lgr, ...@@ -1028,40 +1146,32 @@ static struct smc_buf_desc *smcr_new_buf_create(struct smc_link_group *lgr,
return ERR_PTR(-EAGAIN); return ERR_PTR(-EAGAIN);
} }
buf_desc->cpu_addr = (void *)page_address(buf_desc->pages); buf_desc->cpu_addr = (void *)page_address(buf_desc->pages);
buf_desc->len = bufsize;
return buf_desc;
}
/* build the sg table from the pages */ /* map buf_desc on all usable links,
lnk = &lgr->lnk[SMC_SINGLE_LINK]; * unused buffers stay mapped as long as the link is up
rc = sg_alloc_table(&buf_desc->sgt[lnk->link_idx], 1, GFP_KERNEL); */
if (rc) { static int smcr_buf_map_usable_links(struct smc_link_group *lgr,
smc_buf_free(lgr, is_rmb, buf_desc); struct smc_buf_desc *buf_desc, bool is_rmb)
return ERR_PTR(rc); {
} int i, rc = 0;
sg_set_buf(buf_desc->sgt[lnk->link_idx].sgl,
buf_desc->cpu_addr, bufsize);
/* map sg table to DMA address */ for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
rc = smc_ib_buf_map_sg(lnk, buf_desc, struct smc_link *lnk = &lgr->lnk[i];
is_rmb ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
/* SMC protocol depends on mapping to one DMA address only */
if (rc != 1) {
smc_buf_free(lgr, is_rmb, buf_desc);
return ERR_PTR(-EAGAIN);
}
/* create a new memory region for the RMB */ if (lnk->state != SMC_LNK_ACTIVE &&
if (is_rmb) { lnk->state != SMC_LNK_ACTIVATING)
rc = smc_ib_get_memory_region(lnk->roce_pd, continue;
IB_ACCESS_REMOTE_WRITE | if (smcr_buf_map_link(buf_desc, is_rmb, lnk)) {
IB_ACCESS_LOCAL_WRITE, smcr_buf_unuse(buf_desc, lnk);
buf_desc, lnk->link_idx); rc = -ENOMEM;
if (rc) { goto out;
smc_buf_free(lgr, is_rmb, buf_desc);
return ERR_PTR(rc);
} }
} }
out:
buf_desc->len = bufsize; return rc;
return buf_desc;
} }
#define SMCD_DMBE_SIZES 7 /* 0 -> 16KB, 1 -> 32KB, .. 6 -> 1MB */ #define SMCD_DMBE_SIZES 7 /* 0 -> 16KB, 1 -> 32KB, .. 6 -> 1MB */
...@@ -1159,6 +1269,12 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) ...@@ -1159,6 +1269,12 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb)
if (IS_ERR(buf_desc)) if (IS_ERR(buf_desc))
return -ENOMEM; return -ENOMEM;
if (!is_smcd) {
if (smcr_buf_map_usable_links(lgr, buf_desc, is_rmb)) {
return -ENOMEM;
}
}
if (is_rmb) { if (is_rmb) {
conn->rmb_desc = buf_desc; conn->rmb_desc = buf_desc;
conn->rmbe_size_short = bufsize_short; conn->rmbe_size_short = bufsize_short;
...@@ -1192,22 +1308,32 @@ void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn) ...@@ -1192,22 +1308,32 @@ void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn)
void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn) void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn)
{ {
struct smc_link_group *lgr = conn->lgr; int i;
if (!conn->lgr || conn->lgr->is_smcd) if (!conn->lgr || conn->lgr->is_smcd)
return; return;
smc_ib_sync_sg_for_cpu(&lgr->lnk[SMC_SINGLE_LINK], for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
conn->rmb_desc, DMA_FROM_DEVICE); if (conn->lgr->lnk[i].state != SMC_LNK_ACTIVE &&
conn->lgr->lnk[i].state != SMC_LNK_ACTIVATING)
continue;
smc_ib_sync_sg_for_cpu(&conn->lgr->lnk[i], conn->rmb_desc,
DMA_FROM_DEVICE);
}
} }
void smc_rmb_sync_sg_for_device(struct smc_connection *conn) void smc_rmb_sync_sg_for_device(struct smc_connection *conn)
{ {
struct smc_link_group *lgr = conn->lgr; int i;
if (!conn->lgr || conn->lgr->is_smcd) if (!conn->lgr || conn->lgr->is_smcd)
return; return;
smc_ib_sync_sg_for_device(&lgr->lnk[SMC_SINGLE_LINK], for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
conn->rmb_desc, DMA_FROM_DEVICE); if (conn->lgr->lnk[i].state != SMC_LNK_ACTIVE &&
conn->lgr->lnk[i].state != SMC_LNK_ACTIVATING)
continue;
smc_ib_sync_sg_for_device(&conn->lgr->lnk[i], conn->rmb_desc,
DMA_FROM_DEVICE);
}
} }
/* create the send and receive buffer for an SMC socket; /* create the send and receive buffer for an SMC socket;
......
...@@ -152,25 +152,32 @@ struct smc_buf_desc { ...@@ -152,25 +152,32 @@ struct smc_buf_desc {
struct page *pages; struct page *pages;
int len; /* length of buffer */ int len; /* length of buffer */
u32 used; /* currently used / unused */ u32 used; /* currently used / unused */
u8 wr_reg : 1; /* mem region registered */
u8 regerr : 1; /* err during registration */
union { union {
struct { /* SMC-R */ struct { /* SMC-R */
struct sg_table sgt[SMC_LINKS_PER_LGR_MAX]; struct sg_table sgt[SMC_LINKS_PER_LGR_MAX];
/* virtual buffer */ /* virtual buffer */
struct ib_mr *mr_rx[SMC_LINKS_PER_LGR_MAX]; struct ib_mr *mr_rx[SMC_LINKS_PER_LGR_MAX];
/* for rmb only: memory region /* for rmb only: memory region
* incl. rkey provided to peer * incl. rkey provided to peer
*/ */
u32 order; /* allocation order */ u32 order; /* allocation order */
u8 is_conf_rkey;
/* confirm_rkey done */
u8 is_reg_mr[SMC_LINKS_PER_LGR_MAX];
/* mem region registered */
u8 is_map_ib[SMC_LINKS_PER_LGR_MAX];
/* mem region mapped to lnk */
u8 is_reg_err;
/* buffer registration err */
}; };
struct { /* SMC-D */ struct { /* SMC-D */
unsigned short sba_idx; unsigned short sba_idx;
/* SBA index number */ /* SBA index number */
u64 token; u64 token;
/* DMB token number */ /* DMB token number */
dma_addr_t dma_addr; dma_addr_t dma_addr;
/* DMA address */ /* DMA address */
}; };
}; };
}; };
......
...@@ -662,6 +662,8 @@ void smc_llc_link_deleting(struct smc_link *link) ...@@ -662,6 +662,8 @@ void smc_llc_link_deleting(struct smc_link *link)
/* called in tasklet context */ /* called in tasklet context */
void smc_llc_link_inactive(struct smc_link *link) void smc_llc_link_inactive(struct smc_link *link)
{ {
if (link->state == SMC_LNK_INACTIVE)
return;
link->state = SMC_LNK_INACTIVE; link->state = SMC_LNK_INACTIVE;
cancel_delayed_work(&link->llc_testlink_wrk); cancel_delayed_work(&link->llc_testlink_wrk);
smc_wr_wakeup_reg_wait(link); smc_wr_wakeup_reg_wait(link);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment