drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
Extension
.c
Size
21917 bytes
Lines
841
Domain
Driver Families
Bucket
drivers/net
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

if (eq->cons_idx == eq->eq_len) {
			eq->cons_idx = 0;
			eq->wrapped = !eq->wrapped;
		}

		if (++eqe_cnt >= HINIC3_EQ_UPDATE_CI_STEP) {
			eqe_cnt = 0;
			set_eq_cons_idx(eq, HINIC3_EQ_NOT_ARMED);
		}
	}

	return -EAGAIN;
}

static int ceq_irq_handler(struct hinic3_eq *eq)
{
	struct hinic3_ceqs *ceqs;
	u32 eqe_cnt = 0;
	__be32 ceqe_raw;
	__le32 ceqe;
	u32 i;

	ceqs = ceq_to_ceqs(eq);
	for (i = 0; i < HINIC3_TASK_PROCESS_EQE_LIMIT; i++) {
		ceqe_raw = *get_curr_ceq_elem(eq);
		ceqe = (__force __le32)swab32((__force __u32)ceqe_raw);

		/* HW updates wrapped bit, when it adds eq element event */
		if (EQ_ELEM_DESC_GET(ceqe, WRAPPED) == eq->wrapped)
			return 0;

		ceq_event_handler(ceqs, ceqe);
		eq->cons_idx++;
		if (eq->cons_idx == eq->eq_len) {
			eq->cons_idx = 0;
			eq->wrapped = !eq->wrapped;
		}

		if (++eqe_cnt >= HINIC3_EQ_UPDATE_CI_STEP) {
			eqe_cnt = 0;
			set_eq_cons_idx(eq, HINIC3_EQ_NOT_ARMED);
		}
	}

	return -EAGAIN;
}

static void reschedule_aeq_handler(struct hinic3_eq *eq)
{
	struct hinic3_aeqs *aeqs = aeq_to_aeqs(eq);

	queue_work(aeqs->workq, &eq->aeq_work);
}

static int eq_irq_handler(struct hinic3_eq *eq)
{
	int err;

	if (eq->type == HINIC3_AEQ)
		err = aeq_irq_handler(eq);
	else
		err = ceq_irq_handler(eq);

	set_eq_cons_idx(eq, err ? HINIC3_EQ_NOT_ARMED :
			HINIC3_EQ_ARMED);

	return err;
}

static void aeq_irq_work(struct work_struct *work)
{
	struct hinic3_eq *eq = container_of(work, struct hinic3_eq, aeq_work);
	int err;

	err = eq_irq_handler(eq);
	if (err)
		reschedule_aeq_handler(eq);
}

static irqreturn_t aeq_interrupt(int irq, void *data)
{
	struct workqueue_struct *workq;
	struct hinic3_eq *aeq = data;
	struct hinic3_hwdev *hwdev;
	struct hinic3_aeqs *aeqs;

	aeqs = aeq_to_aeqs(aeq);
	hwdev = aeq->hwdev;

	/* clear resend timer cnt register */

Annotation

Implementation Notes