linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30
@ 2013-10-30 11:42 Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 01/12] ath10k: remove ar_pci->ce_count Michal Kazior
                   ` (14 more replies)
  0 siblings, 15 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

Hi,

This patchset contains a slew of PCI/CE cleanups
and fixes. The aim of the patchset is to deal with
CE null dereference bugs Ben has been reporting on
the mailing list for some time now.

I've done some brief testing and don't see any
major regressions. I wasn't able to reproduce the
reported bugs though. @Ben: Could you perhaps test
this, please?


Michal Kazior (12):
  ath10k: remove ar_pci->ce_count
  ath10k: don't forget to kill fw error tasklet
  ath10k: split tasklet killing function
  ath10k: rename function to match it's role
  ath10k: make sure to mask all CE irqs
  ath10k: fix ath10k_ce_init() failpath
  ath10k: remove meaningless check
  ath10k: use ath10k_do_pci_wake/sleep
  ath10k: propagate ath10k_ce_disable_interrupts() errors
  ath10k: guard against CE corruption from firmware
  ath10k: re-arrange PCI init code
  ath10k: add some debug prints

 drivers/net/wireless/ath/ath10k/ce.c  |  56 ++++++---
 drivers/net/wireless/ath/ath10k/ce.h  |   3 +-
 drivers/net/wireless/ath/ath10k/htc.c |   5 +
 drivers/net/wireless/ath/ath10k/pci.c | 221 ++++++++++++++++++----------------
 drivers/net/wireless/ath/ath10k/pci.h |   3 -
 5 files changed, 161 insertions(+), 127 deletions(-)

-- 
1.8.4.rc3


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH/RFT 01/12] ath10k: remove ar_pci->ce_count
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 02/12] ath10k: don't forget to kill fw error tasklet Michal Kazior
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

It wasn't really useful to have it to begin with.
This makes it a little simpler to re-arrange PCI
init code as some function depended on
ar_pci->ce_count being set.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c  |  9 +++------
 drivers/net/wireless/ath/ath10k/pci.c | 18 ++++++++----------
 drivers/net/wireless/ath/ath10k/pci.h |  3 ---
 3 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index d243f28..2b99bd4 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -731,7 +731,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
 
 void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ce_id, ret;
 	u32 intr_summary;
 
@@ -741,7 +740,7 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 
 	intr_summary = CE_INTERRUPT_SUMMARY(ar);
 
-	for (ce_id = 0; intr_summary && (ce_id < ar_pci->ce_count); ce_id++) {
+	for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {
 		if (intr_summary & (1 << ce_id))
 			intr_summary &= ~(1 << ce_id);
 		else
@@ -785,16 +784,14 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
 
 void ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ce_id, ret;
 
 	ret = ath10k_pci_wake(ar);
 	if (ret)
 		return;
 
-	for (ce_id = 0; ce_id < ar_pci->ce_count; ce_id++) {
-		struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
-		u32 ctrl_addr = ce_state->ctrl_addr;
+	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
+		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
 
 		ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
 	}
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 42d2473..05cdbf0 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -831,7 +831,7 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
 	spin_lock_init(&ar_pci->compl_lock);
 	INIT_LIST_HEAD(&ar_pci->compl_process);
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 
 		spin_lock_init(&pipe_info->pipe_lock);
@@ -924,7 +924,7 @@ static void ath10k_pci_cleanup_ce(struct ath10k *ar)
 	spin_unlock_bh(&ar_pci->compl_lock);
 
 	/* Free unused completions for each pipe. */
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 
 		spin_lock_bh(&pipe_info->pipe_lock);
@@ -1166,7 +1166,7 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
 	const struct ce_attr *attr;
 	int pipe_num, ret = 0;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 		attr = &host_ce_config_wlan[pipe_num];
 
@@ -1295,7 +1295,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int pipe_num;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		struct ath10k_pci_pipe *pipe_info;
 
 		pipe_info = &ar_pci->pipe_info[pipe_num];
@@ -1310,7 +1310,7 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
 	struct ath10k_pci_pipe *pipe_info;
 	int pipe_num;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 		if (pipe_info->ce_hdl) {
 			ath10k_ce_deinit(pipe_info->ce_hdl);
@@ -1755,7 +1755,7 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 	const struct ce_attr *attr;
 	int pipe_num;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 		pipe_info->pipe_num = pipe_num;
 		pipe_info->hif_ce_state = ar;
@@ -1772,13 +1772,12 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 			return -1;
 		}
 
-		if (pipe_num == ar_pci->ce_count - 1) {
+		if (pipe_num == CE_COUNT - 1) {
 			/*
 			 * Reserve the ultimate CE for
 			 * diagnostic Window support
 			 */
-			ar_pci->ce_diag =
-			ar_pci->pipe_info[ar_pci->ce_count - 1].ce_hdl;
+			ar_pci->ce_diag = pipe_info->ce_hdl;
 			continue;
 		}
 
@@ -2235,7 +2234,6 @@ static int ath10k_pci_start_intr(struct ath10k *ar)
 
 exit:
 	ar_pci->num_msi_intrs = num;
-	ar_pci->ce_count = CE_COUNT;
 	return ret;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index a304c33..73a3d4e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -199,9 +199,6 @@ struct ath10k_pci {
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct msi_fw_err;
 
-	/* Number of Copy Engines supported */
-	unsigned int ce_count;
-
 	int started;
 
 	atomic_t keep_awake_count;
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 02/12] ath10k: don't forget to kill fw error tasklet
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 01/12] ath10k: remove ar_pci->ce_count Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 03/12] ath10k: split tasklet killing function Michal Kazior
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

It was possible for FW error tasklet to be
executed during teardown. This could lead to
system crashes and/or memory corruption.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 05cdbf0..aa43466 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -888,6 +888,7 @@ static void ath10k_pci_stop_ce(struct ath10k *ar)
 
 	/* Cancel the pending tasklet */
 	tasklet_kill(&ar_pci->intr_tq);
+	tasklet_kill(&ar_pci->msi_fw_err);
 
 	for (i = 0; i < CE_COUNT; i++)
 		tasklet_kill(&ar_pci->pipe_info[i].intr);
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 03/12] ath10k: split tasklet killing function
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 01/12] ath10k: remove ar_pci->ce_count Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 02/12] ath10k: don't forget to kill fw error tasklet Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 04/12] ath10k: rename function to match it's role Michal Kazior
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

The function will soon be called from more than 1
place.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index aa43466..d9467e5 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -877,21 +877,26 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
 	return 0;
 }
 
-static void ath10k_pci_stop_ce(struct ath10k *ar)
+static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	struct ath10k_pci_compl *compl;
-	struct sk_buff *skb;
 	int i;
 
-	ath10k_ce_disable_interrupts(ar);
-
-	/* Cancel the pending tasklet */
 	tasklet_kill(&ar_pci->intr_tq);
 	tasklet_kill(&ar_pci->msi_fw_err);
 
 	for (i = 0; i < CE_COUNT; i++)
 		tasklet_kill(&ar_pci->pipe_info[i].intr);
+}
+
+static void ath10k_pci_stop_ce(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_pci_compl *compl;
+	struct sk_buff *skb;
+
+	ath10k_ce_disable_interrupts(ar);
+	ath10k_pci_kill_tasklet(ar);
 
 	/* Mark pending completions as aborted, so that upper layers free up
 	 * their associated resources */
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 04/12] ath10k: rename function to match it's role
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (2 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 03/12] ath10k: split tasklet killing function Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-11-06 13:08   ` Kalle Valo
  2013-10-30 11:42 ` [PATCH/RFT 05/12] ath10k: make sure to mask all CE irqs Michal Kazior
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

What the function does is to actually wait for the
firmware indication bit to be set. Prerequisite
for this is having interrupts registered.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index d9467e5..1e430d0 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -53,7 +53,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(struct ath10k *ar);
 static void ath10k_pci_device_reset(struct ath10k *ar);
-static int ath10k_pci_reset_target(struct ath10k *ar);
+static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
 static int ath10k_pci_start_intr(struct ath10k *ar);
 static void ath10k_pci_stop_intr(struct ath10k *ar);
 
@@ -1857,7 +1857,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	 */
 	ath10k_pci_device_reset(ar);
 
-	ret = ath10k_pci_reset_target(ar);
+	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret)
 		goto err_irq;
 
@@ -2257,7 +2257,7 @@ static void ath10k_pci_stop_intr(struct ath10k *ar)
 		pci_disable_msi(ar_pci->pdev);
 }
 
-static int ath10k_pci_reset_target(struct ath10k *ar)
+static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int wait_limit = 300; /* 3 sec */
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 05/12] ath10k: make sure to mask all CE irqs
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (3 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 04/12] ath10k: rename function to match it's role Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 06/12] ath10k: fix ath10k_ce_init() failpath Michal Kazior
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

CE error interrupts were not disabled. This could
lead to invalid memory accesses / memory
corruption.

Also make sure CE watermark interrupts are also
disabled.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 2b99bd4..7a49cde 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -243,6 +243,16 @@ static inline void ath10k_ce_error_intr_enable(struct ath10k *ar,
 			   misc_ie_addr | CE_ERROR_MASK);
 }
 
+static inline void ath10k_ce_error_intr_disable(struct ath10k *ar,
+						u32 ce_ctrl_addr)
+{
+	u32 misc_ie_addr = ath10k_pci_read32(ar,
+					     ce_ctrl_addr + MISC_IE_ADDRESS);
+
+	ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS,
+			   misc_ie_addr & ~CE_ERROR_MASK);
+}
+
 static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
 						     u32 ce_ctrl_addr,
 						     unsigned int mask)
@@ -794,6 +804,8 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar)
 		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
 
 		ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
+		ath10k_ce_error_intr_disable(ar, ctrl_addr);
+		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
 	}
 	ath10k_pci_sleep(ar);
 }
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 06/12] ath10k: fix ath10k_ce_init() failpath
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (4 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 05/12] ath10k: make sure to mask all CE irqs Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 07/12] ath10k: remove meaningless check Michal Kazior
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

Make sure to put target back to sleep. This was a
minor issue as it didn't really matter if we put
target back to sleep at this point. It just looked
wrong.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 7a49cde..657e8f2 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -1077,7 +1077,7 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 	ce_state = ath10k_ce_init_state(ar, ce_id, attr);
 	if (!ce_state) {
 		ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id);
-		return NULL;
+		goto out;
 	}
 
 	if (attr->src_nentries) {
@@ -1086,7 +1086,8 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 			ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
 				   ce_id, ret);
 			ath10k_ce_deinit(ce_state);
-			return NULL;
+			ce_state = NULL;
+			goto out;
 		}
 	}
 
@@ -1096,15 +1097,16 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 			ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
 				   ce_id, ret);
 			ath10k_ce_deinit(ce_state);
-			return NULL;
+			ce_state = NULL;
+			goto out;
 		}
 	}
 
 	/* Enable CE error interrupts */
 	ath10k_ce_error_intr_enable(ar, ctrl_addr);
 
+out:
 	ath10k_pci_sleep(ar);
-
 	return ce_state;
 }
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 07/12] ath10k: remove meaningless check
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (5 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 06/12] ath10k: fix ath10k_ce_init() failpath Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 08/12] ath10k: use ath10k_do_pci_wake/sleep Michal Kazior
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

The check doesn't make much sense. If the address
were to be 0x0000 the check would fail. In this
case a 0 address isn't wrong.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 1e430d0..5a1ac9e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2307,9 +2307,6 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
 	int i;
 	u32 val;
 
-	if (!SOC_GLOBAL_RESET_ADDRESS)
-		return;
-
 	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
 			       PCIE_SOC_WAKE_V_MASK);
 	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 08/12] ath10k: use ath10k_do_pci_wake/sleep
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (6 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 07/12] ath10k: remove meaningless check Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 09/12] ath10k: propagate ath10k_ce_disable_interrupts() errors Michal Kazior
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

This removes some remaining direct use of the wake
register which could interfere with power state
tracking of the target device. This will allow
initialization code reordering.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 84 +++++++++++------------------------
 1 file changed, 26 insertions(+), 58 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 5a1ac9e..ffc63cc 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -52,7 +52,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 					     int num);
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(struct ath10k *ar);
-static void ath10k_pci_device_reset(struct ath10k *ar);
+static int ath10k_pci_device_reset(struct ath10k *ar);
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
 static int ath10k_pci_start_intr(struct ath10k *ar);
 static void ath10k_pci_stop_intr(struct ath10k *ar);
@@ -526,21 +526,6 @@ static bool ath10k_pci_target_is_awake(struct ath10k *ar)
 	return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);
 }
 
-static int ath10k_pci_wait(struct ath10k *ar)
-{
-	int n = 100;
-
-	while (n-- && !ath10k_pci_target_is_awake(ar))
-		msleep(10);
-
-	if (n < 0) {
-		ath10k_warn("Unable to wakeup target\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
 int ath10k_do_pci_wake(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -1855,7 +1840,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	 * is in an unexpected state. We try to catch that here in order to
 	 * reset the Target and retry the probe.
 	 */
-	ath10k_pci_device_reset(ar);
+	ret = ath10k_pci_device_reset(ar);
+	if (ret) {
+		ath10k_err("failed to reset target (%d)\n", ret);
+		goto err_irq;
+	}
 
 	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret)
@@ -2156,19 +2145,10 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Make sure to wake the Target before enabling Legacy
-	 * Interrupt.
-	 */
-	iowrite32(PCIE_SOC_WAKE_V_MASK,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
-
-	ret = ath10k_pci_wait(ar);
+	ret = ath10k_do_pci_wake(ar);
 	if (ret) {
-		ath10k_warn("Failed to enable legacy interrupt, target did not wake up: %d\n",
-			    ret);
 		free_irq(ar_pci->pdev->irq, ar);
+		ath10k_err("target didn't wake up (%d)\n", ret);
 		return ret;
 	}
 
@@ -2184,10 +2164,8 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 		  PCIE_INTR_CE_MASK_ALL,
 		  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
 				 PCIE_INTR_ENABLE_ADDRESS));
-	iowrite32(PCIE_SOC_WAKE_RESET,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
 
+	ath10k_do_pci_sleep(ar);
 	ath10k_info("legacy interrupt handling\n");
 	return 0;
 }
@@ -2263,15 +2241,9 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	int wait_limit = 300; /* 3 sec */
 	int ret;
 
-	/* Wait for Target to finish initialization before we proceed. */
-	iowrite32(PCIE_SOC_WAKE_V_MASK,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
-
-	ret = ath10k_pci_wait(ar);
+	ret = ath10k_do_pci_wake(ar);
 	if (ret) {
-		ath10k_warn("Failed to reset target, target did not wake up: %d\n",
-			    ret);
+		ath10k_err("target didn't wake up (%d)\n", ret);
 		return ret;
 	}
 
@@ -2288,31 +2260,26 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	}
 
 	if (wait_limit < 0) {
-		ath10k_err("Target stalled\n");
-		iowrite32(PCIE_SOC_WAKE_RESET,
-			  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-			  PCIE_SOC_WAKE_ADDRESS);
-		return -EIO;
+		ath10k_err("target stalled\n");
+		ret = -EIO;
+		goto out;
 	}
 
-	iowrite32(PCIE_SOC_WAKE_RESET,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
-
-	return 0;
+out:
+	ath10k_do_pci_sleep(ar);
+	return ret;
 }
 
-static void ath10k_pci_device_reset(struct ath10k *ar)
+static int ath10k_pci_device_reset(struct ath10k *ar)
 {
-	int i;
+	int i, ret;
 	u32 val;
 
-	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
-			       PCIE_SOC_WAKE_V_MASK);
-	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-		if (ath10k_pci_target_is_awake(ar))
-			break;
-		msleep(1);
+	ret = ath10k_do_pci_wake(ar);
+	if (ret) {
+		ath10k_err("failed to reset target - couldn't wake target (%d)\n",
+			   ret);
+		return ret;
 	}
 
 	/* Put Target, including PCIe, into RESET. */
@@ -2338,7 +2305,8 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
 		msleep(1);
 	}
 
-	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET);
+	ath10k_do_pci_sleep(ar);
+	return 0;
 }
 
 static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 09/12] ath10k: propagate ath10k_ce_disable_interrupts() errors
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (7 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 08/12] ath10k: use ath10k_do_pci_wake/sleep Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-11-06 12:34   ` Kalle Valo
  2013-10-30 11:42 ` [PATCH/RFT 10/12] ath10k: guard against CE corruption from firmware Michal Kazior
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

This shouldn't be silenced. This will be necessary
for PCI init code reordering.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c  | 6 ++++--
 drivers/net/wireless/ath/ath10k/ce.h  | 2 +-
 drivers/net/wireless/ath/ath10k/pci.c | 6 +++++-
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 657e8f2..3e8395d 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -792,13 +792,13 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
 	ath10k_pci_sleep(ar);
 }
 
-void ath10k_ce_disable_interrupts(struct ath10k *ar)
+int ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
 	int ce_id, ret;
 
 	ret = ath10k_pci_wake(ar);
 	if (ret)
-		return;
+		return ret;
 
 	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
 		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -807,7 +807,9 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar)
 		ath10k_ce_error_intr_disable(ar, ctrl_addr);
 		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
 	}
+
 	ath10k_pci_sleep(ar);
+	return ret;
 }
 
 void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 15d45b5..67dbde6 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -234,7 +234,7 @@ void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
 /*==================CE Interrupt Handlers====================*/
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
-void ath10k_ce_disable_interrupts(struct ath10k *ar);
+int ath10k_ce_disable_interrupts(struct ath10k *ar);
 
 /* ce_attr.flags values */
 /* Use NonSnooping PCIe accesses? */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index ffc63cc..63ad250 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -879,8 +879,12 @@ static void ath10k_pci_stop_ce(struct ath10k *ar)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	struct ath10k_pci_compl *compl;
 	struct sk_buff *skb;
+	int ret;
+
+	ret = ath10k_ce_disable_interrupts(ar);
+	if (ret)
+		ath10k_warn("failed to disable CE interrupts (%d)\n", ret);
 
-	ath10k_ce_disable_interrupts(ar);
 	ath10k_pci_kill_tasklet(ar);
 
 	/* Mark pending completions as aborted, so that upper layers free up
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 10/12] ath10k: guard against CE corruption from firmware
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (8 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 09/12] ath10k: propagate ath10k_ce_disable_interrupts() errors Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 11/12] ath10k: re-arrange PCI init code Michal Kazior
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

In case firmware crashes it may report CE
completions for entries that were never
submitted/filled with meaningful data. This in
turn led to NULL dereferences.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/htc.c | 5 +++++
 drivers/net/wireless/ath/ath10k/pci.c | 7 +++++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 3118d75..c59f5b4 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -191,6 +191,11 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
 	struct ath10k_htc *htc = &ar->htc;
 	struct ath10k_htc_ep *ep = &htc->endpoint[eid];
 
+	if (!skb) {
+		ath10k_warn("invalid sk_buff completion - NULL pointer. firmware crashed?");
+		return 0;
+	}
+
 	ath10k_htc_notify_tx_completion(ep, skb);
 	/* the skb now belongs to the completion handler */
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 63ad250..43cdc35 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1270,6 +1270,13 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
 		 * Indicate the completion to higer layer to free
 		 * the buffer
 		 */
+
+		if (!netbuf) {
+			ath10k_warn("invalid sk_buff on CE %d - NULL pointer. firmware crashed?",
+				    ce_hdl->id);
+			continue;
+		}
+
 		ATH10K_SKB_CB(netbuf)->is_aborted = true;
 		ar_pci->msg_callbacks_current.tx_completion(ar,
 							    netbuf,
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 11/12] ath10k: re-arrange PCI init code
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (9 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 10/12] ath10k: guard against CE corruption from firmware Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 11:42 ` [PATCH/RFT 12/12] ath10k: add some debug prints Michal Kazior
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

