drivers/infiniband/core/frmr_pools.c

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

File Facts

System
Linux kernel
Corpus path
drivers/infiniband/core/frmr_pools.c
Extension
.c
Size
14802 bytes
Lines
596
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

while (free_in_tail && src->ci) {
			handle = pop_handle_from_queue_locked(src);
			push_handle_to_queue_locked(dst, handle);
			free_in_tail--;
		}
	}

	if (src->ci > 0) {
		list_splice_tail_init(&src->pages_list, &dst->pages_list);
		dst->num_pages += src->num_pages;
		dst->ci += src->ci;
		src->num_pages = 0;
		src->ci = 0;
	}
}

static bool age_pinned_pool(struct ib_device *device, struct ib_frmr_pool *pool)
{
	struct ib_frmr_pools *pools = device->frmr_pools;
	u32 total, to_destroy, destroyed = 0;
	bool has_work = false;
	u32 *handles;

	spin_lock(&pool->lock);
	total = pool->queue.ci + pool->inactive_queue.ci + pool->in_use;
	if (total <= pool->pinned_handles) {
		spin_unlock(&pool->lock);
		return false;
	}

	to_destroy = min(total - pool->pinned_handles, pool->inactive_queue.ci);

	handles = kcalloc(to_destroy, sizeof(*handles), GFP_ATOMIC);
	if (!handles) {
		spin_unlock(&pool->lock);
		return true;
	}

	/* Destroy all excess handles in the inactive queue */
	for (; destroyed < to_destroy; destroyed++)
		handles[destroyed] = pop_handle_from_queue_locked(
			&pool->inactive_queue);

	/* Move all handles from regular queue to inactive queue */
	if (pool->queue.ci > 0) {
		splice_frmr_queue_locked(&pool->inactive_queue, &pool->queue);
		has_work = true;
	}

	spin_unlock(&pool->lock);

	if (destroyed)
		pools->pool_ops->destroy_frmrs(device, handles, destroyed);
	kfree(handles);
	return has_work;
}

static void pool_aging_work(struct work_struct *work)
{
	struct ib_frmr_pool *pool = container_of(
		to_delayed_work(work), struct ib_frmr_pool, aging_work);
	struct ib_frmr_pools *pools = pool->device->frmr_pools;
	bool has_work = false;

	if (pool->pinned_handles) {
		has_work = age_pinned_pool(pool->device, pool);
		goto out;
	}

	destroy_all_handles_in_queue(pool->device, pool, &pool->inactive_queue);

	/* Move all pages from regular queue to inactive queue */
	spin_lock(&pool->lock);
	if (pool->queue.ci > 0) {
		splice_frmr_queue_locked(&pool->inactive_queue, &pool->queue);
		has_work = true;
	}
	spin_unlock(&pool->lock);

out:
	/* Reschedule if there are handles to age in next aging period */
	if (has_work)
		queue_delayed_work(
			pools->aging_wq, &pool->aging_work,
			secs_to_jiffies(READ_ONCE(pools->aging_period_sec)));
}

static void destroy_frmr_pool(struct ib_device *device,
			      struct ib_frmr_pool *pool)
{

Annotation

Implementation Notes