Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / net / wireless / ath / carl9170 / main.c
index 84bd38e9961cb62d84a7d25f314c5b72713186eb..870df8c42622bab94db2aab3da880ad61381bb16 100644 (file)
@@ -380,6 +380,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
        if (err)
                goto out;
 
+       if (ar->fw.rx_filter) {
+               err = carl9170_rx_filter(ar, CARL9170_RX_FILTER_OTHER_RA |
+                       CARL9170_RX_FILTER_CTL_OTHER | CARL9170_RX_FILTER_BAD);
+               if (err)
+                       goto out;
+       }
+
        err = carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER,
                                 AR9170_DMA_TRIGGER_RXQ);
        if (err)
@@ -421,6 +428,7 @@ static void carl9170_cancel_worker(struct ar9170 *ar)
        cancel_delayed_work_sync(&ar->led_work);
 #endif /* CONFIG_CARL9170_LEDS */
        cancel_work_sync(&ar->ps_work);
+       cancel_work_sync(&ar->ping_work);
        cancel_work_sync(&ar->ampdu_work);
 }
 
@@ -526,6 +534,21 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
         */
 }
 
+static void carl9170_ping_work(struct work_struct *work)
+{
+       struct ar9170 *ar = container_of(work, struct ar9170, ping_work);
+       int err;
+
+       if (!IS_STARTED(ar))
+               return;
+
+       mutex_lock(&ar->mutex);
+       err = carl9170_echo_test(ar, 0xdeadbeef);
+       if (err)
+               carl9170_restart(ar, CARL9170_RR_UNRESPONSIVE_DEVICE);
+       mutex_unlock(&ar->mutex);
+}
+
 static int carl9170_init_interface(struct ar9170 *ar,
                                   struct ieee80211_vif *vif)
 {
@@ -632,15 +655,15 @@ init:
                if (err)
                        goto unlock;
        } else {
-               err = carl9170_mod_virtual_mac(ar, vif_id, vif->addr);
                rcu_read_unlock();
+               err = carl9170_mod_virtual_mac(ar, vif_id, vif->addr);
 
                if (err)
                        goto unlock;
        }
 
 unlock:
-       if (err && (vif_id != -1)) {
+       if (err && (vif_id >= 0)) {
                vif_priv->active = false;
                bitmap_release_region(&ar->vif_bitmap, vif_id, 0);
                ar->vifs--;
@@ -840,8 +863,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
        struct ar9170 *ar = hw->priv;
 
        /* mask supported flags */
-       *new_flags &= FIF_ALLMULTI | FIF_FCSFAIL | FIF_PLCPFAIL |
-                     FIF_OTHER_BSS | FIF_PROMISC_IN_BSS;
+       *new_flags &= FIF_ALLMULTI | ar->rx_filter_caps;
 
        if (!IS_ACCEPTING_CMD(ar))
                return;
@@ -867,6 +889,26 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
                WARN_ON(carl9170_set_operating_mode(ar));
        }
 
+       if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) {
+               u32 rx_filter = 0;
+
+               if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)))
+                       rx_filter |= CARL9170_RX_FILTER_BAD;
+
+               if (!(*new_flags & FIF_CONTROL))
+                       rx_filter |= CARL9170_RX_FILTER_CTL_OTHER;
+
+               if (!(*new_flags & FIF_PSPOLL))
+                       rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
+
+               if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) {
+                       rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
+                       rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
+               }
+
+               WARN_ON(carl9170_rx_filter(ar, rx_filter));
+       }
+
        mutex_unlock(&ar->mutex);
 }
 
@@ -1588,6 +1630,7 @@ void *carl9170_alloc(size_t priv_size)
                skb_queue_head_init(&ar->tx_pending[i]);
        }
        INIT_WORK(&ar->ps_work, carl9170_ps_work);
+       INIT_WORK(&ar->ping_work, carl9170_ping_work);
        INIT_WORK(&ar->restart_work, carl9170_restart_work);
        INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
        INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
@@ -1605,7 +1648,8 @@ void *carl9170_alloc(size_t priv_size)
         * supports these modes. The code which will add the
         * additional interface_modes is in fw.c.
         */
-       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                    BIT(NL80211_IFTYPE_P2P_CLIENT);
 
        hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
@@ -1802,7 +1846,7 @@ int carl9170_register(struct ar9170 *ar)
        err = carl9170_led_register(ar);
        if (err)
                goto err_unreg;
-#endif /* CONFIG_CAR9L170_LEDS */
+#endif /* CONFIG_CARL9170_LEDS */
 
 #ifdef CONFIG_CARL9170_WPC
        err = carl9170_register_wps_button(ar);