aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorLilach Edelstein <lilach.edelstein@intel.com>2013-01-16 04:34:49 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-01 05:27:22 -0500
commite56b04efc1f795da42cf1d9651b52a4a5bebd730 (patch)
treea9740ffd4d47ffb7b90507691a0a066c20f42a2d /drivers/net/wireless
parente139dc4aebf52a9c88552963b9794fd1dff036f1 (diff)
iwlwifi: move register access lock into transport
Move the reg_lock that protects HW register access into the transport implementation. Locking is no longer exposed, but handled internally in grab and release NIC access. This simplifies the users. Signed-off-by: Lilach Edelstein <lilach.edelstein@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c6
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c17
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tt.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c43
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h23
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h4
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c47
8 files changed, 75 insertions, 88 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index b55181275fd0..c2f03ecd4bf8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -459,14 +459,12 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
459 459
460 base = priv->device_pointers.error_event_table; 460 base = priv->device_pointers.error_event_table;
461 if (iwlagn_hw_valid_rtc_data_addr(base)) { 461 if (iwlagn_hw_valid_rtc_data_addr(base)) {
462 spin_lock_irqsave(&priv->trans->reg_lock, flags); 462 if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) {
463 if (iwl_trans_grab_nic_access(priv->trans, true)) {
464 iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); 463 iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
465 status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); 464 status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
466 iwl_trans_release_nic_access(priv->trans); 465 iwl_trans_release_nic_access(priv->trans, &flags);
467 ret = 0; 466 ret = 0;
468 } 467 }
469 spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
470 468
471#ifdef CONFIG_IWLWIFI_DEBUGFS 469#ifdef CONFIG_IWLWIFI_DEBUGFS
472 if (ret == 0) { 470 if (ret == 0) {
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index f5f91644adaa..b9e3517652d6 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -353,11 +353,8 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
353 ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); 353 ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
354 354
355 /* Make sure device is powered up for SRAM reads */ 355 /* Make sure device is powered up for SRAM reads */
356 spin_lock_irqsave(&priv->trans->reg_lock, reg_flags); 356 if (!iwl_trans_grab_nic_access(priv->trans, false, &reg_flags))
357 if (!iwl_trans_grab_nic_access(priv->trans, false)) {
358 spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
359 return; 357 return;
360 }
361 358
362 /* Set starting address; reads will auto-increment */ 359 /* Set starting address; reads will auto-increment */
363 iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); 360 iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
@@ -388,8 +385,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
388 } 385 }
389 } 386 }
390 /* Allow device to power down */ 387 /* Allow device to power down */
391 iwl_trans_release_nic_access(priv->trans); 388 iwl_trans_release_nic_access(priv->trans, &reg_flags);
392 spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
393} 389}
394 390
395static void iwl_continuous_event_trace(struct iwl_priv *priv) 391static void iwl_continuous_event_trace(struct iwl_priv *priv)
@@ -1717,9 +1713,8 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
1717 ptr = base + EVENT_START_OFFSET + (start_idx * event_size); 1713 ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
1718 1714
1719 /* Make sure device is powered up for SRAM reads */ 1715 /* Make sure device is powered up for SRAM reads */
1720 spin_lock_irqsave(&trans->reg_lock, reg_flags); 1716 if (!iwl_trans_grab_nic_access(trans, false, &reg_flags))
1721 if (!iwl_trans_grab_nic_access(trans, false)) 1717 return pos;
1722 goto out_unlock;
1723 1718
1724 /* Set starting address; reads will auto-increment */ 1719 /* Set starting address; reads will auto-increment */
1725 iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); 1720 iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
@@ -1757,9 +1752,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
1757 } 1752 }
1758 1753
1759 /* Allow device to power down */ 1754 /* Allow device to power down */
1760 iwl_trans_release_nic_access(trans); 1755 iwl_trans_release_nic_access(trans, &reg_flags);
1761out_unlock:
1762 spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
1763 return pos; 1756 return pos;
1764} 1757}
1765 1758
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
index 617fca3cffe0..67e2e1321b40 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.c
@@ -185,10 +185,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
185 priv->thermal_throttle.ct_kill_toggle = true; 185 priv->thermal_throttle.ct_kill_toggle = true;
186 } 186 }
187 iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); 187 iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
188 spin_lock_irqsave(&priv->trans->reg_lock, flags); 188 if (iwl_trans_grab_nic_access(priv->trans, false, &flags))
189 if (iwl_trans_grab_nic_access(priv->trans, false)) 189 iwl_trans_release_nic_access(priv->trans, &flags);
190 iwl_trans_release_nic_access(priv->trans);
191 spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
192 190
193 /* Reschedule the ct_kill timer to occur in 191 /* Reschedule the ct_kill timer to occur in
194 * CT_KILL_EXIT_DURATION seconds to ensure we get a 192 * CT_KILL_EXIT_DURATION seconds to ensure we get a
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 7ef47389953e..276410d82de4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -55,13 +55,10 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
55{ 55{
56 u32 value = 0x5a5a5a5a; 56 u32 value = 0x5a5a5a5a;
57 unsigned long flags; 57 unsigned long flags;
58 58 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
59 spin_lock_irqsave(&trans->reg_lock, flags);
60 if (iwl_trans_grab_nic_access(trans, false)) {
61 value = iwl_read32(trans, reg); 59 value = iwl_read32(trans, reg);
62 iwl_trans_release_nic_access(trans); 60 iwl_trans_release_nic_access(trans, &flags);
63 } 61 }
64 spin_unlock_irqrestore(&trans->reg_lock, flags);
65 62
66 return value; 63 return value;
67} 64}
@@ -71,12 +68,10 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
71{ 68{
72 unsigned long flags; 69 unsigned long flags;
73 70
74 spin_lock_irqsave(&trans->reg_lock, flags); 71 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
75 if (iwl_trans_grab_nic_access(trans, false)) {
76 iwl_write32(trans, reg, value); 72 iwl_write32(trans, reg, value);
77 iwl_trans_release_nic_access(trans); 73 iwl_trans_release_nic_access(trans, &flags);
78 } 74 }
79 spin_unlock_irqrestore(&trans->reg_lock, flags);
80} 75}
81EXPORT_SYMBOL_GPL(iwl_write_direct32); 76EXPORT_SYMBOL_GPL(iwl_write_direct32);
82 77
@@ -114,12 +109,10 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
114 unsigned long flags; 109 unsigned long flags;
115 u32 val = 0x5a5a5a5a; 110 u32 val = 0x5a5a5a5a;
116 111
117 spin_lock_irqsave(&trans->reg_lock, flags); 112 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
118 if (iwl_trans_grab_nic_access(trans, false)) {
119 val = __iwl_read_prph(trans, ofs); 113 val = __iwl_read_prph(trans, ofs);
120 iwl_trans_release_nic_access(trans); 114 iwl_trans_release_nic_access(trans, &flags);
121 } 115 }
122 spin_unlock_irqrestore(&trans->reg_lock, flags);
123 return val; 116 return val;
124} 117}
125EXPORT_SYMBOL_GPL(iwl_read_prph); 118EXPORT_SYMBOL_GPL(iwl_read_prph);
@@ -128,12 +121,10 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
128{ 121{
129 unsigned long flags; 122 unsigned long flags;
130 123
131 spin_lock_irqsave(&trans->reg_lock, flags); 124 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
132 if (iwl_trans_grab_nic_access(trans, false)) {
133 __iwl_write_prph(trans, ofs, val); 125 __iwl_write_prph(trans, ofs, val);
134 iwl_trans_release_nic_access(trans); 126 iwl_trans_release_nic_access(trans, &flags);
135 } 127 }
136 spin_unlock_irqrestore(&trans->reg_lock, flags);
137} 128}
138EXPORT_SYMBOL_GPL(iwl_write_prph); 129EXPORT_SYMBOL_GPL(iwl_write_prph);
139 130
@@ -141,13 +132,11 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
141{ 132{
142 unsigned long flags; 133 unsigned long flags;
143 134
144 spin_lock_irqsave(&trans->reg_lock, flags); 135 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
145 if (iwl_trans_grab_nic_access(trans, false)) {
146 __iwl_write_prph(trans, ofs, 136 __iwl_write_prph(trans, ofs,
147 __iwl_read_prph(trans, ofs) | mask); 137 __iwl_read_prph(trans, ofs) | mask);
148 iwl_trans_release_nic_access(trans); 138 iwl_trans_release_nic_access(trans, &flags);
149 } 139 }
150 spin_unlock_irqrestore(&trans->reg_lock, flags);
151} 140}
152EXPORT_SYMBOL_GPL(iwl_set_bits_prph); 141EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
153 142
@@ -156,13 +145,11 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
156{ 145{
157 unsigned long flags; 146 unsigned long flags;
158 147
159 spin_lock_irqsave(&trans->reg_lock, flags); 148 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
160 if (iwl_trans_grab_nic_access(trans, false)) {
161 __iwl_write_prph(trans, ofs, 149 __iwl_write_prph(trans, ofs,
162 (__iwl_read_prph(trans, ofs) & mask) | bits); 150 (__iwl_read_prph(trans, ofs) & mask) | bits);
163 iwl_trans_release_nic_access(trans); 151 iwl_trans_release_nic_access(trans, &flags);
164 } 152 }
165 spin_unlock_irqrestore(&trans->reg_lock, flags);
166} 153}
167EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph); 154EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
168 155
@@ -171,12 +158,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
171 unsigned long flags; 158 unsigned long flags;
172 u32 val; 159 u32 val;
173 160
174 spin_lock_irqsave(&trans->reg_lock, flags); 161 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
175 if (iwl_trans_grab_nic_access(trans, false)) {
176 val = __iwl_read_prph(trans, ofs); 162 val = __iwl_read_prph(trans, ofs);
177 __iwl_write_prph(trans, ofs, (val & ~mask)); 163 __iwl_write_prph(trans, ofs, (val & ~mask));
178 iwl_trans_release_nic_access(trans); 164 iwl_trans_release_nic_access(trans, &flags);
179 } 165 }
180 spin_unlock_irqrestore(&trans->reg_lock, flags);
181} 166}
182EXPORT_SYMBOL_GPL(iwl_clear_bits_prph); 167EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index d06fc55067df..ce0c67b425ee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -466,9 +466,7 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
466 /* Hard-coded periphery absolute address */ 466 /* Hard-coded periphery absolute address */
467 if (IWL_ABS_PRPH_START <= addr && 467 if (IWL_ABS_PRPH_START <= addr &&
468 addr < IWL_ABS_PRPH_START + PRPH_END) { 468 addr < IWL_ABS_PRPH_START + PRPH_END) {
469 spin_lock_irqsave(&trans->reg_lock, flags); 469 if (!iwl_trans_grab_nic_access(trans, false, &flags)) {
470 if (!iwl_trans_grab_nic_access(trans, false)) {
471 spin_unlock_irqrestore(&trans->reg_lock, flags);
472 return -EIO; 470 return -EIO;
473 } 471 }
474 iwl_write32(trans, HBUS_TARG_PRPH_RADDR, 472 iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
@@ -476,8 +474,7 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
476 for (i = 0; i < size; i += 4) 474 for (i = 0; i < size; i += 4)
477 *(u32 *)(tst->mem.addr + i) = 475 *(u32 *)(tst->mem.addr + i) =
478 iwl_read32(trans, HBUS_TARG_PRPH_RDAT); 476 iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
479 iwl_trans_release_nic_access(trans); 477 iwl_trans_release_nic_access(trans, &flags);
480 spin_unlock_irqrestore(&trans->reg_lock, flags);
481 } else { /* target memory (SRAM) */ 478 } else { /* target memory (SRAM) */
482 iwl_trans_read_mem(trans, addr, tst->mem.addr, 479 iwl_trans_read_mem(trans, addr, tst->mem.addr,
483 tst->mem.size / 4); 480 tst->mem.size / 4);
@@ -506,19 +503,13 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
506 /* Periphery writes can be 1-3 bytes long, or DWORDs */ 503 /* Periphery writes can be 1-3 bytes long, or DWORDs */
507 if (size < 4) { 504 if (size < 4) {
508 memcpy(&val, buf, size); 505 memcpy(&val, buf, size);
509 spin_lock_irqsave(&trans->reg_lock, flags); 506 if (!iwl_trans_grab_nic_access(trans, false, &flags))
510 if (!iwl_trans_grab_nic_access(trans, false)) {
511 spin_unlock_irqrestore(&trans->reg_lock, flags);
512 return -EIO; 507 return -EIO;
513 }
514 iwl_write32(trans, HBUS_TARG_PRPH_WADDR, 508 iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
515 (addr & 0x0000FFFF) | 509 (addr & 0x0000FFFF) |
516 ((size - 1) << 24)); 510 ((size - 1) << 24));
517 iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); 511 iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
518 iwl_trans_release_nic_access(trans); 512 iwl_trans_release_nic_access(trans, &flags);
519 /* needed after consecutive writes w/o read */
520 mmiowb();
521 spin_unlock_irqrestore(&trans->reg_lock, flags);
522 } else { 513 } else {
523 if (size % 4) 514 if (size % 4)
524 return -EINVAL; 515 return -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index c2b7e856a726..0a3d4df5f434 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -416,8 +416,11 @@ struct iwl_trans;
416 * the op_mode. May be called several times before start_fw, can't be 416 * the op_mode. May be called several times before start_fw, can't be
417 * called after that. 417 * called after that.
418 * @set_pmi: set the power pmi state 418 * @set_pmi: set the power pmi state
419 * @grab_nic_access: wake the NIC to be able to access non-HBUS regs 419 * @grab_nic_access: wake the NIC to be able to access non-HBUS regs.
420 * @release_nic_access: let the NIC go to sleep 420 * Sleeping is not allowed between grab_nic_access and
421 * release_nic_access.
422 * @release_nic_access: let the NIC go to sleep. The "flags" parameter
423 * must be the same one that was sent before to the grab_nic_access.
421 * @set_bits_mask - set SRAM register according to value and mask. 424 * @set_bits_mask - set SRAM register according to value and mask.
422 */ 425 */
423struct iwl_trans_ops { 426struct iwl_trans_ops {
@@ -461,8 +464,10 @@ struct iwl_trans_ops {
461 void (*configure)(struct iwl_trans *trans, 464 void (*configure)(struct iwl_trans *trans,
462 const struct iwl_trans_config *trans_cfg); 465 const struct iwl_trans_config *trans_cfg);
463 void (*set_pmi)(struct iwl_trans *trans, bool state); 466 void (*set_pmi)(struct iwl_trans *trans, bool state);
464 bool (*grab_nic_access)(struct iwl_trans *trans, bool silent); 467 bool (*grab_nic_access)(struct iwl_trans *trans, bool silent,
465 void (*release_nic_access)(struct iwl_trans *trans); 468 unsigned long *flags);
469 void (*release_nic_access)(struct iwl_trans *trans,
470 unsigned long *flags);
466 void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, 471 void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask,
467 u32 value); 472 u32 value);
468}; 473};
@@ -484,7 +489,6 @@ enum iwl_trans_state {
484 * @ops - pointer to iwl_trans_ops 489 * @ops - pointer to iwl_trans_ops
485 * @op_mode - pointer to the op_mode 490 * @op_mode - pointer to the op_mode
486 * @cfg - pointer to the configuration 491 * @cfg - pointer to the configuration
487 * @reg_lock - protect hw register access
488 * @dev - pointer to struct device * that represents the device 492 * @dev - pointer to struct device * that represents the device
489 * @hw_id: a u32 with the ID of the device / subdevice. 493 * @hw_id: a u32 with the ID of the device / subdevice.
490 * Set during transport allocation. 494 * Set during transport allocation.
@@ -505,7 +509,6 @@ struct iwl_trans {
505 struct iwl_op_mode *op_mode; 509 struct iwl_op_mode *op_mode;
506 const struct iwl_cfg *cfg; 510 const struct iwl_cfg *cfg;
507 enum iwl_trans_state state; 511 enum iwl_trans_state state;
508 spinlock_t reg_lock;
509 512
510 struct device *dev; 513 struct device *dev;
511 u32 hw_rev; 514 u32 hw_rev;
@@ -771,14 +774,14 @@ iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
771 trans->ops->set_bits_mask(trans, reg, mask, value); 774 trans->ops->set_bits_mask(trans, reg, mask, value);
772} 775}
773 776
774#define iwl_trans_grab_nic_access(trans, silent) \ 777#define iwl_trans_grab_nic_access(trans, silent, flags) \
775 __cond_lock(nic_access, \ 778 __cond_lock(nic_access, \
776 likely((trans)->ops->grab_nic_access(trans, silent))) 779 likely((trans)->ops->grab_nic_access(trans, silent, flags)))
777 780
778static inline void __releases(nic_access) 781static inline void __releases(nic_access)
779iwl_trans_release_nic_access(struct iwl_trans *trans) 782iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
780{ 783{
781 trans->ops->release_nic_access(trans); 784 trans->ops->release_nic_access(trans, flags);
782 __release(nic_access); 785 __release(nic_access);
783} 786}
784 787
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 21395fae03c0..5f6bb4e09d42 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -235,6 +235,7 @@ struct iwl_txq {
235 * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) 235 * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
236 * @rx_page_order: page order for receive buffer size 236 * @rx_page_order: page order for receive buffer size
237 * @wd_timeout: queue watchdog timeout (jiffies) 237 * @wd_timeout: queue watchdog timeout (jiffies)
238 * @reg_lock: protect hw register access
238 */ 239 */
239struct iwl_trans_pcie { 240struct iwl_trans_pcie {
240 struct iwl_rxq rxq; 241 struct iwl_rxq rxq;
@@ -283,6 +284,9 @@ struct iwl_trans_pcie {
283 284
284 /* queue watchdog */ 285 /* queue watchdog */
285 unsigned long wd_timeout; 286 unsigned long wd_timeout;
287
288 /*protect hw register */
289 spinlock_t reg_lock;
286}; 290};
287 291
288/** 292/**
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 8692494c1c48..56d4f72500bc 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -806,11 +806,12 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
806} 806}
807#endif /* CONFIG_PM_SLEEP */ 807#endif /* CONFIG_PM_SLEEP */
808 808
809static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) 809static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
810 unsigned long *flags)
810{ 811{
811 int ret; 812 int ret;
812 813 struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
813 lockdep_assert_held(&trans->reg_lock); 814 spin_lock_irqsave(&pcie_trans->reg_lock, *flags);
814 815
815 /* this bit wakes up the NIC */ 816 /* this bit wakes up the NIC */
816 __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, 817 __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
@@ -846,16 +847,32 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
846 WARN_ONCE(1, 847 WARN_ONCE(1,
847 "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", 848 "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
848 val); 849 val);
850 spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
849 return false; 851 return false;
850 } 852 }
851 } 853 }
852 854
855 /*
856 * Fool sparse by faking we release the lock - sparse will
857 * track nic_access anyway.
858 */
859 __release(&pcie_trans->reg_lock);
853 return true; 860 return true;
854} 861}
855 862
856static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) 863static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
864 unsigned long *flags)
857{ 865{
858 lockdep_assert_held(&trans->reg_lock); 866 struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
867
868 lockdep_assert_held(&pcie_trans->reg_lock);
869
870 /*
871 * Fool sparse by faking we acquiring the lock - sparse will
872 * track nic_access anyway.
873 */
874 __acquire(&pcie_trans->reg_lock);
875
859 __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, 876 __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
860 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 877 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
861 /* 878 /*
@@ -865,6 +882,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
865 * scheduled on different CPUs (after we drop reg_lock). 882 * scheduled on different CPUs (after we drop reg_lock).
866 */ 883 */
867 mmiowb(); 884 mmiowb();
885 spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
868} 886}
869 887
870static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, 888static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
@@ -874,16 +892,14 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
874 int offs, ret = 0; 892 int offs, ret = 0;
875 u32 *vals = buf; 893 u32 *vals = buf;
876 894
877 spin_lock_irqsave(&trans->reg_lock, flags); 895 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
878 if (iwl_trans_grab_nic_access(trans, false)) {
879 iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); 896 iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
880 for (offs = 0; offs < dwords; offs++) 897 for (offs = 0; offs < dwords; offs++)
881 vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); 898 vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
882 iwl_trans_release_nic_access(trans); 899 iwl_trans_release_nic_access(trans, &flags);
883 } else { 900 } else {
884 ret = -EBUSY; 901 ret = -EBUSY;
885 } 902 }
886 spin_unlock_irqrestore(&trans->reg_lock, flags);
887 return ret; 903 return ret;
888} 904}
889 905
@@ -894,17 +910,15 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
894 int offs, ret = 0; 910 int offs, ret = 0;
895 u32 *vals = buf; 911 u32 *vals = buf;
896 912
897 spin_lock_irqsave(&trans->reg_lock, flags); 913 if (iwl_trans_grab_nic_access(trans, false, &flags)) {
898 if (iwl_trans_grab_nic_access(trans, false)) {
899 iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); 914 iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
900 for (offs = 0; offs < dwords; offs++) 915 for (offs = 0; offs < dwords; offs++)
901 iwl_write32(trans, HBUS_TARG_MEM_WDAT, 916 iwl_write32(trans, HBUS_TARG_MEM_WDAT,
902 vals ? vals[offs] : 0); 917 vals ? vals[offs] : 0);
903 iwl_trans_release_nic_access(trans); 918 iwl_trans_release_nic_access(trans, &flags);
904 } else { 919 } else {
905 ret = -EBUSY; 920 ret = -EBUSY;
906 } 921 }
907 spin_unlock_irqrestore(&trans->reg_lock, flags);
908 return ret; 922 return ret;
909} 923}
910 924
@@ -982,11 +996,12 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
982static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, 996static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
983 u32 mask, u32 value) 997 u32 mask, u32 value)
984{ 998{
999 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
985 unsigned long flags; 1000 unsigned long flags;
986 1001
987 spin_lock_irqsave(&trans->reg_lock, flags); 1002 spin_lock_irqsave(&trans_pcie->reg_lock, flags);
988 __iwl_trans_pcie_set_bits_mask(trans, reg, mask, value); 1003 __iwl_trans_pcie_set_bits_mask(trans, reg, mask, value);
989 spin_unlock_irqrestore(&trans->reg_lock, flags); 1004 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
990} 1005}
991 1006
992static const char *get_fh_string(int cmd) 1007static const char *get_fh_string(int cmd)
@@ -1467,6 +1482,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
1467 trans->cfg = cfg; 1482 trans->cfg = cfg;
1468 trans_pcie->trans = trans; 1483 trans_pcie->trans = trans;
1469 spin_lock_init(&trans_pcie->irq_lock); 1484 spin_lock_init(&trans_pcie->irq_lock);
1485 spin_lock_init(&trans_pcie->reg_lock);
1470 init_waitqueue_head(&trans_pcie->ucode_write_waitq); 1486 init_waitqueue_head(&trans_pcie->ucode_write_waitq);
1471 1487
1472 /* W/A - seems to solve weird behavior. We need to remove this if we 1488 /* W/A - seems to solve weird behavior. We need to remove this if we
@@ -1533,7 +1549,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
1533 1549
1534 /* Initialize the wait queue for commands */ 1550 /* Initialize the wait queue for commands */
1535 init_waitqueue_head(&trans_pcie->wait_command_queue); 1551 init_waitqueue_head(&trans_pcie->wait_command_queue);
1536 spin_lock_init(&trans->reg_lock);
1537 1552
1538 snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), 1553 snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
1539 "iwl_cmd_pool:%s", dev_name(trans->dev)); 1554 "iwl_cmd_pool:%s", dev_name(trans->dev));