diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-01-30 15:39:54 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-01-30 15:39:54 -0500 |
commit | de8d7a53807c8d2bb04b59ff3a0daa225e81a775 (patch) | |
tree | fcd911aff52d3192af95f1e2aee7ecfd4187d5ec /drivers/net/wireless/ath/carl9170/tx.c | |
parent | 97c7952792018589640ecb3e62e1ab8f06005546 (diff) | |
parent | c331997b6c9ad7f4b8075e6e60d3caa6e36f5938 (diff) |
Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
Diffstat (limited to 'drivers/net/wireless/ath/carl9170/tx.c')
-rw-r--r-- | drivers/net/wireless/ath/carl9170/tx.c | 133 |
1 files changed, 80 insertions, 53 deletions
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index ef4ec0da6e49..9c0b150d5b8e 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c | |||
@@ -1520,35 +1520,92 @@ void carl9170_tx_scheduler(struct ar9170 *ar) | |||
1520 | carl9170_tx(ar); | 1520 | carl9170_tx(ar); |
1521 | } | 1521 | } |
1522 | 1522 | ||
1523 | int carl9170_update_beacon(struct ar9170 *ar, const bool submit) | 1523 | /* caller has to take rcu_read_lock */ |
1524 | static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar) | ||
1524 | { | 1525 | { |
1525 | struct sk_buff *skb = NULL; | ||
1526 | struct carl9170_vif_info *cvif; | 1526 | struct carl9170_vif_info *cvif; |
1527 | int i = 1; | ||
1528 | |||
1529 | /* The AR9170 hardware has no fancy beacon queue or some | ||
1530 | * other scheduling mechanism. So, the driver has to make | ||
1531 | * due by setting the two beacon timers (pretbtt and tbtt) | ||
1532 | * once and then swapping the beacon address in the HW's | ||
1533 | * register file each time the pretbtt fires. | ||
1534 | */ | ||
1535 | |||
1536 | cvif = rcu_dereference(ar->beacon_iter); | ||
1537 | if (ar->vifs > 0 && cvif) { | ||
1538 | do { | ||
1539 | list_for_each_entry_continue_rcu(cvif, &ar->vif_list, | ||
1540 | list) { | ||
1541 | if (cvif->active && cvif->enable_beacon) | ||
1542 | goto out; | ||
1543 | } | ||
1544 | } while (ar->beacon_enabled && i--); | ||
1545 | } | ||
1546 | |||
1547 | out: | ||
1548 | rcu_assign_pointer(ar->beacon_iter, cvif); | ||
1549 | return cvif; | ||
1550 | } | ||
1551 | |||
1552 | static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb, | ||
1553 | u32 *ht1, u32 *plcp) | ||
1554 | { | ||
1527 | struct ieee80211_tx_info *txinfo; | 1555 | struct ieee80211_tx_info *txinfo; |
1528 | struct ieee80211_tx_rate *rate; | 1556 | struct ieee80211_tx_rate *rate; |
1529 | __le32 *data, *old = NULL; | 1557 | unsigned int power, chains; |
1530 | unsigned int plcp, power, chains; | 1558 | bool ht_rate; |
1531 | u32 word, ht1, off, addr, len; | ||
1532 | int i = 0, err = 0; | ||
1533 | 1559 | ||
1534 | rcu_read_lock(); | 1560 | txinfo = IEEE80211_SKB_CB(skb); |
1535 | cvif = rcu_dereference(ar->beacon_iter); | 1561 | rate = &txinfo->control.rates[0]; |
1536 | retry: | 1562 | ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS); |
1537 | if (ar->vifs == 0 || !cvif) | 1563 | carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains); |
1538 | goto out_unlock; | ||
1539 | 1564 | ||
1540 | list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) { | 1565 | *ht1 = AR9170_MAC_BCN_HT1_TX_ANT0; |
1541 | if (cvif->active && cvif->enable_beacon) | 1566 | if (chains == AR9170_TX_PHY_TXCHAIN_2) |
1542 | goto found; | 1567 | *ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1; |
1568 | SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7); | ||
1569 | SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power); | ||
1570 | SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains); | ||
1571 | |||
1572 | if (ht_rate) { | ||
1573 | *ht1 |= AR9170_MAC_BCN_HT1_HT_EN; | ||
1574 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | ||
1575 | *plcp |= AR9170_MAC_BCN_HT2_SGI; | ||
1576 | |||
1577 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | ||
1578 | *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED; | ||
1579 | *plcp |= AR9170_MAC_BCN_HT2_BW40; | ||
1580 | } else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) { | ||
1581 | *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP; | ||
1582 | *plcp |= AR9170_MAC_BCN_HT2_BW40; | ||
1583 | } | ||
1584 | |||
1585 | SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN); | ||
1586 | } else { | ||
1587 | if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M) | ||
1588 | *plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400; | ||
1589 | else | ||
1590 | *plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010; | ||
1543 | } | 1591 | } |
1544 | 1592 | ||
1545 | if (!ar->beacon_enabled || i++) | 1593 | return ht_rate; |
1546 | goto out_unlock; | 1594 | } |
1547 | 1595 | ||
1548 | goto retry; | 1596 | int carl9170_update_beacon(struct ar9170 *ar, const bool submit) |
1597 | { | ||
1598 | struct sk_buff *skb = NULL; | ||
1599 | struct carl9170_vif_info *cvif; | ||
1600 | __le32 *data, *old = NULL; | ||
1601 | u32 word, ht1, plcp, off, addr, len; | ||
1602 | int i = 0, err = 0; | ||
1603 | bool ht_rate; | ||
1549 | 1604 | ||
1550 | found: | 1605 | rcu_read_lock(); |
1551 | rcu_assign_pointer(ar->beacon_iter, cvif); | 1606 | cvif = carl9170_pick_beaconing_vif(ar); |
1607 | if (!cvif) | ||
1608 | goto out_unlock; | ||
1552 | 1609 | ||
1553 | skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif), | 1610 | skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif), |
1554 | NULL, NULL); | 1611 | NULL, NULL); |
@@ -1558,7 +1615,6 @@ found: | |||
1558 | goto err_free; | 1615 | goto err_free; |
1559 | } | 1616 | } |
1560 | 1617 | ||
1561 | txinfo = IEEE80211_SKB_CB(skb); | ||
1562 | spin_lock_bh(&ar->beacon_lock); | 1618 | spin_lock_bh(&ar->beacon_lock); |
1563 | data = (__le32 *)skb->data; | 1619 | data = (__le32 *)skb->data; |
1564 | if (cvif->beacon) | 1620 | if (cvif->beacon) |
@@ -1588,43 +1644,14 @@ found: | |||
1588 | goto err_unlock; | 1644 | goto err_unlock; |
1589 | } | 1645 | } |
1590 | 1646 | ||
1591 | ht1 = AR9170_MAC_BCN_HT1_TX_ANT0; | 1647 | ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp); |
1592 | rate = &txinfo->control.rates[0]; | ||
1593 | carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains); | ||
1594 | if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) { | ||
1595 | if (plcp <= AR9170_TX_PHY_RATE_CCK_11M) | ||
1596 | plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400; | ||
1597 | else | ||
1598 | plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010; | ||
1599 | } else { | ||
1600 | ht1 |= AR9170_MAC_BCN_HT1_HT_EN; | ||
1601 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | ||
1602 | plcp |= AR9170_MAC_BCN_HT2_SGI; | ||
1603 | |||
1604 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | ||
1605 | ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED; | ||
1606 | plcp |= AR9170_MAC_BCN_HT2_BW40; | ||
1607 | } | ||
1608 | if (rate->flags & IEEE80211_TX_RC_DUP_DATA) { | ||
1609 | ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP; | ||
1610 | plcp |= AR9170_MAC_BCN_HT2_BW40; | ||
1611 | } | ||
1612 | |||
1613 | SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN); | ||
1614 | } | ||
1615 | |||
1616 | SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7); | ||
1617 | SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power); | ||
1618 | SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains); | ||
1619 | if (chains == AR9170_TX_PHY_TXCHAIN_2) | ||
1620 | ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1; | ||
1621 | 1648 | ||
1622 | carl9170_async_regwrite_begin(ar); | 1649 | carl9170_async_regwrite_begin(ar); |
1623 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1); | 1650 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1); |
1624 | if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) | 1651 | if (ht_rate) |
1625 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp); | ||
1626 | else | ||
1627 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp); | 1652 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp); |
1653 | else | ||
1654 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp); | ||
1628 | 1655 | ||
1629 | for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { | 1656 | for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { |
1630 | /* | 1657 | /* |