diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-01-08 05:25:44 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-01-16 08:19:54 -0500 |
commit | ddaf5a5b300b8f9d3591b509fd8bedab1c9887be (patch) | |
tree | c78ebe39d33bf334e120d08c3206a5b048f8fcea /drivers/net/wireless/iwlwifi/pcie/trans.c | |
parent | 22dc3c9561825a7c2cd18d01b01358c2141a8e16 (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.c | 91 |
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 | ||
78 | static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans) | 78 | static 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 | ||
548 | static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) | 543 | static 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 | |||
567 | static 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 | ||
559 | static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) | 615 | static 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 | ||