aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie
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
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')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c6
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c91
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c23
4 files changed, 104 insertions, 18 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 8f017c34ab2b..20735a008cab 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -357,6 +357,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
357 struct iwl_rx_cmd_buffer *rxb, int handler_status); 357 struct iwl_rx_cmd_buffer *rxb, int handler_status);
358void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, 358void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
359 struct sk_buff_head *skbs); 359 struct sk_buff_head *skbs);
360void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
361
360/***************************************************** 362/*****************************************************
361* Error handling 363* Error handling
362******************************************************/ 364******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index ea9e9915ad35..96013030fcc7 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -455,6 +455,10 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
455 455
456 /* Stop Rx DMA */ 456 /* Stop Rx DMA */
457 iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); 457 iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
458 /* reset and flush pointers */
459 iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
460 iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
461 iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
458 462
459 /* Reset driver's Rx queue write index */ 463 /* Reset driver's Rx queue write index */
460 iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); 464 iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
@@ -491,7 +495,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
491{ 495{
492 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 496 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
493 struct iwl_rxq *rxq = &trans_pcie->rxq; 497 struct iwl_rxq *rxq = &trans_pcie->rxq;
494
495 int i, err; 498 int i, err;
496 unsigned long flags; 499 unsigned long flags;
497 500
@@ -518,6 +521,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
518 rxq->read = rxq->write = 0; 521 rxq->read = rxq->write = 0;
519 rxq->write_actual = 0; 522 rxq->write_actual = 0;
520 rxq->free_count = 0; 523 rxq->free_count = 0;
524 memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
521 spin_unlock_irqrestore(&rxq->lock, flags); 525 spin_unlock_irqrestore(&rxq->lock, flags);
522 526
523 iwl_pcie_rx_replenish(trans); 527 iwl_pcie_rx_replenish(trans);
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
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index d3c4e8f017ef..fd3280fca445 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -692,6 +692,29 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
692 APMG_PCIDEV_STT_VAL_L1_ACT_DIS); 692 APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
693} 693}
694 694
695void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
696{
697 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
698 int txq_id;
699
700 for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
701 txq_id++) {
702 struct iwl_txq *txq = &trans_pcie->txq[txq_id];
703
704 iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
705 txq->q.dma_addr >> 8);
706 iwl_pcie_txq_unmap(trans, txq_id);
707 txq->q.read_ptr = 0;
708 txq->q.write_ptr = 0;
709 }
710
711 /* Tell NIC where to find the "keep warm" buffer */
712 iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
713 trans_pcie->kw.dma >> 4);
714
715 iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr);
716}
717
695/* 718/*
696 * iwl_pcie_tx_stop - Stop all Tx DMA channels 719 * iwl_pcie_tx_stop - Stop all Tx DMA channels
697 */ 720 */