This patch moves irq registering after necessary
structures have been allocated and initialized.
This should prevent interrupts from causing
tasklet access invalid memory pointers.

Reported-By: Ben Greear <greearb@candelatech.com>
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c  | 19 +++++++--
 drivers/net/wireless/ath/ath10k/ce.h  |  1 +
 drivers/net/wireless/ath/ath10k/pci.c | 79 +++++++++++++++++++++--------------
 3 files changed, 64 insertions(+), 35 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 3e8395d..7517b94 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -792,6 +792,21 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
 	ath10k_pci_sleep(ar);
 }
 
+int ath10k_ce_enable_err_irq(struct ath10k *ar)
+{
+	int i, ret;
+
+	ret = ath10k_pci_wake(ar);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < CE_COUNT; i++)
+		ath10k_ce_error_intr_enable(ar, ath10k_ce_base_address(i));
+
+	ath10k_pci_sleep(ar);
+	return 0;
+}
+
 int ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
 	int ce_id, ret;
@@ -1058,7 +1073,6 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 				const struct ce_attr *attr)
 {
 	struct ath10k_ce_pipe *ce_state;
-	u32 ctrl_addr = ath10k_ce_base_address(ce_id);
 	int ret;
 
 	/*
@@ -1104,9 +1118,6 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 		}
 	}
 
-	/* Enable CE error interrupts */
-	ath10k_ce_error_intr_enable(ar, ctrl_addr);
-
 out:
 	ath10k_pci_sleep(ar);
 	return ce_state;
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 67dbde6..8a58bac 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -235,6 +235,7 @@ void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
 int ath10k_ce_disable_interrupts(struct ath10k *ar);
+int ath10k_ce_enable_err_irq(struct ath10k *ar);
 
 /* ce_attr.flags values */
 /* Use NonSnooping PCIe accesses? */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 43cdc35..7b606d0 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1786,18 +1786,6 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 		pipe_info->buf_sz = (size_t) (attr->src_sz_max);
 	}
 
