drivers/net/wireless/mediatek/mt76/tx.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/mediatek/mt76/tx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/mediatek/mt76/tx.c
Extension
.c
Size
22203 bytes
Lines
958
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 (wcid) {
			status.sta = wcid_to_sta(wcid);
			if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
				rs.rate_idx = wcid->rate;
				status.rates = &rs;
				status.n_rates = 1;
			} else {
				status.n_rates = 0;
			}
		}

		hw = mt76_tx_status_get_hw(dev, skb);
		spin_lock_bh(&dev->rx_lock);
		ieee80211_tx_status_ext(hw, &status);
		spin_unlock_bh(&dev->rx_lock);
	}
	rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(mt76_tx_status_unlock);

static void
__mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags,
			  struct sk_buff_head *list)
{
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
	u8 done = MT_TX_CB_DMA_DONE | MT_TX_CB_TXS_DONE;

	flags |= cb->flags;
	cb->flags = flags;

	if ((flags & done) != done)
		return;

	/* Tx status can be unreliable. if it fails, mark the frame as ACKed */
	if (flags & MT_TX_CB_TXS_FAILED &&
	    (dev->drv->drv_flags & MT_DRV_IGNORE_TXS_FAILED)) {
		info->status.rates[0].count = 0;
		info->status.rates[0].idx = -1;
		info->flags |= IEEE80211_TX_STAT_ACK;
	}

	__skb_queue_tail(list, skb);
}

void
mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,
			struct sk_buff_head *list)
{
	__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_DONE, list);
}
EXPORT_SYMBOL_GPL(mt76_tx_status_skb_done);

int
mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
		       struct sk_buff *skb)
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
	int pid;

	memset(cb, 0, sizeof(*cb));

	if (!wcid || !rcu_access_pointer(dev->wcid[wcid->idx]))
		return MT_PACKET_ID_NO_ACK;

	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
		return MT_PACKET_ID_NO_ACK;

	if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
			     IEEE80211_TX_CTL_RATE_CTRL_PROBE))) {
		if (mtk_wed_device_active(&dev->mmio.wed) &&
		    ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) ||
		     ieee80211_is_data(hdr->frame_control)))
			return MT_PACKET_ID_WED;

		return MT_PACKET_ID_NO_SKB;
	}

	spin_lock_bh(&dev->status_lock);

	pid = idr_alloc(&wcid->pktid, skb, MT_PACKET_ID_FIRST,
			MT_PACKET_ID_MASK, GFP_ATOMIC);
	if (pid < 0) {
		pid = MT_PACKET_ID_NO_SKB;
		goto out;
	}

	cb->wcid = wcid->idx;

Annotation

Implementation Notes