drivers/dibs/dibs_loopback.c

Source file repositories/reference/linux-study-clean/drivers/dibs/dibs_loopback.c

File Facts

System
Linux kernel
Corpus path
drivers/dibs/dibs_loopback.c
Extension
.c
Size
8464 bytes
Lines
362
Domain
Driver Families
Bucket
drivers/dibs
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 (tmp_node->token == dmb_node->token) {
			write_unlock_bh(&ldev->dmb_ht_lock);
			goto again;
		}
	}
	hash_add(ldev->dmb_ht, &dmb_node->list, dmb_node->token);
	write_unlock_bh(&ldev->dmb_ht_lock);
	atomic_inc(&ldev->dmb_cnt);

	dmb->idx = dmb_node->sba_idx;
	dmb->dmb_tok = dmb_node->token;
	dmb->cpu_addr = dmb_node->cpu_addr;
	dmb->dma_addr = dmb_node->dma_addr;
	dmb->dmb_len = dmb_node->len;

	spin_lock_irqsave(&dibs->lock, flags);
	dibs->dmb_clientid_arr[sba_idx] = client->id;
	spin_unlock_irqrestore(&dibs->lock, flags);

	return 0;

err_node:
	kfree(dmb_node);
err_bit:
	clear_bit(sba_idx, ldev->sba_idx_mask);
	return rc;
}

static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
				     struct dibs_lo_dmb_node *dmb_node)
{
	/* remove dmb from hash table */
	write_lock_bh(&ldev->dmb_ht_lock);
	hash_del(&dmb_node->list);
	write_unlock_bh(&ldev->dmb_ht_lock);

	clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
	folio_put(virt_to_folio(dmb_node->cpu_addr));
	kfree(dmb_node);

	if (atomic_dec_and_test(&ldev->dmb_cnt))
		wake_up(&ldev->ldev_release);
}

static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
{
	struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
	struct dibs_lo_dev *ldev;
	unsigned long flags;

	ldev = dibs->drv_priv;

	/* find dmb from hash table */
	read_lock_bh(&ldev->dmb_ht_lock);
	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
		if (tmp_node->token == dmb->dmb_tok) {
			dmb_node = tmp_node;
			break;
		}
	}
	read_unlock_bh(&ldev->dmb_ht_lock);
	if (!dmb_node)
		return -EINVAL;

	if (refcount_dec_and_test(&dmb_node->refcnt)) {
		spin_lock_irqsave(&dibs->lock, flags);
		dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
		spin_unlock_irqrestore(&dibs->lock, flags);

		__dibs_lo_unregister_dmb(ldev, dmb_node);
	}
	return 0;
}

static int dibs_lo_support_dmb_nocopy(struct dibs_dev *dibs)
{
	return DIBS_LO_SUPPORT_NOCOPY;
}

static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
{
	struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
	struct dibs_lo_dev *ldev;

	ldev = dibs->drv_priv;

	/* find dmb_node according to dmb->dmb_tok */
	read_lock_bh(&ldev->dmb_ht_lock);
	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
		if (tmp_node->token == dmb->dmb_tok) {

Annotation

Implementation Notes