-	/*
-	 * Initially, establish CE completion handlers for use with BMI.
-	 * These are overwritten with generic handlers after we exit BMI phase.
-	 */
-	pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
-	ath10k_ce_send_cb_register(pipe_info->ce_hdl,
-				   ath10k_pci_bmi_send_done, 0);
-
-	pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
-	ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
-				   ath10k_pci_bmi_recv_data);
-
 	return 0;
 }
 
@@ -1830,17 +1818,27 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
 	ath10k_pci_sleep(ar);
 }
 
+static void ath10k_pci_start_bmi(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_pci_pipe *pipe;
+
+	/*
+	 * Initially, establish CE completion handlers for use with BMI.
+	 * These are overwritten with generic handlers after we exit BMI phase.
+	 */
+	pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
+	ath10k_ce_send_cb_register(pipe->ce_hdl, ath10k_pci_bmi_send_done, 0);
+
+	pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
+	ath10k_ce_recv_cb_register(pipe->ce_hdl, ath10k_pci_bmi_recv_data);
+}
+
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
 
-	ret = ath10k_pci_start_intr(ar);
-	if (ret) {
-		ath10k_err("could not start interrupt handling (%d)\n", ret);
-		goto err;
-	}
-
 	/*
 	 * Bring the target up cleanly.
 	 *
@@ -1854,13 +1852,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	ret = ath10k_pci_device_reset(ar);
 	if (ret) {
 		ath10k_err("failed to reset target (%d)\n", ret);
-		goto err_irq;
+		goto err;
 	}
 
-	ret = ath10k_pci_wait_for_target_init(ar);
-	if (ret)
-		goto err_irq;
-
 	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
 		/* Force AWAKE forever */
 		ath10k_do_pci_wake(ar);
@@ -1869,25 +1863,48 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	if (ret)
 		goto err_ps;
 
+	ret = ath10k_ce_disable_interrupts(ar);
+	if (ret) {
+		ath10k_err("could not disable CE interrupts (%d)\n", ret);
+		goto err_ce;
+	}
+
+	ret = ath10k_pci_start_intr(ar);
+	if (ret) {
+		ath10k_err("could not start interrupt handling (%d)\n", ret);
+		goto err_ce;
+	}
+
+	ret = ath10k_pci_wait_for_target_init(ar);
+	if (ret)
+		goto err_irq;
+
+	ret = ath10k_ce_enable_err_irq(ar);
+	if (ret)
+		goto err_irq;
+
 	ret = ath10k_pci_init_config(ar);
 	if (ret)
-		goto err_ce;
+		goto err_irq;
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU (%d)\n", ret);
-		goto err_ce;
+		goto err_irq;
 	}
 
+	ath10k_pci_start_bmi(ar);
 	return 0;
 
+err_irq:
+	ath10k_ce_disable_interrupts(ar);
+	ath10k_pci_stop_intr(ar);
+	ath10k_pci_kill_tasklet(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
 err_ps:
 	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
 		ath10k_do_pci_sleep(ar);
-err_irq:
-	ath10k_pci_stop_intr(ar);
 err:
 	return ret;
 }
@@ -2156,7 +2173,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 	if (ret < 0)
 		return ret;
 
-	ret = ath10k_do_pci_wake(ar);
+	ret = ath10k_pci_wake(ar);
 	if (ret) {
 		free_irq(ar_pci->pdev->irq, ar);
 		ath10k_err("target didn't wake up (%d)\n", ret);
@@ -2176,7 +2193,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 		  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
 				 PCIE_INTR_ENABLE_ADDRESS));
 
-	ath10k_do_pci_sleep(ar);
+	ath10k_pci_sleep(ar);
 	ath10k_info("legacy interrupt handling\n");
 	return 0;
 }
@@ -2252,7 +2269,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	int wait_limit = 300; /* 3 sec */
 	int ret;
 
-	ret = ath10k_do_pci_wake(ar);
+	ret = ath10k_pci_wake(ar);
 	if (ret) {
 		ath10k_err("target didn't wake up (%d)\n", ret);
 		return ret;
@@ -2277,7 +2294,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	}
 
 out:
-	ath10k_do_pci_sleep(ar);
+	ath10k_pci_sleep(ar);
 	return ret;
 }
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH/RFT 12/12] ath10k: add some debug prints
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (10 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 11/12] ath10k: re-arrange PCI init code Michal Kazior
@ 2013-10-30 11:42 ` Michal Kazior
  2013-10-30 17:16   ` Joe Perches
  2013-11-06 12:38   ` Kalle Valo
  2013-10-30 17:06 ` [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Ben Greear
                   ` (2 subsequent siblings)
  14 siblings, 2 replies; 35+ messages in thread
From: Michal Kazior @ 2013-10-30 11:42 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, greearb, Michal Kazior

Some errors were handled too silently. Also add a
print indicating BMI is booted.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 7b606d0..42dd0b7 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1832,6 +1832,8 @@ static void ath10k_pci_start_bmi(struct ath10k *ar)
 
 	pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
 	ath10k_ce_recv_cb_register(pipe->ce_hdl, ath10k_pci_bmi_recv_data);
+
+	ath10k_dbg(ATH10K_DBG_BOOT, "boot start bmi\n");
 }
 
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
@@ -1860,8 +1862,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		ath10k_do_pci_wake(ar);
 
 	ret = ath10k_pci_ce_init(ar);
-	if (ret)
+	if (ret) {
+		ath10k_err("could not initialize CE (%d)\n", ret);
 		goto err_ps;
+	}
 
 	ret = ath10k_ce_disable_interrupts(ar);
 	if (ret) {
@@ -1876,16 +1880,22 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	}
 
 	ret = ath10k_pci_wait_for_target_init(ar);
-	if (ret)
+	if (ret) {
+		ath10k_err("failed to wait for target to init (%d)\n", ret);
 		goto err_irq;
+	}
 
 	ret = ath10k_ce_enable_err_irq(ar);
-	if (ret)
+	if (ret) {
+		ath10k_err("failed to enable CE error irq (%d)\n", ret);
 		goto err_irq;
+	}
 
 	ret = ath10k_pci_init_config(ar);
-	if (ret)
+	if (ret) {
+		ath10k_err("failed to setup init config (%d)\n", ret);
 		goto err_irq;
+	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (11 preceding siblings ...)
  2013-10-30 11:42 ` [PATCH/RFT 12/12] ath10k: add some debug prints Michal Kazior
@ 2013-10-30 17:06 ` Ben Greear
  2013-10-30 23:41 ` Ben Greear
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
  14 siblings, 0 replies; 35+ messages in thread
From: Ben Greear @ 2013-10-30 17:06 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, linux-wireless

On 10/30/2013 04:42 AM, Michal Kazior wrote:
> Hi,
> 
> This patchset contains a slew of PCI/CE cleanups
> and fixes. The aim of the patchset is to deal with
> CE null dereference bugs Ben has been reporting on
> the mailing list for some time now.
> 
> I've done some brief testing and don't see any
> major regressions. I wasn't able to reproduce the
> reported bugs though. @Ben: Could you perhaps test
> this, please?

I'll test these later today, thanks!

Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH/RFT 12/12] ath10k: add some debug prints
  2013-10-30 11:42 ` [PATCH/RFT 12/12] ath10k: add some debug prints Michal Kazior
@ 2013-10-30 17:16   ` Joe Perches
  2013-11-06 12:43     ` Kalle Valo
  2013-11-06 12:38   ` Kalle Valo
  1 sibling, 1 reply; 35+ messages in thread
