Commit 7a65d170 authored by Emmanuel Grumbach's avatar Emmanuel Grumbach Committed by Johannes Berg

iwlwifi: virtualize iwl_{grab,release}_nic_access

Since different transports have different ways to wake the
up the NIC, we need to virtualize it.
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f317243a
...@@ -459,11 +459,11 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) ...@@ -459,11 +459,11 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
base = priv->device_pointers.error_event_table; base = priv->device_pointers.error_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) { if (iwlagn_hw_valid_rtc_data_addr(base)) {
spin_lock_irqsave(&priv->trans->reg_lock, flags); spin_lock_irqsave(&priv->trans->reg_lock, flags);
ret = iwl_grab_nic_access_silent(priv->trans); ret = iwl_trans_grab_nic_access(priv->trans, true);
if (likely(ret == 0)) { if (likely(ret == 0)) {
iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
iwl_release_nic_access(priv->trans); iwl_trans_release_nic_access(priv->trans);
} }
spin_unlock_irqrestore(&priv->trans->reg_lock, flags); spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
......
...@@ -354,7 +354,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, ...@@ -354,7 +354,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
/* Make sure device is powered up for SRAM reads */ /* Make sure device is powered up for SRAM reads */
spin_lock_irqsave(&priv->trans->reg_lock, reg_flags); spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
if (unlikely(!iwl_grab_nic_access(priv->trans))) { if (unlikely(!iwl_trans_grab_nic_access(priv->trans, false))) {
spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
return; return;
} }
...@@ -388,7 +388,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, ...@@ -388,7 +388,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
} }
} }
/* Allow device to power down */ /* Allow device to power down */
iwl_release_nic_access(priv->trans); iwl_trans_release_nic_access(priv->trans);
spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
} }
...@@ -1717,7 +1717,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ...@@ -1717,7 +1717,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
/* Make sure device is powered up for SRAM reads */ /* Make sure device is powered up for SRAM reads */
spin_lock_irqsave(&trans->reg_lock, reg_flags); spin_lock_irqsave(&trans->reg_lock, reg_flags);
if (unlikely(!iwl_grab_nic_access(trans))) if (unlikely(!iwl_trans_grab_nic_access(trans, false)))
goto out_unlock; goto out_unlock;
/* Set starting address; reads will auto-increment */ /* Set starting address; reads will auto-increment */
...@@ -1756,7 +1756,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ...@@ -1756,7 +1756,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
} }
/* Allow device to power down */ /* Allow device to power down */
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
out_unlock: out_unlock:
spin_unlock_irqrestore(&trans->reg_lock, reg_flags); spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
return pos; return pos;
......
...@@ -186,8 +186,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) ...@@ -186,8 +186,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
} }
iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
spin_lock_irqsave(&priv->trans->reg_lock, flags); spin_lock_irqsave(&priv->trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(priv->trans))) if (likely(iwl_trans_grab_nic_access(priv->trans, false)))
iwl_release_nic_access(priv->trans); iwl_trans_release_nic_access(priv->trans);
spin_unlock_irqrestore(&priv->trans->reg_lock, flags); spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
/* Reschedule the ct_kill timer to occur in /* Reschedule the ct_kill timer to occur in
......
...@@ -35,12 +35,12 @@ ...@@ -35,12 +35,12 @@
#define IWL_POLL_INTERVAL 10 /* microseconds */ #define IWL_POLL_INTERVAL 10 /* microseconds */
static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
{ {
iwl_write32(trans, reg, iwl_read32(trans, reg) | mask); iwl_write32(trans, reg, iwl_read32(trans, reg) | mask);
} }
static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
{ {
iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask); iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask);
} }
...@@ -99,86 +99,15 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr, ...@@ -99,86 +99,15 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
} }
EXPORT_SYMBOL_GPL(iwl_poll_bit); EXPORT_SYMBOL_GPL(iwl_poll_bit);
int iwl_grab_nic_access_silent(struct iwl_trans *trans)
{
int ret;
lockdep_assert_held(&trans->reg_lock);
/* this bit wakes up the NIC */
__iwl_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* These bits say the device is running, and should keep running for
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
* but they do not indicate that embedded SRAM is restored yet;
* 3945 and 4965 have volatile SRAM, and must save/restore contents
* to/from host DRAM when sleeping/waking for power-saving.
* Each direction takes approximately 1/4 millisecond; with this
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
* series of register accesses are expected (e.g. reading Event Log),
* to keep device from sleeping.
*
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
* SRAM is okay/restored. We don't check that here because this call
* is just for hardware register access; but GP1 MAC_SLEEP check is a
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
*
* 5000 series and later (including 1000 series) have non-volatile SRAM,
* and do not save/restore SRAM when power cycling.
*/
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
if (ret < 0) {
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
return -EIO;
}
return 0;
}
EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
bool iwl_grab_nic_access(struct iwl_trans *trans)
{
int ret = iwl_grab_nic_access_silent(trans);
if (unlikely(ret)) {
u32 val = iwl_read32(trans, CSR_GP_CNTRL);
WARN_ONCE(1, "Timeout waiting for hardware access "
"(CSR_GP_CNTRL 0x%08x)\n", val);
return false;
}
return true;
}
EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
void iwl_release_nic_access(struct iwl_trans *trans)
{
lockdep_assert_held(&trans->reg_lock);
__iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* Above we read the CSR_GP_CNTRL register, which will flush
* any previous writes, but we need the write that clears the
* MAC_ACCESS_REQ bit to be performed before any other writes
* scheduled on different CPUs (after we drop reg_lock).
*/
mmiowb();
}
EXPORT_SYMBOL_GPL(iwl_release_nic_access);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{ {
u32 value; u32 value;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans); iwl_trans_grab_nic_access(trans, false);
value = iwl_read32(trans, reg); value = iwl_read32(trans, reg);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
return value; return value;
...@@ -190,9 +119,9 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) ...@@ -190,9 +119,9 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) { if (likely(iwl_trans_grab_nic_access(trans, false))) {
iwl_write32(trans, reg, value); iwl_write32(trans, reg, value);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
} }
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
} }
...@@ -233,9 +162,9 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) ...@@ -233,9 +162,9 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
u32 val; u32 val;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans); iwl_trans_grab_nic_access(trans, false);
val = __iwl_read_prph(trans, ofs); val = __iwl_read_prph(trans, ofs);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
return val; return val;
} }
...@@ -246,9 +175,9 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) ...@@ -246,9 +175,9 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) { if (likely(iwl_trans_grab_nic_access(trans, false))) {
__iwl_write_prph(trans, ofs, val); __iwl_write_prph(trans, ofs, val);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
} }
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
} }
...@@ -259,10 +188,10 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) ...@@ -259,10 +188,10 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) { if (likely(iwl_trans_grab_nic_access(trans, false))) {
__iwl_write_prph(trans, ofs, __iwl_write_prph(trans, ofs,
__iwl_read_prph(trans, ofs) | mask); __iwl_read_prph(trans, ofs) | mask);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
} }
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
} }
...@@ -274,10 +203,10 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, ...@@ -274,10 +203,10 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) { if (likely(iwl_trans_grab_nic_access(trans, false))) {
__iwl_write_prph(trans, ofs, __iwl_write_prph(trans, ofs,
(__iwl_read_prph(trans, ofs) & mask) | bits); (__iwl_read_prph(trans, ofs) & mask) | bits);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
} }
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
} }
...@@ -289,10 +218,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) ...@@ -289,10 +218,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
u32 val; u32 val;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) { if (likely(iwl_trans_grab_nic_access(trans, false))) {
val = __iwl_read_prph(trans, ofs); val = __iwl_read_prph(trans, ofs);
__iwl_write_prph(trans, ofs, (val & ~mask)); __iwl_write_prph(trans, ofs, (val & ~mask));
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
} }
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
} }
...@@ -306,11 +235,11 @@ void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr, ...@@ -306,11 +235,11 @@ void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
u32 *vals = buf; u32 *vals = buf;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) { if (likely(iwl_trans_grab_nic_access(trans, false))) {
iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
for (offs = 0; offs < dwords; offs++) for (offs = 0; offs < dwords; offs++)
vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
} }
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
} }
...@@ -334,13 +263,14 @@ int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr, ...@@ -334,13 +263,14 @@ int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
const u32 *vals = buf; const u32 *vals = buf;
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) { if (likely(iwl_trans_grab_nic_access(trans, false))) {
iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
for (offs = 0; offs < dwords; offs++) for (offs = 0; offs < dwords; offs++)
iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]); iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
} else } else {
result = -EBUSY; result = -EBUSY;
}
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
return result; return result;
......
...@@ -53,6 +53,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs) ...@@ -53,6 +53,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
...@@ -61,10 +63,6 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr, ...@@ -61,10 +63,6 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
int timeout); int timeout);
int iwl_grab_nic_access_silent(struct iwl_trans *trans);
bool iwl_grab_nic_access(struct iwl_trans *trans);
void iwl_release_nic_access(struct iwl_trans *trans);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
......
...@@ -467,13 +467,13 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size) ...@@ -467,13 +467,13 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
if (IWL_ABS_PRPH_START <= addr && if (IWL_ABS_PRPH_START <= addr &&
addr < IWL_ABS_PRPH_START + PRPH_END) { addr < IWL_ABS_PRPH_START + PRPH_END) {
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans); iwl_trans_grab_nic_access(trans, false);
iwl_write32(trans, HBUS_TARG_PRPH_RADDR, iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
addr | (3 << 24)); addr | (3 << 24));
for (i = 0; i < size; i += 4) for (i = 0; i < size; i += 4)
*(u32 *)(tst->mem.addr + i) = *(u32 *)(tst->mem.addr + i) =
iwl_read32(trans, HBUS_TARG_PRPH_RDAT); iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
} else { /* target memory (SRAM) */ } else { /* target memory (SRAM) */
_iwl_read_targ_mem_dwords(trans, addr, _iwl_read_targ_mem_dwords(trans, addr,
...@@ -505,12 +505,12 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr, ...@@ -505,12 +505,12 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
if (size < 4) { if (size < 4) {
memcpy(&val, buf, size); memcpy(&val, buf, size);
spin_lock_irqsave(&trans->reg_lock, flags); spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans); iwl_trans_grab_nic_access(trans, false);
iwl_write32(trans, HBUS_TARG_PRPH_WADDR, iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
(addr & 0x0000FFFF) | (addr & 0x0000FFFF) |
((size - 1) << 24)); ((size - 1) << 24));
iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
iwl_release_nic_access(trans); iwl_trans_release_nic_access(trans);
/* needed after consecutive writes w/o read */ /* needed after consecutive writes w/o read */
mmiowb(); mmiowb();
spin_unlock_irqrestore(&trans->reg_lock, flags); spin_unlock_irqrestore(&trans->reg_lock, flags);
......
...@@ -394,6 +394,8 @@ struct iwl_trans; ...@@ -394,6 +394,8 @@ struct iwl_trans;
* the op_mode. May be called several times before start_fw, can't be * the op_mode. May be called several times before start_fw, can't be
* called after that. * called after that.
* @set_pmi: set the power pmi state * @set_pmi: set the power pmi state
* @grab_nic_access: wake the NIC to be able to access non-HBUS regs
* @release_nic_access: let the NIC go to sleep
*/ */
struct iwl_trans_ops { struct iwl_trans_ops {
...@@ -431,6 +433,8 @@ struct iwl_trans_ops { ...@@ -431,6 +433,8 @@ struct iwl_trans_ops {
void (*configure)(struct iwl_trans *trans, void (*configure)(struct iwl_trans *trans,
const struct iwl_trans_config *trans_cfg); const struct iwl_trans_config *trans_cfg);
void (*set_pmi)(struct iwl_trans *trans, bool state); void (*set_pmi)(struct iwl_trans *trans, bool state);
bool (*grab_nic_access)(struct iwl_trans *trans, bool silent);
void (*release_nic_access)(struct iwl_trans *trans);
}; };
/** /**
...@@ -689,6 +693,17 @@ static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) ...@@ -689,6 +693,17 @@ static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
trans->ops->set_pmi(trans, state); trans->ops->set_pmi(trans, state);
} }
static inline bool iwl_trans_grab_nic_access(struct iwl_trans *trans,
bool silent)
{
return trans->ops->grab_nic_access(trans, silent);
}
static inline void iwl_trans_release_nic_access(struct iwl_trans *trans)
{
trans->ops->release_nic_access(trans);
}
/***************************************************** /*****************************************************
* driver (transport) register/unregister functions * driver (transport) register/unregister functions
******************************************************/ ******************************************************/
......
...@@ -759,6 +759,68 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) ...@@ -759,6 +759,68 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
{
int ret;
lockdep_assert_held(&trans->reg_lock);
/* this bit wakes up the NIC */
__iwl_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* These bits say the device is running, and should keep running for
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
* but they do not indicate that embedded SRAM is restored yet;
* 3945 and 4965 have volatile SRAM, and must save/restore contents
* to/from host DRAM when sleeping/waking for power-saving.
* Each direction takes approximately 1/4 millisecond; with this
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
* series of register accesses are expected (e.g. reading Event Log),
* to keep device from sleeping.
*
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
* SRAM is okay/restored. We don't check that here because this call
* is just for hardware register access; but GP1 MAC_SLEEP check is a
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
*
* 5000 series and later (including 1000 series) have non-volatile SRAM,
* and do not save/restore SRAM when power cycling.
*/
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
if (unlikely(ret < 0)) {
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
if (!silent) {
u32 val = iwl_read32(trans, CSR_GP_CNTRL);
WARN_ONCE(1,
"Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
val);
return false;
}
}
return true;
}
static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
{
lockdep_assert_held(&trans->reg_lock);
__iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* Above we read the CSR_GP_CNTRL register, which will flush
* any previous writes, but we need the write that clears the
* MAC_ACCESS_REQ bit to be performed before any other writes
* scheduled on different CPUs (after we drop reg_lock).
*/
mmiowb();
}
#define IWL_FLUSH_WAIT_MS 2000 #define IWL_FLUSH_WAIT_MS 2000
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
...@@ -1238,6 +1300,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { ...@@ -1238,6 +1300,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.write_prph = iwl_trans_pcie_write_prph, .write_prph = iwl_trans_pcie_write_prph,
.configure = iwl_trans_pcie_configure, .configure = iwl_trans_pcie_configure,
.set_pmi = iwl_trans_pcie_set_pmi, .set_pmi = iwl_trans_pcie_set_pmi,
.grab_nic_access = iwl_trans_pcie_grab_nic_access,
.release_nic_access = iwl_trans_pcie_release_nic_access
}; };
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment