]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Tue, 15 Mar 2011 18:16:48 +0000 (14:16 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 15 Mar 2011 18:16:48 +0000 (14:16 -0400)
1  2 
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/iwlwifi/iwl-agn.c

index 5efc869d65ff3772591203bbdc82368a49dffa42,cb5d81426d57331d0a9a03eca7b62f0acba90db1..562257ac52cfecf77ee58cd7f1318507f14d9b75
@@@ -143,84 -143,59 +143,59 @@@ bool ath9k_hw_updatetxtriglevel(struct 
  }
  EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
  
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
  {
- #define ATH9K_TX_STOP_DMA_TIMEOUT     4000    /* usec */
- #define ATH9K_TIME_QUANTUM            100     /* usec */
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_hw_capabilities *pCap = &ah->caps;
-       struct ath9k_tx_queue_info *qi;
-       u32 tsfLow, j, wait;
-       u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
-       if (q >= pCap->total_queues) {
-               ath_dbg(common, ATH_DBG_QUEUE,
-                       "Stopping TX DMA, invalid queue: %u\n", q);
-               return false;
-       }
+       int i, q;
  
-       qi = &ah->txq[q];
-       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-               ath_dbg(common, ATH_DBG_QUEUE,
-                       "Stopping TX DMA, inactive queue: %u\n", q);
-               return false;
-       }
+       REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
  
-       REG_WRITE(ah, AR_Q_TXD, 1 << q);
+       REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
+       REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+       REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
  
-       for (wait = wait_time; wait != 0; wait--) {
-               if (ath9k_hw_numtxpending(ah, q) == 0)
-                       break;
-               udelay(ATH9K_TIME_QUANTUM);
-       }
+       for (q = 0; q < AR_NUM_QCU; q++) {
+               for (i = 0; i < 1000; i++) {
+                       if (i)
+                               udelay(5);
  
-       if (ath9k_hw_numtxpending(ah, q)) {
-               ath_dbg(common, ATH_DBG_QUEUE,
-                       "%s: Num of pending TX Frames %d on Q %d\n",
-                       __func__, ath9k_hw_numtxpending(ah, q), q);
-               for (j = 0; j < 2; j++) {
-                       tsfLow = REG_READ(ah, AR_TSF_L32);
-                       REG_WRITE(ah, AR_QUIET2,
-                                 SM(10, AR_QUIET2_QUIET_DUR));
-                       REG_WRITE(ah, AR_QUIET_PERIOD, 100);
-                       REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
-                       REG_SET_BIT(ah, AR_TIMER_MODE,
-                                      AR_QUIET_TIMER_EN);
-                       if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
+                       if (!ath9k_hw_numtxpending(ah, q))
                                break;
-                       ath_dbg(common, ATH_DBG_QUEUE,
-                               "TSF has moved while trying to set quiet time TSF: 0x%08x\n",
-                               tsfLow);
                }
+       }
  
-               REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+       REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
+       REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+       REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
  
-               udelay(200);
-               REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+       REG_WRITE(ah, AR_Q_TXD, 0);
+ }
+ EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
  
-               wait = wait_time;
-               while (ath9k_hw_numtxpending(ah, q)) {
-                       if ((--wait) == 0) {
-                               ath_err(common,
-                                       "Failed to stop TX DMA in 100 msec after killing last frame\n");
-                               break;
-                       }
+ bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
+ {
+ #define ATH9K_TX_STOP_DMA_TIMEOUT     1000    /* usec */
+ #define ATH9K_TIME_QUANTUM            100     /* usec */
+       int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
+       int wait;
+       REG_WRITE(ah, AR_Q_TXD, 1 << q);
+       for (wait = wait_time; wait != 0; wait--) {
+               if (wait != wait_time)
                        udelay(ATH9K_TIME_QUANTUM);
-               }
  
-               REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+               if (ath9k_hw_numtxpending(ah, q) == 0)
+                       break;
        }
  
        REG_WRITE(ah, AR_Q_TXD, 0);
        return wait != 0;
  
  #undef ATH9K_TX_STOP_DMA_TIMEOUT
  #undef ATH9K_TIME_QUANTUM
  }
- EXPORT_SYMBOL(ath9k_hw_stoptxdma);
+ EXPORT_SYMBOL(ath9k_hw_stop_dma_queue);
  
  void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
  {
@@@ -891,7 -866,7 +866,7 @@@ void ath9k_hw_set_interrupts(struct ath
        struct ath_common *common = ath9k_hw_common(ah);
  
        if (!(ints & ATH9K_INT_GLOBAL))
 -              ath9k_hw_enable_interrupts(ah);
 +              ath9k_hw_disable_interrupts(ah);
  
        ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
  
                        REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
        }
  
 -      ath9k_hw_enable_interrupts(ah);
 +      if (ints & ATH9K_INT_GLOBAL)
 +              ath9k_hw_enable_interrupts(ah);
  
        return;
  }
index e0cd3e27a0d92825c0cc5048853c9beb202e7fb4,b57fbbf3fb64cb56a4f42ad04d32d02778d7f55e..581dc9f102738a3433da6f56438ea242484eaf6c
@@@ -2937,6 -2937,91 +2937,91 @@@ static void iwl_bg_rx_replenish(struct 
        mutex_unlock(&priv->mutex);
  }
  
+ static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+                                struct ieee80211_channel *chan,
+                                enum nl80211_channel_type channel_type,
+                                unsigned int wait)
+ {
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+       /* Not supported if we don't have PAN */
+       if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) {
+               ret = -EOPNOTSUPP;
+               goto free;
+       }
+       /* Not supported on pre-P2P firmware */
+       if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
+                                       BIT(NL80211_IFTYPE_P2P_CLIENT))) {
+               ret = -EOPNOTSUPP;
+               goto free;
+       }
+       mutex_lock(&priv->mutex);
+       if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) {
+               /*
+                * If the PAN context is free, use the normal
+                * way of doing remain-on-channel offload + TX.
+                */
+               ret = 1;
+               goto out;
+       }
+       /* TODO: queue up if scanning? */
+       if (test_bit(STATUS_SCANNING, &priv->status) ||
+           priv->_agn.offchan_tx_skb) {
+               ret = -EBUSY;
+               goto out;
+       }
+       /*
+        * max_scan_ie_len doesn't include the blank SSID or the header,
+        * so need to add that again here.
+        */
+       if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) {
+               ret = -ENOBUFS;
+               goto out;
+       }
+       priv->_agn.offchan_tx_skb = skb;
+       priv->_agn.offchan_tx_timeout = wait;
+       priv->_agn.offchan_tx_chan = chan;
+       ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif,
+                               IWL_SCAN_OFFCH_TX, chan->band);
+       if (ret)
+               priv->_agn.offchan_tx_skb = NULL;
+  out:
+       mutex_unlock(&priv->mutex);
+  free:
+       if (ret < 0)
+               kfree_skb(skb);
+       return ret;
+ }
+ static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw)
+ {
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+       mutex_lock(&priv->mutex);
+       if (!priv->_agn.offchan_tx_skb)
+               return -EINVAL;
+       priv->_agn.offchan_tx_skb = NULL;
+       ret = iwl_scan_cancel_timeout(priv, 200);
+       if (ret)
+               ret = -EIO;
+       mutex_unlock(&priv->mutex);
+       return ret;
+ }
  /*****************************************************************************
   *
   * mac80211 entry point functions
@@@ -3815,13 -3900,15 +3900,15 @@@ struct ieee80211_ops iwlagn_hw_ops = 
        .tx_last_beacon = iwl_mac_tx_last_beacon,
        .remain_on_channel = iwl_mac_remain_on_channel,
        .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
+       .offchannel_tx = iwl_mac_offchannel_tx,
+       .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
  };
  
  static void iwl_hw_detect(struct iwl_priv *priv)
  {
        priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
        priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
 -      pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
 +      priv->rev_id = priv->pci_dev->revision;
        IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
  }