diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 111 |
1 files changed, 70 insertions, 41 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 28ebaec80be6..9f5ecef297e5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -74,6 +74,14 @@ MODULE_PARM_DESC(ap_mode_default, | |||
74 | #define MWL8K_A2H_INT_RX_READY (1 << 1) | 74 | #define MWL8K_A2H_INT_RX_READY (1 << 1) |
75 | #define MWL8K_A2H_INT_TX_DONE (1 << 0) | 75 | #define MWL8K_A2H_INT_TX_DONE (1 << 0) |
76 | 76 | ||
77 | /* HW micro second timer register | ||
78 | * located at offset 0xA600. This | ||
79 | * will be used to timestamp tx | ||
80 | * packets. | ||
81 | */ | ||
82 | |||
83 | #define MWL8K_HW_TIMER_REGISTER 0x0000a600 | ||
84 | |||
77 | #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ | 85 | #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ |
78 | MWL8K_A2H_INT_CHNL_SWITCHED | \ | 86 | MWL8K_A2H_INT_CHNL_SWITCHED | \ |
79 | MWL8K_A2H_INT_QUEUE_EMPTY | \ | 87 | MWL8K_A2H_INT_QUEUE_EMPTY | \ |
@@ -773,8 +781,10 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) | |||
773 | skb_pull(skb, sizeof(*tr) - hdrlen); | 781 | skb_pull(skb, sizeof(*tr) - hdrlen); |
774 | } | 782 | } |
775 | 783 | ||
784 | #define REDUCED_TX_HEADROOM 8 | ||
785 | |||
776 | static void | 786 | static void |
777 | mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) | 787 | mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad) |
778 | { | 788 | { |
779 | struct ieee80211_hdr *wh; | 789 | struct ieee80211_hdr *wh; |
780 | int hdrlen; | 790 | int hdrlen; |
@@ -790,6 +800,22 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) | |||
790 | wh = (struct ieee80211_hdr *)skb->data; | 800 | wh = (struct ieee80211_hdr *)skb->data; |
791 | 801 | ||
792 | hdrlen = ieee80211_hdrlen(wh->frame_control); | 802 | hdrlen = ieee80211_hdrlen(wh->frame_control); |
803 | |||
804 | /* | ||
805 | * Check if skb_resize is required because of | ||
806 | * tx_headroom adjustment. | ||
807 | */ | ||
808 | if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) | ||
809 | + REDUCED_TX_HEADROOM))) { | ||
810 | if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { | ||
811 | |||
812 | wiphy_err(priv->hw->wiphy, | ||
813 | "Failed to reallocate TX buffer\n"); | ||
814 | return; | ||
815 | } | ||
816 | skb->truesize += REDUCED_TX_HEADROOM; | ||
817 | } | ||
818 | |||
793 | reqd_hdrlen = sizeof(*tr); | 819 | reqd_hdrlen = sizeof(*tr); |
794 | 820 | ||
795 | if (hdrlen != reqd_hdrlen) | 821 | if (hdrlen != reqd_hdrlen) |
@@ -812,7 +838,8 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) | |||
812 | tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); | 838 | tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); |
813 | } | 839 | } |
814 | 840 | ||
815 | static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) | 841 | static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, |
842 | struct sk_buff *skb) | ||
816 | { | 843 | { |
817 | struct ieee80211_hdr *wh; | 844 | struct ieee80211_hdr *wh; |
818 | struct ieee80211_tx_info *tx_info; | 845 | struct ieee80211_tx_info *tx_info; |
@@ -853,7 +880,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) | |||
853 | break; | 880 | break; |
854 | } | 881 | } |
855 | } | 882 | } |
856 | mwl8k_add_dma_header(skb, data_pad); | 883 | mwl8k_add_dma_header(priv, skb, data_pad); |
857 | } | 884 | } |
858 | 885 | ||
859 | /* | 886 | /* |
@@ -1554,24 +1581,11 @@ static int mwl8k_tid_queue_mapping(u8 tid) | |||
1554 | 1581 | ||
1555 | /* The firmware will fill in the rate information | 1582 | /* The firmware will fill in the rate information |
1556 | * for each packet that gets queued in the hardware | 1583 | * for each packet that gets queued in the hardware |
1557 | * in this structure | 1584 | * and these macros will interpret that info. |
1558 | */ | 1585 | */ |
1559 | 1586 | ||
1560 | struct rateinfo { | 1587 | #define RI_FORMAT(a) (a & 0x0001) |
1561 | __le16 format:1; | 1588 | #define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3) |
1562 | __le16 short_gi:1; | ||
1563 | __le16 band_width:1; | ||
1564 | __le16 rate_id_mcs:6; | ||
1565 | __le16 adv_coding:2; | ||
1566 | __le16 antenna:2; | ||
1567 | __le16 act_sub_chan:2; | ||
1568 | __le16 preamble_type:1; | ||
1569 | __le16 power_id:4; | ||
1570 | __le16 antenna2:1; | ||
1571 | __le16 reserved:1; | ||
1572 | __le16 tx_bf_frame:1; | ||
1573 | __le16 green_field:1; | ||
1574 | } __packed; | ||
1575 | 1589 | ||
1576 | static int | 1590 | static int |
1577 | mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | 1591 | mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) |
@@ -1592,7 +1606,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1592 | struct ieee80211_sta *sta; | 1606 | struct ieee80211_sta *sta; |
1593 | struct mwl8k_sta *sta_info = NULL; | 1607 | struct mwl8k_sta *sta_info = NULL; |
1594 | u16 rate_info; | 1608 | u16 rate_info; |
1595 | struct rateinfo *rate; | ||
1596 | struct ieee80211_hdr *wh; | 1609 | struct ieee80211_hdr *wh; |
1597 | 1610 | ||
1598 | tx = txq->head; | 1611 | tx = txq->head; |
@@ -1635,14 +1648,13 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1635 | sta_info = MWL8K_STA(sta); | 1648 | sta_info = MWL8K_STA(sta); |
1636 | BUG_ON(sta_info == NULL); | 1649 | BUG_ON(sta_info == NULL); |
1637 | rate_info = le16_to_cpu(tx_desc->rate_info); | 1650 | rate_info = le16_to_cpu(tx_desc->rate_info); |
1638 | rate = (struct rateinfo *)&rate_info; | ||
1639 | /* If rate is < 6.5 Mpbs for an ht station | 1651 | /* If rate is < 6.5 Mpbs for an ht station |
1640 | * do not form an ampdu. If the station is a | 1652 | * do not form an ampdu. If the station is a |
1641 | * legacy station (format = 0), do not form an | 1653 | * legacy station (format = 0), do not form an |
1642 | * ampdu | 1654 | * ampdu |
1643 | */ | 1655 | */ |
1644 | if (rate->rate_id_mcs < 1 || | 1656 | if (RI_RATE_ID_MCS(rate_info) < 1 || |
1645 | rate->format == 0) { | 1657 | RI_FORMAT(rate_info) == 0) { |
1646 | sta_info->is_ampdu_allowed = false; | 1658 | sta_info->is_ampdu_allowed = false; |
1647 | } else { | 1659 | } else { |
1648 | sta_info->is_ampdu_allowed = true; | 1660 | sta_info->is_ampdu_allowed = true; |
@@ -1666,10 +1678,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1666 | processed++; | 1678 | processed++; |
1667 | } | 1679 | } |
1668 | 1680 | ||
1669 | if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on && | ||
1670 | !mutex_is_locked(&priv->fw_mutex)) | ||
1671 | ieee80211_wake_queue(hw, index); | ||
1672 | |||
1673 | return processed; | 1681 | return processed; |
1674 | } | 1682 | } |
1675 | 1683 | ||
@@ -1814,6 +1822,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1814 | u8 tid = 0; | 1822 | u8 tid = 0; |
1815 | struct mwl8k_ampdu_stream *stream = NULL; | 1823 | struct mwl8k_ampdu_stream *stream = NULL; |
1816 | bool start_ba_session = false; | 1824 | bool start_ba_session = false; |
1825 | bool mgmtframe = false; | ||
1817 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | 1826 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; |
1818 | 1827 | ||
1819 | wh = (struct ieee80211_hdr *)skb->data; | 1828 | wh = (struct ieee80211_hdr *)skb->data; |
@@ -1822,10 +1831,13 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1822 | else | 1831 | else |
1823 | qos = 0; | 1832 | qos = 0; |
1824 | 1833 | ||
1834 | if (ieee80211_is_mgmt(wh->frame_control)) | ||
1835 | mgmtframe = true; | ||
1836 | |||
1825 | if (priv->ap_fw) | 1837 | if (priv->ap_fw) |
1826 | mwl8k_encapsulate_tx_frame(skb); | 1838 | mwl8k_encapsulate_tx_frame(priv, skb); |
1827 | else | 1839 | else |
1828 | mwl8k_add_dma_header(skb, 0); | 1840 | mwl8k_add_dma_header(priv, skb, 0); |
1829 | 1841 | ||
1830 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; | 1842 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; |
1831 | 1843 | ||
@@ -1951,14 +1963,26 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1951 | 1963 | ||
1952 | txq = priv->txq + index; | 1964 | txq = priv->txq + index; |
1953 | 1965 | ||
1954 | if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) { | 1966 | /* Mgmt frames that go out frequently are probe |
1955 | /* This is the case in which the tx packet is destined for an | 1967 | * responses. Other mgmt frames got out relatively |
1956 | * AMPDU queue and that AMPDU queue is full. Because we don't | 1968 | * infrequently. Hence reserve 2 buffers so that |
1957 | * start and stop the AMPDU queues, we must drop these packets. | 1969 | * other mgmt frames do not get dropped due to an |
1958 | */ | 1970 | * already queued probe response in one of the |
1959 | dev_kfree_skb(skb); | 1971 | * reserved buffers. |
1960 | spin_unlock_bh(&priv->tx_lock); | 1972 | */ |
1961 | return; | 1973 | |
1974 | if (txq->len >= MWL8K_TX_DESCS - 2) { | ||
1975 | if (mgmtframe == false || | ||
1976 | txq->len == MWL8K_TX_DESCS) { | ||
1977 | if (start_ba_session) { | ||
1978 | spin_lock(&priv->stream_lock); | ||
1979 | mwl8k_remove_stream(hw, stream); | ||
1980 | spin_unlock(&priv->stream_lock); | ||
1981 | } | ||
1982 | spin_unlock_bh(&priv->tx_lock); | ||
1983 | dev_kfree_skb(skb); | ||
1984 | return; | ||
1985 | } | ||
1962 | } | 1986 | } |
1963 | 1987 | ||
1964 | BUG_ON(txq->skb[txq->tail] != NULL); | 1988 | BUG_ON(txq->skb[txq->tail] != NULL); |
@@ -1975,6 +1999,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1975 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; | 1999 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; |
1976 | else | 2000 | else |
1977 | tx->peer_id = 0; | 2001 | tx->peer_id = 0; |
2002 | |||
2003 | if (priv->ap_fw) | ||
2004 | tx->timestamp = cpu_to_le32(ioread32(priv->regs + | ||
2005 | MWL8K_HW_TIMER_REGISTER)); | ||
2006 | |||
1978 | wmb(); | 2007 | wmb(); |
1979 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); | 2008 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); |
1980 | 2009 | ||
@@ -1985,9 +2014,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1985 | if (txq->tail == MWL8K_TX_DESCS) | 2014 | if (txq->tail == MWL8K_TX_DESCS) |
1986 | txq->tail = 0; | 2015 | txq->tail = 0; |
1987 | 2016 | ||
1988 | if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES) | ||
1989 | ieee80211_stop_queue(hw, index); | ||
1990 | |||
1991 | mwl8k_tx_start(priv); | 2017 | mwl8k_tx_start(priv); |
1992 | 2018 | ||
1993 | spin_unlock_bh(&priv->tx_lock); | 2019 | spin_unlock_bh(&priv->tx_lock); |
@@ -2482,7 +2508,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | |||
2482 | 2508 | ||
2483 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | | 2509 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | |
2484 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | | 2510 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | |
2485 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); | 2511 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | |
2512 | MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); | ||
2486 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | 2513 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); |
2487 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | 2514 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
2488 | 2515 | ||
@@ -5466,6 +5493,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
5466 | hw->extra_tx_headroom = | 5493 | hw->extra_tx_headroom = |
5467 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); | 5494 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); |
5468 | 5495 | ||
5496 | hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; | ||
5497 | |||
5469 | hw->channel_change_time = 10; | 5498 | hw->channel_change_time = 10; |
5470 | 5499 | ||
5471 | hw->queues = MWL8K_TX_WMM_QUEUES; | 5500 | hw->queues = MWL8K_TX_WMM_QUEUES; |