From: Joe Perches @ 2013-10-30 17:16 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, linux-wireless, greearb

On Wed, 2013-10-30 at 12:42 +0100, Michal Kazior wrote:
> Some errors were handled too silently.

These aren't really debug prints.

> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
[]
> @@ -1860,8 +1862,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
>  		ath10k_do_pci_wake(ar);
>  
>  	ret = ath10k_pci_ce_init(ar);
> -	if (ret)
> +	if (ret) {
> +		ath10k_err("could not initialize CE (%d)\n", ret);

Rather than try to reinterpret the function name,
perhaps it's better to simply emit the function name
as is done most other places like:

		ath10k_err("ath10k_pci_ce_init failed: (%d)\n", ret);


> @@ -1876,16 +1880,22 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
>  	}
>  
>  	ret = ath10k_pci_wait_for_target_init(ar);
> -	if (ret)
> +	if (ret) {
> +		ath10k_err("failed to wait for target to init (%d)\n", ret);
>  		goto err_irq;
> +	}

Like this one, because the function did wait,
but the init was unsuccessful.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (12 preceding siblings ...)
  2013-10-30 17:06 ` [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Ben Greear
@ 2013-10-30 23:41 ` Ben Greear
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
  14 siblings, 0 replies; 35+ messages in thread
From: Ben Greear @ 2013-10-30 23:41 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, linux-wireless

On 10/30/2013 04:42 AM, Michal Kazior wrote:
> Hi,
> 
> This patchset contains a slew of PCI/CE cleanups
> and fixes. The aim of the patchset is to deal with
> CE null dereference bugs Ben has been reporting on
> the mailing list for some time now.
> 
> I've done some brief testing and don't see any
> major regressions. I wasn't able to reproduce the
> reported bugs though. @Ben: Could you perhaps test
> this, please?

I have done a bit of testing on this.  First, I did see
a total machine lockup, but I have been seeing those fairly
often on module reloads, so probably that was nothing new
in your patches.

I am also still running the crash avoidance patches I posted
recently.

And good news for me at least...with some modified firmware,
I am getting two stations to associate to the same AP and
pass traffic to each other (no encryption..that probably
doesn't work yet) :)

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH/RFT 09/12] ath10k: propagate ath10k_ce_disable_interrupts() errors
  2013-10-30 11:42 ` [PATCH/RFT 09/12] ath10k: propagate ath10k_ce_disable_interrupts() errors Michal Kazior
@ 2013-11-06 12:34   ` Kalle Valo
  0 siblings, 0 replies; 35+ messages in thread
From: Kalle Valo @ 2013-11-06 12:34 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, greearb, linux-wireless

Michal Kazior <michal.kazior@tieto.com> writes:

> This shouldn't be silenced. This will be necessary
> for PCI init code reordering.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>

[...]

> -void ath10k_ce_disable_interrupts(struct ath10k *ar)
> +int ath10k_ce_disable_interrupts(struct ath10k *ar)
>  {
>  	int ce_id, ret;
>  
>  	ret = ath10k_pci_wake(ar);
>  	if (ret)
> -		return;
> +		return ret;
>  
>  	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
>  		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
> @@ -807,7 +807,9 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar)
>  		ath10k_ce_error_intr_disable(ar, ctrl_addr);
>  		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
>  	}
> +
>  	ath10k_pci_sleep(ar);
> +	return ret;

Empty line before the return. And I think 'return 0' is more clear here.

> --- a/drivers/net/wireless/ath/ath10k/pci.c
> +++ b/drivers/net/wireless/ath/ath10k/pci.c
> @@ -879,8 +879,12 @@ static void ath10k_pci_stop_ce(struct ath10k *ar)
>  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
>  	struct ath10k_pci_compl *compl;
>  	struct sk_buff *skb;
> +	int ret;
> +
> +	ret = ath10k_ce_disable_interrupts(ar);
> +	if (ret)
> +		ath10k_warn("failed to disable CE interrupts (%d)\n", ret);

"failed to disable CE interrupts: %d\n"

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH/RFT 12/12] ath10k: add some debug prints
  2013-10-30 11:42 ` [PATCH/RFT 12/12] ath10k: add some debug prints Michal Kazior
  2013-10-30 17:16   ` Joe Perches
@ 2013-11-06 12:38   ` Kalle Valo
  1 sibling, 0 replies; 35+ messages in thread
From: Kalle Valo @ 2013-11-06 12:38 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, greearb, linux-wireless

Michal Kazior <michal.kazior@tieto.com> writes:

> Some errors were handled too silently. Also add a
> print indicating BMI is booted.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>

[...]

>  static int ath10k_pci_hif_power_up(struct ath10k *ar)
> @@ -1860,8 +1862,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
>  		ath10k_do_pci_wake(ar);
>  
>  	ret = ath10k_pci_ce_init(ar);
> -	if (ret)
> +	if (ret) {
> +		ath10k_err("could not initialize CE (%d)\n", ret);

"could not initialize CE: %d\n"

That comment applies to all the error codes printed.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH/RFT 12/12] ath10k: add some debug prints
  2013-10-30 17:16   ` Joe Perches
@ 2013-11-06 12:43     ` Kalle Valo
  0 siblings, 0 replies; 35+ messages in thread
From: Kalle Valo @ 2013-11-06 12:43 UTC (permalink / raw)
  To: Joe Perches; +Cc: Michal Kazior, greearb, linux-wireless, ath10k

Joe Perches <joe@perches.com> writes:

> On Wed, 2013-10-30 at 12:42 +0100, Michal Kazior wrote:
>> Some errors were handled too silently.
>
> These aren't really debug prints.

Yeah, the patch title needs work.

>> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
> []
>> @@ -1860,8 +1862,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
>>  		ath10k_do_pci_wake(ar);
>>  
>>  	ret = ath10k_pci_ce_init(ar);
>> -	if (ret)
>> +	if (ret) {
>> +		ath10k_err("could not initialize CE (%d)\n", ret);
>
> Rather than try to reinterpret the function name,
> perhaps it's better to simply emit the function name
> as is done most other places like:
>
> 		ath10k_err("ath10k_pci_ce_init failed: (%d)\n", ret);

I don't think that's any better. When function names change but people
forget to change the error message and then it's even more confusing.
And I prefer that a developer puts a bit more effort to the warning
message by writing it in english instead of just copying the function
name.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH/RFT 04/12] ath10k: rename function to match it's role
  2013-10-30 11:42 ` [PATCH/RFT 04/12] ath10k: rename function to match it's role Michal Kazior
@ 2013-11-06 13:08   ` Kalle Valo
  0 siblings, 0 replies; 35+ messages in thread
From: Kalle Valo @ 2013-11-06 13:08 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, greearb, linux-wireless

Michal Kazior <michal.kazior@tieto.com> writes:

> What the function does is to actually wait for the
> firmware indication bit to be set. Prerequisite
> for this is having interrupts registered.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>

I think the title could be a bit more specific, like "ath10k: rename
ath10k_pci_reset_target()" or something like that.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCHv2 00/13] ath10k: pci fixes 2013-10-30
  2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
                   ` (13 preceding siblings ...)
  2013-10-30 23:41 ` Ben Greear
@ 2013-11-08  7:01 ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 01/13] ath10k: remove ar_pci->ce_count Michal Kazior
                     ` (13 more replies)
  14 siblings, 14 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

Hi,

This patchset contains a slew of PCI/CE cleanups
and fixes. The aim of the patchset is to deal with
CE null dereference bugs Ben has been reporting on
the mailing list for some time now.

v2:
 * fix prints
 * fix commit messages
 * add additional patch
   (ath10k: reset device upon stopping/power down)


Michal Kazior (13):
  ath10k: remove ar_pci->ce_count
  ath10k: don't forget to kill fw error tasklet
  ath10k: split tasklet killing function
  ath10k: rename ath10k_pci_reset_target()
  ath10k: make sure to mask all CE irqs
  ath10k: fix ath10k_ce_init() failpath
  ath10k: remove meaningless check
  ath10k: use ath10k_do_pci_wake/sleep
  ath10k: propagate ath10k_ce_disable_interrupts() errors
  ath10k: guard against CE corruption from firmware
  ath10k: re-arrange PCI init code
  ath10k: add and fix some PCI prints
  ath10k: reset device upon stopping/power down

 drivers/net/wireless/ath/ath10k/ce.c  |  57 +++++--
 drivers/net/wireless/ath/ath10k/ce.h  |   3 +-
 drivers/net/wireless/ath/ath10k/htc.c |   5 +
 drivers/net/wireless/ath/ath10k/pci.c | 293 ++++++++++++++++++----------------
 drivers/net/wireless/ath/ath10k/pci.h |   3 -
 5 files changed, 205 insertions(+), 156 deletions(-)

