Merge tag 'for-linville-20131203' of git://github.com/kvalo/ath
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / mac.c
index 97ac8c8..ce9ef34 100644 (file)
@@ -322,12 +322,16 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
        lockdep_assert_held(&ar->conf_mutex);
 
        ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
-       if (ret)
+       if (ret) {
+               ath10k_warn("Failed to create wmi peer: %i\n", ret);
                return ret;
+       }
 
        ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
-       if (ret)
+       if (ret) {
+               ath10k_warn("Failed to wait for created wmi peer: %i\n", ret);
                return ret;
+       }
 
        return 0;
 }
@@ -450,15 +454,19 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
 
        arg.channel.mode = chan_to_phymode(&conf->chandef);
 
-       arg.channel.min_power = channel->max_power * 3;
-       arg.channel.max_power = channel->max_power * 4;
-       arg.channel.max_reg_power = channel->max_reg_power * 4;
-       arg.channel.max_antenna_gain = channel->max_antenna_gain;
+       arg.channel.min_power = 0;
+       arg.channel.max_power = channel->max_power * 2;
+       arg.channel.max_reg_power = channel->max_reg_power * 2;
+       arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
                arg.ssid = arvif->u.ap.ssid;
                arg.ssid_len = arvif->u.ap.ssid_len;
                arg.hidden_ssid = arvif->u.ap.hidden_ssid;
+
+               /* For now allow DFS for AP mode */
+               arg.channel.chan_radar =
+                       !!(channel->flags & IEEE80211_CHAN_RADAR);
        } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
                arg.ssid = arvif->vif->bss_conf.ssid;
                arg.ssid_len = arvif->vif->bss_conf.ssid_len;
@@ -516,6 +524,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       if (!ar->monitor_present) {
+               ath10k_warn("mac montor stop -- monitor is not present\n");
+               return -EINVAL;
+       }
+
        arg.vdev_id = vdev_id;
        arg.channel.freq = channel->center_freq;
        arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
@@ -523,11 +536,13 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
        /* TODO setup this dynamically, what in case we
           don't have any vifs? */
        arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef);
+       arg.channel.chan_radar =
+                       !!(channel->flags & IEEE80211_CHAN_RADAR);
 
-       arg.channel.min_power = channel->max_power * 3;
-       arg.channel.max_power = channel->max_power * 4;
-       arg.channel.max_reg_power = channel->max_reg_power * 4;
-       arg.channel.max_antenna_gain = channel->max_antenna_gain;
+       arg.channel.min_power = 0;
+       arg.channel.max_power = channel->max_power * 2;
+       arg.channel.max_reg_power = channel->max_reg_power * 2;
+       arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
 
        ret = ath10k_wmi_vdev_start(ar, &arg);
        if (ret) {
@@ -566,6 +581,16 @@ static int ath10k_monitor_stop(struct ath10k *ar)
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       if (!ar->monitor_present) {
+               ath10k_warn("mac montor stop -- monitor is not present\n");
+               return -EINVAL;
+       }
+
+       if (!ar->monitor_enabled) {
+               ath10k_warn("mac montor stop -- monitor is not enabled\n");
+               return -EINVAL;
+       }
+
        ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
        if (ret)
                ath10k_warn("Monitor vdev down failed: %d\n", ret);
@@ -647,6 +672,107 @@ static int ath10k_monitor_destroy(struct ath10k *ar)
        return ret;
 }
 
