2013-01-03 14:45:03

by Johannes Berg

[permalink] [raw]
Subject: pull-request: iwlwifi-next 2012-01-03

John,

My last pull request for today :-)

For iwlwifi-next, I have a few cleanups/improvements as well as a few
not very important fixes and more preparations for new devices.

Let me know if there are any problems.

Thanks,
johannes


The following changes since commit a49f0d1ea3ec94fc7cf33a7c36a16343b74bd565:

Linux 3.8-rc1 (2012-12-21 17:19:00 -0800)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git for-john

for you to fetch changes up to abae2386d55aff1d395cdb665f03684c227a6a69:

iwlwifi: always check that grab_nic_access succeeds (2013-01-03 15:34:11 +0100)

----------------------------------------------------------------
Emmanuel Grumbach (8):
iwlwifi: make the BC table layout configurable
iwlwifi: clean up code in AGG
iwlwifi: don't verify fw after download
iwlwifi: let the op_mode run a FW while in RFKILL
iwlwifi: virtualize iwl_{grab,release}_nic_access
iwlwifi: virtualize SRAM access
iwlwifi: don't treat a bool as an error code
iwlwifi: always check that grab_nic_access succeeds

Eytan Lifshitz (1):
iwlwifi: fix spelling and value in LED registers.

Johannes Berg (3):
iwlwifi: use __packed
iwlwifi: request IRQ only once
iwlwifi: move some PCIe calls to better places

drivers/net/wireless/iwlwifi/dvm/commands.h | 8 +-
drivers/net/wireless/iwlwifi/dvm/debugfs.c | 4 +-
drivers/net/wireless/iwlwifi/dvm/led.c | 2 +-
drivers/net/wireless/iwlwifi/dvm/mac80211.c | 8 +-
drivers/net/wireless/iwlwifi/dvm/main.c | 21 ++--
drivers/net/wireless/iwlwifi/dvm/tt.c | 4 +-
drivers/net/wireless/iwlwifi/dvm/tx.c | 21 ++--
drivers/net/wireless/iwlwifi/dvm/ucode.c | 96 +-------------
drivers/net/wireless/iwlwifi/iwl-csr.h | 4 +-
drivers/net/wireless/iwlwifi/iwl-io.c | 168 ++++---------------------
drivers/net/wireless/iwlwifi/iwl-io.h | 21 +---
drivers/net/wireless/iwlwifi/iwl-test.c | 53 ++++----
drivers/net/wireless/iwlwifi/iwl-trans.h | 69 ++++++++++-
drivers/net/wireless/iwlwifi/pcie/internal.h | 6 +-
drivers/net/wireless/iwlwifi/pcie/rx.c | 2 +
drivers/net/wireless/iwlwifi/pcie/trans.c | 179 ++++++++++++++++++++-------
drivers/net/wireless/iwlwifi/pcie/tx.c | 31 ++---
17 files changed, 311 insertions(+), 386 deletions(-)


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2013-01-03 14:45:55

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 08/12] iwlwifi: don't treat a bool as an error code

From: Emmanuel Grumbach <[email protected]>

iwl_trans_grab_nic_access returns a boolean. So ret should
explicitely set to an error code and not rely on the value
returned by iwl_trans_grab_nic_access.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/mac80211.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 9c1f055..1ed4bc6 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -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_trans_grab_nic_access(priv->trans, true);
- if (likely(ret == 0)) {
+ if (iwl_trans_grab_nic_access(priv->trans, true)) {
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);
+ ret = 0;
}
spin_unlock_irqrestore(&priv->trans->reg_lock, flags);

--
1.8.0


2013-01-03 14:45:51

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 02/12] iwlwifi: clean up code in AGG

From: Emmanuel Grumbach <[email protected]>

If we take a pointer to the tid_data, then use it.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/tx.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index da21328..df76881 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -541,9 +541,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
spin_lock_bh(&priv->sta_lock);

tid_data = &priv->tid_data[sta_id][tid];
- txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+ txq_id = tid_data->agg.txq_id;

