drivers/net/wireless/intersil/p54/txrx.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/intersil/p54/txrx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intersil/p54/txrx.c
Extension
.c
Size
25964 bytes
Lines
948
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 (!target_skb && hole_size >= len) {
			target_skb = entry->prev;
			hole_size -= len;
			target_addr = last_addr;
			break;
		}
		last_addr = range->end_addr;
	}
	if (unlikely(!target_skb)) {
		if (priv->rx_end - last_addr >= len) {
			target_skb = skb_peek_tail(&priv->tx_queue);
			if (target_skb) {
				info = IEEE80211_SKB_CB(target_skb);
				range = (void *)info->rate_driver_data;
				target_addr = range->end_addr;
			}
		} else {
			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
			return -ENOSPC;
		}
	}

	info = IEEE80211_SKB_CB(skb);
	range = (void *) info->rate_driver_data;
	range->start_addr = target_addr;
	range->end_addr = target_addr + len;
	data->req_id = cpu_to_le32(target_addr + priv->headroom);
	if (IS_DATA_FRAME(skb) &&
	    unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
		priv->beacon_req_id = data->req_id;

	if (target_skb)
		__skb_queue_after(&priv->tx_queue, target_skb, skb);
	else
		__skb_queue_head(&priv->tx_queue, skb);
	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
	return 0;
}

static void p54_tx_pending(struct p54_common *priv)
{
	struct sk_buff *skb;
	int ret;

	skb = skb_dequeue(&priv->tx_pending);
	if (unlikely(!skb))
		return ;

	ret = p54_assign_address(priv, skb);
	if (unlikely(ret))
		skb_queue_head(&priv->tx_pending, skb);
	else
		priv->tx(priv->hw, skb);
}

static void p54_wake_queues(struct p54_common *priv)
{
	unsigned long flags;
	unsigned int i;

	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
		return ;

	p54_tx_pending(priv);

	spin_lock_irqsave(&priv->tx_stats_lock, flags);
	for (i = 0; i < priv->hw->queues; i++) {
		if (priv->tx_stats[i + P54_QUEUE_DATA].len <
		    priv->tx_stats[i + P54_QUEUE_DATA].limit)
			ieee80211_wake_queue(priv->hw, i);
	}
	spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
}

static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
				       struct sk_buff *skb,
				       const u16 p54_queue)
{
	struct p54_tx_queue_stats *queue;
	unsigned long flags;

	if (WARN_ON(p54_queue >= P54_QUEUE_NUM))
		return -EINVAL;

	queue = &priv->tx_stats[p54_queue];

	spin_lock_irqsave(&priv->tx_stats_lock, flags);
	if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
		spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
		return -ENOSPC;

Annotation

Implementation Notes