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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/qlogic/qed/qed_ll2.c
Extension
.c
Size
78670 bytes
Lines
2822
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

struct qed_cb_ll2_info {
	int rx_cnt;
	u32 rx_size;
	u8 handle;

	/* Lock protecting LL2 buffer lists in sleepless context */
	spinlock_t lock;
	struct list_head list;

	const struct qed_ll2_cb_ops *cbs;
	void *cb_cookie;
};

struct qed_ll2_buffer {
	struct list_head list;
	void *data;
	dma_addr_t phys_addr;
};

static u8 qed_ll2_handle_to_stats_id(struct qed_hwfn *p_hwfn,
				     u8 ll2_queue_type, u8 qid)
{
	u8 stats_id;

	/* For legacy (RAM based) queues, the stats_id will be set as the
	 * queue_id. Otherwise (context based queue), it will be set to
	 * the "abs_pf_id" offset from the end of the RAM based queue IDs.
	 * If the final value exceeds the total counters amount, return
	 * INVALID value to indicate that the stats for this connection should
	 * be disabled.
	 */
	if (ll2_queue_type == QED_LL2_RX_TYPE_LEGACY)
		stats_id = qid;
	else
		stats_id = MAX_NUM_LL2_RX_RAM_QUEUES + p_hwfn->abs_pf_id;

	if (stats_id < MAX_NUM_LL2_TX_STATS_COUNTERS)
		return stats_id;
	else
		return QED_LL2_INVALID_STATS_ID;
}

static void qed_ll2b_complete_tx_packet(void *cxt,
					u8 connection_handle,
					void *cookie,
					dma_addr_t first_frag_addr,
					bool b_last_fragment,
					bool b_last_packet)
{
	struct qed_hwfn *p_hwfn = cxt;
	struct qed_dev *cdev = p_hwfn->cdev;
	struct sk_buff *skb = cookie;

	/* All we need to do is release the mapping */
	dma_unmap_single(&p_hwfn->cdev->pdev->dev, first_frag_addr,
			 skb_headlen(skb), DMA_TO_DEVICE);

	if (cdev->ll2->cbs && cdev->ll2->cbs->tx_cb)
		cdev->ll2->cbs->tx_cb(cdev->ll2->cb_cookie, skb,
				      b_last_fragment);

	dev_kfree_skb_any(skb);
}

static int qed_ll2_alloc_buffer(struct qed_dev *cdev,
				u8 **data, dma_addr_t *phys_addr)
{
	size_t size = cdev->ll2->rx_size + NET_SKB_PAD +
		      SKB_DATA_ALIGN(sizeof(struct skb_shared_info));

	*data = kmalloc(size, GFP_ATOMIC);
	if (!(*data)) {
		DP_INFO(cdev, "Failed to allocate LL2 buffer data\n");
		return -ENOMEM;
	}

	*phys_addr = dma_map_single(&cdev->pdev->dev,
				    ((*data) + NET_SKB_PAD),
				    cdev->ll2->rx_size, DMA_FROM_DEVICE);
	if (dma_mapping_error(&cdev->pdev->dev, *phys_addr)) {
		DP_INFO(cdev, "Failed to map LL2 buffer data\n");
		kfree((*data));
		return -ENOMEM;
	}

	return 0;
}

static int qed_ll2_dealloc_buffer(struct qed_dev *cdev,
				  struct qed_ll2_buffer *buffer)

Annotation

Implementation Notes