drivers/net/wireless/ath/carl9170/tx.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/ath/carl9170/tx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/ath/carl9170/tx.c
Extension
.c
Size
43683 bytes
Lines
1720
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 (mem_full || ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
			ieee80211_stop_queue(ar->hw, i);
			ar->queue_stop_timeout[i] = jiffies;
		}
	}

	spin_unlock_bh(&ar->tx_stats_lock);
}

/* needs rcu_read_lock */
static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar,
						   struct sk_buff *skb)
{
	struct _carl9170_tx_superframe *super = (void *) skb->data;
	struct ieee80211_hdr *hdr = (void *) super->frame_data;
	struct ieee80211_vif *vif;
	unsigned int vif_id;

	vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
		 CARL9170_TX_SUPER_MISC_VIF_ID_S;

	if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC))
		return NULL;

	vif = rcu_dereference(ar->vif_priv[vif_id].vif);
	if (unlikely(!vif))
		return NULL;

	/*
	 * Normally we should use wrappers like ieee80211_get_DA to get
	 * the correct peer ieee80211_sta.
	 *
	 * But there is a problem with indirect traffic (broadcasts, or
	 * data which is designated for other stations) in station mode.
	 * The frame will be directed to the AP for distribution and not
	 * to the actual destination.
	 */

	return ieee80211_find_sta(vif, hdr->addr1);
}

static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb)
{
	struct ieee80211_sta *sta;
	struct carl9170_sta_info *sta_info;

	rcu_read_lock();
	sta = __carl9170_get_tx_sta(ar, skb);
	if (unlikely(!sta))
		goto out_rcu;

	sta_info = (struct carl9170_sta_info *) sta->drv_priv;
	if (atomic_dec_return(&sta_info->pending_frames) == 0)
		ieee80211_sta_block_awake(ar->hw, sta, false);

out_rcu:
	rcu_read_unlock();
}

static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb)
{
	int queue;

	queue = skb_get_queue_mapping(skb);

	spin_lock_bh(&ar->tx_stats_lock);

	ar->tx_stats[queue].len--;

	if (!is_mem_full(ar)) {
		unsigned int i;
		for (i = 0; i < ar->hw->queues; i++) {
			if (ar->tx_stats[i].len >= CARL9170_NUM_TX_LIMIT_SOFT)
				continue;

			if (ieee80211_queue_stopped(ar->hw, i)) {
				unsigned long tmp;

				tmp = jiffies - ar->queue_stop_timeout[i];
				if (tmp > ar->max_queue_stop_timeout[i])
					ar->max_queue_stop_timeout[i] = tmp;
			}

			ieee80211_wake_queue(ar->hw, i);
		}
	}

	spin_unlock_bh(&ar->tx_stats_lock);

	if (atomic_dec_and_test(&ar->tx_total_queued))

Annotation

Implementation Notes