- switch (priv->tid_data[sta_id][tid].agg.state) {
+ switch (tid_data->agg.state) {
case IWL_EMPTYING_HW_QUEUE_ADDBA:
/*
* This can happen if the peer stops aggregation
@@ -563,9 +563,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
case IWL_AGG_ON:
break;
default:
- IWL_WARN(priv, "Stopping AGG while state not ON "
- "or starting for %d on %d (%d)\n", sta_id, tid,
- priv->tid_data[sta_id][tid].agg.state);
+ IWL_WARN(priv,
+ "Stopping AGG while state not ON or starting for %d on %d (%d)\n",
+ sta_id, tid, tid_data->agg.state);
spin_unlock_bh(&priv->sta_lock);
return 0;
}
@@ -578,12 +578,11 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
"stopping AGG on STA/TID %d/%d but hwq %d not used\n",
sta_id, tid, txq_id);
} else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
- IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
- "next_recl = %d\n",
+ IWL_DEBUG_TX_QUEUES(priv,
+ "Can't proceed: ssn %d, next_recl = %d\n",
tid_data->agg.ssn,
tid_data->next_reclaimed);
- priv->tid_data[sta_id][tid].agg.state =
- IWL_EMPTYING_HW_QUEUE_DELBA;
+ tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA;
spin_unlock_bh(&priv->sta_lock);
return 0;
}
@@ -591,8 +590,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
tid_data->agg.ssn);
turn_off:
- agg_state = priv->tid_data[sta_id][tid].agg.state;
- priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
+ agg_state = tid_data->agg.state;
+ tid_data->agg.state = IWL_AGG_OFF;

spin_unlock_bh(&priv->sta_lock);

--
1.8.0


2013-01-03 14:45:55

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 10/12] iwlwifi: move some PCIe calls to better places

From: Johannes Berg <[email protected]>

Synchronizing the IRQ is pointless when we will
then enable the RF-Kill interrupt again, but is
needed before we free it and the data needed to
handle IRQs; move it to the free function.

Simiarly, cancelling the replenish work struct
can move to the function that frees the RX data
structures.

Reviewed-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/pcie/rx.c | 2 ++
drivers/net/wireless/iwlwifi/pcie/trans.c | 9 +++------
2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index dad4c4a..02c9016 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -545,6 +545,8 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
return;
}

+ cancel_work_sync(&trans_pcie->rx_replenish);
+
spin_lock_irqsave(&rxq->lock, flags);
iwl_pcie_rxq_free_rbs(trans);
spin_unlock_irqrestore(&rxq->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 48cd65e..bca6203 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -534,12 +534,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)

iwl_enable_rfkill_int(trans);

- /* wait to make sure we flush pending tasklet*/
- synchronize_irq(trans_pcie->pci_dev->irq);
- tasklet_kill(&trans_pcie->irq_tasklet);
-
- cancel_work_sync(&trans_pcie->rx_replenish);
-
/* stop and reset the on-board processor */
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);

@@ -682,6 +676,9 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);

+ synchronize_irq(trans_pcie->pci_dev->irq);
+ tasklet_kill(&trans_pcie->irq_tasklet);
+
iwl_pcie_tx_free(trans);
iwl_pcie_rx_free(trans);

--
1.8.0


2013-01-03 14:49:36

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 11/12] iwlwifi: fix spelling and value in LED registers.

From: Eytan Lifshitz <[email protected]>

Fix typo in the macro name and the wrong value.

Signed-off-by: Eytan Lifshitz <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/led.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-csr.h | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c
index bf479f7..844a17f 100644
--- a/drivers/net/wireless/iwlwifi/dvm/led.c
+++ b/drivers/net/wireless/iwlwifi/dvm/led.c
@@ -69,7 +69,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = {
/* Set led register off */
void iwlagn_led_enable(struct iwl_priv *priv)
{
- iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+ iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
}

/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 34a5287..b419a1e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -381,8 +381,8 @@

/* LED */
#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
-#define CSR_LED_REG_TRUN_ON (0x78)
-#define CSR_LED_REG_TRUN_OFF (0x38)
+#define CSR_LED_REG_TURN_ON (0x60)
+#define CSR_LED_REG_TURN_OFF (0x20)

/* ANA_PLL */
#define CSR50_ANA_PLL_CFG_VAL (0x00880300)
--
1.8.0


2013-01-03 14:45:51

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 01/12] iwlwifi: make the BC table layout configurable

From: Emmanuel Grumbach <[email protected]>

This is needed for newer NICs.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans.h | 3 +++
drivers/net/wireless/iwlwifi/pcie/internal.h | 2 ++
drivers/net/wireless/iwlwifi/pcie/trans.c | 1 +
drivers/net/wireless/iwlwifi/pcie/tx.c | 5 ++++-
4 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index b76532e..15b4700 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -321,6 +321,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
* @n_no_reclaim_cmds: # of commands in list
* @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs,
* if unset 4k will be the RX buffer size
+ * @bc_table_dword: set to true if the BC table expects the byte count to be
+ * in DWORD (as opposed to bytes)
* @queue_watchdog_timeout: time (in ms) after which queues
* are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries
@@ -335,6 +337,7 @@ struct iwl_trans_config {
int n_no_reclaim_cmds;

bool rx_buf_size_8k;
+ bool bc_table_dword;
unsigned int queue_watchdog_timeout;
const char **command_names;
};
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index d91d2e8..15f7975 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -234,6 +234,7 @@ struct iwl_txq {
* @status - transport specific status flags
* @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size
+ * @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)
*/
@@ -279,6 +280,7 @@ struct iwl_trans_pcie {
u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];

bool rx_buf_size_8k;
+ bool bc_table_dword;
u32 rx_page_order;

