diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-06-13 03:44:55 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-14 12:18:11 -0400 |
commit | 14a08a7fcf72a8d69cdee225cc76c50b229faa20 (patch) | |
tree | fed4f75ab3551b205184a7cbecf6b7f532dd3c08 | |
parent | 14b3d3387c95cc78f3d740ea53577d9ff41415e3 (diff) |
iwlwifi: unify SW rf-kill flow
This patch unifies SW rf-kill flow between 4965 and 5000. It enables SW
RF-kill for 5000. This patch also solves a bug in iwl4965_mac_config:
bad mutex locking balance.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 87 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rfkill.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rfkill.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 90 |
7 files changed, 103 insertions, 94 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9662fae0f739..df345cb6fd7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -3388,7 +3388,6 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
3388 | .check_version = iwl4965_eeprom_check_version, | 3388 | .check_version = iwl4965_eeprom_check_version, |
3389 | .query_addr = iwlcore_eeprom_query_addr, | 3389 | .query_addr = iwlcore_eeprom_query_addr, |
3390 | }, | 3390 | }, |
3391 | .radio_kill_sw = iwl4965_radio_kill_sw, | ||
3392 | .set_power = iwl4965_set_power, | 3391 | .set_power = iwl4965_set_power, |
3393 | .send_tx_power = iwl4965_send_tx_power, | 3392 | .send_tx_power = iwl4965_send_tx_power, |
3394 | .update_chain_flags = iwl4965_update_chain_flags, | 3393 | .update_chain_flags = iwl4965_update_chain_flags, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index fa17cd9838cb..eb74a40a62eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1319,3 +1319,90 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) | |||
1319 | cmd.critical_temperature_R); | 1319 | cmd.critical_temperature_R); |
1320 | } | 1320 | } |
1321 | EXPORT_SYMBOL(iwl_rf_kill_ct_config); | 1321 | EXPORT_SYMBOL(iwl_rf_kill_ct_config); |
1322 | |||
1323 | /* | ||
1324 | * CARD_STATE_CMD | ||
1325 | * | ||
1326 | * Use: Sets the device's internal card state to enable, disable, or halt | ||
1327 | * | ||
1328 | * When in the 'enable' state the card operates as normal. | ||
1329 | * When in the 'disable' state, the card enters into a low power mode. | ||
1330 | * When in the 'halt' state, the card is shut down and must be fully | ||
1331 | * restarted to come back on. | ||
1332 | */ | ||
1333 | static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) | ||
1334 | { | ||
1335 | struct iwl_host_cmd cmd = { | ||
1336 | .id = REPLY_CARD_STATE_CMD, | ||
1337 | .len = sizeof(u32), | ||
1338 | .data = &flags, | ||
1339 | .meta.flags = meta_flag, | ||
1340 | }; | ||
1341 | |||
1342 | return iwl_send_cmd(priv, &cmd); | ||
1343 | } | ||
1344 | |||
1345 | void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv) | ||
1346 | { | ||
1347 | unsigned long flags; | ||
1348 | |||
1349 | if (test_bit(STATUS_RF_KILL_SW, &priv->status)) | ||
1350 | return; | ||
1351 | |||
1352 | IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO OFF\n"); | ||
1353 | |||
1354 | iwl_scan_cancel(priv); | ||
1355 | /* FIXME: This is a workaround for AP */ | ||
1356 | if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { | ||
1357 | spin_lock_irqsave(&priv->lock, flags); | ||
1358 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | ||
1359 | CSR_UCODE_SW_BIT_RFKILL); | ||
1360 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1361 | /* call the host command only if no hw rf-kill set */ | ||
1362 | if (!test_bit(STATUS_RF_KILL_HW, &priv->status) && | ||
1363 | iwl_is_ready(priv)) | ||
1364 | iwl_send_card_state(priv, | ||
1365 | CARD_STATE_CMD_DISABLE, 0); | ||
1366 | set_bit(STATUS_RF_KILL_SW, &priv->status); | ||
1367 | /* make sure mac80211 stop sending Tx frame */ | ||
1368 | if (priv->mac80211_registered) | ||
1369 | ieee80211_stop_queues(priv->hw); | ||
1370 | } | ||
1371 | } | ||
1372 | EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio); | ||
1373 | |||
1374 | int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) | ||
1375 | { | ||
1376 | unsigned long flags; | ||
1377 | |||
1378 | if (!test_bit(STATUS_RF_KILL_SW, &priv->status)) | ||
1379 | return 0; | ||
1380 | |||
1381 | IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO ON\n"); | ||
1382 | |||
1383 | spin_lock_irqsave(&priv->lock, flags); | ||
1384 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
1385 | |||
1386 | clear_bit(STATUS_RF_KILL_SW, &priv->status); | ||
1387 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1388 | |||
1389 | /* wake up ucode */ | ||
1390 | msleep(10); | ||
1391 | |||
1392 | spin_lock_irqsave(&priv->lock, flags); | ||
1393 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | ||
1394 | if (!iwl_grab_nic_access(priv)) | ||
1395 | iwl_release_nic_access(priv); | ||
1396 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1397 | |||
1398 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { | ||
1399 | IWL_DEBUG_RF_KILL("Can not turn radio back on - " | ||
1400 | "disabled by HW switch\n"); | ||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | if (priv->is_open) | ||
1405 | queue_work(priv->workqueue, &priv->restart); | ||
1406 | return 1; | ||
1407 | } | ||
1408 | EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 662666553171..2838093b4459 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -128,8 +128,6 @@ struct iwl_lib_ops { | |||
128 | int (*is_valid_rtc_data_addr)(u32 addr); | 128 | int (*is_valid_rtc_data_addr)(u32 addr); |
129 | /* 1st ucode load */ | 129 | /* 1st ucode load */ |
130 | int (*load_ucode)(struct iwl_priv *priv); | 130 | int (*load_ucode)(struct iwl_priv *priv); |
131 | /* rfkill */ | ||
132 | int (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio); | ||
133 | /* power management */ | 131 | /* power management */ |
134 | struct { | 132 | struct { |
135 | int (*init)(struct iwl_priv *priv); | 133 | int (*init)(struct iwl_priv *priv); |
@@ -243,6 +241,13 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); | |||
243 | ****************************************************/ | 241 | ****************************************************/ |
244 | int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); | 242 | int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); |
245 | 243 | ||
244 | /***************************************************** | ||
245 | * RF -Kill - here and not in iwl-rfkill.h to be available when | ||
246 | * RF-kill subsystem is not compiled. | ||
247 | ****************************************************/ | ||
248 | void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); | ||
249 | int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); | ||
250 | |||
246 | /******************************************************************************* | 251 | /******************************************************************************* |
247 | * Rate | 252 | * Rate |
248 | ******************************************************************************/ | 253 | ******************************************************************************/ |
@@ -359,10 +364,10 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv) | |||
359 | return iwl_is_ready(priv); | 364 | return iwl_is_ready(priv); |
360 | } | 365 | } |
361 | 366 | ||
367 | extern void iwl_rf_kill_ct_config(struct iwl_priv *priv); | ||
362 | extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); | 368 | extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); |
363 | extern int iwl_verify_ucode(struct iwl_priv *priv); | 369 | extern int iwl_verify_ucode(struct iwl_priv *priv); |
364 | extern void iwl_rf_kill_ct_config(struct iwl_priv *priv); | 370 | extern int iwl_send_lq_cmd(struct iwl_priv *priv, |
365 | int iwl_send_lq_cmd(struct iwl_priv *priv, | ||
366 | struct iwl_link_quality_cmd *lq, u8 flags); | 371 | struct iwl_link_quality_cmd *lq, u8 flags); |
367 | 372 | ||
368 | static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) | 373 | static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c508b11b6fc8..81ff4c2c6a5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -653,7 +653,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) | |||
653 | 653 | ||
654 | struct iwl_priv; | 654 | struct iwl_priv; |
655 | 655 | ||
656 | extern int iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); | ||
657 | /* | 656 | /* |
658 | * Forward declare iwl-4965.c functions for iwl-base.c | 657 | * Forward declare iwl-4965.c functions for iwl-base.c |
659 | */ | 658 | */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 59c8a716bd96..5f098747cf95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c | |||
@@ -55,13 +55,13 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) | |||
55 | 55 | ||
56 | switch (state) { | 56 | switch (state) { |
57 | case RFKILL_STATE_ON: | 57 | case RFKILL_STATE_ON: |
58 | priv->cfg->ops->lib->radio_kill_sw(priv, 0); | 58 | iwl_radio_kill_sw_enable_radio(priv); |
59 | /* if HW rf-kill is set dont allow ON state */ | 59 | /* if HW rf-kill is set dont allow ON state */ |
60 | if (iwl_is_rfkill(priv)) | 60 | if (iwl_is_rfkill(priv)) |
61 | err = -EBUSY; | 61 | err = -EBUSY; |
62 | break; | 62 | break; |
63 | case RFKILL_STATE_OFF: | 63 | case RFKILL_STATE_OFF: |
64 | priv->cfg->ops->lib->radio_kill_sw(priv, 1); | 64 | iwl_radio_kill_sw_disable_radio(priv); |
65 | if (!iwl_is_rfkill(priv)) | 65 | if (!iwl_is_rfkill(priv)) |
66 | err = -EBUSY; | 66 | err = -EBUSY; |
67 | break; | 67 | break; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h index a7f04b855403..b3c04dba45cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h | |||
@@ -33,7 +33,6 @@ struct iwl_priv; | |||
33 | #include <linux/rfkill.h> | 33 | #include <linux/rfkill.h> |
34 | #include <linux/input.h> | 34 | #include <linux/input.h> |
35 | 35 | ||
36 | |||
37 | #ifdef CONFIG_IWLWIFI_RFKILL | 36 | #ifdef CONFIG_IWLWIFI_RFKILL |
38 | struct iwl_rfkill_mngr { | 37 | struct iwl_rfkill_mngr { |
39 | struct rfkill *rfkill; | 38 | struct rfkill *rfkill; |
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a9da17ce0e1d..f5911687671b 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
@@ -379,28 +379,6 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv) | |||
379 | sizeof(struct iwl4965_bt_cmd), &bt_cmd); | 379 | sizeof(struct iwl4965_bt_cmd), &bt_cmd); |
380 | } | 380 | } |
381 | 381 | ||
382 | /* | ||
383 | * CARD_STATE_CMD | ||
384 | * | ||
385 | * Use: Sets the device's internal card state to enable, disable, or halt | ||
386 | * | ||
387 | * When in the 'enable' state the card operates as normal. | ||
388 | * When in the 'disable' state, the card enters into a low power mode. | ||
389 | * When in the 'halt' state, the card is shut down and must be fully | ||
390 | * restarted to come back on. | ||
391 | */ | ||
392 | static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) | ||
393 | { | ||
394 | struct iwl_host_cmd cmd = { | ||
395 | .id = REPLY_CARD_STATE_CMD, | ||
396 | .len = sizeof(u32), | ||
397 | .data = &flags, | ||
398 | .meta.flags = meta_flag, | ||
399 | }; | ||
400 | |||
401 | return iwl_send_cmd(priv, &cmd); | ||
402 | } | ||
403 | |||
404 | static void iwl_clear_free_frames(struct iwl_priv *priv) | 382 | static void iwl_clear_free_frames(struct iwl_priv *priv) |
405 | { | 383 | { |
406 | struct list_head *element; | 384 | struct list_head *element; |
@@ -916,65 +894,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv) | |||
916 | (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; | 894 | (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; |
917 | } | 895 | } |
918 | 896 | ||
919 | int iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio) | ||
920 | { | ||
921 | unsigned long flags; | ||
922 | |||
923 | if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status)) | ||
924 | return 0; | ||
925 | |||
926 | IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n", | ||
927 | disable_radio ? "OFF" : "ON"); | ||
928 | |||
929 | if (disable_radio) { | ||
930 | iwl_scan_cancel(priv); | ||
931 | /* FIXME: This is a workaround for AP */ | ||
932 | if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { | ||
933 | spin_lock_irqsave(&priv->lock, flags); | ||
934 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | ||
935 | CSR_UCODE_SW_BIT_RFKILL); | ||
936 | spin_unlock_irqrestore(&priv->lock, flags); | ||
937 | /* call the host command only if no hw rf-kill set */ | ||
938 | if (!test_bit(STATUS_RF_KILL_HW, &priv->status) && | ||
939 | iwl_is_ready(priv)) | ||
940 | iwl4965_send_card_state(priv, | ||
941 | CARD_STATE_CMD_DISABLE, | ||
942 | 0); | ||
943 | set_bit(STATUS_RF_KILL_SW, &priv->status); | ||
944 | |||
945 | /* make sure mac80211 stop sending Tx frame */ | ||
946 | if (priv->mac80211_registered) | ||
947 | ieee80211_stop_queues(priv->hw); | ||
948 | } | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | spin_lock_irqsave(&priv->lock, flags); | ||
953 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
954 | |||
955 | clear_bit(STATUS_RF_KILL_SW, &priv->status); | ||
956 | spin_unlock_irqrestore(&priv->lock, flags); | ||
957 | |||
958 | /* wake up ucode */ | ||
959 | msleep(10); | ||
960 | |||
961 | spin_lock_irqsave(&priv->lock, flags); | ||
962 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | ||
963 | if (!iwl_grab_nic_access(priv)) | ||
964 | iwl_release_nic_access(priv); | ||
965 | spin_unlock_irqrestore(&priv->lock, flags); | ||
966 | |||
967 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { | ||
968 | IWL_DEBUG_RF_KILL("Can not turn radio back on - " | ||
969 | "disabled by HW switch\n"); | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | if (priv->is_open) | ||
974 | queue_work(priv->workqueue, &priv->restart); | ||
975 | return 1; | ||
976 | } | ||
977 | |||
978 | #define IWL_PACKET_RETRY_TIME HZ | 897 | #define IWL_PACKET_RETRY_TIME HZ |
979 | 898 | ||
980 | int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) | 899 | int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) |
@@ -2982,13 +2901,14 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co | |||
2982 | 2901 | ||
2983 | priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); | 2902 | priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); |
2984 | 2903 | ||
2985 | 2904 | if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { | |
2986 | if (priv->cfg->ops->lib->radio_kill_sw && | ||
2987 | priv->cfg->ops->lib->radio_kill_sw(priv, !conf->radio_enabled)) { | ||
2988 | IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); | 2905 | IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); |
2989 | mutex_unlock(&priv->mutex); | 2906 | goto out; |
2990 | } | 2907 | } |
2991 | 2908 | ||
2909 | if (!conf->radio_enabled) | ||
2910 | iwl_radio_kill_sw_disable_radio(priv); | ||
2911 | |||
2992 | if (!iwl_is_ready(priv)) { | 2912 | if (!iwl_is_ready(priv)) { |
2993 | IWL_DEBUG_MAC80211("leave - not ready\n"); | 2913 | IWL_DEBUG_MAC80211("leave - not ready\n"); |
2994 | ret = -EIO; | 2914 | ret = -EIO; |