aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNishant Sarmukadam <nishants@marvell.com>2011-03-17 14:58:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-03-30 14:15:13 -0400
commit65f3ddcd08fe24490359274a8c9bf526e81357a5 (patch)
treece6242a2c0a2eb179fb4b78f22b84e378e11f72b
parentac109fd0427008e5b55e0e52e59c364de6d686fe (diff)
mwl8k: Initiate BA sessions
Specifically, handle ampdu_action and attempt to start a BA session on receiving the first qos packet from mac80211 for transmission to a HT sta. While the BA session is being created, all the packets belonging to that stream will be dropped to prevent sequence number mismatch at the recipient. Contains contributions from: Yogesh Powar <yogeshp@marvell.com> Pradeep Nemavat <pnemavat@marvell.com> Brian Cavagnolo <brian@cozybit.com> Signed-off-by: Brian Cavagnolo <brian@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/mwl8k.c194
1 files changed, 187 insertions, 7 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index dcd4508b1fd4..ec1190ab0f8e 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1577,7 +1577,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
1577 processed++; 1577 processed++;
1578 } 1578 }
1579 1579
1580 if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) 1580 if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on &&
1581 !mutex_is_locked(&priv->fw_mutex))
1581 ieee80211_wake_queue(hw, index); 1582 ieee80211_wake_queue(hw, index);
1582 1583
1583 return processed; 1584 return processed;
@@ -1677,6 +1678,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1677 struct mwl8k_priv *priv = hw->priv; 1678 struct mwl8k_priv *priv = hw->priv;
1678 struct ieee80211_tx_info *tx_info; 1679 struct ieee80211_tx_info *tx_info;
1679 struct mwl8k_vif *mwl8k_vif; 1680 struct mwl8k_vif *mwl8k_vif;
1681 struct ieee80211_sta *sta;
1680 struct ieee80211_hdr *wh; 1682 struct ieee80211_hdr *wh;
1681 struct mwl8k_tx_queue *txq; 1683 struct mwl8k_tx_queue *txq;
1682 struct mwl8k_tx_desc *tx; 1684 struct mwl8k_tx_desc *tx;
@@ -1684,6 +1686,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1684 u32 txstatus; 1686 u32 txstatus;
1685 u8 txdatarate; 1687 u8 txdatarate;
1686 u16 qos; 1688 u16 qos;
1689 int txpriority;
1690 u8 tid = 0;
1691 struct mwl8k_ampdu_stream *stream = NULL;
1692 bool start_ba_session = false;
1687 1693
1688 wh = (struct ieee80211_hdr *)skb->data; 1694 wh = (struct ieee80211_hdr *)skb->data;
1689 if (ieee80211_is_data_qos(wh->frame_control)) 1695 if (ieee80211_is_data_qos(wh->frame_control))
@@ -1699,6 +1705,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1699 wh = &((struct mwl8k_dma_data *)skb->data)->wh; 1705 wh = &((struct mwl8k_dma_data *)skb->data)->wh;
1700 1706
1701 tx_info = IEEE80211_SKB_CB(skb); 1707 tx_info = IEEE80211_SKB_CB(skb);
1708 sta = tx_info->control.sta;
1702 mwl8k_vif = MWL8K_VIF(tx_info->control.vif); 1709 mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
1703 1710
1704 if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 1711 if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
@@ -1726,12 +1733,70 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1726 qos |= MWL8K_QOS_ACK_POLICY_NORMAL; 1733 qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
1727 } 1734 }
1728 1735
1736 txpriority = index;
1737
1738 if (ieee80211_is_data_qos(wh->frame_control) &&
1739 skb->protocol != cpu_to_be16(ETH_P_PAE) &&
1740 sta->ht_cap.ht_supported && priv->ap_fw) {
1741 tid = qos & 0xf;
1742 spin_lock(&priv->stream_lock);
1743 stream = mwl8k_lookup_stream(hw, sta->addr, tid);
1744 if (stream != NULL) {
1745 if (stream->state == AMPDU_STREAM_ACTIVE) {
1746 txpriority = stream->txq_idx;
1747 index = stream->txq_idx;
1748 } else if (stream->state == AMPDU_STREAM_NEW) {
1749 /* We get here if the driver sends us packets
1750 * after we've initiated a stream, but before
1751 * our ampdu_action routine has been called
1752 * with IEEE80211_AMPDU_TX_START to get the SSN
1753 * for the ADDBA request. So this packet can
1754 * go out with no risk of sequence number
1755 * mismatch. No special handling is required.
1756 */
1757 } else {
1758 /* Drop packets that would go out after the
1759 * ADDBA request was sent but before the ADDBA
1760 * response is received. If we don't do this,
1761 * the recipient would probably receive it
1762 * after the ADDBA request with SSN 0. This
1763 * will cause the recipient's BA receive window
1764 * to shift, which would cause the subsequent
1765 * packets in the BA stream to be discarded.
1766 * mac80211 queues our packets for us in this
1767 * case, so this is really just a safety check.
1768 */
1769 wiphy_warn(hw->wiphy,
1770 "Cannot send packet while ADDBA "
1771 "dialog is underway.\n");
1772 spin_unlock(&priv->stream_lock);
1773 dev_kfree_skb(skb);
1774 return;
1775 }
1776 } else {
1777 /* Defer calling mwl8k_start_stream so that the current
1778 * skb can go out before the ADDBA request. This
1779 * prevents sequence number mismatch at the recepient
1780 * as described above.
1781 */
1782 stream = mwl8k_add_stream(hw, sta, tid);
1783 if (stream != NULL)
1784 start_ba_session = true;
1785 }
1786 spin_unlock(&priv->stream_lock);
1787 }
1788
1729 dma = pci_map_single(priv->pdev, skb->data, 1789 dma = pci_map_single(priv->pdev, skb->data,
1730 skb->len, PCI_DMA_TODEVICE); 1790 skb->len, PCI_DMA_TODEVICE);
1731 1791
1732 if (pci_dma_mapping_error(priv->pdev, dma)) { 1792 if (pci_dma_mapping_error(priv->pdev, dma)) {
1733 wiphy_debug(hw->wiphy, 1793 wiphy_debug(hw->wiphy,
1734 "failed to dma map skb, dropping TX frame.\n"); 1794 "failed to dma map skb, dropping TX frame.\n");
1795 if (start_ba_session) {
1796 spin_lock(&priv->stream_lock);
1797 mwl8k_remove_stream(hw, stream);
1798 spin_unlock(&priv->stream_lock);
1799 }
1735 dev_kfree_skb(skb); 1800 dev_kfree_skb(skb);
1736 return; 1801 return;
1737 } 1802 }
@@ -1740,12 +1805,22 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1740 1805
1741 txq = priv->txq + index; 1806 txq = priv->txq + index;
1742 1807
1808 if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) {
1809 /* This is the case in which the tx packet is destined for an
1810 * AMPDU queue and that AMPDU queue is full. Because we don't
1811 * start and stop the AMPDU queues, we must drop these packets.
1812 */
1813 dev_kfree_skb(skb);
1814 spin_unlock_bh(&priv->tx_lock);
1815 return;
1816 }
1817
1743 BUG_ON(txq->skb[txq->tail] != NULL); 1818 BUG_ON(txq->skb[txq->tail] != NULL);
1744 txq->skb[txq->tail] = skb; 1819 txq->skb[txq->tail] = skb;
1745 1820
1746 tx = txq->txd + txq->tail; 1821 tx = txq->txd + txq->tail;
1747 tx->data_rate = txdatarate; 1822 tx->data_rate = txdatarate;
1748 tx->tx_priority = index; 1823 tx->tx_priority = txpriority;
1749 tx->qos_control = cpu_to_le16(qos); 1824 tx->qos_control = cpu_to_le16(qos);
1750 tx->pkt_phys_addr = cpu_to_le32(dma); 1825 tx->pkt_phys_addr = cpu_to_le32(dma);
1751 tx->pkt_len = cpu_to_le16(skb->len); 1826 tx->pkt_len = cpu_to_le16(skb->len);
@@ -1764,12 +1839,20 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1764 if (txq->tail == MWL8K_TX_DESCS) 1839 if (txq->tail == MWL8K_TX_DESCS)
1765 txq->tail = 0; 1840 txq->tail = 0;
1766 1841
1767 if (txq->head == txq->tail) 1842 if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES)
1768 ieee80211_stop_queue(hw, index); 1843 ieee80211_stop_queue(hw, index);
1769 1844
1770 mwl8k_tx_start(priv); 1845 mwl8k_tx_start(priv);
1771 1846
1772 spin_unlock_bh(&priv->tx_lock); 1847 spin_unlock_bh(&priv->tx_lock);
1848
1849 /* Initiate the ampdu session here */
1850 if (start_ba_session) {
1851 spin_lock(&priv->stream_lock);
1852 if (mwl8k_start_stream(hw, stream))
1853 mwl8k_remove_stream(hw, stream);
1854 spin_unlock(&priv->stream_lock);
1855 }
1773} 1856}
1774 1857
1775 1858
@@ -4632,21 +4715,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
4632 return 0; 4715 return 0;
4633} 4716}
4634 4717
4718#define MAX_AMPDU_ATTEMPTS 5
4719
4635static int 4720static int
4636mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4721mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
4637 enum ieee80211_ampdu_mlme_action action, 4722 enum ieee80211_ampdu_mlme_action action,
4638 struct ieee80211_sta *sta, u16 tid, u16 *ssn, 4723 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4639 u8 buf_size) 4724 u8 buf_size)
4640{ 4725{
4726
4727 int i, rc = 0;
4728 struct mwl8k_priv *priv = hw->priv;
4729 struct mwl8k_ampdu_stream *stream;
4730 u8 *addr = sta->addr;
4731
4732 if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
4733 return -ENOTSUPP;
4734
4735 spin_lock(&priv->stream_lock);
4736 stream = mwl8k_lookup_stream(hw, addr, tid);
4737
4641 switch (action) { 4738 switch (action) {
4642 case IEEE80211_AMPDU_RX_START: 4739 case IEEE80211_AMPDU_RX_START:
4643 case IEEE80211_AMPDU_RX_STOP: 4740 case IEEE80211_AMPDU_RX_STOP:
4644 if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) 4741 break;
4645 return -ENOTSUPP; 4742 case IEEE80211_AMPDU_TX_START:
4646 return 0; 4743 /* By the time we get here the hw queues may contain outgoing
4744 * packets for this RA/TID that are not part of this BA
4745 * session. The hw will assign sequence numbers to these
4746 * packets as they go out. So if we query the hw for its next
4747 * sequence number and use that for the SSN here, it may end up
4748 * being wrong, which will lead to sequence number mismatch at
4749 * the recipient. To avoid this, we reset the sequence number
4750 * to O for the first MPDU in this BA stream.
4751 */
4752 *ssn = 0;
4753 if (stream == NULL) {
4754 /* This means that somebody outside this driver called
4755 * ieee80211_start_tx_ba_session. This is unexpected
4756 * because we do our own rate control. Just warn and
4757 * move on.
4758 */
4759 wiphy_warn(hw->wiphy, "Unexpected call to %s. "
4760 "Proceeding anyway.\n", __func__);
4761 stream = mwl8k_add_stream(hw, sta, tid);
4762 }
4763 if (stream == NULL) {
4764 wiphy_debug(hw->wiphy, "no free AMPDU streams\n");
4765 rc = -EBUSY;
4766 break;
4767 }
4768 stream->state = AMPDU_STREAM_IN_PROGRESS;
4769
4770 /* Release the lock before we do the time consuming stuff */
4771 spin_unlock(&priv->stream_lock);
4772 for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
4773 rc = mwl8k_check_ba(hw, stream);
4774
4775 if (!rc)
4776 break;
4777 /*
4778 * HW queues take time to be flushed, give them
4779 * sufficient time
4780 */
4781
4782 msleep(1000);
4783 }
4784 spin_lock(&priv->stream_lock);
4785 if (rc) {
4786 wiphy_err(hw->wiphy, "Stream for tid %d busy after %d"
4787 " attempts\n", tid, MAX_AMPDU_ATTEMPTS);
4788 mwl8k_remove_stream(hw, stream);
4789 rc = -EBUSY;
4790 break;
4791 }
4792 ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
4793 break;
4794 case IEEE80211_AMPDU_TX_STOP:
4795 if (stream == NULL)
4796 break;
4797 if (stream->state == AMPDU_STREAM_ACTIVE) {
4798 spin_unlock(&priv->stream_lock);
4799 mwl8k_destroy_ba(hw, stream);
4800 spin_lock(&priv->stream_lock);
4801 }
4802 mwl8k_remove_stream(hw, stream);
4803 ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
4804 break;
4805 case IEEE80211_AMPDU_TX_OPERATIONAL:
4806 BUG_ON(stream == NULL);
4807 BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS);
4808 spin_unlock(&priv->stream_lock);
4809 rc = mwl8k_create_ba(hw, stream, buf_size);
4810 spin_lock(&priv->stream_lock);
4811 if (!rc)
4812 stream->state = AMPDU_STREAM_ACTIVE;
4813 else {
4814 spin_unlock(&priv->stream_lock);
4815 mwl8k_destroy_ba(hw, stream);
4816 spin_lock(&priv->stream_lock);
4817 wiphy_debug(hw->wiphy,
4818 "Failed adding stream for sta %pM tid %d\n",
4819 addr, tid);
4820 mwl8k_remove_stream(hw, stream);
4821 }
4822 break;
4823
4647 default: 4824 default:
4648 return -ENOTSUPP; 4825 rc = -ENOTSUPP;
4649 } 4826 }
4827
4828 spin_unlock(&priv->stream_lock);
4829 return rc;
4650} 4830}
4651 4831
4652static const struct ieee80211_ops mwl8k_ops = { 4832static const struct ieee80211_ops mwl8k_ops = {