const char **command_names;
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 35708b9..ab179ce 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -703,6 +703,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);

trans_pcie->command_names = trans_cfg->command_names;
+ trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
}

void iwl_trans_pcie_free(struct iwl_trans *trans)
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 6c5b867..7af8f0b 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -237,7 +237,10 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
break;
}

- bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+ if (trans_pcie->bc_table_dword)
+ len = DIV_ROUND_UP(len, 4);
+
+ bc_ent = cpu_to_le16(len | (sta_id << 12));

scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;

--
1.8.0


2013-01-03 14:45:54

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 06/12] iwlwifi: virtualize iwl_{grab,release}_nic_access

From: Emmanuel Grumbach <[email protected]>

Since different transports have different ways to wake the
up the NIC, we need to virtualize it.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]el.com>
---
drivers/net/wireless/iwlwifi/dvm/mac80211.c | 4 +-
drivers/net/wireless/iwlwifi/dvm/main.c | 8 +-
drivers/net/wireless/iwlwifi/dvm/tt.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-io.c | 114 ++++++----------------------
drivers/net/wireless/iwlwifi/iwl-io.h | 6 +-
drivers/net/wireless/iwlwifi/iwl-test.c | 8 +-
drivers/net/wireless/iwlwifi/iwl-trans.h | 15 ++++
drivers/net/wireless/iwlwifi/pcie/trans.c | 64 ++++++++++++++++
8 files changed, 115 insertions(+), 108 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 3163e0f..8965a98 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -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);

diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index faa0593..c4caedd 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -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;
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
index eb86443..a8ae513 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.c
@@ -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
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index cdaff95..cb36fed 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -35,12 +35,12 @@

#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;
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 48dc753..40eb0a1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -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);

diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index 81e8c71..08c1cfe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 16a82b5..1d1f5d0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -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
******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index e67e179..80b05d8 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -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,
--
1.8.0


2013-01-03 14:45:54

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 07/12] iwlwifi: virtualize SRAM access

From: Emmanuel Grumbach <[email protected]>

Different transports implement the access to the SRAM in
different ways. Virtualize it.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/debugfs.c | 4 +--
drivers/net/wireless/iwlwifi/dvm/mac80211.c | 2 +-
drivers/net/wireless/iwlwifi/dvm/main.c | 13 +++----
drivers/net/wireless/iwlwifi/iwl-io.c | 56 -----------------------------
drivers/net/wireless/iwlwifi/iwl-io.h | 15 --------
drivers/net/wireless/iwlwifi/iwl-test.c | 7 ++--
drivers/net/wireless/iwlwifi/iwl-trans.h | 43 +++++++++++++++++++++-
drivers/net/wireless/iwlwifi/pcie/trans.c | 41 +++++++++++++++++++++
drivers/net/wireless/iwlwifi/pcie/tx.c | 26 +++++++-------
9 files changed, 109 insertions(+), 98 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
index 5b9533e..72c74af 100644
--- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
@@ -157,7 +157,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
sram = priv->dbgfs_sram_offset & ~0x3;

/* read the first u32 from sram */
- val = iwl_read_targ_mem(priv->trans, sram);
+ val = iwl_trans_read_mem32(priv->trans, sram);

for (; len; len--) {
/* put the address at the start of every line */
@@ -176,7 +176,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
if (++offset == 4) {
sram += 4;
offset = 0;
- val = iwl_read_targ_mem(priv->trans, sram);
+ val = iwl_trans_read_mem32(priv->trans, sram);
}

/* put in extra spaces and split lines for human readability */
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 8965a98..9c1f055 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -479,7 +479,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
}

if (priv->wowlan_sram)
- _iwl_read_targ_mem_dwords(
+ iwl_trans_read_mem(
priv->trans, 0x800000,
priv->wowlan_sram,
img->sec[IWL_UCODE_SECTION_DATA].len / 4);
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index c4caedd..517d7ae 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -408,7 +408,8 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)

base = priv->device_pointers.log_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) {
- iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read));
+ iwl_trans_read_mem_bytes(priv->trans, base,
+ &read, sizeof(read));
capacity = read.capacity;
mode = read.mode;
num_wraps = read.wrap_counter;
@@ -1627,7 +1628,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
}

/*TODO: Update dbgfs with ISR error stats obtained below */
- iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table));
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));

if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -1835,10 +1836,10 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
}

/* event log header */
- capacity = iwl_read_targ_mem(trans, base);
- mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
+ capacity = iwl_trans_read_mem32(trans, base);
+ mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32)));
+ num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32)));
+ next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32)));

