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