-- 
1.8.4.rc3


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCHv2 01/13] ath10k: remove ar_pci->ce_count
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 02/13] ath10k: don't forget to kill fw error tasklet Michal Kazior
                     ` (12 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

It wasn't really useful to have it to begin with.
This makes it a little simpler to re-arrange PCI
init code as some function depended on
ar_pci->ce_count being set.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c  |  9 +++------
 drivers/net/wireless/ath/ath10k/pci.c | 18 ++++++++----------
 drivers/net/wireless/ath/ath10k/pci.h |  3 ---
 3 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index d243f28..2b99bd4 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -731,7 +731,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
 
 void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ce_id, ret;
 	u32 intr_summary;
 
@@ -741,7 +740,7 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 
 	intr_summary = CE_INTERRUPT_SUMMARY(ar);
 
-	for (ce_id = 0; intr_summary && (ce_id < ar_pci->ce_count); ce_id++) {
+	for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {
 		if (intr_summary & (1 << ce_id))
 			intr_summary &= ~(1 << ce_id);
 		else
@@ -785,16 +784,14 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
 
 void ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ce_id, ret;
 
 	ret = ath10k_pci_wake(ar);
 	if (ret)
 		return;
 
-	for (ce_id = 0; ce_id < ar_pci->ce_count; ce_id++) {
-		struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
-		u32 ctrl_addr = ce_state->ctrl_addr;
+	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
+		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
 
 		ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
 	}
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 25ed07b..f054d4c 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -831,7 +831,7 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
 	spin_lock_init(&ar_pci->compl_lock);
 	INIT_LIST_HEAD(&ar_pci->compl_process);
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 
 		spin_lock_init(&pipe_info->pipe_lock);
@@ -924,7 +924,7 @@ static void ath10k_pci_cleanup_ce(struct ath10k *ar)
 	spin_unlock_bh(&ar_pci->compl_lock);
 
 	/* Free unused completions for each pipe. */
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 
 		spin_lock_bh(&pipe_info->pipe_lock);
@@ -1166,7 +1166,7 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
 	const struct ce_attr *attr;
 	int pipe_num, ret = 0;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 		attr = &host_ce_config_wlan[pipe_num];
 
@@ -1295,7 +1295,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int pipe_num;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		struct ath10k_pci_pipe *pipe_info;
 
 		pipe_info = &ar_pci->pipe_info[pipe_num];
@@ -1310,7 +1310,7 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
 	struct ath10k_pci_pipe *pipe_info;
 	int pipe_num;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 		if (pipe_info->ce_hdl) {
 			ath10k_ce_deinit(pipe_info->ce_hdl);
@@ -1755,7 +1755,7 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 	const struct ce_attr *attr;
 	int pipe_num;
 
-	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
 		pipe_info = &ar_pci->pipe_info[pipe_num];
 		pipe_info->pipe_num = pipe_num;
 		pipe_info->hif_ce_state = ar;
@@ -1772,13 +1772,12 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 			return -1;
 		}
 
-		if (pipe_num == ar_pci->ce_count - 1) {
+		if (pipe_num == CE_COUNT - 1) {
 			/*
 			 * Reserve the ultimate CE for
 			 * diagnostic Window support
 			 */
-			ar_pci->ce_diag =
-			ar_pci->pipe_info[ar_pci->ce_count - 1].ce_hdl;
+			ar_pci->ce_diag = pipe_info->ce_hdl;
 			continue;
 		}
 
@@ -2235,7 +2234,6 @@ static int ath10k_pci_start_intr(struct ath10k *ar)
 
 exit:
 	ar_pci->num_msi_intrs = num;
-	ar_pci->ce_count = CE_COUNT;
 	return ret;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index a304c33..73a3d4e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -199,9 +199,6 @@ struct ath10k_pci {
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct msi_fw_err;
 
-	/* Number of Copy Engines supported */
-	unsigned int ce_count;
-
 	int started;
 
 	atomic_t keep_awake_count;
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 02/13] ath10k: don't forget to kill fw error tasklet
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 01/13] ath10k: remove ar_pci->ce_count Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 03/13] ath10k: split tasklet killing function Michal Kazior
                     ` (11 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

It was possible for FW error tasklet to be
executed during teardown. This could lead to
system crashes and/or memory corruption.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index f054d4c..31cdde0 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -888,6 +888,7 @@ static void ath10k_pci_stop_ce(struct ath10k *ar)
 
 	/* Cancel the pending tasklet */
 	tasklet_kill(&ar_pci->intr_tq);
+	tasklet_kill(&ar_pci->msi_fw_err);
 
 	for (i = 0; i < CE_COUNT; i++)
 		tasklet_kill(&ar_pci->pipe_info[i].intr);
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 03/13] ath10k: split tasklet killing function
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 01/13] ath10k: remove ar_pci->ce_count Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 02/13] ath10k: don't forget to kill fw error tasklet Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 04/13] ath10k: rename ath10k_pci_reset_target() Michal Kazior
                     ` (10 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

The function will soon be called from more than 1
place.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 31cdde0..a001ff2 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -877,21 +877,26 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
 	return 0;
 }
 
-static void ath10k_pci_stop_ce(struct ath10k *ar)
+static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	struct ath10k_pci_compl *compl;
-	struct sk_buff *skb;
 	int i;
 
-	ath10k_ce_disable_interrupts(ar);
-
-	/* Cancel the pending tasklet */
 	tasklet_kill(&ar_pci->intr_tq);
 	tasklet_kill(&ar_pci->msi_fw_err);
 
 	for (i = 0; i < CE_COUNT; i++)
 		tasklet_kill(&ar_pci->pipe_info[i].intr);
+}
+
+static void ath10k_pci_stop_ce(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_pci_compl *compl;
+	struct sk_buff *skb;
+
+	ath10k_ce_disable_interrupts(ar);
+	ath10k_pci_kill_tasklet(ar);
 
 	/* Mark pending completions as aborted, so that upper layers free up
 	 * their associated resources */
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 04/13] ath10k: rename ath10k_pci_reset_target()
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (2 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 03/13] ath10k: split tasklet killing function Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 05/13] ath10k: make sure to mask all CE irqs Michal Kazior
                     ` (9 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

What the function does is to actually wait for the
firmware indication bit to be set. Prerequisite
for this is having interrupts registered.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index a001ff2..4aa7992 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -53,7 +53,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(struct ath10k *ar);
 static void ath10k_pci_device_reset(struct ath10k *ar);
-static int ath10k_pci_reset_target(struct ath10k *ar);
+static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
 static int ath10k_pci_start_intr(struct ath10k *ar);
 static void ath10k_pci_stop_intr(struct ath10k *ar);
 
@@ -1857,7 +1857,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	 */
 	ath10k_pci_device_reset(ar);
 
-	ret = ath10k_pci_reset_target(ar);
+	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret)
 		goto err_irq;
 
@@ -2257,7 +2257,7 @@ static void ath10k_pci_stop_intr(struct ath10k *ar)
 		pci_disable_msi(ar_pci->pdev);
 }
 
-static int ath10k_pci_reset_target(struct ath10k *ar)
+static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int wait_limit = 300; /* 3 sec */
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 05/13] ath10k: make sure to mask all CE irqs
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (3 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 04/13] ath10k: rename ath10k_pci_reset_target() Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 06/13] ath10k: fix ath10k_ce_init() failpath Michal Kazior
                     ` (8 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

CE error interrupts were not disabled. This could
lead to invalid memory accesses / memory
corruption.

Also make sure CE watermark interrupts are also
disabled.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 2b99bd4..7a49cde 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -243,6 +243,16 @@ static inline void ath10k_ce_error_intr_enable(struct ath10k *ar,
 			   misc_ie_addr | CE_ERROR_MASK);
 }
 
+static inline void ath10k_ce_error_intr_disable(struct ath10k *ar,
+						u32 ce_ctrl_addr)
+{
+	u32 misc_ie_addr = ath10k_pci_read32(ar,
+					     ce_ctrl_addr + MISC_IE_ADDRESS);
+
+	ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS,
+			   misc_ie_addr & ~CE_ERROR_MASK);
+}
+
 static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
 						     u32 ce_ctrl_addr,
 						     unsigned int mask)
@@ -794,6 +804,8 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar)
 		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
 
 		ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
+		ath10k_ce_error_intr_disable(ar, ctrl_addr);
+		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
 	}
 	ath10k_pci_sleep(ar);
 }
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 06/13] ath10k: fix ath10k_ce_init() failpath
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (4 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 05/13] ath10k: make sure to mask all CE irqs Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 07/13] ath10k: remove meaningless check Michal Kazior
                     ` (7 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

Make sure to put target back to sleep. This was a
minor issue as it didn't really matter if we put
target back to sleep at this point. It just looked
wrong.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 7a49cde..657e8f2 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -1077,7 +1077,7 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 	ce_state = ath10k_ce_init_state(ar, ce_id, attr);
 	if (!ce_state) {
 		ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id);
-		return NULL;
+		goto out;
 	}
 
 	if (attr->src_nentries) {
@@ -1086,7 +1086,8 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 			ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
 				   ce_id, ret);
 			ath10k_ce_deinit(ce_state);
-			return NULL;
+			ce_state = NULL;
+			goto out;
 		}
 	}
 
@@ -1096,15 +1097,16 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 			ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
 				   ce_id, ret);
 			ath10k_ce_deinit(ce_state);
-			return NULL;
+			ce_state = NULL;
+			goto out;
 		}
 	}
 
 	/* Enable CE error interrupts */
 	ath10k_ce_error_intr_enable(ar, ctrl_addr);
 
+out:
 	ath10k_pci_sleep(ar);
-
 	return ce_state;
 }
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 07/13] ath10k: remove meaningless check
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (5 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 06/13] ath10k: fix ath10k_ce_init() failpath Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 08/13] ath10k: use ath10k_do_pci_wake/sleep Michal Kazior
                     ` (6 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

The check doesn't make much sense. If the address
were to be 0x0000 the check would fail. In this
case a 0 address isn't wrong.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 4aa7992..62df0dd 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2307,9 +2307,6 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
 	int i;
 	u32 val;
 
-	if (!SOC_GLOBAL_RESET_ADDRESS)
-		return;
-
 	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
 			       PCIE_SOC_WAKE_V_MASK);
 	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 08/13] ath10k: use ath10k_do_pci_wake/sleep
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (6 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 07/13] ath10k: remove meaningless check Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 09/13] ath10k: propagate ath10k_ce_disable_interrupts() errors Michal Kazior
                     ` (5 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

This removes some remaining direct use of the wake
register which could interfere with power state
tracking of the target device. This will allow
initialization code reordering.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 84 +++++++++++------------------------
 1 file changed, 26 insertions(+), 58 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 62df0dd..2b4f7d3 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -52,7 +52,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 					     int num);
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(struct ath10k *ar);
-static void ath10k_pci_device_reset(struct ath10k *ar);
+static int ath10k_pci_device_reset(struct ath10k *ar);
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
 static int ath10k_pci_start_intr(struct ath10k *ar);
 static void ath10k_pci_stop_intr(struct ath10k *ar);
