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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/silabs/wfx/data_tx.c
Extension
.c
Size
17979 bytes
Lines
595
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 (rate->idx > 7) {
			WARN(1, "wrong rate->idx value: %d", rate->idx);
			return -1;
		}
		return rate->idx + 14;
	}
	/* The device only support 2GHz, else band information should be retrieved from
	 * ieee80211_tx_info
	 */
	band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
	if (rate->idx >= band->n_bitrates) {
		WARN(1, "wrong rate->idx value: %d", rate->idx);
		return -1;
	}
	return band->bitrates[rate->idx].hw_value;
}

/* TX policy cache implementation */

static void wfx_tx_policy_build(struct wfx_vif *wvif, struct wfx_tx_policy *policy,
				struct ieee80211_tx_rate *rates)
{
	struct wfx_dev *wdev = wvif->wdev;
	int i, rateid;
	u8 count;

	WARN(rates[0].idx < 0, "invalid rate policy");
	memset(policy, 0, sizeof(*policy));
	for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) {
		if (rates[i].idx < 0)
			break;
		WARN_ON(rates[i].count > 15);
		rateid = wfx_get_hw_rate(wdev, &rates[i]);
		/* Pack two values in each byte of policy->rates */
		count = rates[i].count;
		if (rateid % 2)
			count <<= 4;
		policy->rates[rateid / 2] |= count;
	}
}

static bool wfx_tx_policy_is_equal(const struct wfx_tx_policy *a, const struct wfx_tx_policy *b)
{
	return !memcmp(a->rates, b->rates, sizeof(a->rates));
}

static int wfx_tx_policy_find(struct wfx_tx_policy_cache *cache, struct wfx_tx_policy *wanted)
{
	struct wfx_tx_policy *it;

	list_for_each_entry(it, &cache->used, link)
		if (wfx_tx_policy_is_equal(wanted, it))
			return it - cache->cache;
	list_for_each_entry(it, &cache->free, link)
		if (wfx_tx_policy_is_equal(wanted, it))
			return it - cache->cache;
	return -1;
}

static void wfx_tx_policy_use(struct wfx_tx_policy_cache *cache, struct wfx_tx_policy *entry)
{
	++entry->usage_count;
	list_move(&entry->link, &cache->used);
}

static int wfx_tx_policy_release(struct wfx_tx_policy_cache *cache, struct wfx_tx_policy *entry)
{
	int ret = --entry->usage_count;

	if (!ret)
		list_move(&entry->link, &cache->free);
	return ret;
}

static int wfx_tx_policy_get(struct wfx_vif *wvif, struct ieee80211_tx_rate *rates, bool *renew)
{
	int idx;
	struct wfx_tx_policy_cache *cache = &wvif->tx_policy_cache;
	struct wfx_tx_policy wanted;
	struct wfx_tx_policy *entry;

	wfx_tx_policy_build(wvif, &wanted, rates);

	spin_lock_bh(&cache->lock);
	if (list_empty(&cache->free)) {
		WARN(1, "unable to get a valid Tx policy");
		spin_unlock_bh(&cache->lock);
		return HIF_TX_RETRY_POLICY_INVALID;
	}
	idx = wfx_tx_policy_find(cache, &wanted);

Annotation

Implementation Notes