drivers/net/ethernet/amd/pds_core/adminq.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/amd/pds_core/adminq.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/amd/pds_core/adminq.c
Extension
.c
Size
7851 bytes
Lines
311
Domain
Driver Families
Bucket
drivers/net
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

switch (ecode) {
		case PDS_EVENT_LINK_CHANGE:
			dev_info(pdsc->dev, "NotifyQ LINK_CHANGE ecode %d eid %lld\n",
				 ecode, eid);
			pdsc_notify(PDS_EVENT_LINK_CHANGE, comp);
			break;

		case PDS_EVENT_RESET:
			dev_info(pdsc->dev, "NotifyQ RESET ecode %d eid %lld\n",
				 ecode, eid);
			pdsc_notify(PDS_EVENT_RESET, comp);
			break;

		case PDS_EVENT_XCVR:
			dev_info(pdsc->dev, "NotifyQ XCVR ecode %d eid %lld\n",
				 ecode, eid);
			break;

		default:
			dev_info(pdsc->dev, "NotifyQ ecode %d eid %lld\n",
				 ecode, eid);
			break;
		}

		pdsc->last_eid = eid;
		cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
		cq_info = &cq->info[cq->tail_idx];
		comp = cq_info->comp;
		eid = le64_to_cpu(comp->event.eid);

		nq_work++;
	}

	qcq->accum_work += nq_work;

	return nq_work;
}

static bool pdsc_adminq_inc_if_up(struct pdsc *pdsc)
{
	if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER) ||
	    pdsc->state & BIT_ULL(PDSC_S_FW_DEAD))
		return false;

	return refcount_inc_not_zero(&pdsc->adminq_refcnt);
}

void pdsc_process_adminq(struct pdsc_qcq *qcq)
{
	union pds_core_adminq_comp *comp;
	struct pdsc_queue *q = &qcq->q;
	struct pdsc *pdsc = qcq->pdsc;
	struct pdsc_cq *cq = &qcq->cq;
	struct pdsc_q_info *q_info;
	unsigned long irqflags;
	int nq_work = 0;
	int aq_work = 0;

	/* Don't process AdminQ when it's not up */
	if (!pdsc_adminq_inc_if_up(pdsc)) {
		dev_err(pdsc->dev, "%s: called while adminq is unavailable\n",
			__func__);
		return;
	}

	/* Check for NotifyQ event */
	nq_work = pdsc_process_notifyq(&pdsc->notifyqcq);

	/* Check for empty queue, which can happen if the interrupt was
	 * for a NotifyQ event and there are no new AdminQ completions.
	 */
	if (q->tail_idx == q->head_idx)
		goto credits;

	/* Find the first completion to clean,
	 * run the callback in the related q_info,
	 * and continue while we still match done color
	 */
	spin_lock_irqsave(&pdsc->adminq_lock, irqflags);
	comp = cq->info[cq->tail_idx].comp;
	while (pdsc_color_match(comp->color, cq->done_color)) {
		q_info = &q->info[q->tail_idx];
		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);

		if (!completion_done(&q_info->completion)) {
			memcpy(q_info->dest, comp, sizeof(*comp));
			complete(&q_info->completion);
		}

		if (cq->tail_idx == cq->num_descs - 1)

Annotation

Implementation Notes