net/smc/smc_wr.c

Source file repositories/reference/linux-study-clean/net/smc/smc_wr.c

File Facts

System
Linux kernel
Corpus path
net/smc/smc_wr.c
Extension
.c
Size
26331 bytes
Lines
934
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct smc_wr_tx_pend {	/* control data for a pending send request */
	u64			wr_id;		/* work request id sent */
	smc_wr_tx_handler	handler;
	enum ib_wc_status	wc_status;	/* CQE status */
	struct smc_link		*link;
	u32			idx;
	struct smc_wr_tx_pend_priv priv;
	u8			compl_requested;
};

/******************************** send queue *********************************/

/*------------------------------- completion --------------------------------*/

/* returns true if at least one tx work request is pending on the given link */
static inline bool smc_wr_is_tx_pend(struct smc_link *link)
{
	return !bitmap_empty(link->wr_tx_mask, link->wr_tx_cnt);
}

/* wait till all pending tx work requests on the given link are completed */
void smc_wr_tx_wait_no_pending_sends(struct smc_link *link)
{
	wait_event(link->wr_tx_wait, !smc_wr_is_tx_pend(link));
}

static inline int smc_wr_tx_find_pending_index(struct smc_link *link, u64 wr_id)
{
	u32 i;

	for (i = 0; i < link->wr_tx_cnt; i++) {
		if (link->wr_tx_pends[i].wr_id == wr_id)
			return i;
	}
	return link->wr_tx_cnt;
}

static inline void smc_wr_tx_process_cqe(struct ib_wc *wc)
{
	struct smc_wr_tx_pend pnd_snd;
	struct smc_link *link;
	u32 pnd_snd_idx;

	link = wc->qp->qp_context;

	if (wc->opcode == IB_WC_REG_MR) {
		if (wc->status)
			link->wr_reg_state = FAILED;
		else
			link->wr_reg_state = CONFIRMED;
		smc_wr_wakeup_reg_wait(link);
		return;
	}

	pnd_snd_idx = smc_wr_tx_find_pending_index(link, wc->wr_id);
	if (pnd_snd_idx == link->wr_tx_cnt) {
		if (link->lgr->smc_version != SMC_V2 ||
		    link->wr_tx_v2_pend->wr_id != wc->wr_id)
			return;
		link->wr_tx_v2_pend->wc_status = wc->status;
		memcpy(&pnd_snd, link->wr_tx_v2_pend, sizeof(pnd_snd));
		/* clear the full struct smc_wr_tx_pend including .priv */
		memset(link->wr_tx_v2_pend, 0,
		       sizeof(*link->wr_tx_v2_pend));
		memset(link->lgr->wr_tx_buf_v2, 0,
		       sizeof(*link->lgr->wr_tx_buf_v2));
	} else {
		link->wr_tx_pends[pnd_snd_idx].wc_status = wc->status;
		if (link->wr_tx_pends[pnd_snd_idx].compl_requested)
			complete(&link->wr_tx_compl[pnd_snd_idx]);
		memcpy(&pnd_snd, &link->wr_tx_pends[pnd_snd_idx],
		       sizeof(pnd_snd));
		/* clear the full struct smc_wr_tx_pend including .priv */
		memset(&link->wr_tx_pends[pnd_snd_idx], 0,
		       sizeof(link->wr_tx_pends[pnd_snd_idx]));
		memset(&link->wr_tx_bufs[pnd_snd_idx], 0,
		       sizeof(link->wr_tx_bufs[pnd_snd_idx]));
		if (!test_and_clear_bit(pnd_snd_idx, link->wr_tx_mask))
			return;
	}

	if (wc->status) {
		if (link->lgr->smc_version == SMC_V2) {
			memset(link->wr_tx_v2_pend, 0,
			       sizeof(*link->wr_tx_v2_pend));
			memset(link->lgr->wr_tx_buf_v2, 0,
			       sizeof(*link->lgr->wr_tx_buf_v2));
		}
		/* terminate link */
		smcr_link_down_cond_sched(link);

Annotation

Implementation Notes