Skip to content

Commit

Permalink
iwlwifi: introduce trans_ops->stop_hw
Browse files Browse the repository at this point in the history
This handler stops the HW and puts it in low power state.
It will allow to clean up the flows in the upper layers.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
  • Loading branch information
Emmanuel Grumbach authored and Wey-Yi Guy committed Feb 2, 2012
1 parent a6c684e commit cc56feb
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 44 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/iwlwifi/iwl-agn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1839,7 +1839,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
/* Read the EEPROM */
err = iwl_eeprom_init(priv, hw_rev);
/* Reset chip to save power until we load uCode during "up". */
iwl_apm_stop(priv);
iwl_trans_stop_hw(trans(priv));
if (err) {
IWL_ERR(priv, "Unable to init EEPROM\n");
goto out_free_traffic_mem;
Expand Down
40 changes: 0 additions & 40 deletions drivers/net/wireless/iwlwifi/iwl-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -883,46 +883,6 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
}
}

static int iwl_apm_stop_master(struct iwl_priv *priv)
{
int ret = 0;

/* stop device's busmaster DMA activity */
iwl_set_bit(trans(priv), CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);

ret = iwl_poll_bit(trans(priv), CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (ret)
IWL_WARN(priv, "Master Disable Timed Out, 100 usec\n");

IWL_DEBUG_INFO(priv, "stop master\n");

return ret;
}

void iwl_apm_stop(struct iwl_priv *priv)
{
IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");

clear_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status);

/* Stop device's DMA activity */
iwl_apm_stop_master(priv);

/* Reset the entire device */
iwl_set_bit(trans(priv), CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);

udelay(10);

/*
* Clear "initialization complete" bit to move adapter from
* D0A* (powered-up Active) --> D0U* (Uninitialized) state.
*/
iwl_clear_bit(trans(priv), CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
}

int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
int ret;
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl-shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,6 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr);
void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state);
void iwl_nic_config(struct iwl_priv *priv);
void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb);
void iwl_apm_stop(struct iwl_priv *priv);
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
const char *get_cmd_string(u8 cmd);
bool iwl_check_for_ct_kill(struct iwl_priv *priv);
Expand Down
54 changes: 52 additions & 2 deletions drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,46 @@ static int iwl_apm_init(struct iwl_trans *trans)
return ret;
}

static int iwl_apm_stop_master(struct iwl_trans *trans)
{
int ret = 0;

/* stop device's busmaster DMA activity */
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);

ret = iwl_poll_bit(trans, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (ret)
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");

IWL_DEBUG_INFO(trans, "stop master\n");

return ret;
}

static void iwl_apm_stop(struct iwl_trans *trans)
{
IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");

clear_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status);

/* Stop device's DMA activity */
iwl_apm_stop_master(trans);

/* Reset the entire device */
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);

udelay(10);

/*
* Clear "initialization complete" bit to move adapter from
* D0A* (powered-up Active) --> D0U* (Uninitialized) state.
*/
iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
}

static int iwl_nic_init(struct iwl_trans *trans)
{
unsigned long flags;
Expand Down Expand Up @@ -1118,7 +1158,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);

/* Stop the device, and put it in low power state */
iwl_apm_stop(priv(trans));
iwl_apm_stop(trans);

/* Upon stop, the APM issues an interrupt if HW RF kill is set.
* Clean again the interrupt here
Expand Down Expand Up @@ -1361,6 +1401,15 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
return err;
}

static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans)
{
iwl_apm_stop(trans);

/* Even if we stop the HW, we still want the RF kill interrupt */
IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
}

static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
int txq_id, int ssn, u32 status,
struct sk_buff_head *skbs)
Expand Down Expand Up @@ -1455,7 +1504,7 @@ static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
* things already :-)
*/
if (!trans->shrd->wowlan) {
iwl_apm_stop(priv(trans));
iwl_apm_stop(trans);
} else {
iwl_disable_interrupts(trans);
iwl_clear_bit(trans, CSR_GP_CNTRL,
Expand Down Expand Up @@ -2024,6 +2073,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,

const struct iwl_trans_ops trans_ops_pcie = {
.start_hw = iwl_trans_pcie_start_hw,
.stop_hw = iwl_trans_pcie_stop_hw,
.fw_alive = iwl_trans_pcie_fw_alive,
.start_device = iwl_trans_pcie_start_device,
.stop_device = iwl_trans_pcie_stop_device,
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-trans.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ struct iwl_host_cmd {
/**
* struct iwl_trans_ops - transport specific operations
* @start_hw: starts the HW- from that point on, the HW can send interrupts
* @stop_hw: stops the HW- from that point on, the HW will be in low power but
* will still issue interrupt if the HW RF kill is triggered.
* @start_device: allocates and inits all the resources for the transport
* layer.
* @fw_alive: called when the fw sends alive notification
Expand Down Expand Up @@ -163,6 +165,7 @@ struct iwl_host_cmd {
struct iwl_trans_ops {

int (*start_hw)(struct iwl_trans *iwl_trans);
void (*stop_hw)(struct iwl_trans *iwl_trans);
int (*start_device)(struct iwl_trans *trans);
void (*fw_alive)(struct iwl_trans *trans);
void (*stop_device)(struct iwl_trans *trans);
Expand Down Expand Up @@ -271,6 +274,11 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
return trans->ops->start_hw(trans);
}

static inline void iwl_trans_stop_hw(struct iwl_trans *trans)
{
trans->ops->stop_hw(trans);
}

static inline void iwl_trans_fw_alive(struct iwl_trans *trans)
{
trans->ops->fw_alive(trans);
Expand Down

0 comments on commit cc56feb

Please sign in to comment.