base = priv->device_pointers.error_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) {
- spin_lock_irqsave(&priv->trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(priv->trans, true)) {
+ if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) {
iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
- iwl_trans_release_nic_access(priv->trans);
+ iwl_trans_release_nic_access(priv->trans, &flags);
ret = 0;
}
- spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (ret == 0) {
ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
/* Make sure device is powered up for SRAM reads */
- spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
- if (!iwl_trans_grab_nic_access(priv->trans, false)) {
- spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+ if (!iwl_trans_grab_nic_access(priv->trans, false, ®_flags))
return;
- }
/* Set starting address; reads will auto-increment */
iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
}
}
/* Allow device to power down */
- iwl_trans_release_nic_access(priv->trans);
- spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+ iwl_trans_release_nic_access(priv->trans, ®_flags);
}
static void iwl_continuous_event_trace(struct iwl_priv *priv)
ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
/* Make sure device is powered up for SRAM reads */
- spin_lock_irqsave(&trans->reg_lock, reg_flags);
- if (!iwl_trans_grab_nic_access(trans, false))
- goto out_unlock;
+ if (!iwl_trans_grab_nic_access(trans, false, ®_flags))
+ return pos;
/* Set starting address; reads will auto-increment */
iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
}
/* Allow device to power down */
- iwl_trans_release_nic_access(trans);
-out_unlock:
- spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
+ iwl_trans_release_nic_access(trans, ®_flags);
return pos;
}
priv->thermal_throttle.ct_kill_toggle = true;
}
iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
- spin_lock_irqsave(&priv->trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(priv->trans, false))
- iwl_trans_release_nic_access(priv->trans);
- spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+ if (iwl_trans_grab_nic_access(priv->trans, false, &flags))
+ iwl_trans_release_nic_access(priv->trans, &flags);
/* Reschedule the ct_kill timer to occur in
* CT_KILL_EXIT_DURATION seconds to ensure we get a
{
u32 value = 0x5a5a5a5a;
unsigned long flags;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
value = iwl_read32(trans, reg);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
return value;
}
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
iwl_write32(trans, reg, value);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_write_direct32);
unsigned long flags;
u32 val = 0x5a5a5a5a;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
val = __iwl_read_prph(trans, ofs);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
return val;
}
EXPORT_SYMBOL_GPL(iwl_read_prph);
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
__iwl_write_prph(trans, ofs, val);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_write_prph);
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
__iwl_write_prph(trans, ofs,
__iwl_read_prph(trans, ofs) | mask);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
__iwl_write_prph(trans, ofs,
(__iwl_read_prph(trans, ofs) & mask) | bits);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
unsigned long flags;
u32 val;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
val = __iwl_read_prph(trans, ofs);
__iwl_write_prph(trans, ofs, (val & ~mask));
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
/* Hard-coded periphery absolute address */
if (IWL_ABS_PRPH_START <= addr &&
addr < IWL_ABS_PRPH_START + PRPH_END) {
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (!iwl_trans_grab_nic_access(trans, false)) {
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ if (!iwl_trans_grab_nic_access(trans, false, &flags)) {
return -EIO;
}
iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
for (i = 0; i < size; i += 4)
*(u32 *)(tst->mem.addr + i) =
iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
- iwl_trans_release_nic_access(trans);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ iwl_trans_release_nic_access(trans, &flags);
} else { /* target memory (SRAM) */
iwl_trans_read_mem(trans, addr, tst->mem.addr,
tst->mem.size / 4);
/* Periphery writes can be 1-3 bytes long, or DWORDs */
if (size < 4) {
memcpy(&val, buf, size);
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (!iwl_trans_grab_nic_access(trans, false)) {
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ if (!iwl_trans_grab_nic_access(trans, false, &flags))
return -EIO;
- }
iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
(addr & 0x0000FFFF) |
((size - 1) << 24));
iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
- iwl_trans_release_nic_access(trans);
- /* needed after consecutive writes w/o read */
- mmiowb();
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ iwl_trans_release_nic_access(trans, &flags);
} else {
if (size % 4)
return -EINVAL;
* 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
+ * @grab_nic_access: wake the NIC to be able to access non-HBUS regs.
+ * Sleeping is not allowed between grab_nic_access and
+ * release_nic_access.
+ * @release_nic_access: let the NIC go to sleep. The "flags" parameter
+ * must be the same one that was sent before to the grab_nic_access.
* @set_bits_mask - set SRAM register according to value and mask.
*/
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);
+ bool (*grab_nic_access)(struct iwl_trans *trans, bool silent,
+ unsigned long *flags);
+ void (*release_nic_access)(struct iwl_trans *trans,
+ unsigned long *flags);
void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask,
u32 value);
};
* @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @cfg - pointer to the configuration
- * @reg_lock - protect hw register access
* @dev - pointer to struct device * that represents the device
* @hw_id: a u32 with the ID of the device / subdevice.
* Set during transport allocation.
struct iwl_op_mode *op_mode;
const struct iwl_cfg *cfg;
enum iwl_trans_state state;
- spinlock_t reg_lock;
struct device *dev;
u32 hw_rev;
trans->ops->set_bits_mask(trans, reg, mask, value);
}
-#define iwl_trans_grab_nic_access(trans, silent) \
+#define iwl_trans_grab_nic_access(trans, silent, flags) \
__cond_lock(nic_access, \
- likely((trans)->ops->grab_nic_access(trans, silent)))
+ likely((trans)->ops->grab_nic_access(trans, silent, flags)))
static inline void __releases(nic_access)
-iwl_trans_release_nic_access(struct iwl_trans *trans)
+iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
{
- trans->ops->release_nic_access(trans);
+ trans->ops->release_nic_access(trans, flags);
__release(nic_access);
}
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
* @rx_page_order: page order for receive buffer size
* @wd_timeout: queue watchdog timeout (jiffies)
+ * @reg_lock: protect hw register access
*/
struct iwl_trans_pcie {
struct iwl_rxq rxq;
/* queue watchdog */
unsigned long wd_timeout;
+
+ /*protect hw register */
+ spinlock_t reg_lock;
};
/**
}
#endif /* CONFIG_PM_SLEEP */
-static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
+static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
+ unsigned long *flags)
{
int ret;
-
- lockdep_assert_held(&trans->reg_lock);
+ struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
+ spin_lock_irqsave(&pcie_trans->reg_lock, *flags);
/* this bit wakes up the NIC */
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
WARN_ONCE(1,
"Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
val);
+ spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
return false;
}
}
+ /*
+ * Fool sparse by faking we release the lock - sparse will
+ * track nic_access anyway.
+ */
+ __release(&pcie_trans->reg_lock);
return true;
}
-static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
+static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
+ unsigned long *flags)
{
- lockdep_assert_held(&trans->reg_lock);
+ struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ lockdep_assert_held(&pcie_trans->reg_lock);
+
+ /*
+ * Fool sparse by faking we acquiring the lock - sparse will
+ * track nic_access anyway.
+ */
+ __acquire(&pcie_trans->reg_lock);
+
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* scheduled on different CPUs (after we drop reg_lock).
*/
mmiowb();
+ spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
}
static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
int offs, ret = 0;
u32 *vals = buf;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
for (offs = 0; offs < dwords; offs++)
vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
} else {
ret = -EBUSY;
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
return ret;
}
int offs, ret = 0;
u32 *vals = buf;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (iwl_trans_grab_nic_access(trans, false)) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
for (offs = 0; offs < dwords; offs++)
iwl_write32(trans, HBUS_TARG_MEM_WDAT,
vals ? vals[offs] : 0);
- iwl_trans_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
} else {
ret = -EBUSY;
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
return ret;
}
static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
u32 mask, u32 value)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
+ spin_lock_irqsave(&trans_pcie->reg_lock, flags);
__iwl_trans_pcie_set_bits_mask(trans, reg, mask, value);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
}
static const char *get_fh_string(int cmd)
trans->cfg = cfg;
trans_pcie->trans = trans;
spin_lock_init(&trans_pcie->irq_lock);
+ spin_lock_init(&trans_pcie->reg_lock);
init_waitqueue_head(&trans_pcie->ucode_write_waitq);
/* W/A - seems to solve weird behavior. We need to remove this if we
/* Initialize the wait queue for commands */
init_waitqueue_head(&trans_pcie->wait_command_queue);
- spin_lock_init(&trans->reg_lock);
snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
"iwl_cmd_pool:%s", dev_name(trans->dev));