drivers/net/wwan/t7xx/t7xx_hif_cldma.c

Source file repositories/reference/linux-study-clean/drivers/net/wwan/t7xx/t7xx_hif_cldma.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wwan/t7xx/t7xx_hif_cldma.c
Extension
.c
Size
38163 bytes
Lines
1363
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 ((gpd->flags & GPD_FLAGS_HWO) || !req->skb) {
			dma_addr_t gpd_addr;

			if (!pci_device_is_present(to_pci_dev(md_ctrl->dev))) {
				dev_err(md_ctrl->dev, "PCIe Link disconnected\n");
				return -ENODEV;
			}

			gpd_addr = ioread64_lo_hi(hw_info->ap_pdn_base +
						  REG_CLDMA_DL_CURRENT_ADDRL_0 +
						  queue->index * sizeof(u64));
			if (req->gpd_addr == gpd_addr || hwo_polling_count++ >= 100)
				return 0;

			udelay(1);
			continue;
		}

		hwo_polling_count = 0;
		skb = req->skb;

		if (req->mapped_buff) {
			dma_unmap_single(md_ctrl->dev, req->mapped_buff,
					 queue->tr_ring->pkt_size, DMA_FROM_DEVICE);
			req->mapped_buff = 0;
		}

		skb->len = 0;
		skb_reset_tail_pointer(skb);
		skb_put(skb, le16_to_cpu(gpd->data_buff_len));

		ret = queue->recv_skb(queue, skb);
		/* Break processing, will try again later */
		if (ret < 0)
			return ret;

		req->skb = NULL;
		t7xx_cldma_gpd_set_data_ptr(gpd, 0);

		spin_lock_irqsave(&queue->ring_lock, flags);
		queue->tr_done = list_next_entry_circular(req, &queue->tr_ring->gpd_ring, entry);
		spin_unlock_irqrestore(&queue->ring_lock, flags);
		req = queue->rx_refill;

		ret = t7xx_cldma_alloc_and_map_skb(md_ctrl, req, queue->tr_ring->pkt_size, GFP_KERNEL);
		if (ret)
			return ret;

		gpd = req->gpd;
		t7xx_cldma_gpd_set_data_ptr(gpd, req->mapped_buff);
		gpd->data_buff_len = 0;
		gpd->flags = GPD_FLAGS_IOC | GPD_FLAGS_HWO;

		spin_lock_irqsave(&queue->ring_lock, flags);
		queue->rx_refill = list_next_entry_circular(req, &queue->tr_ring->gpd_ring, entry);
		spin_unlock_irqrestore(&queue->ring_lock, flags);

		rx_not_done = ++count < budget || !need_resched();
	} while (rx_not_done);

	*over_budget = true;
	return 0;
}

static int t7xx_cldma_gpd_rx_collect(struct cldma_queue *queue, int budget)
{
	struct cldma_ctrl *md_ctrl = queue->md_ctrl;
	struct t7xx_cldma_hw *hw_info;
	unsigned int pending_rx_int;
	bool over_budget = false;
	unsigned long flags;
	int ret;

	hw_info = &md_ctrl->hw_info;

	do {
		ret = t7xx_cldma_gpd_rx_from_q(queue, budget, &over_budget);
		if (ret == -ENODATA)
			return 0;
		else if (ret)
			return ret;

		pending_rx_int = 0;

		spin_lock_irqsave(&md_ctrl->cldma_lock, flags);
		if (md_ctrl->rxq_active & BIT(queue->index)) {
			if (!t7xx_cldma_hw_queue_status(hw_info, queue->index, MTK_RX))
				t7xx_cldma_hw_resume_queue(hw_info, queue->index, MTK_RX);

			pending_rx_int = t7xx_cldma_hw_int_status(hw_info, BIT(queue->index),

Annotation

Implementation Notes