@@ -526,21 +526,6 @@ static bool ath10k_pci_target_is_awake(struct ath10k *ar)
 	return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);
 }
 
-static int ath10k_pci_wait(struct ath10k *ar)
-{
-	int n = 100;
-
-	while (n-- && !ath10k_pci_target_is_awake(ar))
-		msleep(10);
-
-	if (n < 0) {
-		ath10k_warn("Unable to wakeup target\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
 int ath10k_do_pci_wake(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -1855,7 +1840,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	 * is in an unexpected state. We try to catch that here in order to
 	 * reset the Target and retry the probe.
 	 */
-	ath10k_pci_device_reset(ar);
+	ret = ath10k_pci_device_reset(ar);
+	if (ret) {
+		ath10k_err("failed to reset target: %d\n", ret);
+		goto err_irq;
+	}
 
 	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret)
@@ -2156,19 +2145,10 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Make sure to wake the Target before enabling Legacy
-	 * Interrupt.
-	 */
-	iowrite32(PCIE_SOC_WAKE_V_MASK,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
-
-	ret = ath10k_pci_wait(ar);
+	ret = ath10k_do_pci_wake(ar);
 	if (ret) {
-		ath10k_warn("Failed to enable legacy interrupt, target did not wake up: %d\n",
-			    ret);
 		free_irq(ar_pci->pdev->irq, ar);
+		ath10k_err("failed to wake up target: %d\n", ret);
 		return ret;
 	}
 
@@ -2184,10 +2164,8 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 		  PCIE_INTR_CE_MASK_ALL,
 		  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
 				 PCIE_INTR_ENABLE_ADDRESS));
-	iowrite32(PCIE_SOC_WAKE_RESET,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
 
+	ath10k_do_pci_sleep(ar);
 	ath10k_info("legacy interrupt handling\n");
 	return 0;
 }
@@ -2263,15 +2241,9 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	int wait_limit = 300; /* 3 sec */
 	int ret;
 
-	/* Wait for Target to finish initialization before we proceed. */
-	iowrite32(PCIE_SOC_WAKE_V_MASK,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
-
-	ret = ath10k_pci_wait(ar);
+	ret = ath10k_do_pci_wake(ar);
 	if (ret) {
-		ath10k_warn("Failed to reset target, target did not wake up: %d\n",
-			    ret);
+		ath10k_err("failed to wake up target: %d\n", ret);
 		return ret;
 	}
 
@@ -2288,31 +2260,26 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	}
 
 	if (wait_limit < 0) {
-		ath10k_err("Target stalled\n");
-		iowrite32(PCIE_SOC_WAKE_RESET,
-			  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-			  PCIE_SOC_WAKE_ADDRESS);
-		return -EIO;
+		ath10k_err("target stalled\n");
+		ret = -EIO;
+		goto out;
 	}
 
-	iowrite32(PCIE_SOC_WAKE_RESET,
-		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
-		  PCIE_SOC_WAKE_ADDRESS);
-
-	return 0;
+out:
+	ath10k_do_pci_sleep(ar);
+	return ret;
 }
 
-static void ath10k_pci_device_reset(struct ath10k *ar)
+static int ath10k_pci_device_reset(struct ath10k *ar)
 {
-	int i;
+	int i, ret;
 	u32 val;
 
-	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
-			       PCIE_SOC_WAKE_V_MASK);
-	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-		if (ath10k_pci_target_is_awake(ar))
-			break;
-		msleep(1);
+	ret = ath10k_do_pci_wake(ar);
+	if (ret) {
+		ath10k_err("failed to wake up target: %d\n",
+			   ret);
+		return ret;
 	}
 
 	/* Put Target, including PCIe, into RESET. */
@@ -2338,7 +2305,8 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
 		msleep(1);
 	}
 
