aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwmc3200wifi/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi/main.c')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c103
1 files changed, 65 insertions, 38 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 8be206d58222..d668e4756324 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -53,11 +53,12 @@
static struct iwm_conf def_iwm_conf = {
.sdio_ior_timeout = 5000,
- .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
- BIT(PHY_CALIBRATE_LO_CMD) |
- BIT(PHY_CALIBRATE_TX_IQ_CMD) |
- BIT(PHY_CALIBRATE_RX_IQ_CMD),
- .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
+ .calib_map = BIT(CALIB_CFG_DC_IDX) |
+ BIT(CALIB_CFG_LO_IDX) |
+ BIT(CALIB_CFG_TX_IQ_IDX) |
+ BIT(CALIB_CFG_RX_IQ_IDX) |
+ BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+ .expected_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
BIT(PHY_CALIBRATE_LO_CMD) |
BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) |
@@ -112,8 +113,28 @@ static void iwm_statistics_request(struct work_struct *work)
iwm_send_umac_stats_req(iwm, 0);
}
-int __iwm_up(struct iwm_priv *iwm);
-int __iwm_down(struct iwm_priv *iwm);
+static void iwm_disconnect_work(struct work_struct *work)
+{
+ struct iwm_priv *iwm =
+ container_of(work, struct iwm_priv, disconnect.work);
+
+ if (iwm->umac_profile_active)
+ iwm_invalidate_mlme_profile(iwm);
+
+ clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
+ iwm->umac_profile_active = 0;
+ memset(iwm->bssid, 0, ETH_ALEN);
+ iwm->channel = 0;
+
+ iwm_link_off(iwm);
+
+ wake_up_interruptible(&iwm->mlme_queue);
+
+ cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
+}
+
+static int __iwm_up(struct iwm_priv *iwm);
+static int __iwm_down(struct iwm_priv *iwm);
static void iwm_reset_worker(struct work_struct *work)
{
@@ -166,7 +187,8 @@ static void iwm_reset_worker(struct work_struct *work)
memcpy(iwm->umac_profile, profile, sizeof(*profile));
iwm_send_mlme_profile(iwm);
kfree(profile);
- }
+ } else
+ clear_bit(IWM_STATUS_RESETTING, &iwm->status);
out:
mutex_unlock(&iwm->mutex);
@@ -179,7 +201,7 @@ static void iwm_watchdog(unsigned long data)
IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n");
if (modparam_reset)
- schedule_work(&iwm->reset_worker);
+ iwm_resetting(iwm);
}
int iwm_priv_init(struct iwm_priv *iwm)
@@ -191,6 +213,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
INIT_LIST_HEAD(&iwm->pending_notif);
init_waitqueue_head(&iwm->notif_queue);
init_waitqueue_head(&iwm->nonwifi_queue);
+ init_waitqueue_head(&iwm->wifi_ntfy_queue);
init_waitqueue_head(&iwm->mlme_queue);
memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
spin_lock_init(&iwm->tx_credit.lock);
@@ -201,6 +224,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
spin_lock_init(&iwm->cmd_lock);
iwm->scan_id = 1;
INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
+ INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
INIT_LIST_HEAD(&iwm->bss_list);
@@ -229,13 +253,18 @@ int iwm_priv_init(struct iwm_priv *iwm)
for (i = 0; i < IWM_NUM_KEYS; i++)
memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
- iwm->default_key = NULL;
+ iwm->default_key = -1;
init_timer(&iwm->watchdog);
iwm->watchdog.function = iwm_watchdog;
iwm->watchdog.data = (unsigned long)iwm;
mutex_init(&iwm->mutex);
+ iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr),
+ GFP_KERNEL);
+ if (iwm->last_fw_err == NULL)
+ return -ENOMEM;
+
return 0;
}
@@ -247,6 +276,7 @@ void iwm_priv_deinit(struct iwm_priv *iwm)
destroy_workqueue(iwm->txq[i].wq);
destroy_workqueue(iwm->rx_wq);
+ kfree(iwm->last_fw_err);
}
/*
@@ -261,7 +291,11 @@ void iwm_reset(struct iwm_priv *iwm)
if (test_bit(IWM_STATUS_READY, &iwm->status))
iwm_target_reset(iwm);
- iwm->status = 0;
+ if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) {
+ iwm->status = 0;
+ set_bit(IWM_STATUS_RESETTING, &iwm->status);
+ } else
+ iwm->status = 0;
iwm->scan_id = 1;
list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
@@ -277,6 +311,13 @@ void iwm_reset(struct iwm_priv *iwm)
iwm_link_off(iwm);
}
+void iwm_resetting(struct iwm_priv *iwm)
+{
+ set_bit(IWM_STATUS_RESETTING, &iwm->status);
+
+ schedule_work(&iwm->reset_worker);
+}
+
/*
* Notification code:
*
@@ -500,6 +541,13 @@ void iwm_link_off(struct iwm_priv *iwm)
memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID;
+ kfree(iwm->req_ie);
+ iwm->req_ie = NULL;
+ iwm->req_ie_len = 0;
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = NULL;
+ iwm->resp_ie_len = 0;
+
del_timer_sync(&iwm->watchdog);
}
@@ -518,13 +566,6 @@ static int iwm_channels_init(struct iwm_priv *iwm)
{
int ret;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
- return 0;
- }
-#endif
-
ret = iwm_send_umac_channel_list(iwm);
if (ret) {
IWM_ERR(iwm, "Send channel list failed\n");
@@ -541,7 +582,7 @@ static int iwm_channels_init(struct iwm_priv *iwm)
return 0;
}
-int __iwm_up(struct iwm_priv *iwm)
+static int __iwm_up(struct iwm_priv *iwm)
{
int ret;
struct iwm_notif *notif_reboot, *notif_ack = NULL;
@@ -642,19 +683,10 @@ int __iwm_up(struct iwm_priv *iwm)
}
}
- iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
- GFP_KERNEL);
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
- goto err_fw;
- }
-
- iwm_init_default_profile(iwm, iwm->umac_profile);
-
ret = iwm_channels_init(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't init channels\n");
- goto err_profile;
+ goto err_fw;
}
/* Set the READY bit to indicate interface is brought up successfully */
@@ -662,10 +694,6 @@ int __iwm_up(struct iwm_priv *iwm)
return 0;
- err_profile:
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
-
err_fw:
iwm_eeprom_exit(iwm);
@@ -688,7 +716,7 @@ int iwm_up(struct iwm_priv *iwm)
return ret;
}
-int __iwm_down(struct iwm_priv *iwm)
+static int __iwm_down(struct iwm_priv *iwm)
{
int ret;
@@ -704,11 +732,10 @@ int __iwm_down(struct iwm_priv *iwm)
clear_bit(IWM_STATUS_READY, &iwm->status);
iwm_eeprom_exit(iwm);
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
iwm_bss_list_clean(iwm);
-
- iwm->default_key = NULL;
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+ iwm->umac_profile_active = false;
+ iwm->default_key = -1;
iwm->core_enabled = 0;
ret = iwm_bus_disable(iwm);