if (capacity > logsize) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index cb36fed..2bd84ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -226,59 +226,3 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
-
-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- void *buf, int dwords)
-{
- unsigned long flags;
- int offs;
- u32 *vals = buf;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- 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_trans_release_nic_access(trans);
- }
- spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
-{
- u32 value;
-
- _iwl_read_targ_mem_dwords(trans, addr, &value, 1);
-
- return value;
-}
-EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- const void *buf, int dwords)
-{
- unsigned long flags;
- int offs, result = 0;
- const u32 *vals = buf;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- 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_trans_release_nic_access(trans);
- } else {
- result = -EBUSY;
- }
- spin_unlock_irqrestore(&trans->reg_lock, flags);
-
- return result;
-}
-EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords);
-
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
-{
- return _iwl_write_targ_mem_dwords(trans, addr, &val, 1);
-}
-EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 40eb0a1..dc47806 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -74,19 +74,4 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
u32 bits, u32 mask);
void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);

-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- void *buf, int dwords);
-
-#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize) \
- do { \
- BUILD_BUG_ON((bufsize) % sizeof(u32)); \
- _iwl_read_targ_mem_dwords(trans, addr, buf, \
- (bufsize) / sizeof(u32));\
- } while (0)
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- const void *buf, int dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index 08c1cfe..f8d8df8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -476,9 +476,8 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
iwl_trans_release_nic_access(trans);
spin_unlock_irqrestore(&trans->reg_lock, flags);
} else { /* target memory (SRAM) */
- _iwl_read_targ_mem_dwords(trans, addr,
- tst->mem.addr,
- tst->mem.size / 4);
+ iwl_trans_read_mem(trans, addr, tst->mem.addr,
+ tst->mem.size / 4);
}

tst->mem.nchunks =
@@ -522,7 +521,7 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
*(u32 *)(buf+i));
}
} else if (iwl_test_valid_hw_addr(tst, addr)) {
- _iwl_write_targ_mem_dwords(trans, addr, buf, size / 4);
+ iwl_trans_write_mem(trans, addr, buf, size / 4);
} else {
return -EINVAL;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 1d1f5d0..7584d55 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -390,6 +390,8 @@ struct iwl_trans;
* @read32: read a u32 register at offset ofs from the BAR
* @read_prph: read a DWORD from a periphery register
* @write_prph: write a DWORD to a periphery register
+ * @read_mem: read device's SRAM in DWORD
+ * @write_mem: write device's SRAM in DWORD
* @configure: configure parameters required by the transport layer from
* the op_mode. May be called several times before start_fw, can't be
* called after that.
@@ -430,6 +432,10 @@ struct iwl_trans_ops {
u32 (*read32)(struct iwl_trans *trans, u32 ofs);
u32 (*read_prph)(struct iwl_trans *trans, u32 ofs);
void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val);
+ int (*read_mem)(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords);
+ int (*write_mem)(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords);
void (*configure)(struct iwl_trans *trans,
const struct iwl_trans_config *trans_cfg);
void (*set_pmi)(struct iwl_trans *trans, bool state);
@@ -645,7 +651,7 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
}

static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
- struct dentry *dir)
+ struct dentry *dir)
{
return trans->ops->dbgfs_register(trans, dir);
}
@@ -688,6 +694,41 @@ static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs,
return trans->ops->write_prph(trans, ofs, val);
}

+static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ return trans->ops->read_mem(trans, addr, buf, dwords);
+}
+
+#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \
+ do { \
+ if (__builtin_constant_p(bufsize)) \
+ BUILD_BUG_ON((bufsize) % sizeof(u32)); \
+ iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\
+ } while (0)
+
+static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
+{
+ u32 value;
+
+ if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1)))
+ return 0xa5a5a5a5;
+
+ return value;
+}
+
+static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ return trans->ops->write_mem(trans, addr, buf, dwords);
+}
+
+static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
+ u32 val)
+{
+ return iwl_trans_write_mem(trans, addr, &val, 1);
+}
+
static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
{
trans->ops->set_pmi(trans, state);
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 80b05d8..3a40607 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -820,6 +820,45 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
mmiowb();
}

+static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ unsigned long flags;
+ int offs, ret = 0;
+ u32 *vals = buf;
+
+ spin_lock_irqsave(&trans->reg_lock, flags);
+ 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_trans_release_nic_access(trans);
+ } else {
+ ret = -EBUSY;
+ }
+ spin_unlock_irqrestore(&trans->reg_lock, flags);
+ return ret;
+}
+
+static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ unsigned long flags;
+ int offs, ret = 0;
+ u32 *vals = buf;
+
+ spin_lock_irqsave(&trans->reg_lock, flags);
+ 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_trans_release_nic_access(trans);
+ } else {
+ ret = -EBUSY;
+ }
+ spin_unlock_irqrestore(&trans->reg_lock, flags);
+ return ret;
+}

#define IWL_FLUSH_WAIT_MS 2000

