drivers/infiniband/core/agent.c

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

File Facts

System
Linux kernel
Corpus path
drivers/infiniband/core/agent.c
Extension
.c
Size
6856 bytes
Lines
233
Domain
Driver Families
Bucket
drivers/infiniband
Inferred role
Driver Families: implementation source
Status
source 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

struct ib_agent_port_private {
	struct list_head port_list;
	struct ib_mad_agent *agent[2];
};

static DEFINE_SPINLOCK(ib_agent_port_list_lock);
static LIST_HEAD(ib_agent_port_list);

static struct ib_agent_port_private *
__ib_get_agent_port(const struct ib_device *device, int port_num)
{
	struct ib_agent_port_private *entry;

	list_for_each_entry(entry, &ib_agent_port_list, port_list) {
		/* Need to check both agent[0] and agent[1], as an agent port
		 * may only have one of them
		 */
		if (entry->agent[0] &&
		    entry->agent[0]->device == device &&
		    entry->agent[0]->port_num == port_num)
			return entry;

		if (entry->agent[1] &&
		    entry->agent[1]->device == device &&
		    entry->agent[1]->port_num == port_num)
			return entry;
	}
	return NULL;
}

static struct ib_agent_port_private *
ib_get_agent_port(const struct ib_device *device, int port_num)
{
	struct ib_agent_port_private *entry;
	unsigned long flags;

	spin_lock_irqsave(&ib_agent_port_list_lock, flags);
	entry = __ib_get_agent_port(device, port_num);
	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
	return entry;
}

void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *grh,
			 const struct ib_wc *wc, const struct ib_device *device,
			 int port_num, int qpn, size_t resp_mad_len, bool opa)
{
	struct ib_agent_port_private *port_priv;
	struct ib_mad_agent *agent;
	struct ib_mad_send_buf *send_buf;
	struct ib_ah *ah;
	struct ib_mad_send_wr_private *mad_send_wr;

	if (rdma_cap_ib_switch(device))
		port_priv = ib_get_agent_port(device, 0);
	else
		port_priv = ib_get_agent_port(device, port_num);

	if (!port_priv) {
		dev_err(&device->dev, "Unable to find port agent\n");
		return;
	}

	agent = port_priv->agent[qpn];
	ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num);
	if (IS_ERR(ah)) {
		dev_err(&device->dev, "ib_create_ah_from_wc error %pe\n", ah);
		return;
	}

	if (opa && mad_hdr->base_version != OPA_MGMT_BASE_VERSION)
		resp_mad_len = IB_MGMT_MAD_SIZE;

	send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0,
				      IB_MGMT_MAD_HDR,
				      resp_mad_len - IB_MGMT_MAD_HDR,
				      GFP_KERNEL,
				      mad_hdr->base_version);
	if (IS_ERR(send_buf)) {
		dev_err(&device->dev, "ib_create_send_mad error\n");
		goto err1;
	}

	memcpy(send_buf->mad, mad_hdr, resp_mad_len);
	send_buf->ah = ah;

	if (rdma_cap_ib_switch(device)) {
		mad_send_wr = container_of(send_buf,
					   struct ib_mad_send_wr_private,
					   send_buf);
		mad_send_wr->send_wr.port_num = port_num;

Annotation

Implementation Notes