carl9170: refactor carl9170_update_beacon

This patch moves parts of carl9170_update_beacon
into separate subroutines, so the parts become
more manageable.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Christian Lamparter 2012-12-22 15:05:26 +01:00 committed by John W. Linville
parent 558925f313
commit 1f1d9654e1
1 changed files with 81 additions and 54 deletions

View File

@ -1520,36 +1520,93 @@ void carl9170_tx_scheduler(struct ar9170 *ar)
carl9170_tx(ar);
}
/* caller has to take rcu_read_lock */
static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
{
struct carl9170_vif_info *cvif;
int i = 1;
/* The AR9170 hardware has no fancy beacon queue or some
* other scheduling mechanism. So, the driver has to make
* due by setting the two beacon timers (pretbtt and tbtt)
* once and then swapping the beacon address in the HW's
* register file each time the pretbtt fires.
*/
cvif = rcu_dereference(ar->beacon_iter);
if (ar->vifs > 0 && cvif) {
do {
list_for_each_entry_continue_rcu(cvif, &ar->vif_list,
list) {
if (cvif->active && cvif->enable_beacon)
goto out;
}
} while (ar->beacon_enabled && i--);
}
out:
rcu_assign_pointer(ar->beacon_iter, cvif);
return cvif;
}
static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb,
u32 *ht1, u32 *plcp)
{
struct ieee80211_tx_info *txinfo;
struct ieee80211_tx_rate *rate;
unsigned int power, chains;
bool ht_rate;
txinfo = IEEE80211_SKB_CB(skb);
rate = &txinfo->control.rates[0];
ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS);
carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains);
*ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
if (chains == AR9170_TX_PHY_TXCHAIN_2)
*ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7);
SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power);
SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains);
if (ht_rate) {
*ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
*plcp |= AR9170_MAC_BCN_HT2_SGI;
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
*ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
*plcp |= AR9170_MAC_BCN_HT2_BW40;
} else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
*ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
*plcp |= AR9170_MAC_BCN_HT2_BW40;
}
SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN);
} else {
if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M)
*plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
else
*plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
}
return ht_rate;
}
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;
struct ieee80211_tx_rate *rate;
__le32 *data, *old = NULL;
unsigned int plcp, power, chains;
u32 word, ht1, off, addr, len;
u32 word, ht1, plcp, off, addr, len;
int i = 0, err = 0;
bool ht_rate;
rcu_read_lock();
cvif = rcu_dereference(ar->beacon_iter);
retry:
if (ar->vifs == 0 || !cvif)
cvif = carl9170_pick_beaconing_vif(ar);
if (!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);
@ -1558,7 +1615,6 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
goto err_free;
}
txinfo = IEEE80211_SKB_CB(skb);
spin_lock_bh(&ar->beacon_lock);
data = (__le32 *)skb->data;
if (cvif->beacon)
@ -1588,43 +1644,14 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
goto err_unlock;
}
ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
rate = &txinfo->control.rates[0];
carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains);
if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
if (plcp <= AR9170_TX_PHY_RATE_CCK_11M)
plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
else
plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
} else {
ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
plcp |= AR9170_MAC_BCN_HT2_SGI;
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
plcp |= AR9170_MAC_BCN_HT2_BW40;
}
if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
plcp |= AR9170_MAC_BCN_HT2_BW40;
}
SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN);
}
SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7);
SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power);
SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains);
if (chains == AR9170_TX_PHY_TXCHAIN_2)
ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp);
carl9170_async_regwrite_begin(ar);
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1);
if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS))
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
else
if (ht_rate)
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp);
else
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
/*