drivers/infiniband/sw/siw/siw_qp_tx.c

Source file repositories/reference/linux-study-clean/drivers/infiniband/sw/siw/siw_qp_tx.c

File Facts

System
Linux kernel
Corpus path
drivers/infiniband/sw/siw/siw_qp_tx.c
Extension
.c
Size
32143 bytes
Lines
1307
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 tx_task_t {
	struct llist_head active;
	wait_queue_head_t waiting;
};

static DEFINE_PER_CPU(struct tx_task_t, siw_tx_task_g);

int siw_create_tx_threads(void)
{
	int cpu, assigned = 0;

	for_each_online_cpu(cpu) {
		struct tx_task_t *tx_task;

		/* Skip HT cores */
		if (cpu % cpumask_weight(topology_sibling_cpumask(cpu)))
			continue;

		tx_task = &per_cpu(siw_tx_task_g, cpu);
		init_llist_head(&tx_task->active);
		init_waitqueue_head(&tx_task->waiting);

		siw_tx_thread[cpu] =
			kthread_run_on_cpu(siw_run_sq,
					   (unsigned long *)(long)cpu,
					   cpu, "siw_tx/%u");
		if (IS_ERR(siw_tx_thread[cpu])) {
			siw_tx_thread[cpu] = NULL;
			continue;
		}
		assigned++;
	}
	return assigned;
}

void siw_stop_tx_threads(void)
{
	int cpu;

	for_each_possible_cpu(cpu) {
		if (siw_tx_thread[cpu]) {
			kthread_stop(siw_tx_thread[cpu]);
			wake_up(&per_cpu(siw_tx_task_g, cpu).waiting);
			siw_tx_thread[cpu] = NULL;
		}
	}
}

int siw_run_sq(void *data)
{
	const int nr_cpu = (unsigned int)(long)data;
	struct llist_node *active;
	struct siw_qp *qp;
	struct tx_task_t *tx_task = &per_cpu(siw_tx_task_g, nr_cpu);

	while (1) {
		struct llist_node *fifo_list = NULL;

		wait_event_interruptible(tx_task->waiting,
					 !llist_empty(&tx_task->active) ||
						 kthread_should_stop());

		if (kthread_should_stop())
			break;

		active = llist_del_all(&tx_task->active);
		/*
		 * llist_del_all returns a list with newest entry first.
		 * Re-order list for fairness among QP's.
		 */
		fifo_list = llist_reverse_order(active);
		while (fifo_list) {
			qp = container_of(fifo_list, struct siw_qp, tx_list);
			fifo_list = llist_next(fifo_list);
			qp->tx_list.next = NULL;

			siw_sq_resume(qp);
		}
	}
	active = llist_del_all(&tx_task->active);
	if (active) {
		llist_for_each_entry(qp, active, tx_list) {
			qp->tx_list.next = NULL;
			siw_sq_resume(qp);
		}
	}
	return 0;
}

int siw_sq_start(struct siw_qp *qp)

Annotation

Implementation Notes