+static int ath10k_start_cac(struct ath10k *ar)
+{
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+       ret = ath10k_monitor_create(ar);
+       if (ret) {
+               clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+               return ret;
+       }
+
+       ret = ath10k_monitor_start(ar, ar->monitor_vdev_id);
+       if (ret) {
+               clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+               ath10k_monitor_destroy(ar);
+               return ret;
+       }
+
+       ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
+                  ar->monitor_vdev_id);
+
+       return 0;
+}
+
+static int ath10k_stop_cac(struct ath10k *ar)
+{
+       lockdep_assert_held(&ar->conf_mutex);
+
+       /* CAC is not running - do nothing */
+       if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags))
+               return 0;
+
+       ath10k_monitor_stop(ar);
+       ath10k_monitor_destroy(ar);
+       clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+       ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
+
+       return 0;
+}
+
+static const char *ath10k_dfs_state(enum nl80211_dfs_state dfs_state)
+{
+       switch (dfs_state) {
+       case NL80211_DFS_USABLE:
+               return "USABLE";
+       case NL80211_DFS_UNAVAILABLE:
+               return "UNAVAILABLE";
+       case NL80211_DFS_AVAILABLE:
+               return "AVAILABLE";
+       default:
+               WARN_ON(1);
+               return "bug";
+       }
+}
+
+static void ath10k_config_radar_detection(struct ath10k *ar)
+{
+       struct ieee80211_channel *chan = ar->hw->conf.chandef.chan;
+       bool radar = ar->hw->conf.radar_enabled;
+       bool chan_radar = !!(chan->flags & IEEE80211_CHAN_RADAR);
+       enum nl80211_dfs_state dfs_state = chan->dfs_state;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ath10k_dbg(ATH10K_DBG_MAC,
+                  "mac radar config update: chan %dMHz radar %d chan radar %d chan state %s\n",
+                  chan->center_freq, radar, chan_radar,
+                  ath10k_dfs_state(dfs_state));
+
+       /*
+        * It's safe to call it even if CAC is not started.
+        * This call here guarantees changing channel, etc. will stop CAC.
+        */
+       ath10k_stop_cac(ar);
+
+       if (!radar)
+               return;
+
+       if (!chan_radar)
+               return;
+
+       if (dfs_state != NL80211_DFS_USABLE)
+               return;
+
+       ret = ath10k_start_cac(ar);
+       if (ret) {
+               /*
+                * Not possible to start CAC on current channel so starting
+                * radiation is not allowed, make this channel DFS_UNAVAILABLE
+                * by indicating that radar was detected.
+                */
+               ath10k_warn("failed to start CAC (%d)\n", ret);
+               ieee80211_radar_detected(ar->hw);
+       }
+}
+
 static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                                struct ieee80211_bss_conf *info)
 {
@@ -1351,19 +1477,22 @@ static int ath10k_update_channel_list(struct ath10k *ar)
                        ch->allow_vht = true;
 
                        ch->allow_ibss =
-                               !(channel->flags & IEEE80211_CHAN_NO_IBSS);
+                               !(channel->flags & IEEE80211_CHAN_NO_IR);
 
                        ch->ht40plus =
                                !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS);
 
-                       passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN;
+                       ch->chan_radar =
+                               !!(channel->flags & IEEE80211_CHAN_RADAR);
+
+                       passive = channel->flags & IEEE80211_CHAN_NO_IR;
                        ch->passive = passive;
 
                        ch->freq = channel->center_freq;