-	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET);
+	ath10k_do_pci_sleep(ar);
+	return 0;
 }
 
 static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 09/13] ath10k: propagate ath10k_ce_disable_interrupts() errors
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (7 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 08/13] ath10k: use ath10k_do_pci_wake/sleep Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 10/13] ath10k: guard against CE corruption from firmware Michal Kazior
                     ` (4 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

This shouldn't be silenced. This will be necessary
for PCI init code reordering.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c  | 7 +++++--
 drivers/net/wireless/ath/ath10k/ce.h  | 2 +-
 drivers/net/wireless/ath/ath10k/pci.c | 6 +++++-
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 657e8f2..ab22d14 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -792,13 +792,13 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
 	ath10k_pci_sleep(ar);
 }
 
-void ath10k_ce_disable_interrupts(struct ath10k *ar)
+int ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
 	int ce_id, ret;
 
 	ret = ath10k_pci_wake(ar);
 	if (ret)
-		return;
+		return ret;
 
 	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
 		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -807,7 +807,10 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar)
 		ath10k_ce_error_intr_disable(ar, ctrl_addr);
 		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
 	}
+
 	ath10k_pci_sleep(ar);
+
+	return 0;
 }
 
 void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 15d45b5..67dbde6 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -234,7 +234,7 @@ void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
 /*==================CE Interrupt Handlers====================*/
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
-void ath10k_ce_disable_interrupts(struct ath10k *ar);
+int ath10k_ce_disable_interrupts(struct ath10k *ar);
 
 /* ce_attr.flags values */
 /* Use NonSnooping PCIe accesses? */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 2b4f7d3..e41665f 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -879,8 +879,12 @@ static void ath10k_pci_stop_ce(struct ath10k *ar)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	struct ath10k_pci_compl *compl;
 	struct sk_buff *skb;
+	int ret;
+
+	ret = ath10k_ce_disable_interrupts(ar);
+	if (ret)
+		ath10k_warn("failed to disable CE interrupts: %d\n", ret);
 
-	ath10k_ce_disable_interrupts(ar);
 	ath10k_pci_kill_tasklet(ar);
 
 	/* Mark pending completions as aborted, so that upper layers free up
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 10/13] ath10k: guard against CE corruption from firmware
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (8 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 09/13] ath10k: propagate ath10k_ce_disable_interrupts() errors Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 11/13] ath10k: re-arrange PCI init code Michal Kazior
                     ` (3 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

In case firmware crashes it may report CE
completions for entries that were never
submitted/filled with meaningful data. This in
turn led to NULL dereferences.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/htc.c | 5 +++++
 drivers/net/wireless/ath/ath10k/pci.c | 7 +++++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 3118d75..6d7a72e 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -191,6 +191,11 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
 	struct ath10k_htc *htc = &ar->htc;
 	struct ath10k_htc_ep *ep = &htc->endpoint[eid];
 
+	if (!skb) {
+		ath10k_warn("invalid sk_buff completion - NULL pointer. firmware crashed?\n");
+		return 0;
+	}
+
 	ath10k_htc_notify_tx_completion(ep, skb);
 	/* the skb now belongs to the completion handler */
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index e41665f..0b89726 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1270,6 +1270,13 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
 		 * Indicate the completion to higer layer to free
 		 * the buffer
 		 */
+
+		if (!netbuf) {
+			ath10k_warn("invalid sk_buff on CE %d - NULL pointer. firmware crashed?\n",
+				    ce_hdl->id);
+			continue;
+		}
+
 		ATH10K_SKB_CB(netbuf)->is_aborted = true;
 		ar_pci->msg_callbacks_current.tx_completion(ar,
 							    netbuf,
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 11/13] ath10k: re-arrange PCI init code
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (9 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 10/13] ath10k: guard against CE corruption from firmware Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 12/13] ath10k: add and fix some PCI prints Michal Kazior
                     ` (2 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

This patch moves irq registering after necessary
structures have been allocated and initialized.
This should prevent interrupts from causing
tasklet access invalid memory pointers.

Reported-By: Ben Greear <greearb@candelatech.com>
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/ce.c  | 19 ++++++--
 drivers/net/wireless/ath/ath10k/ce.h  |  1 +
 drivers/net/wireless/ath/ath10k/pci.c | 87 ++++++++++++++++++++++-------------
 3 files changed, 71 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index ab22d14..476928f 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -792,6 +792,21 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
 	ath10k_pci_sleep(ar);
 }
 
+int ath10k_ce_enable_err_irq(struct ath10k *ar)
+{
+	int i, ret;
+
+	ret = ath10k_pci_wake(ar);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < CE_COUNT; i++)
+		ath10k_ce_error_intr_enable(ar, ath10k_ce_base_address(i));
+
+	ath10k_pci_sleep(ar);
+	return 0;
+}
+
 int ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
 	int ce_id, ret;
@@ -1059,7 +1074,6 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 				const struct ce_attr *attr)
 {
 	struct ath10k_ce_pipe *ce_state;
-	u32 ctrl_addr = ath10k_ce_base_address(ce_id);
 	int ret;
 
 	/*
@@ -1105,9 +1119,6 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
 		}
 	}
 
-	/* Enable CE error interrupts */
-	ath10k_ce_error_intr_enable(ar, ctrl_addr);
-
 out:
 	ath10k_pci_sleep(ar);
 	return ce_state;
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 67dbde6..8a58bac 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -235,6 +235,7 @@ void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
 int ath10k_ce_disable_interrupts(struct ath10k *ar);
+int ath10k_ce_enable_err_irq(struct ath10k *ar);
 
 /* ce_attr.flags values */
 /* Use NonSnooping PCIe accesses? */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 0b89726..e552770 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1786,18 +1786,6 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 		pipe_info->buf_sz = (size_t) (attr->src_sz_max);
 	}
 
-	/*
-	 * Initially, establish CE completion handlers for use with BMI.
-	 * These are overwritten with generic handlers after we exit BMI phase.
-	 */
-	pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
-	ath10k_ce_send_cb_register(pipe_info->ce_hdl,
-				   ath10k_pci_bmi_send_done, 0);
-
-	pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
-	ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
-				   ath10k_pci_bmi_recv_data);
-
 	return 0;
 }
 
@@ -1830,17 +1818,27 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
 	ath10k_pci_sleep(ar);
 }
 
+static void ath10k_pci_start_bmi(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_pci_pipe *pipe;
+
+	/*
+	 * Initially, establish CE completion handlers for use with BMI.
+	 * These are overwritten with generic handlers after we exit BMI phase.
+	 */
+	pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
+	ath10k_ce_send_cb_register(pipe->ce_hdl, ath10k_pci_bmi_send_done, 0);
+
+	pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
+	ath10k_ce_recv_cb_register(pipe->ce_hdl, ath10k_pci_bmi_recv_data);
+}
+
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
 
-	ret = ath10k_pci_start_intr(ar);
-	if (ret) {
-		ath10k_err("could not start interrupt handling (%d)\n", ret);
-		goto err;
-	}
-
 	/*
 	 * Bring the target up cleanly.
 	 *
@@ -1854,13 +1852,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	ret = ath10k_pci_device_reset(ar);
 	if (ret) {
 		ath10k_err("failed to reset target: %d\n", ret);
-		goto err_irq;
+		goto err;
 	}
 
-	ret = ath10k_pci_wait_for_target_init(ar);
-	if (ret)
-		goto err_irq;
-
 	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
 		/* Force AWAKE forever */
 		ath10k_do_pci_wake(ar);
@@ -1869,25 +1863,54 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	if (ret)
 		goto err_ps;
 
-	ret = ath10k_pci_init_config(ar);
-	if (ret)
+	ret = ath10k_ce_disable_interrupts(ar);
+	if (ret) {
+		ath10k_err("failed to disable CE interrupts: %d\n", ret);
+		goto err_ce;
+	}
+
+	ret = ath10k_pci_start_intr(ar);
+	if (ret) {
+		ath10k_err("failed to start interrupt handling: %d\n", ret);
 		goto err_ce;
+	}
+
+	ret = ath10k_pci_wait_for_target_init(ar);
+	if (ret) {
+		ath10k_err("failed to wait for target to init: %d\n", ret);
+		goto err_irq;
+	}
+
+	ret = ath10k_ce_enable_err_irq(ar);
+	if (ret) {
+		ath10k_err("failed to enable CE error irq: %d\n", ret);
+		goto err_irq;
+	}
+
+	ret = ath10k_pci_init_config(ar);
+	if (ret) {
+		ath10k_err("failed to setup init config: %d\n", ret);
+		goto err_irq;
+	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU (%d)\n", ret);
-		goto err_ce;
+		goto err_irq;
 	}
 
+	ath10k_pci_start_bmi(ar);
 	return 0;
 
+err_irq:
+	ath10k_ce_disable_interrupts(ar);
+	ath10k_pci_stop_intr(ar);
+	ath10k_pci_kill_tasklet(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
 err_ps:
 	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
 		ath10k_do_pci_sleep(ar);
-err_irq:
-	ath10k_pci_stop_intr(ar);
 err:
 	return ret;
 }
@@ -2156,7 +2179,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 	if (ret < 0)
 		return ret;
 
-	ret = ath10k_do_pci_wake(ar);
+	ret = ath10k_pci_wake(ar);
 	if (ret) {
 		free_irq(ar_pci->pdev->irq, ar);
 		ath10k_err("failed to wake up target: %d\n", ret);
@@ -2176,7 +2199,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 		  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
 				 PCIE_INTR_ENABLE_ADDRESS));
 
-	ath10k_do_pci_sleep(ar);
+	ath10k_pci_sleep(ar);
 	ath10k_info("legacy interrupt handling\n");
 	return 0;
 }
@@ -2252,7 +2275,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	int wait_limit = 300; /* 3 sec */
 	int ret;
 
-	ret = ath10k_do_pci_wake(ar);
+	ret = ath10k_pci_wake(ar);
 	if (ret) {
 		ath10k_err("failed to wake up target: %d\n", ret);
 		return ret;
@@ -2277,7 +2300,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 	}
 
 out:
-	ath10k_do_pci_sleep(ar);
+	ath10k_pci_sleep(ar);
 	return ret;
 }
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 12/13] ath10k: add and fix some PCI prints
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (10 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 11/13] ath10k: re-arrange PCI init code Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-08  7:01   ` [PATCHv2 13/13] ath10k: reset device upon stopping/power down Michal Kazior
  2013-11-12 18:07   ` [PATCHv2 00/13] ath10k: pci fixes 2013-10-30 Kalle Valo
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

Add missing error reporting and adjust other
prints to make everything more consistent.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 69 ++++++++++++++++++++---------------
 1 file changed, 39 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index e552770..eaa9956 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -712,7 +712,7 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
 	ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id,
 			     flags);
 	if (ret)
-		ath10k_warn("CE send failed: %p\n", nbuf);
+		ath10k_warn("failed to send sk_buff to CE: %p\n", nbuf);
 
 	return ret;
 }
@@ -739,9 +739,10 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
 		   ar->fw_version_build);
 
 	host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
-	if (ath10k_pci_diag_read_mem(ar, host_addr,
-				     &reg_dump_area, sizeof(u32)) != 0) {
-		ath10k_warn("could not read hi_failure_state\n");
+	ret = ath10k_pci_diag_read_mem(ar, host_addr,
+				       &reg_dump_area, sizeof(u32));
+	if (ret) {
+		ath10k_err("failed to read FW dump area address: %d\n", ret);
 		return;
 	}
 
@@ -751,7 +752,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
 				       &reg_dump_values[0],
 				       REG_DUMP_COUNT_QCA988X * sizeof(u32));
 	if (ret != 0) {
-		ath10k_err("could not dump FW Dump Area\n");
+		ath10k_err("failed to read FW dump area: %d\n", ret);
 		return;
 	}
 
@@ -973,8 +974,8 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
 		case ATH10K_PCI_COMPL_RECV:
 			ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1);
 			if (ret) {
-				ath10k_warn("Unable to post recv buffer for pipe: %d\n",
-					    compl->pipe_info->pipe_num);
+				ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
+					    compl->pipe_info->pipe_num, ret);
 				break;
 			}
 
@@ -1113,7 +1114,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 	for (i = 0; i < num; i++) {
 		skb = dev_alloc_skb(pipe_info->buf_sz);
 		if (!skb) {
-			ath10k_warn("could not allocate skbuff for pipe %d\n",
+			ath10k_warn("failed to allocate skbuff for pipe %d\n",
 				    num);
 			ret = -ENOMEM;
 			goto err;
@@ -1126,7 +1127,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 					 DMA_FROM_DEVICE);
 
 		if (unlikely(dma_mapping_error(ar->dev, ce_data))) {
-			ath10k_warn("could not dma map skbuff\n");
+			ath10k_warn("failed to DMA map sk_buff\n");
 			dev_kfree_skb_any(skb);
 			ret = -EIO;
 			goto err;
@@ -1141,7 +1142,7 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 		ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb,
 						 ce_data);
 		if (ret) {
-			ath10k_warn("could not enqueue to pipe %d (%d)\n",
+			ath10k_warn("failed to enqueue to pipe %d: %d\n",
 				    num, ret);
 			goto err;
 		}
@@ -1171,8 +1172,8 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
 		ret = ath10k_pci_post_rx_pipe(pipe_info,
 					      attr->dest_nentries - 1);
 		if (ret) {
-			ath10k_warn("Unable to replenish recv buffers for pipe: %d\n",
-				    pipe_num);
+			ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
+				    pipe_num, ret);
 
 			for (; pipe_num >= 0; pipe_num--) {
 				pipe_info = &ar_pci->pipe_info[pipe_num];
@@ -1192,14 +1193,15 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 
 	ret = ath10k_pci_start_ce(ar);
 	if (ret) {
-		ath10k_warn("could not start CE (%d)\n", ret);
+		ath10k_warn("failed to start CE: %d\n", ret);
 		return ret;
 	}
 
 	/* Post buffers once to start things off. */
 	ret = ath10k_pci_post_rx(ar);
 	if (ret) {
-		ath10k_warn("could not post rx pipes (%d)\n", ret);
+		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
+			    ret);
 		return ret;
 	}
 
@@ -1593,7 +1595,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
 					      CORE_CTRL_ADDRESS,
 					  &core_ctrl);
 	if (ret) {
-		ath10k_warn("Unable to read core ctrl\n");
+		ath10k_warn("failed to read core_ctrl: %d\n", ret);
 		return ret;
 	}
 
@@ -1603,10 +1605,13 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
 	ret = ath10k_pci_diag_write_access(ar, SOC_CORE_BASE_ADDRESS |
 					       CORE_CTRL_ADDRESS,
 					   core_ctrl);
-	if (ret)
-		ath10k_warn("Unable to set interrupt mask\n");
+	if (ret) {
+		ath10k_warn("failed to set target CPU interrupt mask: %d\n",
+			    ret);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 
 static int ath10k_pci_init_config(struct ath10k *ar)
@@ -1765,7 +1770,7 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
 
 		pipe_info->ce_hdl = ath10k_ce_init(ar, pipe_num, attr);
 		if (pipe_info->ce_hdl == NULL) {
-			ath10k_err("Unable to initialize CE for pipe: %d\n",
+			ath10k_err("failed to initialize CE for pipe: %d\n",
 				   pipe_num);
 
 			/* It is safe to call it here. It checks if ce_hdl is
@@ -1832,6 +1837,8 @@ static void ath10k_pci_start_bmi(struct ath10k *ar)
 
 	pipe = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
 	ath10k_ce_recv_cb_register(pipe->ce_hdl, ath10k_pci_bmi_recv_data);
+
+	ath10k_dbg(ATH10K_DBG_BOOT, "boot start bmi\n");
 }
 
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
@@ -1860,8 +1867,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		ath10k_do_pci_wake(ar);
 
 	ret = ath10k_pci_ce_init(ar);
-	if (ret)
+	if (ret) {
+		ath10k_err("failed to initialize CE: %d\n", ret);
 		goto err_ps;
+	}
 
 	ret = ath10k_ce_disable_interrupts(ar);
 	if (ret) {
@@ -1895,7 +1904,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
-		ath10k_err("could not wake up target CPU (%d)\n", ret);
+		ath10k_err("could not wake up target CPU: %d\n", ret);
 		goto err_irq;
 	}
 
@@ -2397,7 +2406,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 
 	ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
 	if (!ar) {
-		ath10k_err("ath10k_core_create failed!\n");
+		ath10k_err("failed to create driver core\n");
 		ret = -EINVAL;
 		goto err_ar_pci;
 	}
@@ -2416,20 +2425,20 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 	 */
 	ret = pci_assign_resource(pdev, BAR_NUM);
 	if (ret) {
-		ath10k_err("cannot assign PCI space: %d\n", ret);
+		ath10k_err("failed to assign PCI space: %d\n", ret);
 		goto err_ar;
 	}
 
 	ret = pci_enable_device(pdev);
 	if (ret) {
-		ath10k_err("cannot enable PCI device: %d\n", ret);
+		ath10k_err("failed to enable PCI device: %d\n", ret);
 		goto err_ar;
 	}
 
 	/* Request MMIO resources */
 	ret = pci_request_region(pdev, BAR_NUM, "ath");
 	if (ret) {
-		ath10k_err("PCI MMIO reservation error: %d\n", ret);
+		ath10k_err("failed to request MMIO region: %d\n", ret);
 		goto err_device;
 	}
 
@@ -2439,13 +2448,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 	 */
 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 	if (ret) {
-		ath10k_err("32-bit DMA not available: %d\n", ret);
+		ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret);
 		goto err_region;
 	}
 
 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 	if (ret) {
-		ath10k_err("cannot enable 32-bit consistent DMA\n");
+		ath10k_err("failed to set consistent DMA mask to 32-bit\n");
 		goto err_region;
 	}
 
@@ -2462,7 +2471,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 	/* Arrange for access to Target SoC registers. */
 	mem = pci_iomap(pdev, BAR_NUM, 0);
 	if (!mem) {
-		ath10k_err("PCI iomap error\n");
+		ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM);
 		ret = -EIO;
 		goto err_master;
 	}
@@ -2485,7 +2494,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 
 	ret = ath10k_core_register(ar, chip_id);
 	if (ret) {
-		ath10k_err("could not register driver core (%d)\n", ret);
+		ath10k_err("failed to register driver core: %d\n", ret);
 		goto err_iomap;
 	}
 
@@ -2551,7 +2560,7 @@ static int __init ath10k_pci_init(void)
 
 	ret = pci_register_driver(&ath10k_pci_driver);
 	if (ret)
-		ath10k_err("pci_register_driver failed [%d]\n", ret);
+		ath10k_err("failed to register PCI driver: %d\n", ret);
 
 	return ret;
 }
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCHv2 13/13] ath10k: reset device upon stopping/power down
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (11 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 12/13] ath10k: add and fix some PCI prints Michal Kazior
@ 2013-11-08  7:01   ` Michal Kazior
  2013-11-12 18:07   ` [PATCHv2 00/13] ath10k: pci fixes 2013-10-30 Kalle Valo
  13 siblings, 0 replies; 35+ messages in thread
From: Michal Kazior @ 2013-11-08  7:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

This should make sure the device won't issue any
interrupts nor access any memory after the driver
is stopped/freed thus avoid memory corruption in
some cases.

Reported-By: Ben Greear <greearb@candelatech.com>
Reported-By: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index eaa9956..46c94ce 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1353,6 +1353,13 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
 	ath10k_pci_cleanup_ce(ar);
 	ath10k_pci_buffer_cleanup(ar);
 
+	/* Make the sure the device won't access any structures on the host by
+	 * resetting it. The device was fed with PCI CE ringbuffer
+	 * configuration during init. If ringbuffers are freed and the device
+	 * were to access them this could lead to memory corruption on the
+	 * host. */
+	ath10k_pci_device_reset(ar);
+
 	ar_pci->started = 0;
 }
 
@@ -1915,6 +1922,7 @@ err_irq:
 	ath10k_ce_disable_interrupts(ar);
 	ath10k_pci_stop_intr(ar);
 	ath10k_pci_kill_tasklet(ar);
+	ath10k_pci_device_reset(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
 err_ps:
@@ -1929,6 +1937,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
 	ath10k_pci_stop_intr(ar);
+	ath10k_pci_device_reset(ar);
 
 	ath10k_pci_ce_deinit(ar);
 	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCHv2 00/13] ath10k: pci fixes 2013-10-30
  2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
                     ` (12 preceding siblings ...)
  2013-11-08  7:01   ` [PATCHv2 13/13] ath10k: reset device upon stopping/power down Michal Kazior
@ 2013-11-12 18:07   ` Kalle Valo
  13 siblings, 0 replies; 35+ messages in thread