@@ -1298,6 +1337,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.read32 = iwl_trans_pcie_read32,
.read_prph = iwl_trans_pcie_read_prph,
.write_prph = iwl_trans_pcie_write_prph,
+ .read_mem = iwl_trans_pcie_read_mem,
+ .write_mem = iwl_trans_pcie_write_mem,
.configure = iwl_trans_pcie_configure,
.set_pmi = iwl_trans_pcie_set_pmi,
.grab_nic_access = iwl_trans_pcie_grab_nic_access,
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 7af8f0b..d25fc8a 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -160,7 +160,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
txq->q.read_ptr, txq->q.write_ptr);

- iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+ iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));

iwl_print_hex_error(trans, buf, sizeof(buf));

@@ -173,9 +173,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
u32 tbl_dw =
- iwl_read_targ_mem(trans,
- trans_pcie->scd_base_addr +
- SCD_TRANS_TBL_OFFSET_QUEUE(i));
+ iwl_trans_read_mem32(trans,
+ trans_pcie->scd_base_addr +
+ SCD_TRANS_TBL_OFFSET_QUEUE(i));

if (i & 0x1)
tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
@@ -659,16 +659,16 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
/* reset conext data memory */
for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
a += 4)
- iwl_write_targ_mem(trans, a, 0);
+ iwl_trans_write_mem32(trans, a, 0);
/* reset tx status memory */
for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
a += 4)
- iwl_write_targ_mem(trans, a, 0);
+ iwl_trans_write_mem32(trans, a, 0);
for (; a < trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(
trans->cfg->base_params->num_of_queues);
a += 4)
- iwl_write_targ_mem(trans, a, 0);
+ iwl_trans_write_mem32(trans, a, 0);

iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
trans_pcie->scd_bc_tbls.dma >> 10);
@@ -1005,14 +1005,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
tbl_dw_addr = trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);

- tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
+ tbl_dw = iwl_trans_read_mem32(trans, tbl_dw_addr);

if (txq_id & 0x1)
tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
else
tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);

- iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
+ iwl_trans_write_mem32(trans, tbl_dw_addr, tbl_dw);

return 0;
}
@@ -1071,9 +1071,9 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);

/* Set up Tx window size and frame limit for this queue */
- iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+ iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
- iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+ iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
@@ -1104,8 +1104,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)

iwl_pcie_txq_set_inactive(trans, txq_id);

- _iwl_write_targ_mem_dwords(trans, stts_addr,
- zero_val, ARRAY_SIZE(zero_val));
+ iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+ ARRAY_SIZE(zero_val));

iwl_pcie_txq_unmap(trans, txq_id);

--
1.8.0


2013-01-03 14:45:55

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 09/12] iwlwifi: request IRQ only once

From: Johannes Berg <[email protected]>

There's no need to request the IRQ every time the
device is started, we can request it just once.

Reviewed-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/pcie/internal.h | 4 --
drivers/net/wireless/iwlwifi/pcie/trans.c | 62 +++++++++++-----------------
2 files changed, 25 insertions(+), 41 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 15f7975..8f017c3 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -222,8 +222,6 @@ struct iwl_txq {
* @rx_replenish: work that will be called when buffers need to be allocated
* @drv - pointer to iwl_drv
* @trans: pointer to the generic transport area
- * @irq - the irq number for the device
- * @irq_requested: true when the irq has been requested
* @scd_base_addr: scheduler sram base address in SRAM
* @scd_bc_tbls: pointer to the byte count table of the scheduler
* @kw: keep warm address
@@ -250,11 +248,9 @@ struct iwl_trans_pcie {
int ict_index;
u32 inta;
bool use_ict;
- bool irq_requested;
struct tasklet_struct irq_tasklet;
struct isr_statistics isr_stats;

- unsigned int irq;
spinlock_t irq_lock;
u32 inta_mask;
u32 scd_base_addr;
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 3a40607..48cd65e 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -535,7 +535,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_enable_rfkill_int(trans);

/* wait to make sure we flush pending tasklet*/
- synchronize_irq(trans_pcie->irq);
+ synchronize_irq(trans_pcie->pci_dev->irq);
tasklet_kill(&trans_pcie->irq_tasklet);

cancel_work_sync(&trans_pcie->rx_replenish);
@@ -564,33 +564,13 @@ static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)

static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- int err;
bool hw_rfkill;
-
- trans_pcie->inta_mask = CSR_INI_SET_MASK;
-
- if (!trans_pcie->irq_requested) {
- tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
- iwl_pcie_tasklet, (unsigned long)trans);
-
- iwl_pcie_alloc_ict(trans);
-
- err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict,
- IRQF_SHARED, DRV_NAME, trans);
- if (err) {
- IWL_ERR(trans, "Error allocating IRQ %d\n",
- trans_pcie->irq);
- goto error;
- }
-
- trans_pcie->irq_requested = true;
- }
+ int err;

err = iwl_pcie_prepare_card_hw(trans);
if (err) {
IWL_ERR(trans, "Error while preparing HW: %d\n", err);
- goto err_free_irq;
+ return err;
}

iwl_pcie_apm_init(trans);
@@ -601,15 +581,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);

- return err;
-
-err_free_irq:
- trans_pcie->irq_requested = false;
- free_irq(trans_pcie->irq, trans);
-error:
- iwl_pcie_free_ict(trans);
- tasklet_kill(&trans_pcie->irq_tasklet);
- return err;
+ return 0;
}

static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
@@ -713,10 +685,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
iwl_pcie_tx_free(trans);
iwl_pcie_rx_free(trans);

- if (trans_pcie->irq_requested == true) {
- free_irq(trans_pcie->irq, trans);
- iwl_pcie_free_ict(trans);
- }
+ free_irq(trans_pcie->pci_dev->irq, trans);
+ iwl_pcie_free_ict(trans);

pci_disable_msi(trans_pcie->pci_dev);
iounmap(trans_pcie->hw_base);
@@ -1424,7 +1394,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
}

trans->dev = &pdev->dev;
- trans_pcie->irq = pdev->irq;
trans_pcie->pci_dev = pdev;
trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
@@ -1450,8 +1419,27 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
if (!trans->dev_cmd_pool)
goto out_pci_disable_msi;

+ trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+ tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
+ iwl_pcie_tasklet, (unsigned long)trans);
+
+ if (iwl_pcie_alloc_ict(trans))
+ goto out_free_cmd_pool;
+
+ err = request_irq(pdev->irq, iwl_pcie_isr_ict,
+ IRQF_SHARED, DRV_NAME, trans);
+ if (err) {
+ IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
+ goto out_free_ict;
+ }
+
return trans;

+out_free_ict:
+ iwl_pcie_free_ict(trans);
+out_free_cmd_pool:
+ kmem_cache_destroy(trans->dev_cmd_pool);
out_pci_disable_msi:
pci_disable_msi(pdev);
out_pci_release_regions:
--
1.8.0


2013-01-03 14:45:52

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 03/12] iwlwifi: don't verify fw after download

From: Emmanuel Grumbach <[email protected]>

No need to verify that the fw has been written correctly.
In case it hasn't, we won't get ALIVE notification.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/ucode.c | 94 --------------------------------
1 file changed, 94 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
index c6467e5..ecf700b 100644
--- a/drivers/net/wireless/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -286,89 +286,6 @@ static int iwl_alive_notify(struct iwl_priv *priv)
return iwl_send_calib_results(priv);
}

-
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- * using sample data 100 bytes apart. If these sample points are good,
- * it's a pretty good bet that everything between them is good, too.
- */
-static int iwl_verify_sec_sparse(struct iwl_priv *priv,
- const struct fw_desc *fw_desc)
-{
- __le32 *image = (__le32 *)fw_desc->data;
- u32 len = fw_desc->len;
- u32 val;
- u32 i;
-
- IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
- for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
- i + fw_desc->offset);
- val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image))
- return -EIO;
- }
-
- return 0;
-}
-
-static void iwl_print_mismatch_sec(struct iwl_priv *priv,
- const struct fw_desc *fw_desc)
-{
- __le32 *image = (__le32 *)fw_desc->data;
- u32 len = fw_desc->len;
- u32 val;
- u32 offs;
- int errors = 0;
-
- IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
- iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
- fw_desc->offset);
-
- for (offs = 0;
- offs < len && errors < 20;
- offs += sizeof(u32), image++) {
- /* read data comes through single port, auto-incr addr */
- val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- IWL_ERR(priv, "uCode INST section at "
- "offset 0x%x, is 0x%x, s/b 0x%x\n",
- offs, val, le32_to_cpu(*image));
- errors++;
- }
- }
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- * and verify its contents
- */
-static int iwl_verify_ucode(struct iwl_priv *priv,
- enum iwl_ucode_type ucode_type)
-{
- const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
-
- if (!img) {
- IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
- return -EINVAL;
- }
-
- if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
- IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
- return 0;
- }
-
- IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
-
- iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
- return -EIO;
-}
-
struct iwl_alive_data {
bool valid;
u8 subtype;
@@ -450,18 +367,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return -EIO;
}

- /*
- * This step takes a long time (60-80ms!!) and
- * WoWLAN image should be loaded quickly, so
- * skip it for WoWLAN.
- */
if (ucode_type != IWL_UCODE_WOWLAN) {
- ret = iwl_verify_ucode(priv, ucode_type);
- if (ret) {
- priv->cur_ucode = old_type;
- return ret;
- }
-
/* delay a bit to give rfkill time to run */
msleep(5);
}
--
1.8.0


2013-01-03 14:49:38

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 12/12] iwlwifi: always check that grab_nic_access succeeds

From: Emmanuel Grumbach <[email protected]>

