drivers/net/wireless/intel/iwlwifi/fw/paging.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/intel/iwlwifi/fw/paging.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intel/iwlwifi/fw/paging.c
Extension
.c
Size
8228 bytes
Lines
297
Domain
Driver Families
Bucket
drivers/net
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

if (!paging->fw_paging_block) {
			IWL_DEBUG_FW(fwrt,
				     "Paging: block %d already freed, continue to next page\n",
				     i);

			continue;
		}
		dma_unmap_page(fwrt->trans->dev, paging->fw_paging_phys,
			       paging->fw_paging_size, DMA_BIDIRECTIONAL);

		__free_pages(paging->fw_paging_block,
			     get_order(paging->fw_paging_size));
		paging->fw_paging_block = NULL;
	}

	memset(fwrt->fw_paging_db, 0, sizeof(fwrt->fw_paging_db));
}
IWL_EXPORT_SYMBOL(iwl_free_fw_paging);

static int iwl_alloc_fw_paging_mem(struct iwl_fw_runtime *fwrt,
				   const struct fw_img *image)
{
	struct page *block;
	dma_addr_t phys = 0;
	int blk_idx, order, num_of_pages, size;

	if (fwrt->fw_paging_db[0].fw_paging_block)
		return 0;

	/* ensure BLOCK_2_EXP_SIZE is power of 2 of PAGING_BLOCK_SIZE */
	BUILD_BUG_ON(BIT(BLOCK_2_EXP_SIZE) != PAGING_BLOCK_SIZE);

	num_of_pages = image->paging_mem_size / FW_PAGING_SIZE;
	fwrt->num_of_paging_blk =
		DIV_ROUND_UP(num_of_pages, NUM_OF_PAGE_PER_GROUP);
	fwrt->num_of_pages_in_last_blk =
		num_of_pages -
		NUM_OF_PAGE_PER_GROUP * (fwrt->num_of_paging_blk - 1);

	IWL_DEBUG_FW(fwrt,
		     "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n",
		     fwrt->num_of_paging_blk,
		     fwrt->num_of_pages_in_last_blk);

	/*
	 * Allocate CSS and paging blocks in dram.
	 */
	for (blk_idx = 0; blk_idx < fwrt->num_of_paging_blk + 1; blk_idx++) {
		/* For CSS allocate 4KB, for others PAGING_BLOCK_SIZE (32K) */
		size = blk_idx ? PAGING_BLOCK_SIZE : FW_PAGING_SIZE;
		order = get_order(size);
		block = alloc_pages(GFP_KERNEL, order);
		if (!block) {
			/* free all the previous pages since we failed */
			iwl_free_fw_paging(fwrt);
			return -ENOMEM;
		}

		fwrt->fw_paging_db[blk_idx].fw_paging_block = block;
		fwrt->fw_paging_db[blk_idx].fw_paging_size = size;

		phys = dma_map_page(fwrt->trans->dev, block, 0,
				    PAGE_SIZE << order,
				    DMA_BIDIRECTIONAL);
		if (dma_mapping_error(fwrt->trans->dev, phys)) {
			/*
			 * free the previous pages and the current one
			 * since we failed to map_page.
			 */
			iwl_free_fw_paging(fwrt);
			return -ENOMEM;
		}
		fwrt->fw_paging_db[blk_idx].fw_paging_phys = phys;

		if (!blk_idx)
			IWL_DEBUG_FW(fwrt,
				     "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n",
				     order);
		else
			IWL_DEBUG_FW(fwrt,
				     "Paging: allocated 32K bytes (order %d) for firmware paging.\n",
				     order);
	}

	return 0;
}

static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
			       const struct fw_img *image)
{

Annotation

Implementation Notes