drivers/net/wireless/ath/ath11k/qmi.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/ath/ath11k/qmi.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/ath/ath11k/qmi.c
Extension
.c
Size
86395 bytes
Lines
3366
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

test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {
			iounmap(ab->qmi.target_mem[i].iaddr);
			ab->qmi.target_mem[i].iaddr = NULL;
			continue;
		}

		dma_free_coherent(ab->dev,
				  ab->qmi.target_mem[i].prev_size,
				  ab->qmi.target_mem[i].vaddr,
				  ab->qmi.target_mem[i].paddr);
		ab->qmi.target_mem[i].vaddr = NULL;
	}
}

static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
{
	int i;
	struct target_mem_chunk *chunk;

	ab->qmi.target_mem_delayed = false;

	for (i = 0; i < ab->qmi.mem_seg_count; i++) {
		chunk = &ab->qmi.target_mem[i];

		/* Firmware reloads in coldboot/firmware recovery.
		 * in such case, no need to allocate memory for FW again.
		 */
		if (chunk->vaddr) {
			if (chunk->prev_type == chunk->type &&
			    chunk->prev_size == chunk->size)
				continue;

			if (ab->qmi.mem_seg_count <= ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT) {
				ath11k_dbg(ab, ATH11K_DBG_QMI,
					   "size/type mismatch (current %d %u) (prev %d %u), try later with small size\n",
					    chunk->size, chunk->type,
					    chunk->prev_size, chunk->prev_type);
				ab->qmi.target_mem_delayed = true;
				return 0;
			}

			/* cannot reuse the existing chunk */
			dma_free_coherent(ab->dev, chunk->prev_size,
					  chunk->vaddr, chunk->paddr);
			chunk->vaddr = NULL;
		}

		chunk->vaddr = dma_alloc_coherent(ab->dev,
						  chunk->size,
						  &chunk->paddr,
						  GFP_KERNEL | __GFP_NOWARN);
		if (!chunk->vaddr) {
			if (ab->qmi.mem_seg_count <= ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT) {
				ath11k_dbg(ab, ATH11K_DBG_QMI,
					   "dma allocation failed (%d B type %u), will try later with small size\n",
					    chunk->size,
					    chunk->type);
				ath11k_qmi_free_target_mem_chunk(ab);
				ab->qmi.target_mem_delayed = true;
				return 0;
			}

			ath11k_err(ab, "failed to allocate dma memory for qmi (%d B type %u)\n",
				   chunk->size,
				   chunk->type);
			return -EINVAL;
		}
		chunk->prev_type = chunk->type;
		chunk->prev_size = chunk->size;
	}

	return 0;
}

static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
{
	struct device *dev = ab->dev;
	struct resource res = {};
	u32 host_ddr_sz;
	int i, idx, ret;

	for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) {
		switch (ab->qmi.target_mem[i].type) {
		case HOST_DDR_REGION_TYPE:
			ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
			if (ret) {
				ath11k_dbg(ab, ATH11K_DBG_QMI,
					   "fail to get reg from hremote\n");
				return ret;
			}

Annotation

Implementation Notes