drivers/net/wireless/ath/wil6210/txrx_edma.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/ath/wil6210/txrx_edma.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/ath/wil6210/txrx_edma.c
Extension
.c
Size
43992 bytes
Lines
1646
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 (unlikely(rc)) {
			if (rc == -EAGAIN)
				wil_dbg_txrx(wil, "No free buffer ID found\n");
			else
				wil_err_ratelimited(wil,
						    "Error %d in refill desc[%d]\n",
						    rc, ring->swhead);
			break;
		}
	}

	/* make sure all writes to descriptors (shared memory) are done before
	 * committing them to HW
	 */
	wmb();

	wil_w(wil, ring->hwtail, ring->swhead);

	return rc;
}

static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
					      struct wil_ring *ring)
{
	struct device *dev = wil_to_dev(wil);
	struct list_head *active = &wil->rx_buff_mgmt.active;
	dma_addr_t pa;

	if (!wil->rx_buff_mgmt.buff_arr)
		return;

	while (!list_empty(active)) {
		struct wil_rx_buff *rx_buff =
			list_first_entry(active, struct wil_rx_buff, list);
		struct sk_buff *skb = rx_buff->skb;

		if (unlikely(!skb)) {
			wil_err(wil, "No Rx skb at buff_id %d\n", rx_buff->id);
		} else {
			rx_buff->skb = NULL;
			memcpy(&pa, skb->cb, sizeof(pa));
			dma_unmap_single(dev, pa, wil->rx_buf_len,
					 DMA_FROM_DEVICE);
			kfree_skb(skb);
		}

		/* Move the buffer from the active to the free list */
		list_move(&rx_buff->list, &wil->rx_buff_mgmt.free);
	}
}

static void wil_free_rx_buff_arr(struct wil6210_priv *wil)
{
	struct wil_ring *ring = &wil->ring_rx;

	if (!wil->rx_buff_mgmt.buff_arr)
		return;

	/* Move all the buffers to the free list in case active list is
	 * not empty in order to release all SKBs before deleting the array
	 */
	wil_move_all_rx_buff_to_free_list(wil, ring);

	kfree(wil->rx_buff_mgmt.buff_arr);
	wil->rx_buff_mgmt.buff_arr = NULL;
}

static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
				size_t size)
{
	struct wil_rx_buff *buff_arr;
	struct list_head *active = &wil->rx_buff_mgmt.active;
	struct list_head *free = &wil->rx_buff_mgmt.free;
	int i;

	wil->rx_buff_mgmt.buff_arr = kzalloc_objs(struct wil_rx_buff, size + 1);
	if (!wil->rx_buff_mgmt.buff_arr)
		return -ENOMEM;

	/* Set list heads */
	INIT_LIST_HEAD(active);
	INIT_LIST_HEAD(free);

	/* Linkify the list.
	 * buffer id 0 should not be used (marks invalid id).
	 */
	buff_arr = wil->rx_buff_mgmt.buff_arr;
	for (i = 1; i <= size; i++) {
		list_add(&buff_arr[i].list, free);
		buff_arr[i].id = i;

Annotation

Implementation Notes