-                       ch->min_power = channel->max_power * 3;
-                       ch->max_power = channel->max_power * 4;
-                       ch->max_reg_power = channel->max_reg_power * 4;
-                       ch->max_antenna_gain = channel->max_antenna_gain;
+                       ch->min_power = 0;
+                       ch->max_power = channel->max_power * 2;
+                       ch->max_reg_power = channel->max_reg_power * 2;
+                       ch->max_antenna_gain = channel->max_antenna_gain * 2;
                        ch->reg_class_id = 0; /* FIXME */
 
                        /* FIXME: why use only legacy modes, why not any
@@ -1423,9 +1552,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct ath10k *ar = hw->priv;
+       bool result;
 
        ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
 
+       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
+               ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
+                          request->dfs_region);
+               result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
+                                                         request->dfs_region);
+               if (!result)
+                       ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n",
+                                   request->dfs_region);
+       }
+
        mutex_lock(&ar->conf_mutex);
        if (ar->state == ATH10K_STATE_ON)
                ath10k_regd_update(ar);
@@ -1714,8 +1854,10 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
                        break;
 
                ret = ath10k_wmi_mgmt_tx(ar, skb);
-               if (ret)
+               if (ret) {
                        ath10k_warn("wmi mgmt_tx failed (%d)\n", ret);
+                       ieee80211_free_txskb(ar->hw, skb);
+               }
        }
 }
 
@@ -1889,6 +2031,7 @@ void ath10k_halt(struct ath10k *ar)
 {
        lockdep_assert_held(&ar->conf_mutex);
 
+       ath10k_stop_cac(ar);
        del_timer_sync(&ar->scan.timeout);
        ath10k_offchan_tx_purge(ar);
        ath10k_mgmt_over_wmi_tx_purge(ar);
@@ -1943,7 +2086,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
                ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
                            ret);
 
-       ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 0);
+       ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
        if (ret)
                ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
                            ret);
@@ -1998,15 +2141,40 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
        struct ath10k *ar = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
        int ret = 0;
+       u32 param;
 
        mutex_lock(&ar->conf_mutex);
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac config channel %d mhz\n",
-                          conf->chandef.chan->center_freq);
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac config channel %d mhz flags 0x%x\n",
+                          conf->chandef.chan->center_freq,
+                          conf->chandef.chan->flags);
+
                spin_lock_bh(&ar->data_lock);
                ar->rx_channel = conf->chandef.chan;
                spin_unlock_bh(&ar->data_lock);
+
+               ath10k_config_radar_detection(ar);
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_POWER) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n",
+                          hw->conf.power_level);
+
+               param = ar->wmi.pdev_param->txpower_limit2g;
+               ret = ath10k_wmi_pdev_set_param(ar, param,
+                                               hw->conf.power_level * 2);
+               if (ret)
+                       ath10k_warn("mac failed to set 2g txpower %d (%d)\n",
+                                   hw->conf.power_level, ret);
+
+               param = ar->wmi.pdev_param->txpower_limit5g;
+               ret = ath10k_wmi_pdev_set_param(ar, param,
+                                               hw->conf.power_level * 2);
+               if (ret)
+                       ath10k_warn("mac failed to set 5g txpower %d (%d)\n",
+                                   hw->conf.power_level, ret);
        }
 
        if (changed & IEEE80211_CONF_CHANGE_PS)
@@ -2049,6 +2217,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        arvif->vif = vif;
 
        INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
+       INIT_LIST_HEAD(&arvif->list);
 
        if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) {
                ath10k_warn("Only one monitor interface allowed\n");
@@ -2265,8 +2434,14 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
        *total_flags &= SUPPORTED_FILTERS;
        ar->filter_flags = *total_flags;
 
+       /* Monitor must not be started if it wasn't created first.
+        * Promiscuous mode may be started on a non-monitor interface - in
+        * such case the monitor vdev is not created so starting the
+        * monitor makes no sense. Since ath10k uses no special RX filters
+        * (only BSS filter in STA mode) there's no need for any special
+        * action here. */
        if ((ar->filter_flags & FIF_PROMISC_IN_BSS) &&
-           !ar->monitor_enabled) {
+           !ar->monitor_enabled && ar->monitor_present) {
                ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d start\n",
                           ar->monitor_vdev_id);
 
@@ -2274,7 +2449,7 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
                if (ret)
                        ath10k_warn("Unable to start monitor mode\n");
        } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) &&
-                  ar->monitor_enabled) {
+                  ar->monitor_enabled && ar->monitor_present) {
                ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d stop\n",
                           ar->monitor_vdev_id);
 
@@ -2360,8 +2535,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                        ret = ath10k_peer_create(ar, arvif->vdev_id,
                                                 info->bssid);
                        if (ret)
