iwmc3200wifi: Enable wimax core through module parameter
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / iwmc3200wifi / main.c
index 222eb2cf1b30706b3f73c50f1aa91fe1fda39822..7f34d6dd3c41a8158055798c665293aada555419 100644 (file)
@@ -64,9 +64,10 @@ static struct iwm_conf def_iwm_conf = {
                                  BIT(PHY_CALIBRATE_TX_IQ_CMD)  |
                                  BIT(PHY_CALIBRATE_RX_IQ_CMD)  |
                                  BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+       .ct_kill_entry          = 110,
+       .ct_kill_exit           = 110,
        .reset_on_fatal_err     = 1,
        .auto_connect           = 1,
-       .wimax_not_present      = 0,
        .enable_qos             = 1,
        .mode                   = UMAC_MODE_BSS,
 
@@ -78,8 +79,8 @@ static struct iwm_conf def_iwm_conf = {
 
        .assoc_timeout          = 2,
        .roam_timeout           = 10,
-       .wireless_mode          = WIRELESS_MODE_11A | WIRELESS_MODE_11G,
-       .coexist_mode           = COEX_MODE_CM,
+       .wireless_mode          = WIRELESS_MODE_11A | WIRELESS_MODE_11G |
+                                 WIRELESS_MODE_11N,
 
        /* IBSS */
        .ibss_band              = UMAC_BAND_2GHZ,
@@ -92,6 +93,10 @@ static int modparam_reset;
 module_param_named(reset, modparam_reset, bool, 0644);
 MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])");
 
+static int modparam_wimax_enable = 1;
+module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644);
+MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])");
+
 int iwm_mode_to_nl80211_iftype(int mode)
 {
        switch (mode) {
@@ -134,6 +139,17 @@ static void iwm_disconnect_work(struct work_struct *work)
        cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
 }
 
+static void iwm_ct_kill_work(struct work_struct *work)
+{
+       struct iwm_priv *iwm =
+               container_of(work, struct iwm_priv, ct_kill_delay.work);
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
+
+       IWM_INFO(iwm, "CT kill delay timeout\n");
+
+       wiphy_rfkill_set_hw_state(wiphy, false);
+}
+
 static int __iwm_up(struct iwm_priv *iwm);
 static int __iwm_down(struct iwm_priv *iwm);
 
@@ -195,6 +211,33 @@ static void iwm_reset_worker(struct work_struct *work)
        mutex_unlock(&iwm->mutex);
 }
 
+static void iwm_auth_retry_worker(struct work_struct *work)
+{
+       struct iwm_priv *iwm;
+       int i, ret;
+
+       iwm = container_of(work, struct iwm_priv, auth_retry_worker);
+       if (iwm->umac_profile_active) {
+               ret = iwm_invalidate_mlme_profile(iwm);
+               if (ret < 0)
+                       return;
+       }
+
+       iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+
+       ret = iwm_send_mlme_profile(iwm);
+       if (ret < 0)
+               return;
+
+       for (i = 0; i < IWM_NUM_KEYS; i++)
+               if (iwm->keys[i].key_len)
+                       iwm_set_key(iwm, 0, &iwm->keys[i]);
+
+       iwm_set_tx_key(iwm, iwm->default_key);
+}
+
+
+
 static void iwm_watchdog(unsigned long data)
 {
        struct iwm_priv *iwm = (struct iwm_priv *)data;
@@ -207,7 +250,7 @@ static void iwm_watchdog(unsigned long data)
 
 int iwm_priv_init(struct iwm_priv *iwm)
 {
-       int i;
+       int i, j;
        char name[32];
 
        iwm->status = 0;
@@ -226,7 +269,9 @@ int iwm_priv_init(struct iwm_priv *iwm)
        iwm->scan_id = 1;
        INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
        INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
+       INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work);
        INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
+       INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker);
        INIT_LIST_HEAD(&iwm->bss_list);
 
        skb_queue_head_init(&iwm->rx_list);
@@ -249,6 +294,8 @@ int iwm_priv_init(struct iwm_priv *iwm)
                        return -EAGAIN;
 
                skb_queue_head_init(&iwm->txq[i].queue);
+               skb_queue_head_init(&iwm->txq[i].stopped_queue);
+               spin_lock_init(&iwm->txq[i].lock);
        }
 
        for (i = 0; i < IWM_NUM_KEYS; i++)
@@ -256,6 +303,12 @@ int iwm_priv_init(struct iwm_priv *iwm)
 
        iwm->default_key = -1;
 
+       for (i = 0; i < IWM_STA_TABLE_NUM; i++)
+               for (j = 0; j < IWM_UMAC_TID_NR; j++) {
+                       mutex_init(&iwm->sta_table[i].tid_info[j].mutex);
+                       iwm->sta_table[i].tid_info[j].stopped = false;
+               }
+
        init_timer(&iwm->watchdog);
        iwm->watchdog.function = iwm_watchdog;
        iwm->watchdog.data = (unsigned long)iwm;
@@ -436,7 +489,7 @@ static int iwm_config_boot_params(struct iwm_priv *iwm)
        int ret;
 
        /* check Wimax is off and config debug monitor */
-       if (iwm->conf.wimax_not_present) {
+       if (!modparam_wimax_enable) {
                u32 data1 = 0x1f;
                u32 addr1 = 0x606BE258;
 
@@ -529,6 +582,7 @@ void iwm_link_off(struct iwm_priv *iwm)
 
        for (i = 0; i < IWM_TX_QUEUES; i++) {
                skb_queue_purge(&iwm->txq[i].queue);
+               skb_queue_purge(&iwm->txq[i].stopped_queue);
 
                iwm->txq[i].concat_count = 0;
                iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf;
@@ -587,6 +641,8 @@ static int __iwm_up(struct iwm_priv *iwm)
 {
        int ret;
        struct iwm_notif *notif_reboot, *notif_ack = NULL;
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
+       u32 wireless_mode;
 
        ret = iwm_bus_enable(iwm);
        if (ret) {
@@ -638,6 +694,8 @@ static int __iwm_up(struct iwm_priv *iwm)
                IWM_ERR(iwm, "MAC reading failed\n");
                goto err_disable;
        }
+       memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr,
+               ETH_ALEN);
 
        /* We can load the FWs */
        ret = iwm_load_fw(iwm);
@@ -646,6 +704,30 @@ static int __iwm_up(struct iwm_priv *iwm)
                goto err_disable;
        }
 
+       ret = iwm_eeprom_fat_channels(iwm);
+       if (ret) {
+               IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n");
+               goto err_fw;
+       }
+
+       /*
+        * Read our SKU capabilities.
+        * If it's valid, we AND the configured wireless mode with the
+        * device EEPROM value as the current profile wireless mode.
+        */
+       wireless_mode = iwm_eeprom_wireless_mode(iwm);
+       if (wireless_mode) {
+               iwm->conf.wireless_mode &= wireless_mode;
+               if (iwm->umac_profile)
+                       iwm->umac_profile->wireless_mode =
+                                       iwm->conf.wireless_mode;
+       } else
+               IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n",
+                       *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP)));
+
+       snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s",
+                iwm->lmac_version, iwm->umac_version);
+
        /* We configure the UMAC and enable the wifi module */
        ret = iwm_send_umac_config(iwm,
                        cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) |