iwlwifi: virtualize iwl_{grab,release}_nic_access
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 24 Dec 2012 13:01:24 +0000 (15:01 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 3 Jan 2013 14:29:46 +0000 (15:29 +0100)
Since different transports have different ways to wake the
up the NIC, we need to virtualize it.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/tt.c
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-test.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/pcie/trans.c

index 3163e0f38c25109a3c5f5a2e7c71f39f37b40eda..8965a9824f502c7bb090a7a3958fa73878a0b5b7 100644 (file)
@@ -459,11 +459,11 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        base = priv->device_pointers.error_event_table;
        if (iwlagn_hw_valid_rtc_data_addr(base)) {
                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)) {
                        iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
                        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);
 
index faa05932efae92e80c322b4a28d606da7cb9808b..c4caedd4fa9cd0a091f0e68947fd3d66b7a3eac7 100644 (file)
@@ -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 */
        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);
                return;
        }
@@ -388,7 +388,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
                }
        }
        /* 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);
 }
 
@@ -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 */
        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;
 
        /* Set starting address; reads will auto-increment */
@@ -1756,7 +1756,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
        }
 
        /* Allow device to power down */
-       iwl_release_nic_access(trans);
+       iwl_trans_release_nic_access(trans);
 out_unlock:
        spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
        return pos;
index eb864433e59de0ec749a3693d950c4065f2d6b32..a8ae51307db4799131e64c6c33e6d69294e9584e 100644 (file)
@@ -186,8 +186,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
                }
                iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
                spin_lock_irqsave(&priv->trans->reg_lock, flags);
-               if (likely(iwl_grab_nic_access(priv->trans)))
-                       iwl_release_nic_access(priv->trans);
+               if (likely(iwl_trans_grab_nic_access(priv->trans, false)))
+                       iwl_trans_release_nic_access(priv->trans);
                spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
 
                /* Reschedule the ct_kill timer to occur in
index cdaff9572059bd162beb8e050a0215d3f632ebcd..cb36fedd157a4dac8091272cfd15923b5c5f82e2 100644 (file)
 
 #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);
 }
 
-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);
 }
@@ -99,86 +99,15 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 }
 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 value;
        unsigned long 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);
-       iwl_release_nic_access(trans);
+       iwl_trans_release_nic_access(trans);
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 
        return value;
@@ -190,9 +119,9 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
        unsigned long 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_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -233,9 +162,9 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
        u32 val;
 
        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);
-       iwl_release_nic_access(trans);
+       iwl_trans_release_nic_access(trans);
        spin_unlock_irqrestore(&trans->reg_lock, flags);
        return val;
 }
@@ -246,9 +175,9 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
        unsigned long 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_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -259,10 +188,10 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
        unsigned long 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_read_prph(trans, ofs) | mask);
-               iwl_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -274,10 +203,10 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
        unsigned long 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_read_prph(trans, ofs) & mask) | bits);
-               iwl_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -289,10 +218,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
        u32 val;
 
        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);
                __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);
 }
@@ -306,11 +235,11 @@ void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
        u32 *vals = buf;
 
        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);
                for (offs = 0; offs < dwords; offs++)
                        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);
 }
@@ -334,13 +263,14 @@ int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
        const u32 *vals = buf;
 
        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);
                for (offs = 0; offs < dwords; offs++)
                        iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
-               iwl_release_nic_access(trans);
-       } else
+               iwl_trans_release_nic_access(trans);
+       } else {
                result = -EBUSY;
+       }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 
        return result;
index 48dc753e3742aab857af7f88617b81206dc163cc..40eb0a1709b1f28185126242516b5d0a2136e3d3 100644 (file)
@@ -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_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);
 
@@ -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 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);
 void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
 
index 81e8c7126d7293016d91e0a787d9a9991fea08ac..08c1cfec85903f153f4c77abc7cf108a33e76e4a 100644 (file)
@@ -467,13 +467,13 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
        if (IWL_ABS_PRPH_START <= addr &&
            addr < IWL_ABS_PRPH_START + PRPH_END) {
                        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,
                                    addr | (3 << 24));
                        for (i = 0; i < size; i += 4)
                                *(u32 *)(tst->mem.addr + i) =
                                        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);
        } else { /* target memory (SRAM) */
                _iwl_read_targ_mem_dwords(trans, addr,
@@ -505,12 +505,12 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
                        if (size < 4) {
                                memcpy(&val, buf, size);
                                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,
                                            (addr & 0x0000FFFF) |
                                            ((size - 1) << 24));
                                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 */
                                mmiowb();
                                spin_unlock_irqrestore(&trans->reg_lock, flags);
index 16a82b5a46711893a59ba47fc87137ca1f0a7b15..1d1f5d0e57269126bdbe0bd9db33c5eaa2c9f4b8 100644 (file)
@@ -394,6 +394,8 @@ struct iwl_trans;
  *     the op_mode. May be called several times before start_fw, can't be
  *     called after that.
  * @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 {
 
@@ -431,6 +433,8 @@ struct iwl_trans_ops {
        void (*configure)(struct iwl_trans *trans,
                          const struct iwl_trans_config *trans_cfg);
        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)
        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
 ******************************************************/
index e67e179bd04b1a11d1bb33675942a00bb800a0cc..80b05d821688c08b0c57e2fc4a820b6a65c6a2de 100644 (file)
@@ -759,6 +759,68 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
 }
 #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
 
 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 = {
        .write_prph = iwl_trans_pcie_write_prph,
        .configure = iwl_trans_pcie_configure,
        .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,