From: Kalle Valo @ 2013-11-12 18:07 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, linux-wireless

Michal Kazior <michal.kazior@tieto.com> writes:

> Hi,
>
> This patchset contains a slew of PCI/CE cleanups
> and fixes. The aim of the patchset is to deal with
> CE null dereference bugs Ben has been reporting on
> the mailing list for some time now.
>
> v2:
>  * fix prints
>  * fix commit messages
>  * add additional patch
>    (ath10k: reset device upon stopping/power down)
>
>
> Michal Kazior (13):
>   ath10k: remove ar_pci->ce_count
>   ath10k: don't forget to kill fw error tasklet
>   ath10k: split tasklet killing function
>   ath10k: rename ath10k_pci_reset_target()
>   ath10k: make sure to mask all CE irqs
>   ath10k: fix ath10k_ce_init() failpath
>   ath10k: remove meaningless check
>   ath10k: use ath10k_do_pci_wake/sleep
>   ath10k: propagate ath10k_ce_disable_interrupts() errors
>   ath10k: guard against CE corruption from firmware
>   ath10k: re-arrange PCI init code
>   ath10k: add and fix some PCI prints
>   ath10k: reset device upon stopping/power down

Thanks, all 13 applied.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2013-11-12 18:07 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-30 11:42 [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 01/12] ath10k: remove ar_pci->ce_count Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 02/12] ath10k: don't forget to kill fw error tasklet Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 03/12] ath10k: split tasklet killing function Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 04/12] ath10k: rename function to match it's role Michal Kazior
2013-11-06 13:08   ` Kalle Valo
2013-10-30 11:42 ` [PATCH/RFT 05/12] ath10k: make sure to mask all CE irqs Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 06/12] ath10k: fix ath10k_ce_init() failpath Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 07/12] ath10k: remove meaningless check Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 08/12] ath10k: use ath10k_do_pci_wake/sleep Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 09/12] ath10k: propagate ath10k_ce_disable_interrupts() errors Michal Kazior
2013-11-06 12:34   ` Kalle Valo
2013-10-30 11:42 ` [PATCH/RFT 10/12] ath10k: guard against CE corruption from firmware Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 11/12] ath10k: re-arrange PCI init code Michal Kazior
2013-10-30 11:42 ` [PATCH/RFT 12/12] ath10k: add some debug prints Michal Kazior
2013-10-30 17:16   ` Joe Perches
2013-11-06 12:43     ` Kalle Valo
2013-11-06 12:38   ` Kalle Valo
2013-10-30 17:06 ` [PATCH/RFT 00/12] ath10k: pci fixes 2013-10-30 Ben Greear
2013-10-30 23:41 ` Ben Greear
2013-11-08  7:01 ` [PATCHv2 00/13] " Michal Kazior
2013-11-08  7:01   ` [PATCHv2 01/13] ath10k: remove ar_pci->ce_count Michal Kazior
2013-11-08  7:01   ` [PATCHv2 02/13] ath10k: don't forget to kill fw error tasklet Michal Kazior
2013-11-08  7:01   ` [PATCHv2 03/13] ath10k: split tasklet killing function Michal Kazior
2013-11-08  7:01   ` [PATCHv2 04/13] ath10k: rename ath10k_pci_reset_target() Michal Kazior
2013-11-08  7:01   ` [PATCHv2 05/13] ath10k: make sure to mask all CE irqs Michal Kazior
2013-11-08  7:01   ` [PATCHv2 06/13] ath10k: fix ath10k_ce_init() failpath Michal Kazior
2013-11-08  7:01   ` [PATCHv2 07/13] ath10k: remove meaningless check Michal Kazior
2013-11-08  7:01   ` [PATCHv2 08/13] ath10k: use ath10k_do_pci_wake/sleep Michal Kazior
2013-11-08  7:01   ` [PATCHv2 09/13] ath10k: propagate ath10k_ce_disable_interrupts() errors Michal Kazior
2013-11-08  7:01   ` [PATCHv2 10/13] ath10k: guard against CE corruption from firmware Michal Kazior
2013-11-08  7:01   ` [PATCHv2 11/13] ath10k: re-arrange PCI init code Michal Kazior
2013-11-08  7:01   ` [PATCHv2 12/13] ath10k: add and fix some PCI prints Michal Kazior
2013-11-08  7:01   ` [PATCHv2 13/13] ath10k: reset device upon stopping/power down Michal Kazior
2013-11-12 18:07   ` [PATCHv2 00/13] ath10k: pci fixes 2013-10-30 Kalle Valo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).