18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Shared Memory Communications over RDMA (SMC-R) and RoCE 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Work Requests exploiting Infiniband API 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2016 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Author(s): Steffen Maier <maier@linux.vnet.ibm.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#ifndef SMC_WR_H 138c2ecf20Sopenharmony_ci#define SMC_WR_H 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/atomic.h> 168c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 178c2ecf20Sopenharmony_ci#include <asm/div64.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "smc.h" 208c2ecf20Sopenharmony_ci#include "smc_core.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SMC_WR_BUF_CNT 16 /* # of ctrl buffers per link */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define SMC_WR_TX_WAIT_FREE_SLOT_TIME (10 * HZ) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define SMC_WR_TX_SIZE 44 /* actual size of wr_send data (<=SMC_WR_BUF_SIZE) */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SMC_WR_TX_PEND_PRIV_SIZE 32 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct smc_wr_tx_pend_priv { 318c2ecf20Sopenharmony_ci u8 priv[SMC_WR_TX_PEND_PRIV_SIZE]; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_citypedef void (*smc_wr_tx_handler)(struct smc_wr_tx_pend_priv *, 358c2ecf20Sopenharmony_ci struct smc_link *, 368c2ecf20Sopenharmony_ci enum ib_wc_status); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_citypedef bool (*smc_wr_tx_filter)(struct smc_wr_tx_pend_priv *, 398c2ecf20Sopenharmony_ci unsigned long); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_citypedef void (*smc_wr_tx_dismisser)(struct smc_wr_tx_pend_priv *); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct smc_wr_rx_handler { 448c2ecf20Sopenharmony_ci struct hlist_node list; /* hash table collision resolution */ 458c2ecf20Sopenharmony_ci void (*handler)(struct ib_wc *, void *); 468c2ecf20Sopenharmony_ci u8 type; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Only used by RDMA write WRs. 508c2ecf20Sopenharmony_ci * All other WRs (CDC/LLC) use smc_wr_tx_send handling WR_ID implicitly 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistatic inline long smc_wr_tx_get_next_wr_id(struct smc_link *link) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return atomic_long_inc_return(&link->wr_tx_id); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic inline void smc_wr_tx_set_wr_id(atomic_long_t *wr_tx_id, long val) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci atomic_long_set(wr_tx_id, val); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline bool smc_wr_tx_link_hold(struct smc_link *link) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci if (!smc_link_sendable(link)) 658c2ecf20Sopenharmony_ci return false; 668c2ecf20Sopenharmony_ci atomic_inc(&link->wr_tx_refcnt); 678c2ecf20Sopenharmony_ci return true; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic inline void smc_wr_tx_link_put(struct smc_link *link) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&link->wr_tx_refcnt)) 738c2ecf20Sopenharmony_ci wake_up_all(&link->wr_tx_wait); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline void smc_wr_wakeup_tx_wait(struct smc_link *lnk) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci wake_up_all(&lnk->wr_tx_wait); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline void smc_wr_wakeup_reg_wait(struct smc_link *lnk) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci wake_up(&lnk->wr_reg_wait); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* post a new receive work request to fill a completed old work request entry */ 878c2ecf20Sopenharmony_cistatic inline int smc_wr_rx_post(struct smc_link *link) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci int rc; 908c2ecf20Sopenharmony_ci u64 wr_id, temp_wr_id; 918c2ecf20Sopenharmony_ci u32 index; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci wr_id = ++link->wr_rx_id; /* tasklet context, thus not atomic */ 948c2ecf20Sopenharmony_ci temp_wr_id = wr_id; 958c2ecf20Sopenharmony_ci index = do_div(temp_wr_id, link->wr_rx_cnt); 968c2ecf20Sopenharmony_ci link->wr_rx_ibs[index].wr_id = wr_id; 978c2ecf20Sopenharmony_ci rc = ib_post_recv(link->roce_qp, &link->wr_rx_ibs[index], NULL); 988c2ecf20Sopenharmony_ci return rc; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciint smc_wr_create_link(struct smc_link *lnk); 1028c2ecf20Sopenharmony_ciint smc_wr_alloc_link_mem(struct smc_link *lnk); 1038c2ecf20Sopenharmony_civoid smc_wr_free_link(struct smc_link *lnk); 1048c2ecf20Sopenharmony_civoid smc_wr_free_link_mem(struct smc_link *lnk); 1058c2ecf20Sopenharmony_civoid smc_wr_remember_qp_attr(struct smc_link *lnk); 1068c2ecf20Sopenharmony_civoid smc_wr_remove_dev(struct smc_ib_device *smcibdev); 1078c2ecf20Sopenharmony_civoid smc_wr_add_dev(struct smc_ib_device *smcibdev); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint smc_wr_tx_get_free_slot(struct smc_link *link, smc_wr_tx_handler handler, 1108c2ecf20Sopenharmony_ci struct smc_wr_buf **wr_buf, 1118c2ecf20Sopenharmony_ci struct smc_rdma_wr **wrs, 1128c2ecf20Sopenharmony_ci struct smc_wr_tx_pend_priv **wr_pend_priv); 1138c2ecf20Sopenharmony_ciint smc_wr_tx_put_slot(struct smc_link *link, 1148c2ecf20Sopenharmony_ci struct smc_wr_tx_pend_priv *wr_pend_priv); 1158c2ecf20Sopenharmony_ciint smc_wr_tx_send(struct smc_link *link, 1168c2ecf20Sopenharmony_ci struct smc_wr_tx_pend_priv *wr_pend_priv); 1178c2ecf20Sopenharmony_ciint smc_wr_tx_send_wait(struct smc_link *link, struct smc_wr_tx_pend_priv *priv, 1188c2ecf20Sopenharmony_ci unsigned long timeout); 1198c2ecf20Sopenharmony_civoid smc_wr_tx_cq_handler(struct ib_cq *ib_cq, void *cq_context); 1208c2ecf20Sopenharmony_civoid smc_wr_tx_dismiss_slots(struct smc_link *lnk, u8 wr_rx_hdr_type, 1218c2ecf20Sopenharmony_ci smc_wr_tx_filter filter, 1228c2ecf20Sopenharmony_ci smc_wr_tx_dismisser dismisser, 1238c2ecf20Sopenharmony_ci unsigned long data); 1248c2ecf20Sopenharmony_civoid smc_wr_tx_wait_no_pending_sends(struct smc_link *link); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler); 1278c2ecf20Sopenharmony_ciint smc_wr_rx_post_init(struct smc_link *link); 1288c2ecf20Sopenharmony_civoid smc_wr_rx_cq_handler(struct ib_cq *ib_cq, void *cq_context); 1298c2ecf20Sopenharmony_ciint smc_wr_reg_send(struct smc_link *link, struct ib_mr *mr); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#endif /* SMC_WR_H */ 132