ath10k: update available channel list for 5G radio
authorTamizh chelvam <c_traja@qti.qualcomm.com>
Thu, 23 Feb 2017 13:18:22 +0000 (18:48 +0530)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 16 Mar 2017 08:53:49 +0000 (10:53 +0200)
If a 5 GHz radio is calibrated for operation in both
the low band (channels 36 to 64) and high band(channels 100 to 169),
hardware allows operations in all the listed channels. However,
if the chip has been calibrated only for the low/high band and
a high/low band channel is configured, due to lack of calibration
there will be potentially invalid signal on those non calibrated channels.
To avoid this problem this patch sets IEEE80211_CHAN_DISABLED flag for
those non calibrated channels by using low_5ghz_chan and high_5ghz_chan
values which we get from target through wmi service ready event.

Driver initialized flags are getting re initialized in handle_channel
in cfg80211. So calling the function to disable the non supported channel
from reg_notifier().

Signed-off-by: Tamizh chelvam <c_traja@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h

index 88d14be7fcceb44539f80c7217e4d6b0ea27dd79..d4b9a0ec1bdc325ac79b23a0e52a59533ece3fc3 100644 (file)
@@ -775,6 +775,8 @@ struct ath10k {
        u32 num_rf_chains;
        u32 max_spatial_stream;
        /* protected by conf_mutex */
+       u32 low_5ghz_chan;
+       u32 high_5ghz_chan;
        bool ani_enabled;
 
        bool p2p;
index f0e46804ad82edc00ebfb71fa6f7b6f4bf00a795..167bde5cbbada6cefdade20723a46f6e2cf97b7a 100644 (file)
@@ -3126,6 +3126,21 @@ static void ath10k_regd_update(struct ath10k *ar)
                ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret);
 }
 
+void ath10k_mac_update_channel_list(struct ath10k *ar,
+                                   struct ieee80211_supported_band *band)
+{
+       int i;
+
+       if (ar->low_5ghz_chan && ar->high_5ghz_chan) {
+               for (i = 0; i < band->n_channels; i++) {
+                       if (band->channels[i].center_freq < ar->low_5ghz_chan ||
+                           band->channels[i].center_freq > ar->high_5ghz_chan)
+                               band->channels[i].flags |=
+                                       IEEE80211_CHAN_DISABLED;
+               }
+       }
+}
+
 static void ath10k_reg_notifier(struct wiphy *wiphy,
                                struct regulatory_request *request)
 {
@@ -3149,6 +3164,10 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
        if (ar->state == ATH10K_STATE_ON)
                ath10k_regd_update(ar);
        mutex_unlock(&ar->conf_mutex);
+
+       if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY)
+               ath10k_mac_update_channel_list(ar,
+                               ar->hw->wiphy->bands[NL80211_BAND_5GHZ]);
 }
 
 /***************/
index 2f1743e60fa1303331fb654a79c745e725cc9eaf..b31c4f71b413d9c728ee6c9bf0ef88a3ff9d4b7a 100644 (file)
@@ -4593,6 +4593,8 @@ ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
        arg->phy_capab = ev->phy_capability;
        arg->num_rf_chains = ev->num_rf_chains;
        arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+       arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan;
+       arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan;
        arg->num_mem_reqs = ev->num_mem_reqs;
        arg->service_map = ev->wmi_service_bitmap;
        arg->service_map_len = sizeof(ev->wmi_service_bitmap);
@@ -4629,6 +4631,8 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
        arg->phy_capab = ev->phy_capability;
        arg->num_rf_chains = ev->num_rf_chains;
        arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+       arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan;
+       arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan;
        arg->num_mem_reqs = ev->num_mem_reqs;
        arg->service_map = ev->wmi_service_bitmap;
        arg->service_map_len = sizeof(ev->wmi_service_bitmap);
@@ -4682,6 +4686,8 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
        ar->phy_capability = __le32_to_cpu(arg.phy_capab);
        ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
        ar->hw_eeprom_rd = __le32_to_cpu(arg.eeprom_rd);
+       ar->low_5ghz_chan = __le32_to_cpu(arg.low_5ghz_chan);
+       ar->high_5ghz_chan = __le32_to_cpu(arg.high_5ghz_chan);
 
        ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
                        arg.service_map, arg.service_map_len);
index 386aa51435f1c4d57e0affa556153c4989b2c8e8..78350d4c7b7918c52ef29d62cb223d778f1f7b57 100644 (file)
@@ -6335,6 +6335,8 @@ struct wmi_svc_rdy_ev_arg {
        __le32 num_rf_chains;
        __le32 eeprom_rd;
        __le32 num_mem_reqs;
+       __le32 low_5ghz_chan;
+       __le32 high_5ghz_chan;
        const __le32 *service_map;
        size_t service_map_len;
        const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];