diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8913180a7bd3..28ebaec80be6 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -289,10 +289,17 @@ struct mwl8k_vif { | |||
289 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) | 289 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) |
290 | #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) | 290 | #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) |
291 | 291 | ||
292 | struct tx_traffic_info { | ||
293 | u32 start_time; | ||
294 | u32 pkts; | ||
295 | }; | ||
296 | |||
297 | #define MWL8K_MAX_TID 8 | ||
292 | struct mwl8k_sta { | 298 | struct mwl8k_sta { |
293 | /* Index into station database. Returned by UPDATE_STADB. */ | 299 | /* Index into station database. Returned by UPDATE_STADB. */ |
294 | u8 peer_id; | 300 | u8 peer_id; |
295 | u8 is_ampdu_allowed; | 301 | u8 is_ampdu_allowed; |
302 | struct tx_traffic_info tx_stats[MWL8K_MAX_TID]; | ||
296 | }; | 303 | }; |
297 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) | 304 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) |
298 | 305 | ||
@@ -701,7 +708,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) | |||
701 | "helper image\n", pci_name(priv->pdev)); | 708 | "helper image\n", pci_name(priv->pdev)); |
702 | return rc; | 709 | return rc; |
703 | } | 710 | } |
704 | msleep(5); | 711 | msleep(20); |
705 | 712 | ||
706 | rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); | 713 | rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); |
707 | } else { | 714 | } else { |
@@ -823,8 +830,8 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) | |||
823 | /* | 830 | /* |
824 | * Make sure the packet header is in the DMA header format (4-address | 831 | * Make sure the packet header is in the DMA header format (4-address |
825 | * without QoS), the necessary crypto padding between the header and the | 832 | * without QoS), the necessary crypto padding between the header and the |
826 | * payload has already been provided by mac80211, but it doesn't add tail | 833 | * payload has already been provided by mac80211, but it doesn't add |
827 | * padding when HW crypto is enabled. | 834 | * tail padding when HW crypto is enabled. |
828 | * | 835 | * |
829 | * We have the following trailer padding requirements: | 836 | * We have the following trailer padding requirements: |
830 | * - WEP: 4 trailer bytes (ICV) | 837 | * - WEP: 4 trailer bytes (ICV) |
@@ -1487,9 +1494,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1487 | 1494 | ||
1488 | if (timeout) { | 1495 | if (timeout) { |
1489 | WARN_ON(priv->pending_tx_pkts); | 1496 | WARN_ON(priv->pending_tx_pkts); |
1490 | if (retry) { | 1497 | if (retry) |
1491 | wiphy_notice(hw->wiphy, "tx rings drained\n"); | 1498 | wiphy_notice(hw->wiphy, "tx rings drained\n"); |
1492 | } | ||
1493 | break; | 1499 | break; |
1494 | } | 1500 | } |
1495 | 1501 | ||
@@ -1649,8 +1655,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1649 | /* Rate control is happening in the firmware. | 1655 | /* Rate control is happening in the firmware. |
1650 | * Ensure no tx rate is being reported. | 1656 | * Ensure no tx rate is being reported. |
1651 | */ | 1657 | */ |
1652 | info->status.rates[0].idx = -1; | 1658 | info->status.rates[0].idx = -1; |
1653 | info->status.rates[0].count = 1; | 1659 | info->status.rates[0].count = 1; |
1654 | 1660 | ||
1655 | if (MWL8K_TXD_SUCCESS(status)) | 1661 | if (MWL8K_TXD_SUCCESS(status)) |
1656 | info->flags |= IEEE80211_TX_STAT_ACK; | 1662 | info->flags |= IEEE80211_TX_STAT_ACK; |
@@ -1688,7 +1694,7 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1688 | } | 1694 | } |
1689 | 1695 | ||
1690 | /* caller must hold priv->stream_lock when calling the stream functions */ | 1696 | /* caller must hold priv->stream_lock when calling the stream functions */ |
1691 | struct mwl8k_ampdu_stream * | 1697 | static struct mwl8k_ampdu_stream * |
1692 | mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) | 1698 | mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) |
1693 | { | 1699 | { |
1694 | struct mwl8k_ampdu_stream *stream; | 1700 | struct mwl8k_ampdu_stream *stream; |
@@ -1755,6 +1761,41 @@ mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) | |||
1755 | return NULL; | 1761 | return NULL; |
1756 | } | 1762 | } |
1757 | 1763 | ||
1764 | #define MWL8K_AMPDU_PACKET_THRESHOLD 64 | ||
1765 | static inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid) | ||
1766 | { | ||
1767 | struct mwl8k_sta *sta_info = MWL8K_STA(sta); | ||
1768 | struct tx_traffic_info *tx_stats; | ||
1769 | |||
1770 | BUG_ON(tid >= MWL8K_MAX_TID); | ||
1771 | tx_stats = &sta_info->tx_stats[tid]; | ||
1772 | |||
1773 | return sta_info->is_ampdu_allowed && | ||
1774 | tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD; | ||
1775 | } | ||
1776 | |||
1777 | static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) | ||
1778 | { | ||
1779 | struct mwl8k_sta *sta_info = MWL8K_STA(sta); | ||
1780 | struct tx_traffic_info *tx_stats; | ||
1781 | |||
1782 | BUG_ON(tid >= MWL8K_MAX_TID); | ||
1783 | tx_stats = &sta_info->tx_stats[tid]; | ||
1784 | |||
1785 | if (tx_stats->start_time == 0) | ||
1786 | tx_stats->start_time = jiffies; | ||
1787 | |||
1788 | /* reset the packet count after each second elapses. If the number of | ||
1789 | * packets ever exceeds the ampdu_min_traffic threshold, we will allow | ||
1790 | * an ampdu stream to be started. | ||
1791 | */ | ||
1792 | if (jiffies - tx_stats->start_time > HZ) { | ||
1793 | tx_stats->pkts = 0; | ||
1794 | tx_stats->start_time = 0; | ||
1795 | } else | ||
1796 | tx_stats->pkts++; | ||
1797 | } | ||
1798 | |||
1758 | static void | 1799 | static void |
1759 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | 1800 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) |
1760 | { | 1801 | { |
@@ -1841,6 +1882,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1841 | skb->protocol != cpu_to_be16(ETH_P_PAE) && | 1882 | skb->protocol != cpu_to_be16(ETH_P_PAE) && |
1842 | sta->ht_cap.ht_supported && priv->ap_fw) { | 1883 | sta->ht_cap.ht_supported && priv->ap_fw) { |
1843 | tid = qos & 0xf; | 1884 | tid = qos & 0xf; |
1885 | mwl8k_tx_count_packet(sta, tid); | ||
1844 | spin_lock(&priv->stream_lock); | 1886 | spin_lock(&priv->stream_lock); |
1845 | stream = mwl8k_lookup_stream(hw, sta->addr, tid); | 1887 | stream = mwl8k_lookup_stream(hw, sta->addr, tid); |
1846 | if (stream != NULL) { | 1888 | if (stream != NULL) { |
@@ -1881,7 +1923,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1881 | * prevents sequence number mismatch at the recepient | 1923 | * prevents sequence number mismatch at the recepient |
1882 | * as described above. | 1924 | * as described above. |
1883 | */ | 1925 | */ |
1884 | if (MWL8K_STA(sta)->is_ampdu_allowed) { | 1926 | if (mwl8k_ampdu_allowed(sta, tid)) { |
1885 | stream = mwl8k_add_stream(hw, sta, tid); | 1927 | stream = mwl8k_add_stream(hw, sta, tid); |
1886 | if (stream != NULL) | 1928 | if (stream != NULL) |
1887 | start_ba_session = true; | 1929 | start_ba_session = true; |
@@ -2657,7 +2699,7 @@ struct mwl8k_cmd_tx_power { | |||
2657 | __le16 bw; | 2699 | __le16 bw; |
2658 | __le16 sub_ch; | 2700 | __le16 sub_ch; |
2659 | __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; | 2701 | __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; |
2660 | } __attribute__((packed)); | 2702 | } __packed; |
2661 | 2703 | ||
2662 | static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, | 2704 | static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, |
2663 | struct ieee80211_conf *conf, | 2705 | struct ieee80211_conf *conf, |
@@ -3520,13 +3562,13 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, | |||
3520 | #define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 | 3562 | #define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 |
3521 | #define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 | 3563 | #define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 |
3522 | 3564 | ||
3523 | enum { | 3565 | enum ba_stream_action_type { |
3524 | MWL8K_BA_CREATE, | 3566 | MWL8K_BA_CREATE, |
3525 | MWL8K_BA_UPDATE, | 3567 | MWL8K_BA_UPDATE, |
3526 | MWL8K_BA_DESTROY, | 3568 | MWL8K_BA_DESTROY, |
3527 | MWL8K_BA_FLUSH, | 3569 | MWL8K_BA_FLUSH, |
3528 | MWL8K_BA_CHECK, | 3570 | MWL8K_BA_CHECK, |
3529 | } ba_stream_action_type; | 3571 | }; |
3530 | 3572 | ||
3531 | 3573 | ||
3532 | struct mwl8k_create_ba_stream { | 3574 | struct mwl8k_create_ba_stream { |
@@ -3780,7 +3822,7 @@ struct mwl8k_cmd_update_encryption { | |||
3780 | __u8 mac_addr[6]; | 3822 | __u8 mac_addr[6]; |
3781 | __u8 encr_type; | 3823 | __u8 encr_type; |
3782 | 3824 | ||
3783 | } __attribute__((packed)); | 3825 | } __packed; |
3784 | 3826 | ||
3785 | struct mwl8k_cmd_set_key { | 3827 | struct mwl8k_cmd_set_key { |
3786 | struct mwl8k_cmd_pkt header; | 3828 | struct mwl8k_cmd_pkt header; |
@@ -3800,7 +3842,7 @@ struct mwl8k_cmd_set_key { | |||
3800 | __le16 tkip_tsc_low; | 3842 | __le16 tkip_tsc_low; |
3801 | __le32 tkip_tsc_high; | 3843 | __le32 tkip_tsc_high; |
3802 | __u8 mac_addr[6]; | 3844 | __u8 mac_addr[6]; |
3803 | } __attribute__((packed)); | 3845 | } __packed; |
3804 | 3846 | ||
3805 | enum { | 3847 | enum { |
3806 | MWL8K_ENCR_ENABLE, | 3848 | MWL8K_ENCR_ENABLE, |
@@ -4285,6 +4327,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
4285 | 4327 | ||
4286 | /* Enable interrupts */ | 4328 | /* Enable interrupts */ |
4287 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4329 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4330 | iowrite32(MWL8K_A2H_EVENTS, | ||
4331 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | ||
4288 | 4332 | ||
4289 | rc = mwl8k_fw_lock(hw); | 4333 | rc = mwl8k_fw_lock(hw); |
4290 | if (!rc) { | 4334 | if (!rc) { |
@@ -4502,7 +4546,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
4502 | struct ieee80211_bss_conf *info, u32 changed) | 4546 | struct ieee80211_bss_conf *info, u32 changed) |
4503 | { | 4547 | { |
4504 | struct mwl8k_priv *priv = hw->priv; | 4548 | struct mwl8k_priv *priv = hw->priv; |
4505 | u32 ap_legacy_rates; | 4549 | u32 ap_legacy_rates = 0; |
4506 | u8 ap_mcs_rates[16]; | 4550 | u8 ap_mcs_rates[16]; |
4507 | int rc; | 4551 | int rc; |
4508 | 4552 | ||
@@ -5283,7 +5327,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
5283 | iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| | 5327 | iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| |
5284 | MWL8K_A2H_INT_BA_WATCHDOG, | 5328 | MWL8K_A2H_INT_BA_WATCHDOG, |
5285 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); | 5329 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); |
5286 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | 5330 | iowrite32(MWL8K_A2H_INT_OPC_DONE, |
5331 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | ||
5287 | 5332 | ||
5288 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, | 5333 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, |
5289 | IRQF_SHARED, MWL8K_NAME, hw); | 5334 | IRQF_SHARED, MWL8K_NAME, hw); |