This allows to let sparse check that the NIC access is
always released.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/main.c | 4 +--
drivers/net/wireless/iwlwifi/dvm/tt.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-io.c | 28 +++++++++++---------
drivers/net/wireless/iwlwifi/iwl-test.c | 44 ++++++++++++++++++-------------
drivers/net/wireless/iwlwifi/iwl-trans.h | 12 ++++-----
drivers/net/wireless/iwlwifi/pcie/trans.c | 4 +--
6 files changed, 51 insertions(+), 43 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index 517d7ae..a64f361 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -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_trans_grab_nic_access(priv->trans, false))) {
+ if (!iwl_trans_grab_nic_access(priv->trans, false)) {
spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
return;
}
@@ -1718,7 +1718,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_trans_grab_nic_access(trans, false)))
+ if (!iwl_trans_grab_nic_access(trans, false))
goto out_unlock;

/* Set starting address; reads will auto-increment */
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
index a8ae513..b28cfc8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.c
@@ -186,7 +186,7 @@ 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_trans_grab_nic_access(priv->trans, false)))
+ if (iwl_trans_grab_nic_access(priv->trans, false))
iwl_trans_release_nic_access(priv->trans);
spin_unlock_irqrestore(&priv->trans->reg_lock, flags);

diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 2bd84ad..bff3ac9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -101,13 +101,14 @@ EXPORT_SYMBOL_GPL(iwl_poll_bit);