-                               ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
-                                           info->bssid, arvif->vdev_id);
+                               ath10k_warn("Failed to add peer %pM for vdev %d when changin bssid: %i\n",
+                                           info->bssid, arvif->vdev_id, ret);
 
                        if (vif->type == NL80211_IFTYPE_STATION) {
                                /*
@@ -2542,6 +2717,44 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw,
        mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
+                                       struct ath10k_vif *arvif,
+                                       enum set_key_cmd cmd,
+                                       struct ieee80211_key_conf *key)
+{
+       u32 vdev_param = arvif->ar->wmi.vdev_param->def_keyid;
+       int ret;
+
+       /* 10.1 firmware branch requires default key index to be set to group
+        * key index after installing it. Otherwise FW/HW Txes corrupted
+        * frames with multi-vif APs. This is not required for main firmware
+        * branch (e.g. 636).
+        *
+        * FIXME: This has been tested only in AP. It remains unknown if this
+        * is required for multi-vif STA interfaces on 10.1 */
+
+       if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+               return;
+
+       if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
+               return;
+
+       if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
+               return;
+
+       if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+               return;
+
+       if (cmd != SET_KEY)
+               return;
+
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+                                       key->keyidx);
+       if (ret)
+               ath10k_warn("failed to set group key as default key: %d\n",
+                           ret);
+}
+
 static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                          struct ieee80211_vif *vif, struct ieee80211_sta *sta,
                          struct ieee80211_key_conf *key)
@@ -2603,6 +2816,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                goto exit;
        }
 
+       ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key);
+
        spin_lock_bh(&ar->data_lock);
        peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr);
        if (peer && cmd == SET_KEY)
@@ -2643,8 +2858,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 
                ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
                if (ret)
-                       ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
-                                   sta->addr, arvif->vdev_id);
+                       ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n",
+                                   sta->addr, arvif->vdev_id, ret);
        } else if ((old_state == IEEE80211_STA_NONE &&
                    new_state == IEEE80211_STA_NOTEXIST)) {
                /*
@@ -3249,12 +3464,36 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
        },
 };
 
-static const struct ieee80211_iface_combination ath10k_if_comb = {
-       .limits = ath10k_if_limits,
-       .n_limits = ARRAY_SIZE(ath10k_if_limits),
-       .max_interfaces = 8,
-       .num_different_channels = 1,
-       .beacon_int_infra_match = true,
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+static const struct ieee80211_iface_limit ath10k_if_dfs_limits[] = {
+       {
+       .max    = 8,
+       .types  = BIT(NL80211_IFTYPE_AP)
+       },
+};
+#endif
+
+static const struct ieee80211_iface_combination ath10k_if_comb[] = {
+       {
+               .limits = ath10k_if_limits,
+               .n_limits = ARRAY_SIZE(ath10k_if_limits),
+               .max_interfaces = 8,
+               .num_different_channels = 1,
+               .beacon_int_infra_match = true,
+       },
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+       {
+               .limits = ath10k_if_dfs_limits,
+               .n_limits = ARRAY_SIZE(ath10k_if_dfs_limits),
+               .max_interfaces = 8,
+               .num_different_channels = 1,
+               .beacon_int_infra_match = true,
+               .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                       BIT(NL80211_CHAN_WIDTH_20) |
+                                       BIT(NL80211_CHAN_WIDTH_40) |
+                                       BIT(NL80211_CHAN_WIDTH_80),
+       }
+#endif
 };
 
 static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
@@ -3478,11 +3717,21 @@ int ath10k_mac_register(struct ath10k *ar)
         */
        ar->hw->queues = 4;
 
-       ar->hw->wiphy->iface_combinations = &ath10k_if_comb;
-       ar->hw->wiphy->n_iface_combinations = 1;
+       ar->hw->wiphy->iface_combinations = ath10k_if_comb;
+       ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb);
 
        ar->hw->netdev_features = NETIF_F_HW_CSUM;
 
+       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
+               /* Init ath dfs pattern detector */
+               ar->ath_common.debug_mask = ATH_DBG_DFS;
+               ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common,
+                                                            NL80211_DFS_UNSET);
+
+               if (!ar->dfs_detector)
+                       ath10k_warn("dfs pattern detector init failed\n");
+       }
+
        ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
                            ath10k_reg_notifier);
        if (ret) {
@@ -3518,6 +3767,9 @@ void ath10k_mac_unregister(struct ath10k *ar)
 {
        ieee80211_unregister_hw(ar->hw);
 
+       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
+               ar->dfs_detector->exit(ar->dfs_detector);
+
        kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels);
        kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels);