Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 943c3399 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville
Browse files

carl9170: move beacon_update into tx.c

parent 43b52a5a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -532,7 +532,6 @@ int carl9170_set_ampdu_settings(struct ar9170 *ar);
int carl9170_set_slot_time(struct ar9170 *ar);
int carl9170_set_mac_rates(struct ar9170 *ar);
int carl9170_set_hwretry_limit(struct ar9170 *ar, const u32 max_retry);
int carl9170_update_beacon(struct ar9170 *ar, const bool submit);
int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac,
	const u8 ktype, const u8 keyidx, const u8 *keydata, const int keylen);
int carl9170_disable_key(struct ar9170 *ar, const u8 id);
@@ -553,6 +552,7 @@ void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb);
void carl9170_tx_scheduler(struct ar9170 *ar);
void carl9170_tx_get_skb(struct sk_buff *skb);
int carl9170_tx_put_skb(struct sk_buff *skb);
int carl9170_update_beacon(struct ar9170 *ar, const bool submit);

/* LEDs */
#ifdef CONFIG_CARL9170_LEDS
+0 −129
Original line number Diff line number Diff line
@@ -455,135 +455,6 @@ int carl9170_set_beacon_timers(struct ar9170 *ar)
	return carl9170_regwrite_result();
}

int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
{
	struct sk_buff *skb = NULL;
	struct carl9170_vif_info *cvif;
	struct ieee80211_tx_info *txinfo;
	__le32 *data, *old = NULL;
	u32 word, off, addr, len;
	int i = 0, err = 0;

	rcu_read_lock();
	cvif = rcu_dereference(ar->beacon_iter);
retry:
	if (ar->vifs == 0 || !cvif)
		goto out_unlock;

	list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
		if (cvif->active && cvif->enable_beacon)
			goto found;
	}

	if (!ar->beacon_enabled || i++)
		goto out_unlock;

	goto retry;

found:
	rcu_assign_pointer(ar->beacon_iter, cvif);

	skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
		NULL, NULL);

	if (!skb) {
		err = -ENOMEM;
		goto err_free;
	}

	txinfo = IEEE80211_SKB_CB(skb);
	if (txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS) {
		err = -EINVAL;
		goto err_free;
	}

	spin_lock_bh(&ar->beacon_lock);
	data = (__le32 *)skb->data;
	if (cvif->beacon)
		old = (__le32 *)cvif->beacon->data;

	off = cvif->id * AR9170_MAC_BCN_LENGTH_MAX;
	addr = ar->fw.beacon_addr + off;
	len = roundup(skb->len + FCS_LEN, 4);

	if ((off + len) > ar->fw.beacon_max_len) {
		if (net_ratelimit()) {
			wiphy_err(ar->hw->wiphy, "beacon does not "
				  "fit into device memory!\n");
		}
		err = -EINVAL;
		goto err_unlock;
	}

	if (len > AR9170_MAC_BCN_LENGTH_MAX) {
		if (net_ratelimit()) {
			wiphy_err(ar->hw->wiphy, "no support for beacons "
				"bigger than %d (yours:%d).\n",
				 AR9170_MAC_BCN_LENGTH_MAX, len);
		}

		err = -EMSGSIZE;
		goto err_unlock;
	}

	i = txinfo->control.rates[0].idx;
	if (txinfo->band != IEEE80211_BAND_2GHZ)
		i += 4;

	word = __carl9170_ratetable[i].hw_value & 0xf;
	if (i < 4)
		word |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
	else
		word |= ((skb->len + FCS_LEN) << 16) + 0x0010;

	carl9170_async_regwrite_begin(ar);
	carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, word);

	for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
		/*
		 * XXX: This accesses beyond skb data for up
		 *	to the last 3 bytes!!
		 */

		if (old && (data[i] == old[i]))
			continue;

		word = le32_to_cpu(data[i]);
		carl9170_async_regwrite(addr + 4 * i, word);
	}
	carl9170_async_regwrite_finish();

	dev_kfree_skb_any(cvif->beacon);
	cvif->beacon = NULL;

	err = carl9170_async_regwrite_result();
	if (!err)
		cvif->beacon = skb;
	spin_unlock_bh(&ar->beacon_lock);
	if (err)
		goto err_free;

	if (submit) {
		err = carl9170_bcn_ctrl(ar, cvif->id,
					CARL9170_BCN_CTRL_CAB_TRIGGER,
					addr, skb->len + FCS_LEN);

		if (err)
			goto err_free;
	}
out_unlock:
	rcu_read_unlock();
	return 0;

err_unlock:
	spin_unlock_bh(&ar->beacon_lock);

err_free:
	rcu_read_unlock();
	dev_kfree_skb_any(skb);
	return err;
}

int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac,
			const u8 ktype, const u8 keyidx, const u8 *keydata,
			const int keylen)
+129 −0
Original line number Diff line number Diff line
@@ -1438,3 +1438,132 @@ void carl9170_tx_scheduler(struct ar9170 *ar)
	if (ar->tx_schedule)
		carl9170_tx(ar);
}

int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
{
	struct sk_buff *skb = NULL;
	struct carl9170_vif_info *cvif;
	struct ieee80211_tx_info *txinfo;
	__le32 *data, *old = NULL;
	u32 word, off, addr, len;
	int i = 0, err = 0;

	rcu_read_lock();
	cvif = rcu_dereference(ar->beacon_iter);
retry:
	if (ar->vifs == 0 || !cvif)
		goto out_unlock;

	list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
		if (cvif->active && cvif->enable_beacon)
			goto found;
	}

	if (!ar->beacon_enabled || i++)
		goto out_unlock;

	goto retry;

found:
	rcu_assign_pointer(ar->beacon_iter, cvif);

	skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
		NULL, NULL);

	if (!skb) {
		err = -ENOMEM;
		goto err_free;
	}

	txinfo = IEEE80211_SKB_CB(skb);
	if (txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS) {
		err = -EINVAL;
		goto err_free;
	}

	spin_lock_bh(&ar->beacon_lock);
	data = (__le32 *)skb->data;
	if (cvif->beacon)
		old = (__le32 *)cvif->beacon->data;

	off = cvif->id * AR9170_MAC_BCN_LENGTH_MAX;
	addr = ar->fw.beacon_addr + off;
	len = roundup(skb->len + FCS_LEN, 4);

	if ((off + len) > ar->fw.beacon_max_len) {
		if (net_ratelimit()) {
			wiphy_err(ar->hw->wiphy, "beacon does not "
				  "fit into device memory!\n");
		}
		err = -EINVAL;
		goto err_unlock;
	}

	if (len > AR9170_MAC_BCN_LENGTH_MAX) {
		if (net_ratelimit()) {
			wiphy_err(ar->hw->wiphy, "no support for beacons "
				"bigger than %d (yours:%d).\n",
				 AR9170_MAC_BCN_LENGTH_MAX, len);
		}

		err = -EMSGSIZE;
		goto err_unlock;
	}

	i = txinfo->control.rates[0].idx;
	if (txinfo->band != IEEE80211_BAND_2GHZ)
		i += 4;

	word = __carl9170_ratetable[i].hw_value & 0xf;
	if (i < 4)
		word |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
	else
		word |= ((skb->len + FCS_LEN) << 16) + 0x0010;

	carl9170_async_regwrite_begin(ar);
	carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, word);

	for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
		/*
		 * XXX: This accesses beyond skb data for up
		 *	to the last 3 bytes!!
		 */

		if (old && (data[i] == old[i]))
			continue;

		word = le32_to_cpu(data[i]);
		carl9170_async_regwrite(addr + 4 * i, word);
	}
	carl9170_async_regwrite_finish();

	dev_kfree_skb_any(cvif->beacon);
	cvif->beacon = NULL;

	err = carl9170_async_regwrite_result();
	if (!err)
		cvif->beacon = skb;
	spin_unlock_bh(&ar->beacon_lock);
	if (err)
		goto err_free;

	if (submit) {
		err = carl9170_bcn_ctrl(ar, cvif->id,
					CARL9170_BCN_CTRL_CAB_TRIGGER,
					addr, skb->len + FCS_LEN);

		if (err)
			goto err_free;
	}
out_unlock:
	rcu_read_unlock();
	return 0;

err_unlock:
	spin_unlock_bh(&ar->beacon_lock);

err_free:
	rcu_read_unlock();
	dev_kfree_skb_any(skb);
	return err;
}