aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie/trans.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-01-08 05:25:44 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-16 08:19:54 -0500
commitddaf5a5b300b8f9d3591b509fd8bedab1c9887be (patch)
treec78ebe39d33bf334e120d08c3206a5b048f8fcea /drivers/net/wireless/iwlwifi/pcie/trans.c
parent22dc3c9561825a7c2cd18d01b01358c2141a8e16 (diff)
iwlwifi: enable communication with WoWLAN firmware
On resuming, the opmode may have to be able to talk to the WoWLAN/D3 firmware in order to query it about its status and wakeup reasons. To do that, the opmode has to call the new d3_resume() transport API which will set up the device for command communcation. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/trans.c')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c91
1 files changed, 74 insertions, 17 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 4028c03eff5f..59340ff13a64 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -75,21 +75,16 @@
75#include "iwl-agn-hw.h" 75#include "iwl-agn-hw.h"
76#include "internal.h" 76#include "internal.h"
77 77
78static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans) 78static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
79{ 79{
80/* 80 if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
81 * (for documentation purposes) 81 iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
82 * to set power to V_AUX, do: 82 APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
83 83 ~APMG_PS_CTRL_MSK_PWR_SRC);
84 if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) 84 else
85 iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, 85 iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
86 APMG_PS_CTRL_VAL_PWR_SRC_VAUX, 86 APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
87 ~APMG_PS_CTRL_MSK_PWR_SRC); 87 ~APMG_PS_CTRL_MSK_PWR_SRC);
88 */
89
90 iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
91 APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
92 ~APMG_PS_CTRL_MSK_PWR_SRC);
93} 88}
94 89
95/* PCI registers */ 90/* PCI registers */
@@ -259,7 +254,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
259 254
260 spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); 255 spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
261 256
262 iwl_pcie_set_pwr_vmain(trans); 257 iwl_pcie_set_pwr(trans, false);
263 258
264 iwl_op_mode_nic_config(trans->op_mode); 259 iwl_op_mode_nic_config(trans->op_mode);
265 260
@@ -545,15 +540,76 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
545 clear_bit(STATUS_RFKILL, &trans_pcie->status); 540 clear_bit(STATUS_RFKILL, &trans_pcie->status);
546} 541}
547 542
548static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) 543static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
549{ 544{
550 /* let the ucode operate on its own */ 545 /* let the ucode operate on its own */
551 iwl_write32(trans, CSR_UCODE_DRV_GP1_SET, 546 iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
552 CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); 547 CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
553 548
554 iwl_disable_interrupts(trans); 549 iwl_disable_interrupts(trans);
550 iwl_pcie_disable_ict(trans);
551
555 iwl_clear_bit(trans, CSR_GP_CNTRL, 552 iwl_clear_bit(trans, CSR_GP_CNTRL,
556 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 553 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
554 iwl_clear_bit(trans, CSR_GP_CNTRL,
555 CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
556
557 /*
558 * reset TX queues -- some of their registers reset during S3
559 * so if we don't reset everything here the D3 image would try
560 * to execute some invalid memory upon resume
561 */
562 iwl_trans_pcie_tx_reset(trans);
563
564 iwl_pcie_set_pwr(trans, true);
565}
566
567static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
568 enum iwl_d3_status *status)
569{
570 u32 val;
571 int ret;
572
573 iwl_pcie_set_pwr(trans, false);
574
575 val = iwl_read32(trans, CSR_RESET);
576 if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
577 *status = IWL_D3_STATUS_RESET;
578 return 0;
579 }
580
581 /*
582 * Also enables interrupts - none will happen as the device doesn't
583 * know we're waking it up, only when the opmode actually tells it
584 * after this call.
585 */
586 iwl_pcie_reset_ict(trans);
587
588 iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
589 iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
590
591 ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
592 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
593 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
594 25000);
595 if (ret) {
596 IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
597 return ret;
598 }
599
600 iwl_trans_pcie_tx_reset(trans);
601
602 ret = iwl_pcie_rx_init(trans);
603 if (ret) {
604 IWL_ERR(trans, "Failed to resume the device (RX reset)\n");
605 return ret;
606 }
607
608 iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
609 CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
610
611 *status = IWL_D3_STATUS_ALIVE;
612 return 0;
557} 613}
558 614
559static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) 615static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
@@ -1279,7 +1335,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
1279 .start_fw = iwl_trans_pcie_start_fw, 1335 .start_fw = iwl_trans_pcie_start_fw,
1280 .stop_device = iwl_trans_pcie_stop_device, 1336 .stop_device = iwl_trans_pcie_stop_device,
1281 1337
1282 .wowlan_suspend = iwl_trans_pcie_wowlan_suspend, 1338 .d3_suspend = iwl_trans_pcie_d3_suspend,
1339 .d3_resume = iwl_trans_pcie_d3_resume,
1283 1340
1284 .send_cmd = iwl_trans_pcie_send_hcmd, 1341 .send_cmd = iwl_trans_pcie_send_hcmd,
1285 1342