drivers/net/ethernet/qlogic/qed/qed_chain.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/qlogic/qed/qed_chain.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/qlogic/qed/qed_chain.c
Extension
.c
Size
8659 bytes
Lines
372
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 (i == 0) {
			qed_chain_init_mem(chain, virt, phys);
			qed_chain_reset(chain);
		} else {
			qed_chain_init_next_ptr_elem(chain, virt_prev, virt,
						     phys);
		}

		virt_prev = virt;
	}

	/* Last page's next element should point to the beginning of the
	 * chain.
	 */
	qed_chain_init_next_ptr_elem(chain, virt_prev, chain->p_virt_addr,
				     chain->p_phys_addr);

	return 0;
}

static int qed_chain_alloc_single(struct qed_dev *cdev,
				  struct qed_chain *chain)
{
	dma_addr_t phys;
	void *virt;

	virt = dma_alloc_coherent(&cdev->pdev->dev, chain->page_size,
				  &phys, GFP_KERNEL);
	if (!virt)
		return -ENOMEM;

	qed_chain_init_mem(chain, virt, phys);
	qed_chain_reset(chain);

	return 0;
}

static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *chain)
{
	struct device *dev = &cdev->pdev->dev;
	struct addr_tbl_entry *addr_tbl;
	dma_addr_t phys, pbl_phys;
	__le64 *pbl_virt;
	u32 page_cnt, i;
	size_t size;
	void *virt;

	page_cnt = chain->page_cnt;

	size = array_size(page_cnt, sizeof(*addr_tbl));
	if (unlikely(size == SIZE_MAX))
		return -EOVERFLOW;

	addr_tbl = vzalloc(size);
	if (!addr_tbl)
		return -ENOMEM;

	chain->pbl.pp_addr_tbl = addr_tbl;

	if (chain->b_external_pbl) {
		pbl_virt = chain->pbl_sp.table_virt;
		goto alloc_pages;
	}

	size = array_size(page_cnt, sizeof(*pbl_virt));
	if (unlikely(size == SIZE_MAX))
		return -EOVERFLOW;

	pbl_virt = dma_alloc_coherent(dev, size, &pbl_phys, GFP_KERNEL);
	if (!pbl_virt)
		return -ENOMEM;

	chain->pbl_sp.table_virt = pbl_virt;
	chain->pbl_sp.table_phys = pbl_phys;
	chain->pbl_sp.table_size = size;

alloc_pages:
	for (i = 0; i < page_cnt; i++) {
		virt = dma_alloc_coherent(dev, chain->page_size, &phys,
					  GFP_KERNEL);
		if (!virt)
			return -ENOMEM;

		if (i == 0) {
			qed_chain_init_mem(chain, virt, phys);
			qed_chain_reset(chain);
		}

		/* Fill the PBL table with the physical address of the page */
		pbl_virt[i] = cpu_to_le64(phys);

Annotation

Implementation Notes