Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ddaf5a5b authored by Johannes Berg's avatar Johannes Berg
Browse files

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: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 22dc3c95
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -206,7 +206,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,

#ifdef CONFIG_PM_SLEEP
	if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
	    priv->trans->ops->wowlan_suspend &&
	    priv->trans->ops->d3_suspend &&
	    priv->trans->ops->d3_resume &&
	    device_can_wakeup(priv->trans->dev)) {
		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
					  WIPHY_WOWLAN_DISCONNECT |
@@ -426,7 +427,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
	if (ret)
		goto error;

	iwl_trans_wowlan_suspend(priv->trans);
	iwl_trans_d3_suspend(priv->trans);

	goto out;

+4 −0
Original line number Diff line number Diff line
@@ -225,6 +225,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG	(FH_MEM_RSCSR_CHNL0 + 0x008)
#define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)

#define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG	(FH_MEM_RSCSR_CHNL0 + 0x00c)
#define FH_RSCSR_CHNL0_RDPTR		FW_RSCSR_CHNL0_RXDCB_RDPTR_REG

/**
 * Rx Config/Status Registers (RCSR)
@@ -257,6 +259,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)

#define FH_MEM_RCSR_CHNL0_CONFIG_REG	(FH_MEM_RCSR_CHNL0)
#define FH_MEM_RCSR_CHNL0_RBDCB_WPTR	(FH_MEM_RCSR_CHNL0 + 0x8)
#define FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ	(FH_MEM_RCSR_CHNL0 + 0x10)

#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK   (0x00001000) /* bits 12 */
+25 −4
Original line number Diff line number Diff line
@@ -307,6 +307,16 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
#define IWL_MAX_TID_COUNT	8
#define IWL_FRAME_LIMIT	64

/**
 * enum iwl_wowlan_status - WoWLAN image/device status
 * @IWL_D3_STATUS_ALIVE: firmware is still running after resume
 * @IWL_D3_STATUS_RESET: device was reset while suspended
 */
enum iwl_d3_status {
	IWL_D3_STATUS_ALIVE,
	IWL_D3_STATUS_RESET,
};

/**
 * struct iwl_trans_config - transport configuration
 *
@@ -363,9 +373,12 @@ struct iwl_trans;
 *	May sleep
 * @stop_device:stops the whole device (embedded CPU put to reset)
 *	May sleep
 * @wowlan_suspend: put the device into the correct mode for WoWLAN during
 * @d3_suspend: put the device into the correct mode for WoWLAN during
 *	suspend. This is optional, if not implemented WoWLAN will not be
 *	supported. This callback may sleep.
 * @d3_resume: resume the device after WoWLAN, enabling the opmode to
 *	talk to the WoWLAN image to get its status. This is optional, if not
 *	implemented WoWLAN will not be supported. This callback may sleep.
 * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
 *	If RFkill is asserted in the middle of a SYNC host command, it must
 *	return -ERFKILL straight away.
@@ -409,7 +422,8 @@ struct iwl_trans_ops {
	void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
	void (*stop_device)(struct iwl_trans *trans);

	void (*wowlan_suspend)(struct iwl_trans *trans);
	void (*d3_suspend)(struct iwl_trans *trans);
	int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);

	int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);

@@ -562,10 +576,17 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
	trans->state = IWL_TRANS_NO_FW;
}

static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
{
	might_sleep();
	trans->ops->d3_suspend(trans);
}

static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
				      enum iwl_d3_status *status)
{
	might_sleep();
	trans->ops->wowlan_suspend(trans);
	return trans->ops->d3_resume(trans, status);
}

static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
+2 −0
Original line number Diff line number Diff line
@@ -357,6 +357,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
			    struct iwl_rx_cmd_buffer *rxb, int handler_status);
void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
			    struct sk_buff_head *skbs);
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);

/*****************************************************
* Error handling
******************************************************/
+5 −1
Original line number Diff line number Diff line
@@ -455,6 +455,10 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)

	/* Stop Rx DMA */
	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
	/* reset and flush pointers */
	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);

	/* Reset driver's Rx queue write index */
	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
@@ -491,7 +495,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
{
	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
	struct iwl_rxq *rxq = &trans_pcie->rxq;

	int i, err;
	unsigned long flags;

@@ -518,6 +521,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
	rxq->read = rxq->write = 0;
	rxq->write_actual = 0;
	rxq->free_count = 0;
	memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
	spin_unlock_irqrestore(&rxq->lock, flags);

	iwl_pcie_rx_replenish(trans);
Loading