u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{
- u32 value;
+ u32 value = 0x5a5a5a5a;
unsigned long flags;

spin_lock_irqsave(&trans->reg_lock, flags);
- iwl_trans_grab_nic_access(trans, false);
- value = iwl_read32(trans, reg);
- iwl_trans_release_nic_access(trans);
+ if (iwl_trans_grab_nic_access(trans, false)) {
+ value = iwl_read32(trans, reg);
+ iwl_trans_release_nic_access(trans);
+ }
spin_unlock_irqrestore(&trans->reg_lock, flags);

return value;
@@ -119,7 +120,7 @@ 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_trans_grab_nic_access(trans, false))) {
+ if (iwl_trans_grab_nic_access(trans, false)) {
iwl_write32(trans, reg, value);
iwl_trans_release_nic_access(trans);
}
@@ -159,12 +160,13 @@ static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
{
unsigned long flags;
- u32 val;
+ u32 val = 0x5a5a5a5a;

spin_lock_irqsave(&trans->reg_lock, flags);
- iwl_trans_grab_nic_access(trans, false);
- val = __iwl_read_prph(trans, ofs);
- iwl_trans_release_nic_access(trans);
+ if (iwl_trans_grab_nic_access(trans, false)) {
+ val = __iwl_read_prph(trans, ofs);
+ iwl_trans_release_nic_access(trans);
+ }
spin_unlock_irqrestore(&trans->reg_lock, flags);
return val;
}
@@ -175,7 +177,7 @@ 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_trans_grab_nic_access(trans, false))) {
+ if (iwl_trans_grab_nic_access(trans, false)) {
__iwl_write_prph(trans, ofs, val);
iwl_trans_release_nic_access(trans);
}
@@ -188,7 +190,7 @@ 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_trans_grab_nic_access(trans, false))) {
+ if (iwl_trans_grab_nic_access(trans, false)) {
__iwl_write_prph(trans, ofs,
__iwl_read_prph(trans, ofs) | mask);
iwl_trans_release_nic_access(trans);
@@ -203,7 +205,7 @@ 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_trans_grab_nic_access(trans, false))) {
+ if (iwl_trans_grab_nic_access(trans, false)) {
__iwl_write_prph(trans, ofs,
(__iwl_read_prph(trans, ofs) & mask) | bits);
iwl_trans_release_nic_access(trans);
@@ -218,7 +220,7 @@ 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_trans_grab_nic_access(trans, false))) {
+ if (iwl_trans_grab_nic_access(trans, false)) {
val = __iwl_read_prph(trans, ofs);
__iwl_write_prph(trans, ofs, (val & ~mask));
iwl_trans_release_nic_access(trans);
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index f8d8df8..1a22611 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -467,7 +467,10 @@ 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_trans_grab_nic_access(trans, false);
+ if (!iwl_trans_grab_nic_access(trans, false)) {
+ spin_unlock_irqrestore(&trans->reg_lock, flags);
+ return -EIO;
+ }
iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
addr | (3 << 24));
for (i = 0; i < size; i += 4)
@@ -500,26 +503,29 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,

if (IWL_ABS_PRPH_START <= addr &&
addr < IWL_ABS_PRPH_START + PRPH_END) {
- /* Periphery writes can be 1-3 bytes long, or DWORDs */
- if (size < 4) {
- memcpy(&val, buf, size);
- spin_lock_irqsave(&trans->reg_lock, flags);
- 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_trans_release_nic_access(trans);
- /* needed after consecutive writes w/o read */
- mmiowb();
+ /* 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);
- } else {
- if (size % 4)
- return -EINVAL;
- for (i = 0; i < size; i += 4)
- iwl_write_prph(trans, addr+i,
- *(u32 *)(buf+i));
+ 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);
+ } else {
+ if (size % 4)
+ return -EINVAL;
+ for (i = 0; i < size; i += 4)
+ iwl_write_prph(trans, addr+i,
+ *(u32 *)(buf+i));
+ }
} else if (iwl_test_valid_hw_addr(tst, addr)) {
iwl_trans_write_mem(trans, addr, buf, size / 4);
} else {
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 7584d55..b0d5c71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -734,15 +734,15 @@ 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);
-}
+#define iwl_trans_grab_nic_access(trans, silent) \
+ __cond_lock(nic_access, \
+ likely((trans)->ops->grab_nic_access(trans, silent)))

-static inline void iwl_trans_release_nic_access(struct iwl_trans *trans)
+static inline void __releases(nic_access)
+iwl_trans_release_nic_access(struct iwl_trans *trans)
{
trans->ops->release_nic_access(trans);
+ __release(nic_access);
}

/*****************************************************
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index bca6203..db3b055 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -795,7 +795,7 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
u32 *vals = buf;

spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_trans_grab_nic_access(trans, false))) {
+ if (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);
@@ -815,7 +815,7 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
u32 *vals = buf;

spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_trans_grab_nic_access(trans, false))) {
+ if (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]);
--
1.8.0


2013-01-03 14:45:52

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 04/12] iwlwifi: let the op_mode run a FW while in RFKILL

From: Emmanuel Grumbach <[email protected]>

In some cases, the fw should run even if the NIC is in
RFKILL. Make the API more flexible to allow that.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/ucode.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-trans.h | 8 +++++---
drivers/net/wireless/iwlwifi/pcie/trans.c | 4 ++--
3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
index ecf700b..ebec13a 100644
--- a/drivers/net/wireless/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -343,7 +343,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
alive_cmd, ARRAY_SIZE(alive_cmd),
iwl_alive_fn, &alive_data);

- ret = iwl_trans_start_fw(priv->trans, fw);
+ ret = iwl_trans_start_fw(priv->trans, fw, false);
if (ret) {
priv->cur_ucode = old_type;
iwl_remove_notification(&priv->notif_wait, &alive_wait);
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 15b4700..16a82b5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -399,7 +399,8 @@ struct iwl_trans_ops {

int (*start_hw)(struct iwl_trans *iwl_trans);
void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
- int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
+ int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
+ bool run_in_rfkill);
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
void (*stop_device)(struct iwl_trans *trans);

@@ -531,13 +532,14 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr)
}

static inline int iwl_trans_start_fw(struct iwl_trans *trans,
- const struct fw_img *fw)
+ const struct fw_img *fw,
+ bool run_in_rfkill)
{
might_sleep();

WARN_ON_ONCE(!trans->rx_mpdu_cmd);

- return trans->ops->start_fw(trans, fw);
+ return trans->ops->start_fw(trans, fw, run_in_rfkill);
}

static inline void iwl_trans_stop_device(struct iwl_trans *trans)
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index ab179ce..e67e179 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -435,7 +435,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
}

static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
- const struct fw_img *fw)
+ const struct fw_img *fw, bool run_in_rfkill)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret;
@@ -454,7 +454,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
/* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
- if (hw_rfkill)
+ if (hw_rfkill && !run_in_rfkill)
return -ERFKILL;

iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
--
1.8.0


2013-01-03 14:45:53

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 05/12] iwlwifi: use __packed

From: Johannes Berg <[email protected]>

Use __packed instead of __attribute__((packed)).

Reviewed-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/commands.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h
index 71ab76b..0ca99c1 100644
--- a/drivers/net/wireless/iwlwifi/dvm/commands.h
+++ b/drivers/net/wireless/iwlwifi/dvm/commands.h
@@ -3695,7 +3695,7 @@ struct iwl_bt_uart_msg {
u8 frame5;
u8 frame6;
u8 frame7;
-} __attribute__((packed));
+} __packed;

struct iwl_bt_coex_profile_notif {
struct iwl_bt_uart_msg last_bt_uart_msg;
@@ -3703,7 +3703,7 @@ struct iwl_bt_coex_profile_notif {
u8 bt_traffic_load; /* 0 .. 3? */
u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
u8 reserved;
-} __attribute__((packed));
+} __packed;

#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS 0
#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK 0x1
@@ -3752,7 +3752,7 @@ enum bt_coex_prio_table_priorities {

struct iwl_bt_coex_prio_table_cmd {
u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
-} __attribute__((packed));
+} __packed;

#define IWL_BT_COEX_ENV_CLOSE 0
#define IWL_BT_COEX_ENV_OPEN 1
@@ -3764,7 +3764,7 @@ struct iwl_bt_coex_prot_env_cmd {
u8 action; /* 0 = closed, 1 = open */
u8 type; /* 0 .. 15 */
u8 reserved[2];
-} __attribute__((packed));
+} __packed;

/*
* REPLY_D3_CONFIG
--
1.8.0