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>
This commit is contained in:

committed by
John W. Linville

parent
14b3d3387c
commit
14a08a7fcf
@@ -3388,7 +3388,6 @@ static struct iwl_lib_ops iwl4965_lib = {
|
|||||||
.check_version = iwl4965_eeprom_check_version,
|
.check_version = iwl4965_eeprom_check_version,
|
||||||
.query_addr = iwlcore_eeprom_query_addr,
|
.query_addr = iwlcore_eeprom_query_addr,
|
||||||
},
|
},
|
||||||
.radio_kill_sw = iwl4965_radio_kill_sw,
|
|
||||||
.set_power = iwl4965_set_power,
|
.set_power = iwl4965_set_power,
|
||||||
.send_tx_power = iwl4965_send_tx_power,
|
.send_tx_power = iwl4965_send_tx_power,
|
||||||
.update_chain_flags = iwl4965_update_chain_flags,
|
.update_chain_flags = iwl4965_update_chain_flags,
|
||||||
|
@@ -1319,3 +1319,90 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
|||||||
cmd.critical_temperature_R);
|
cmd.critical_temperature_R);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
|
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CARD_STATE_CMD
|
||||||
|
*
|
||||||
|
* Use: Sets the device's internal card state to enable, disable, or halt
|
||||||
|
*
|
||||||
|
* When in the 'enable' state the card operates as normal.
|
||||||
|
* When in the 'disable' state, the card enters into a low power mode.
|
||||||
|
* When in the 'halt' state, the card is shut down and must be fully
|
||||||
|
* restarted to come back on.
|
||||||
|
*/
|
||||||
|
static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
|
||||||
|
{
|
||||||
|
struct iwl_host_cmd cmd = {
|
||||||
|
.id = REPLY_CARD_STATE_CMD,
|
||||||
|
.len = sizeof(u32),
|
||||||
|
.data = &flags,
|
||||||
|
.meta.flags = meta_flag,
|
||||||
|
};
|
||||||
|
|
||||||
|
return iwl_send_cmd(priv, &cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (test_bit(STATUS_RF_KILL_SW, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO OFF\n");
|
||||||
|
|
||||||
|
iwl_scan_cancel(priv);
|
||||||
|
/* FIXME: This is a workaround for AP */
|
||||||
|
if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
|
||||||
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
|
||||||
|
CSR_UCODE_SW_BIT_RFKILL);
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
/* call the host command only if no hw rf-kill set */
|
||||||
|
if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
|
||||||
|
iwl_is_ready(priv))
|
||||||
|
iwl_send_card_state(priv,
|
||||||
|
CARD_STATE_CMD_DISABLE, 0);
|
||||||
|
set_bit(STATUS_RF_KILL_SW, &priv->status);
|
||||||
|
/* make sure mac80211 stop sending Tx frame */
|
||||||
|
if (priv->mac80211_registered)
|
||||||
|
ieee80211_stop_queues(priv->hw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio);
|
||||||
|
|
||||||
|
int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!test_bit(STATUS_RF_KILL_SW, &priv->status))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO ON\n");
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
|
||||||
|
|
||||||
|
clear_bit(STATUS_RF_KILL_SW, &priv->status);
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
|
||||||
|
/* wake up ucode */
|
||||||
|
msleep(10);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
iwl_read32(priv, CSR_UCODE_DRV_GP1);
|
||||||
|
if (!iwl_grab_nic_access(priv))
|
||||||
|
iwl_release_nic_access(priv);
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
|
||||||
|
if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
|
||||||
|
IWL_DEBUG_RF_KILL("Can not turn radio back on - "
|
||||||
|
"disabled by HW switch\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->is_open)
|
||||||
|
queue_work(priv->workqueue, &priv->restart);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio);
|
||||||
|
@@ -128,8 +128,6 @@ struct iwl_lib_ops {
|
|||||||
int (*is_valid_rtc_data_addr)(u32 addr);
|
int (*is_valid_rtc_data_addr)(u32 addr);
|
||||||
/* 1st ucode load */
|
/* 1st ucode load */
|
||||||
int (*load_ucode)(struct iwl_priv *priv);
|
int (*load_ucode)(struct iwl_priv *priv);
|
||||||
/* rfkill */
|
|
||||||
int (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
|
|
||||||
/* power management */
|
/* power management */
|
||||||
struct {
|
struct {
|
||||||
int (*init)(struct iwl_priv *priv);
|
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);
|
|||||||
****************************************************/
|
****************************************************/
|
||||||
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
|
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
|
||||||
|
|
||||||
|
/*****************************************************
|
||||||
|
* RF -Kill - here and not in iwl-rfkill.h to be available when
|
||||||
|
* RF-kill subsystem is not compiled.
|
||||||
|
****************************************************/
|
||||||
|
void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv);
|
||||||
|
int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv);
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Rate
|
* Rate
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -359,10 +364,10 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
|
|||||||
return iwl_is_ready(priv);
|
return iwl_is_ready(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
|
||||||
extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
|
extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
|
||||||
extern int iwl_verify_ucode(struct iwl_priv *priv);
|
extern int iwl_verify_ucode(struct iwl_priv *priv);
|
||||||
extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
|
extern int iwl_send_lq_cmd(struct iwl_priv *priv,
|
||||||
int iwl_send_lq_cmd(struct iwl_priv *priv,
|
|
||||||
struct iwl_link_quality_cmd *lq, u8 flags);
|
struct iwl_link_quality_cmd *lq, u8 flags);
|
||||||
|
|
||||||
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
|
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
|
||||||
|
@@ -653,7 +653,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
|
|||||||
|
|
||||||
struct iwl_priv;
|
struct iwl_priv;
|
||||||
|
|
||||||
extern int iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
|
|
||||||
/*
|
/*
|
||||||
* Forward declare iwl-4965.c functions for iwl-base.c
|
* Forward declare iwl-4965.c functions for iwl-base.c
|
||||||
*/
|
*/
|
||||||
|
@@ -55,13 +55,13 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
|||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case RFKILL_STATE_ON:
|
case RFKILL_STATE_ON:
|
||||||
priv->cfg->ops->lib->radio_kill_sw(priv, 0);
|
iwl_radio_kill_sw_enable_radio(priv);
|
||||||
/* if HW rf-kill is set dont allow ON state */
|
/* if HW rf-kill is set dont allow ON state */
|
||||||
if (iwl_is_rfkill(priv))
|
if (iwl_is_rfkill(priv))
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
break;
|
break;
|
||||||
case RFKILL_STATE_OFF:
|
case RFKILL_STATE_OFF:
|
||||||
priv->cfg->ops->lib->radio_kill_sw(priv, 1);
|
iwl_radio_kill_sw_disable_radio(priv);
|
||||||
if (!iwl_is_rfkill(priv))
|
if (!iwl_is_rfkill(priv))
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
break;
|
break;
|
||||||
|
@@ -33,7 +33,6 @@ struct iwl_priv;
|
|||||||
#include <linux/rfkill.h>
|
#include <linux/rfkill.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||||
struct iwl_rfkill_mngr {
|
struct iwl_rfkill_mngr {
|
||||||
struct rfkill *rfkill;
|
struct rfkill *rfkill;
|
||||||
|
@@ -379,28 +379,6 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv)
|
|||||||
sizeof(struct iwl4965_bt_cmd), &bt_cmd);
|
sizeof(struct iwl4965_bt_cmd), &bt_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* CARD_STATE_CMD
|
|
||||||
*
|
|
||||||
* Use: Sets the device's internal card state to enable, disable, or halt
|
|
||||||
*
|
|
||||||
* When in the 'enable' state the card operates as normal.
|
|
||||||
* When in the 'disable' state, the card enters into a low power mode.
|
|
||||||
* When in the 'halt' state, the card is shut down and must be fully
|
|
||||||
* restarted to come back on.
|
|
||||||
*/
|
|
||||||
static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
|
|
||||||
{
|
|
||||||
struct iwl_host_cmd cmd = {
|
|
||||||
.id = REPLY_CARD_STATE_CMD,
|
|
||||||
.len = sizeof(u32),
|
|
||||||
.data = &flags,
|
|
||||||
.meta.flags = meta_flag,
|
|
||||||
};
|
|
||||||
|
|
||||||
return iwl_send_cmd(priv, &cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iwl_clear_free_frames(struct iwl_priv *priv)
|
static void iwl_clear_free_frames(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
struct list_head *element;
|
struct list_head *element;
|
||||||
@@ -916,65 +894,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv)
|
|||||||
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
|
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
|
|
||||||
disable_radio ? "OFF" : "ON");
|
|
||||||
|
|
||||||
if (disable_radio) {
|
|
||||||
iwl_scan_cancel(priv);
|
|
||||||
/* FIXME: This is a workaround for AP */
|
|
||||||
if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
|
|
||||||
CSR_UCODE_SW_BIT_RFKILL);
|
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
/* call the host command only if no hw rf-kill set */
|
|
||||||
if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
|
|
||||||
iwl_is_ready(priv))
|
|
||||||
iwl4965_send_card_state(priv,
|
|
||||||
CARD_STATE_CMD_DISABLE,
|
|
||||||
0);
|
|
||||||
set_bit(STATUS_RF_KILL_SW, &priv->status);
|
|
||||||
|
|
||||||
/* make sure mac80211 stop sending Tx frame */
|
|
||||||
if (priv->mac80211_registered)
|
|
||||||
ieee80211_stop_queues(priv->hw);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
|
|
||||||
|
|
||||||
clear_bit(STATUS_RF_KILL_SW, &priv->status);
|
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
|
|
||||||
/* wake up ucode */
|
|
||||||
msleep(10);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
iwl_read32(priv, CSR_UCODE_DRV_GP1);
|
|
||||||
if (!iwl_grab_nic_access(priv))
|
|
||||||
iwl_release_nic_access(priv);
|
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
|
|
||||||
if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
|
|
||||||
IWL_DEBUG_RF_KILL("Can not turn radio back on - "
|
|
||||||
"disabled by HW switch\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->is_open)
|
|
||||||
queue_work(priv->workqueue, &priv->restart);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define IWL_PACKET_RETRY_TIME HZ
|
#define IWL_PACKET_RETRY_TIME HZ
|
||||||
|
|
||||||
int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
|
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
|
|||||||
|
|
||||||
priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
|
priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
|
||||||
|
|
||||||
|
if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) {
|
||||||
if (priv->cfg->ops->lib->radio_kill_sw &&
|
|
||||||
priv->cfg->ops->lib->radio_kill_sw(priv, !conf->radio_enabled)) {
|
|
||||||
IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n");
|
IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n");
|
||||||
mutex_unlock(&priv->mutex);
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!conf->radio_enabled)
|
||||||
|
iwl_radio_kill_sw_disable_radio(priv);
|
||||||
|
|
||||||
if (!iwl_is_ready(priv)) {
|
if (!iwl_is_ready(priv)) {
|
||||||
IWL_DEBUG_MAC80211("leave - not ready\n");
|
IWL_DEBUG_MAC80211("leave - not ready\n");
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
|
Reference in New Issue
Block a user