drivers/net/wireless/silabs/wfx/queue.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/silabs/wfx/queue.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/silabs/wfx/queue.c
Extension
.c
Size
8842 bytes
Lines
323
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 (wvif) {
			queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
			WARN_ON(skb_get_queue_mapping(skb) > 3);
			WARN_ON(!atomic_read(&queue->pending_frames));
			atomic_dec(&queue->pending_frames);
		}
		skb_queue_head(dropped, skb);
	}
}

struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id)
{
	struct wfx_queue *queue;
	struct wfx_hif_req_tx *req;
	struct wfx_vif *wvif;
	struct wfx_hif_msg *hif;
	struct sk_buff *skb;

	spin_lock_bh(&wdev->tx_pending.lock);
	skb_queue_walk(&wdev->tx_pending, skb) {
		hif = (struct wfx_hif_msg *)skb->data;
		req = (struct wfx_hif_req_tx *)hif->body;
		if (req->packet_id != packet_id)
			continue;
		spin_unlock_bh(&wdev->tx_pending.lock);
		wvif = wfx_skb_wvif(wdev, skb);
		if (wvif) {
			queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
			WARN_ON(skb_get_queue_mapping(skb) > 3);
			WARN_ON(!atomic_read(&queue->pending_frames));
			atomic_dec(&queue->pending_frames);
		}
		skb_unlink(skb, &wdev->tx_pending);
		return skb;
	}
	spin_unlock_bh(&wdev->tx_pending.lock);
	WARN(1, "cannot find packet in pending queue");
	return NULL;
}

void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms)
{
	ktime_t now = ktime_get();
	struct wfx_tx_priv *tx_priv;
	struct wfx_hif_req_tx *req;
	struct sk_buff *skb;
	bool first = true;

	spin_lock_bh(&wdev->tx_pending.lock);
	skb_queue_walk(&wdev->tx_pending, skb) {
		tx_priv = wfx_skb_tx_priv(skb);
		req = wfx_skb_txreq(skb);
		if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp, limit_ms))) {
			if (first) {
				dev_info(wdev->dev, "frames stuck in firmware since %dms or more:\n",
					 limit_ms);
				first = false;
			}
			dev_info(wdev->dev, "   id %08x sent %lldms ago\n",
				 req->packet_id, ktime_ms_delta(now, tx_priv->xmit_timestamp));
		}
	}
	spin_unlock_bh(&wdev->tx_pending.lock);
}

unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, struct sk_buff *skb)
{
	ktime_t now = ktime_get();
	struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb);

	return ktime_us_delta(now, tx_priv->xmit_timestamp);
}

bool wfx_tx_queues_has_cab(struct wfx_vif *wvif)
{
	struct ieee80211_vif *vif = wvif_to_vif(wvif);
	int i;

	if (vif->type != NL80211_IFTYPE_AP)
		return false;
	for (i = 0; i < IEEE80211_NUM_ACS; ++i)
		/* Note: since only AP can have mcast frames in queue and only one vif can be AP,
		 * all queued frames has same interface id
		 */
		if (!skb_queue_empty_lockless(&wvif->tx_queue[i].cab))
			return true;
	return false;
}

static int wfx_tx_queue_get_weight(struct wfx_queue *queue)

Annotation

Implementation Notes