aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2012-10-25 11:25:52 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-31 12:02:06 -0400
commitf946b529502399d09471c5d13845fefbfe8555a6 (patch)
tree597c826ef9bfb679fd765796fd3d83845c76d1cc /drivers
parent3e2c159260eed10c44f0dd028c328a40a27ad235 (diff)
iwlwifi: handle RFKILL logic in the transport layer
No HCMD can be sent while RFKILL is asserted. If a SYNC command is running while RFKILL is asserted the fw will silently discard it. This means that the driver needs to wake the process that sleeps on the CMD_SYNC. Since the RFKILL interrupt is handled in the transport layer and the code that sleeps in CMD_SYNC is also in the transport layer, all this logic can be handled there. This simplifies the work of the op_mode. So the transport layer will now return -ERFKILL when a CMD is sent and RFKILL is asserted. This will be the case even when the CMD is SYNC. The transport layer will return -ERFKILL straight away. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h7
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h13
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c20
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c3
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c16
7 files changed, 44 insertions, 19 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index 475df45c8320..2b50d11720d4 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -1926,8 +1926,6 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
1926 * commands by clearing the ready bit */ 1926 * commands by clearing the ready bit */
1927 clear_bit(STATUS_READY, &priv->status); 1927 clear_bit(STATUS_READY, &priv->status);
1928 1928
1929 wake_up(&priv->trans->wait_command_queue);
1930
1931 if (!ondemand) { 1929 if (!ondemand) {
1932 /* 1930 /*
1933 * If firmware keep reloading, then it indicate something 1931 * If firmware keep reloading, then it indicate something
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c
index 5a9c325804f6..9a8d5020774e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rx.c
@@ -631,8 +631,6 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
631 test_bit(STATUS_RF_KILL_HW, &priv->status))) 631 test_bit(STATUS_RF_KILL_HW, &priv->status)))
632 wiphy_rfkill_set_hw_state(priv->hw->wiphy, 632 wiphy_rfkill_set_hw_state(priv->hw->wiphy,
633 test_bit(STATUS_RF_KILL_HW, &priv->status)); 633 test_bit(STATUS_RF_KILL_HW, &priv->status));
634 else
635 wake_up(&priv->trans->wait_command_queue);
636 return 0; 634 return 0;
637} 635}
638 636
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 47bbe399c068..b065d48de464 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -362,7 +362,9 @@ struct iwl_trans;
362 * @wowlan_suspend: put the device into the correct mode for WoWLAN during 362 * @wowlan_suspend: put the device into the correct mode for WoWLAN during
363 * suspend. This is optional, if not implemented WoWLAN will not be 363 * suspend. This is optional, if not implemented WoWLAN will not be
364 * supported. This callback may sleep. 364 * supported. This callback may sleep.
365 * @send_cmd:send a host command 365 * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
366 * If RFkill is asserted in the middle of a SYNC host command, it must
367 * return -ERFKILL straight away.
366 * May sleep only if CMD_SYNC is set 368 * May sleep only if CMD_SYNC is set
367 * @tx: send an skb 369 * @tx: send an skb
368 * Must be atomic 370 * Must be atomic
@@ -445,7 +447,6 @@ enum iwl_trans_state {
445 * Set during transport allocation. 447 * Set during transport allocation.
446 * @hw_id_str: a string with info about HW ID. Set during transport allocation. 448 * @hw_id_str: a string with info about HW ID. Set during transport allocation.
447 * @pm_support: set to true in start_hw if link pm is supported 449 * @pm_support: set to true in start_hw if link pm is supported
448 * @wait_command_queue: the wait_queue for SYNC host commands
449 * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. 450 * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
450 * The user should use iwl_trans_{alloc,free}_tx_cmd. 451 * The user should use iwl_trans_{alloc,free}_tx_cmd.
451 * @dev_cmd_headroom: room needed for the transport's private use before the 452 * @dev_cmd_headroom: room needed for the transport's private use before the
@@ -472,8 +473,6 @@ struct iwl_trans {
472 473
473 bool pm_support; 474 bool pm_support;
474 475
475 wait_queue_head_t wait_command_queue;
476
477 /* The following fields are internal only */ 476 /* The following fields are internal only */
478 struct kmem_cache *dev_cmd_pool; 477 struct kmem_cache *dev_cmd_pool;
479 size_t dev_cmd_headroom; 478 size_t dev_cmd_headroom;
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index ae0f87e0e585..847ef1e067bb 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -270,6 +270,8 @@ struct iwl_trans_pcie {
270 270
271 bool ucode_write_complete; 271 bool ucode_write_complete;
272 wait_queue_head_t ucode_write_waitq; 272 wait_queue_head_t ucode_write_waitq;
273 wait_queue_head_t wait_command_queue;
274
273 unsigned long status; 275 unsigned long status;
274 u8 cmd_queue; 276 u8 cmd_queue;
275 u8 cmd_fifo; 277 u8 cmd_fifo;
@@ -288,10 +290,13 @@ struct iwl_trans_pcie {
288/***************************************************** 290/*****************************************************
289* DRIVER STATUS FUNCTIONS 291* DRIVER STATUS FUNCTIONS
290******************************************************/ 292******************************************************/
291#define STATUS_HCMD_ACTIVE 0 293enum {
292#define STATUS_DEVICE_ENABLED 1 294 STATUS_HCMD_ACTIVE,
293#define STATUS_TPOWER_PMI 2 295 STATUS_DEVICE_ENABLED,
294#define STATUS_INT_ENABLED 3 296 STATUS_TPOWER_PMI,
297 STATUS_INT_ENABLED,
298 STATUS_RFKILL,
299};
295 300
296#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ 301#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
297 ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) 302 ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 3f03f6e322c3..50c9147278b3 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -568,24 +568,26 @@ static void iwl_rx_handle(struct iwl_trans *trans)
568 */ 568 */
569static void iwl_irq_handle_error(struct iwl_trans *trans) 569static void iwl_irq_handle_error(struct iwl_trans *trans)
570{ 570{
571 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
572
571 /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ 573 /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
572 if (trans->cfg->internal_wimax_coex && 574 if (trans->cfg->internal_wimax_coex &&
573 (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) & 575 (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
574 APMS_CLK_VAL_MRB_FUNC_MODE) || 576 APMS_CLK_VAL_MRB_FUNC_MODE) ||
575 (iwl_read_prph(trans, APMG_PS_CTRL_REG) & 577 (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
576 APMG_PS_CTRL_VAL_RESET_REQ))) { 578 APMG_PS_CTRL_VAL_RESET_REQ))) {
577 struct iwl_trans_pcie *trans_pcie =
578 IWL_TRANS_GET_PCIE_TRANS(trans);
579
580 clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); 579 clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
581 iwl_op_mode_wimax_active(trans->op_mode); 580 iwl_op_mode_wimax_active(trans->op_mode);
582 wake_up(&trans->wait_command_queue); 581 wake_up(&trans_pcie->wait_command_queue);
583 return; 582 return;
584 } 583 }
585 584
586 iwl_dump_csr(trans); 585 iwl_dump_csr(trans);
587 iwl_dump_fh(trans, NULL); 586 iwl_dump_fh(trans, NULL);
588 587
588 clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
589 wake_up(&trans_pcie->wait_command_queue);
590
589 iwl_op_mode_nic_error(trans->op_mode); 591 iwl_op_mode_nic_error(trans->op_mode);
590} 592}
591 593
@@ -679,6 +681,16 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
679 isr_stats->rfkill++; 681 isr_stats->rfkill++;
680 682
681 iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); 683 iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
684 if (hw_rfkill) {
685 set_bit(STATUS_RFKILL, &trans_pcie->status);
686 if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
687 &trans_pcie->status))
688 IWL_DEBUG_RF_KILL(trans,
689 "Rfkill while SYNC HCMD in flight\n");
690 wake_up(&trans_pcie->wait_command_queue);
691 } else {
692 clear_bit(STATUS_RFKILL, &trans_pcie->status);
693 }
682 694
683 handled |= CSR_INT_BIT_RF_KILL; 695 handled |= CSR_INT_BIT_RF_KILL;
684 } 696 }
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index b8a155af12cc..288d2297f77d 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -1246,6 +1246,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
1246 clear_bit(STATUS_INT_ENABLED, &trans_pcie->status); 1246 clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
1247 clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); 1247 clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
1248 clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); 1248 clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
1249 clear_bit(STATUS_RFKILL, &trans_pcie->status);
1249} 1250}
1250 1251
1251static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) 1252static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
@@ -2206,7 +2207,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
2206 } 2207 }
2207 2208
2208 /* Initialize the wait queue for commands */ 2209 /* Initialize the wait queue for commands */
2209 init_waitqueue_head(&trans->wait_command_queue); 2210 init_waitqueue_head(&trans_pcie->wait_command_queue);
2210 spin_lock_init(&trans->reg_lock); 2211 spin_lock_init(&trans->reg_lock);
2211 2212
2212 snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), 2213 snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 9cb30ae5e9a1..ae73bd3944e8 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -827,7 +827,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
827 IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", 827 IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
828 trans_pcie_get_cmd_string(trans_pcie, 828 trans_pcie_get_cmd_string(trans_pcie,
829 cmd->hdr.cmd)); 829 cmd->hdr.cmd));
830 wake_up(&trans->wait_command_queue); 830 wake_up(&trans_pcie->wait_command_queue);
831 } 831 }
832 832
833 meta->flags = 0; 833 meta->flags = 0;
@@ -886,7 +886,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
886 return ret; 886 return ret;
887 } 887 }
888 888
889 ret = wait_event_timeout(trans->wait_command_queue, 889 ret = wait_event_timeout(trans_pcie->wait_command_queue,
890 !test_bit(STATUS_HCMD_ACTIVE, 890 !test_bit(STATUS_HCMD_ACTIVE,
891 &trans_pcie->status), 891 &trans_pcie->status),
892 HOST_COMPLETE_TIMEOUT); 892 HOST_COMPLETE_TIMEOUT);
@@ -915,6 +915,12 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
915 } 915 }
916 } 916 }
917 917
918 if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
919 IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
920 ret = -ERFKILL;
921 goto cancel;
922 }
923
918 if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) { 924 if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
919 IWL_ERR(trans, "Error: Response NULL in '%s'\n", 925 IWL_ERR(trans, "Error: Response NULL in '%s'\n",
920 trans_pcie_get_cmd_string(trans_pcie, cmd->id)); 926 trans_pcie_get_cmd_string(trans_pcie, cmd->id));
@@ -946,9 +952,15 @@ cancel:
946 952
947int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) 953int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
948{ 954{
955 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
956
957 if (test_bit(STATUS_RFKILL, &trans_pcie->status))
958 return -ERFKILL;
959
949 if (cmd->flags & CMD_ASYNC) 960 if (cmd->flags & CMD_ASYNC)
950 return iwl_send_cmd_async(trans, cmd); 961 return iwl_send_cmd_async(trans, cmd);
951 962
963 /* We still can fail on RFKILL that can be asserted while we wait */
952 return iwl_send_cmd_sync(trans, cmd); 964 return iwl_send_cmd_sync(trans, cmd);
953} 965}
954 966