drivers/infiniband/core/rw.c

Source file repositories/reference/linux-study-clean/drivers/infiniband/core/rw.c

File Facts

System
Linux kernel
Corpus path
drivers/infiniband/core/rw.c
Extension
.c
Size
34263 bytes
Lines
1192
Domain
Driver Families
Bucket
drivers/infiniband
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (nents >= nr_bvec) {
			ret = -EINVAL;
			goto out_free_sgl;
		}
		sg_set_page(sg, bv.bv_page, bv.bv_len, bv.bv_offset);
		bvec_iter_advance(bvecs, iter, bv.bv_len);
		nents++;
	}
	sg_mark_end(sg_last(ctx->reg[0].sgt.sgl, nents));
	ctx->reg[0].sgt.orig_nents = nents;

	/* DMA map the scatterlist */
	ret = ib_dma_map_sgtable_attrs(dev, &ctx->reg[0].sgt, dir, 0);
	if (ret)
		goto out_free_sgl;

	ctx->nr_ops = DIV_ROUND_UP(ctx->reg[0].sgt.nents, pages_per_mr);

	sg = ctx->reg[0].sgt.sgl;
	nents = ctx->reg[0].sgt.nents;
	for (i = 0; i < ctx->nr_ops; i++) {
		struct rdma_rw_reg_ctx *reg = &ctx->reg[i];
		u32 sge_cnt = min(nents, pages_per_mr);

		ret = rdma_rw_init_one_mr(qp, port_num, reg, sg, sge_cnt, 0);
		if (ret < 0)
			goto out_free_mrs;
		count += ret;
		count += rdma_rw_init_reg_wr(reg, prev, qp, port_num,
				remote_addr, rkey, dir);
		remote_addr += reg->sge.length;
		nents -= sge_cnt;
		sg += sge_cnt;
		prev = reg;
	}

	if (prev)
		prev->wr.wr.next = NULL;

	ctx->type = RDMA_RW_MR;
	return count;

out_free_mrs:
	while (--i >= 0)
		ib_mr_pool_put(qp, &qp->rdma_mrs, ctx->reg[i].mr);
	ib_dma_unmap_sgtable_attrs(dev, &ctx->reg[0].sgt, dir, 0);
out_free_sgl:
	kfree(ctx->reg[0].sgt.sgl);
out_free_reg:
	kfree(ctx->reg);
	return ret;
}

static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
		struct scatterlist *sg, u32 sg_cnt, u32 offset,
		u64 remote_addr, u32 rkey, enum dma_data_direction dir)
{
	u32 max_sge = dir == DMA_TO_DEVICE ? qp->max_write_sge :
		      qp->max_read_sge;
	struct ib_sge *sge;
	u32 total_len = 0, i, j;

	ctx->nr_ops = DIV_ROUND_UP(sg_cnt, max_sge);

	ctx->map.sges = sge = kzalloc_objs(*sge, sg_cnt);
	if (!ctx->map.sges)
		goto out;

	ctx->map.wrs = kzalloc_objs(*ctx->map.wrs, ctx->nr_ops);
	if (!ctx->map.wrs)
		goto out_free_sges;

	for (i = 0; i < ctx->nr_ops; i++) {
		struct ib_rdma_wr *rdma_wr = &ctx->map.wrs[i];
		u32 nr_sge = min(sg_cnt, max_sge);

		if (dir == DMA_TO_DEVICE)
			rdma_wr->wr.opcode = IB_WR_RDMA_WRITE;
		else
			rdma_wr->wr.opcode = IB_WR_RDMA_READ;
		rdma_wr->remote_addr = remote_addr + total_len;
		rdma_wr->rkey = rkey;
		rdma_wr->wr.num_sge = nr_sge;
		rdma_wr->wr.sg_list = sge;

		for (j = 0; j < nr_sge; j++, sg = sg_next(sg)) {
			sge->addr = sg_dma_address(sg) + offset;
			sge->length = sg_dma_len(sg) - offset;
			sge->lkey = qp->pd->local_dma_lkey;

Annotation

Implementation Notes