From dwliu at qca.qualcomm.com  Mon Nov  4 03:42:44 2013
From: dwliu at qca.qualcomm.com (Liu, David)
Date: Mon, 4 Nov 2013 08:42:44 +0000
Subject: bug report for cus223 and ath10k
Message-ID: <76AF93A11AB52E4187A259215B6252F6315C58CD@apsinexd01a.ap.qualcomm.com>

hi 
Here have problem find form QCA internal about wifi driver and compat driver...
is here can report bug??

If not, please feedback to me the correct contact.

Thanks.

Regards,
David Liu


From greearb at candelatech.com  Mon Nov  4 12:18:16 2013
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Mon,  4 Nov 2013 09:18:16 -0800
Subject: [PATCH] ath10k:  Fix un-initialized debug objects.
Message-ID: <1383585496-17580-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

If the 'ar' registration fails early, the debug
objects were not initialized, and trouble ensued when
the object was later destroyed and the un-initialized
objects were accessed.

Per Kalle's suggestion, move the debug_destroy to the
core_unregister method.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 2a360ca..7d86876 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -738,8 +738,6 @@ EXPORT_SYMBOL(ath10k_core_create);
 
 void ath10k_core_destroy(struct ath10k *ar)
 {
-	ath10k_debug_destroy(ar);
-
 	flush_workqueue(ar->workqueue);
 	destroy_workqueue(ar->workqueue);
 
@@ -986,6 +984,8 @@ void ath10k_core_unregister(struct ath10k *ar)
 	ath10k_mac_unregister(ar);
 
 	ath10k_core_free_firmware_files(ar);
+
+	ath10k_debug_destroy(ar);
 }
 EXPORT_SYMBOL(ath10k_core_unregister);
 
-- 
1.7.11.7



From greearb at candelatech.com  Mon Nov  4 12:19:34 2013
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Mon,  4 Nov 2013 09:19:34 -0800
Subject: [PATCH] ath10k: Add logging to better determine some VIF/STA creation
 failures.
Message-ID: <1383585574-17779-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

---
 drivers/net/wireless/ath/ath10k/mac.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index f45eca0..93e52c5 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -322,12 +322,16 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 	lockdep_assert_held(&ar->conf_mutex);
 
 	ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
-	if (ret)
+	if (ret) {
+		ath10k_dbg(ATH10K_DBG_WMI, "wmi_peer_create failed: %i\n", ret);
 		return ret;
+	}
 
 	ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
-	if (ret)
+	if (ret) {
+		ath10k_dbg(ATH10K_DBG_WMI, "wmi_wait_for_peer_created failed: %i\n", ret);
 		return ret;
+	}
 
 	return 0;
 }
@@ -2404,8 +2408,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 			ret = ath10k_peer_create(ar, arvif->vdev_id,
 						 info->bssid);
 			if (ret)
-				ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
-					    info->bssid, arvif->vdev_id);
+				ath10k_warn("Failed to add peer: %pM for VDEV: %d ret: %i\n",
+					    info->bssid, arvif->vdev_id, ret);
 
 			if (vif->type == NL80211_IFTYPE_STATION) {
 				/*
@@ -2687,8 +2691,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
 		if (ret)
-			ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
-				    sta->addr, arvif->vdev_id);
+			ath10k_warn("Failed to add peer: %pM for VDEV: %d, ret: %i\n",
+				    sta->addr, arvif->vdev_id, ret);
 	} else if ((old_state == IEEE80211_STA_NONE &&
 		    new_state == IEEE80211_STA_NOTEXIST)) {
 		/*
-- 
1.7.11.7



From greearb at candelatech.com  Mon Nov  4 22:03:22 2013
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 04 Nov 2013 19:03:22 -0800
Subject: bug report for cus223 and ath10k
In-Reply-To: <76AF93A11AB52E4187A259215B6252F6315C58CD@apsinexd01a.ap.qualcomm.com>
References: <76AF93A11AB52E4187A259215B6252F6315C58CD@apsinexd01a.ap.qualcomm.com>
Message-ID: <52785FFA.6080801@candelatech.com>

On 11/04/2013 12:42 AM, Liu, David wrote:
> hi
> Here have problem find form QCA internal about wifi driver and compat driver...
> is here can report bug??
>
> If not, please feedback to me the correct contact.

You shouldn't post any proprietary information to this list, but other than
that it should be a good place to report bugs.  There is probably
an internal QCA bug list as well, but I have no idea where it would
be found.

Thanks,
Ben

>
> Thanks.
>
> Regards,
> David Liu
>
> _______________________________________________
> ath10k mailing list
> ath10k at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
>


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



From greearb at candelatech.com  Tue Nov  5 13:51:55 2013
From: greearb at candelatech.com (Ben Greear)
Date: Tue, 05 Nov 2013 10:51:55 -0800
Subject: What to do about hung firmware?
Message-ID: <52793E4B.20302@candelatech.com>

I'm seeing cases where it appears the firmware just gets
stuck and will not answer any WMI requests.

ath10k just patiently keeps timing out WMI commands,
(while holding locks, and making the whole system run slow).

Should we maybe keep a last-msg-from firmware time stamp
and just whack the firmware if we detect it hung?  In addition
to this, we could add some 'ping' message that will get sent
periodically to the firmware to make sure it is alive.
We should be able to do this with existing WMI API, just
need to pick a message to send that expects some response.

Thanks,
Ben

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



From michal.kazior at tieto.com  Wed Nov  6 02:07:15 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 6 Nov 2013 08:07:15 +0100
Subject: What to do about hung firmware?
In-Reply-To: <52793E4B.20302@candelatech.com>
References: <52793E4B.20302@candelatech.com>
Message-ID: <CA+BoTQk2EZddNywAMRLF2qpWafpD4OvyDrtvg+iTM4atcm44ig@mail.gmail.com>

On 5 November 2013 19:51, Ben Greear <greearb at candelatech.com> wrote:
> I'm seeing cases where it appears the firmware just gets
> stuck and will not answer any WMI requests.

You probably mean FW doesn't replenish HTT TX credits for WMI.


> ath10k just patiently keeps timing out WMI commands,
> (while holding locks, and making the whole system run slow).
>
> Should we maybe keep a last-msg-from firmware time stamp
> and just whack the firmware if we detect it hung?  In addition
> to this, we could add some 'ping' message that will get sent
> periodically to the firmware to make sure it is alive.
> We should be able to do this with existing WMI API, just
> need to pick a message to send that expects some response.

Probably the easiest/shortest way to do this is to store a timestamp
in ath10k_wmi_op_ep_tx_credits() and check against it in
ath10k_wmi_cmd_send(). Once you deem FW stopped responding you could
queue ar->restat_work.

You probably could try WMI_ECHO_CMDID to implement a keep alive when
idling (i.e. not sending WMI commands for a few seconds at least).


Micha?


From greearb at candelatech.com  Wed Nov  6 02:21:19 2013
From: greearb at candelatech.com (Ben Greear)
Date: Tue, 05 Nov 2013 23:21:19 -0800
Subject: What to do about hung firmware?
In-Reply-To: <CA+BoTQk2EZddNywAMRLF2qpWafpD4OvyDrtvg+iTM4atcm44ig@mail.gmail.com>
References: <52793E4B.20302@candelatech.com>
 <CA+BoTQk2EZddNywAMRLF2qpWafpD4OvyDrtvg+iTM4atcm44ig@mail.gmail.com>
Message-ID: <5279EDEF.3090009@candelatech.com>

On 11/05/2013 11:07 PM, Michal Kazior wrote:
> On 5 November 2013 19:51, Ben Greear <greearb at candelatech.com> wrote:
>> I'm seeing cases where it appears the firmware just gets
>> stuck and will not answer any WMI requests.
>
> You probably mean FW doesn't replenish HTT TX credits for WMI.

Maybe so..I added some debugging to check on that, but then of course
I could not reproduce the problem.

>> ath10k just patiently keeps timing out WMI commands,
>> (while holding locks, and making the whole system run slow).
>>
>> Should we maybe keep a last-msg-from firmware time stamp
>> and just whack the firmware if we detect it hung?  In addition
>> to this, we could add some 'ping' message that will get sent
>> periodically to the firmware to make sure it is alive.
>> We should be able to do this with existing WMI API, just
>> need to pick a message to send that expects some response.
>
> Probably the easiest/shortest way to do this is to store a timestamp
> in ath10k_wmi_op_ep_tx_credits() and check against it in
> ath10k_wmi_cmd_send(). Once you deem FW stopped responding you could
> queue ar->restat_work.
>
> You probably could try WMI_ECHO_CMDID to implement a keep alive when
> idling (i.e. not sending WMI commands for a few seconds at least).

Sounds good.  I'll work on this if I start seeing the lockups
again...

Thanks,
Ben


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



From kvalo at qca.qualcomm.com  Wed Nov  6 02:46:14 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 09:46:14 +0200
Subject: What to do about hung firmware?
In-Reply-To: <CA+BoTQk2EZddNywAMRLF2qpWafpD4OvyDrtvg+iTM4atcm44ig@mail.gmail.com>
 (Michal Kazior's message of "Wed, 6 Nov 2013 08:07:15 +0100")
References: <52793E4B.20302@candelatech.com>
 <CA+BoTQk2EZddNywAMRLF2qpWafpD4OvyDrtvg+iTM4atcm44ig@mail.gmail.com>
Message-ID: <87ob5yt1kp.fsf@kamboji.qca.qualcomm.com>

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

> You probably could try WMI_ECHO_CMDID to implement a keep alive when
> idling (i.e. not sending WMI commands for a few seconds at least).

Sending something periodically would be bad from power consumption point
of view. We would need to either disable it by default, only send it if
there's a problem or something like that.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov  6 03:50:19 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 10:50:19 +0200
Subject: [PATCH -next] ath10k: fix possible memory leak in
 ath10k_pci_probe()
In-Reply-To: <CAPgLHd9o1oGjjM=9B2H0tB41t8Kinp_1Djp6aA=sW5Eo5M7jfA@mail.gmail.com>
 (Wei Yongjun's message of "Wed, 30 Oct 2013 13:24:39 +0800")
References: <CAPgLHd9o1oGjjM=9B2H0tB41t8Kinp_1Djp6aA=sW5Eo5M7jfA@mail.gmail.com>
Message-ID: <87fvr9ud6c.fsf@kamboji.qca.qualcomm.com>

Wei Yongjun <weiyj.lk at gmail.com> writes:

> From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
>
> memory is malloced in ath10k_pci_probe() and should be freed before
> leaving from the error handling cases, otherwise it will cause
> memory leak.
>
> Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov  6 04:47:11 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 11:47:11 +0200
Subject: [PATCH 1/3] ath10k: add phyerr/dfs handling
In-Reply-To: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
 (Marek Puzyniak's message of "Tue, 29 Oct 2013 13:06:32 +0100")
References: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
Message-ID: <87bo1xuajk.fsf@kamboji.qca.qualcomm.com>

Marek Puzyniak <marek.puzyniak at tieto.com> writes:

> From: Janusz Dziedzic <janusz.dziedzic at tieto.com>
>
> Handle phyerr, dfs event, radar_report and fft_report.
> Add also debugfs dfs_simulate_radar and dfs_stats files.
> Use ath dfs pattern detector.
>
> Signed-off-by: Janusz Dziedzic <janusz.dziedzic at tieto.com>

Are there any dependencies to mac80211 or cfg80211 patches? There has
been quite a lot of changes with DFS lately and it would be good to have
all those patches in ath-next branch before I apply these.

> --- a/drivers/net/wireless/ath/ath10k/debug.c
> +++ b/drivers/net/wireless/ath/ath10k/debug.c
> @@ -21,6 +21,14 @@
>  #include "core.h"
>  #include "debug.h"
>  
> +#define ATH10K_DFS_STAT(s, p) (\
> +	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
> +			 ar->debug.dfs_stats.p))
> +
> +#define ATH10K_DFS_POOL_STAT(s, p) (\
> +	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
> +			 ar->debug.dfs_pool_stats.p))

As these are only used by ath10k_read_file_dfs() better to move those
just to top of that function.

> +static ssize_t ath10k_read_file_dfs(struct file *file, char __user *user_buf,
> +				    size_t count, loff_t *ppos)
> +{

ath10k_read_dfs_stats()?

> +	int retval = 0, size = 8000, len = 0;

Like Joe said, size can be const.

> +	struct ath10k *ar = file->private_data;
> +	char *buf;
> +
> +	buf = kzalloc(size, GFP_KERNEL);
> +	if (buf == NULL)
> +		return -ENOMEM;
> +
> +	if (!ar->dfs_detector) {
> +		len += scnprintf(buf + len, size - len, "DFS not enabled\n");
> +		goto exit;
> +	}
> +
> +	ar->debug.dfs_pool_stats = ar->dfs_detector->get_stats(ar->dfs_detector);

I think we need to take conf_mutex to make sure ar->dfs_detector is not
destroyed while we use it.

> diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
> index 46e640a..cde53d6 100644
> --- a/drivers/net/wireless/ath/ath10k/debug.h
> +++ b/drivers/net/wireless/ath/ath10k/debug.h
> @@ -33,6 +33,7 @@ enum ath10k_debug_mask {
>  	ATH10K_DBG_MGMT		= 0x00000100,
>  	ATH10K_DBG_DATA		= 0x00000200,
>  	ATH10K_DBG_BMI		= 0x00000400,
> +	ATH10K_DBG_REGULATORY	= 0x00000800,
>  	ATH10K_DBG_ANY		= 0xffffffff,
>  };
>  
> @@ -53,6 +54,7 @@ void ath10k_debug_read_service_map(struct ath10k *ar,
>  void ath10k_debug_read_target_stats(struct ath10k *ar,
>  				    struct wmi_stats_event *ev);
>  
> +#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
>  #else

Empty line after #define

>  static inline int ath10k_debug_start(struct ath10k *ar)
>  {
> @@ -82,6 +84,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
>  						  struct wmi_stats_event *ev)
>  {
>  }
> +#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
>  #endif /* CONFIG_ATH10K_DEBUGFS */

Empty line before and after #define.

>  
>  #ifdef CONFIG_ATH10K_DEBUG
> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
> index bbb0efa..79f8bfd 100644
> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -1438,9 +1438,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
>  {
>  	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
>  	struct ath10k *ar = hw->priv;
> +	bool result;
>  
>  	ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
>  
> +	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
> +		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%X\n",
> +			   request->dfs_region);

"0x%x" (also applies to elsewhere in the patch)

> --- a/drivers/net/wireless/ath/ath10k/wmi.c
> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> @@ -1383,9 +1383,251 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
>  	ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
>  }
>  
> +static void ath10k_dfs_radar_report(struct ath10k *ar,
> +				    struct wmi_single_phyerr_rx_event *event,
> +				    struct phyerr_radar_report *rr,
> +				    u64 tsf)
> +{
> +	u32 reg0, reg1, tsf32l;
> +	struct pulse_event pe;
> +	u64 tsf64;
> +	u8 rssi, width;

What about locking? Does this function assume that conf_mutex is held?
If yes, please document that with lockdep_assert_held(). If no, we have
a problem :)

(Reads wmi.c)

Ah, wmi events don't sleep anymore, forgot that. So we can't really use
conf_mutex here. I guess our options are bring back worker for wmi
events or use spinlock.

> +
> +	reg0 = __le32_to_cpu(rr->reg0);
> +	reg1 = __le32_to_cpu(rr->reg1);
> +
> +	ath10k_dbg(ATH10K_DBG_REGULATORY,
> +		   "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
> +		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
> +		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
> +		   MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
> +		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
> +	ath10k_dbg(ATH10K_DBG_REGULATORY,
> +		   "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
> +		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
> +		   MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
> +		   MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
> +		   MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
> +		   MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
> +	ath10k_dbg(ATH10K_DBG_REGULATORY,
> +		   "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
> +		   MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
> +		   MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
> +
> +	if (!ar->dfs_detector)
> +		return;
> +
> +	/* report event to DFS pattern detector */
> +	tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp);
> +	tsf64 = tsf & (~0xFFFFFFFFULL);
> +	tsf64 |= tsf32l;
> +
> +	width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR);
> +	rssi = event->hdr.rssi_combined;
> +
> +	/*
> +	 * hardware store this as 8 bit signed value,
> +	 * set to zero if negative number
> +	 */

to be consistent with rest of the comments in ath10k:

"/* hardware...."

> +	if (rssi & 0x80)
> +		rssi = 0;
> +
> +	pe.ts = tsf64;
> +	pe.freq = ar->hw->conf.chandef.chan->center_freq;
> +	pe.width = width;
> +	pe.rssi = rssi;
> +
> +	ath10k_dbg(ATH10K_DBG_REGULATORY,
> +		   "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
> +		   pe.freq, pe.width, pe.rssi, pe.ts);
> +
> +	ATH10K_DFS_STAT_INC(ar, pulses_detected);
> +
> +	if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
> +		ath10k_dbg(ATH10K_DBG_REGULATORY,
> +			   "dfs no pulse pattern detected, yet\n");
> +		return;
> +	}
> +
> +	ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
> +	ATH10K_DFS_STAT_INC(ar, radar_detected);
> +	ieee80211_radar_detected(ar->hw);
> +}
> +
> +static int ath10k_dfs_fft_report(struct ath10k *ar,
> +				 struct wmi_single_phyerr_rx_event *event,
> +				 struct phyerr_fft_report *fftr,
> +				 u64 tsf)
> +{
> +	u32 reg0, reg1;
> +	u8 rssi, peak_mag;
> +
> +	reg0 = __le32_to_cpu(fftr->reg0);
> +	reg1 = __le32_to_cpu(fftr->reg1);
> +	rssi = event->hdr.rssi_combined;

locking?

> +	ath10k_dbg(ATH10K_DBG_REGULATORY,
> +		   "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
> +		   MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
> +		   MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
> +		   MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
> +		   MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
> +	ath10k_dbg(ATH10K_DBG_REGULATORY,
> +		   "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
> +		   MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
> +		   MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
> +		   MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG),
> +		   MS(reg1, SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB));
> +
> +	peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
> +
> +	/* false event detection */
> +	if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
> +	    peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
> +		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
> +		ATH10K_DFS_STAT_INC(ar, pulses_discarded);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void ath10k_wmi_event_dfs(struct ath10k *ar,
> +				 struct wmi_single_phyerr_rx_event *event,
> +				 u64 tsf)
> +{
> +	int buf_len, tlv_len, res, i = 0;
> +	struct phyerr_tlv *tlv;
> +	struct phyerr_radar_report *rr;
> +	struct phyerr_fft_report *fftr;
> +	u8 *tlv_buf;

locking?

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov  6 04:54:32 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 11:54:32 +0200
Subject: [PATCH 2/3] ath10k: introduce DFS implementation
In-Reply-To: <1383048394-15256-2-git-send-email-marek.puzyniak@tieto.com>
 (Marek Puzyniak's message of "Tue, 29 Oct 2013 13:06:33 +0100")
References: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
 <1383048394-15256-2-git-send-email-marek.puzyniak@tieto.com>
Message-ID: <877gclua7b.fsf@kamboji.qca.qualcomm.com>

Marek Puzyniak <marek.puzyniak at tieto.com> writes:

> Configure interface combination for AP running on channels
> where radar detection is required. It allows only one type
> of interface - AP on DFS channel and limits number of AP
> interfaces to 8. Setup WMI channel flags accordingly to mac
> channel configuration. CAC based on additional monitor vdev
> is started if required for current channel.
>
> Signed-off-by: Marek Puzyniak <marek.puzyniak at tieto.com>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

[...]

> +static const struct ieee80211_iface_limit ath10k_if_dfs_limits[] = {
> +	{
> +	.max	= 8,
> +	.types	= BIT(NL80211_IFTYPE_AP)
> +	},
> +};
> +
> +static const struct ieee80211_iface_combination ath10k_if_comb[] = {
> +	{
> +		.limits = ath10k_if_limits,
> +		.n_limits = ARRAY_SIZE(ath10k_if_limits),
> +		.max_interfaces = 8,
> +		.num_different_channels = 1,
> +		.beacon_int_infra_match = true,
> +	},
> +	{
> +		.limits = ath10k_if_dfs_limits,
> +		.n_limits = ARRAY_SIZE(ath10k_if_dfs_limits),
> +		.max_interfaces = 8,
> +		.num_different_channels = 1,
> +		.beacon_int_infra_match = true,
> +		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) |
> +					BIT(NL80211_CHAN_WIDTH_20) |
> +					BIT(NL80211_CHAN_WIDTH_40) |
> +					BIT(NL80211_CHAN_WIDTH_80),
> +	}
>  };
>  
>  static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
> @@ -3531,8 +3667,8 @@ int ath10k_mac_register(struct ath10k *ar)
>  	 */
>  	ar->hw->queues = 4;
>  
> -	ar->hw->wiphy->iface_combinations = &ath10k_if_comb;
> -	ar->hw->wiphy->n_iface_combinations = 1;
> +	ar->hw->wiphy->iface_combinations = ath10k_if_comb;
> +	ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb);

If ATH10K_DFS_CERTIFIED is disabled should we still enable
radar_detect_widths? Doesn't that enable DFS even it should be disabled?

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov  6 04:55:48 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 11:55:48 +0200
Subject: [PATCH 1/3] ath10k: add phyerr/dfs handling
In-Reply-To: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
 (Marek Puzyniak's message of "Tue, 29 Oct 2013 13:06:32 +0100")
References: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
Message-ID: <8738n9ua57.fsf@kamboji.qca.qualcomm.com>

Marek Puzyniak <marek.puzyniak at tieto.com> writes:

> From: Janusz Dziedzic <janusz.dziedzic at tieto.com>
>
> Handle phyerr, dfs event, radar_report and fft_report.
> Add also debugfs dfs_simulate_radar and dfs_stats files.
> Use ath dfs pattern detector.
>
> Signed-off-by: Janusz Dziedzic <janusz.dziedzic at tieto.com>

Forgot to mention that after I applied these three patches I saw two new
checkpatch warnings:

drivers/net/wireless/ath/ath10k/debug.c:684: WARNING: line over 80 characters
drivers/net/wireless/ath/ath10k/wmi.c:1544: WARNING: line over 80 characters

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov  6 06:50:51 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 13:50:51 +0200
Subject: [PATCH] ath10k: Fix crash due to tasklet race.
In-Reply-To: <CA+BoTQ=qUgR4TEcUMjV88RD+fFreCkkEtHfu5hB2_BguirfNHg@mail.gmail.com>
 (Michal Kazior's message of "Wed, 30 Oct 2013 10:03:48 +0100")
References: <1383082737-20728-1-git-send-email-greearb@candelatech.com>
 <CA+BoTQ=qUgR4TEcUMjV88RD+fFreCkkEtHfu5hB2_BguirfNHg@mail.gmail.com>
Message-ID: <87r4atsq90.fsf@kamboji.qca.qualcomm.com>

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

> On 29 October 2013 22:38,  <greearb at candelatech.com> wrote:
>> From: Ben Greear <greearb at candelatech.com>
>>
>> The tasklet can run after the rings have been cleaned up,
>> so check for NULL before de-referencing the ring.
>>
>> Signed-off-by: Ben Greear <greearb at candelatech.com>
>> ---
>>  drivers/net/wireless/ath/ath10k/ce.c | 10 ++++++++--
>>  1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
>> index d243f28..dfcfda9 100644
>> --- a/drivers/net/wireless/ath/ath10k/ce.c
>> +++ b/drivers/net/wireless/ath/ath10k/ce.c
>> @@ -547,12 +547,18 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
>>         struct ath10k_ce_ring *src_ring = ce_state->src_ring;
>>         u32 ctrl_addr = ce_state->ctrl_addr;
>>         struct ath10k *ar = ce_state->ar;
>> -       unsigned int nentries_mask = src_ring->nentries_mask;
>> -       unsigned int sw_index = src_ring->sw_index;
>> +       unsigned int nentries_mask;
>> +       unsigned int sw_index;
>>         struct ce_desc *sdesc, *sbase;
>>         unsigned int read_index;
>>         int ret;
>>
>> +       if (!src_ring)
>> +               return -EIO;
>
> I don't think this is a proper way to fix the problem. What should be
> done is initialization clean up and some reordering to prevent this
> from happening in the first place.

I agree with Michal, but as we don't have any better fix for this issue
I'm inclined to take the patch anyway. Maybe there just should be a
comment stating that it's an ugly workaround and a WARN_ON() to make
sure that we properly fix the interrupt initialisation.

-- 
Kalle Valo


From michal.kazior at tieto.com  Wed Nov  6 06:54:49 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 6 Nov 2013 12:54:49 +0100
Subject: [PATCH] ath10k: Fix crash due to tasklet race.
In-Reply-To: <87r4atsq90.fsf@kamboji.qca.qualcomm.com>
References: <1383082737-20728-1-git-send-email-greearb@candelatech.com>
 <CA+BoTQ=qUgR4TEcUMjV88RD+fFreCkkEtHfu5hB2_BguirfNHg@mail.gmail.com>
 <87r4atsq90.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQnZTAERWVmwzd_nssQ9t4DwvX7YFQ4V2GXqutQTEpEqWQ@mail.gmail.com>

On 6 November 2013 12:50, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> On 29 October 2013 22:38,  <greearb at candelatech.com> wrote:
>>> From: Ben Greear <greearb at candelatech.com>
>>>
>>> The tasklet can run after the rings have been cleaned up,
>>> so check for NULL before de-referencing the ring.
>>>
>>> Signed-off-by: Ben Greear <greearb at candelatech.com>
>>> ---
>>>  drivers/net/wireless/ath/ath10k/ce.c | 10 ++++++++--
>>>  1 file changed, 8 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
>>> index d243f28..dfcfda9 100644
>>> --- a/drivers/net/wireless/ath/ath10k/ce.c
>>> +++ b/drivers/net/wireless/ath/ath10k/ce.c
>>> @@ -547,12 +547,18 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
>>>         struct ath10k_ce_ring *src_ring = ce_state->src_ring;
>>>         u32 ctrl_addr = ce_state->ctrl_addr;
>>>         struct ath10k *ar = ce_state->ar;
>>> -       unsigned int nentries_mask = src_ring->nentries_mask;
>>> -       unsigned int sw_index = src_ring->sw_index;
>>> +       unsigned int nentries_mask;
>>> +       unsigned int sw_index;
>>>         struct ce_desc *sdesc, *sbase;
>>>         unsigned int read_index;
>>>         int ret;
>>>
>>> +       if (!src_ring)
>>> +               return -EIO;
>>
>> I don't think this is a proper way to fix the problem. What should be
>> done is initialization clean up and some reordering to prevent this
>> from happening in the first place.
>
> I agree with Michal, but as we don't have any better fix for this issue
> I'm inclined to take the patch anyway. Maybe there just should be a
> comment stating that it's an ugly workaround and a WARN_ON() to make
> sure that we properly fix the interrupt initialisation.

This issue alone should actually be fixed in my pci fixes RFT.


Micha?


From kvalo at qca.qualcomm.com  Wed Nov  6 07:34:24 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 14:34:24 +0200
Subject: [PATCH/RFT 09/12] ath10k: propagate
 ath10k_ce_disable_interrupts() errors
In-Reply-To: <1383133346-8135-10-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Wed, 30 Oct 2013 12:42:23 +0100")
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383133346-8135-10-git-send-email-michal.kazior@tieto.com>
Message-ID: <87iow5so8f.fsf@kamboji.qca.qualcomm.com>

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

> This shouldn't be silenced. This will be necessary
> for PCI init code reordering.
>
> Signed-off-by: Michal Kazior <michal.kazior at 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


From kvalo at qca.qualcomm.com  Wed Nov  6 07:38:49 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 14:38:49 +0200
Subject: [PATCH/RFT 12/12] ath10k: add some debug prints
In-Reply-To: <1383133346-8135-13-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Wed, 30 Oct 2013 12:42:26 +0100")
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383133346-8135-13-git-send-email-michal.kazior@tieto.com>
Message-ID: <87eh6tso12.fsf@kamboji.qca.qualcomm.com>

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

> Some errors were handled too silently. Also add a
> print indicating BMI is booted.
>
> Signed-off-by: Michal Kazior <michal.kazior at 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


From kvalo at qca.qualcomm.com  Wed Nov  6 07:43:10 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 14:43:10 +0200
Subject: [PATCH/RFT 12/12] ath10k: add some debug prints
In-Reply-To: <1383153399.9435.33.camel@joe-AO722> (Joe Perches's message of
 "Wed, 30 Oct 2013 10:16:39 -0700")
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383133346-8135-13-git-send-email-michal.kazior@tieto.com>
 <1383153399.9435.33.camel@joe-AO722>
Message-ID: <87a9hhsntt.fsf@kamboji.qca.qualcomm.com>

Joe Perches <joe at 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


From kvalo at qca.qualcomm.com  Wed Nov  6 08:06:49 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 15:06:49 +0200
Subject: [PATCH] ath10k:  Fix crash due to tasklet race.
In-Reply-To: <1383082737-20728-1-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Tue, 29 Oct 2013 14:38:57
 -0700")
References: <1383082737-20728-1-git-send-email-greearb@candelatech.com>
Message-ID: <871u2tsmqe.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> The tasklet can run after the rings have been cleaned up,
> so check for NULL before de-referencing the ring.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

I'll drop this as Michal's patch has a proper fix for this issue.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov  6 08:08:49 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 15:08:49 +0200
Subject: [PATCH/RFT 04/12] ath10k: rename function to match it's role
In-Reply-To: <1383133346-8135-5-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Wed, 30 Oct 2013 12:42:18 +0100")
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383133346-8135-5-git-send-email-michal.kazior@tieto.com>
Message-ID: <87wqklr82m.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at 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 at 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


From janusz.dziedzic at tieto.com  Wed Nov  6 08:52:09 2013
From: janusz.dziedzic at tieto.com (Janusz Dziedzic)
Date: Wed, 6 Nov 2013 14:52:09 +0100
Subject: [PATCH 1/3] ath10k: add phyerr/dfs handling
In-Reply-To: <87bo1xuajk.fsf@kamboji.qca.qualcomm.com>
References: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
 <87bo1xuajk.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CALhHN=oj2hg6zRf5rKyDBexWOdR08=aRXRJtD9gQQs7i_tjjMQ@mail.gmail.com>

On 6 November 2013 10:47, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Marek Puzyniak <marek.puzyniak at tieto.com> writes:
>
>> From: Janusz Dziedzic <janusz.dziedzic at tieto.com>
>>
>> Handle phyerr, dfs event, radar_report and fft_report.
>> Add also debugfs dfs_simulate_radar and dfs_stats files.
>> Use ath dfs pattern detector.
>>
>> Signed-off-by: Janusz Dziedzic <janusz.dziedzic at tieto.com>
>
> Are there any dependencies to mac80211 or cfg80211 patches? There has
> been quite a lot of changes with DFS lately and it would be good to have
> all those patches in ath-next branch before I apply these.
>
>> --- a/drivers/net/wireless/ath/ath10k/debug.c
>> +++ b/drivers/net/wireless/ath/ath10k/debug.c
>> @@ -21,6 +21,14 @@
>>  #include "core.h"
>>  #include "debug.h"
>>
>> +#define ATH10K_DFS_STAT(s, p) (\
>> +     len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
>> +                      ar->debug.dfs_stats.p))
>> +
>> +#define ATH10K_DFS_POOL_STAT(s, p) (\
>> +     len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
>> +                      ar->debug.dfs_pool_stats.p))
>
> As these are only used by ath10k_read_file_dfs() better to move those
> just to top of that function.
>
>> +static ssize_t ath10k_read_file_dfs(struct file *file, char __user *user_buf,
>> +                                 size_t count, loff_t *ppos)
>> +{
>
> ath10k_read_dfs_stats()?
>
>> +     int retval = 0, size = 8000, len = 0;
>
> Like Joe said, size can be const.
>
>> +     struct ath10k *ar = file->private_data;
>> +     char *buf;
>> +
>> +     buf = kzalloc(size, GFP_KERNEL);
>> +     if (buf == NULL)
>> +             return -ENOMEM;
>> +
>> +     if (!ar->dfs_detector) {
>> +             len += scnprintf(buf + len, size - len, "DFS not enabled\n");
>> +             goto exit;
>> +     }
>> +
>> +     ar->debug.dfs_pool_stats = ar->dfs_detector->get_stats(ar->dfs_detector);
>
> I think we need to take conf_mutex to make sure ar->dfs_detector is not
> destroyed while we use it.
>
We deregister dfs_detector in ath10k_mac_unregister() so we will first
destroy debugfs,
then we don't need any mutex here.
BTW I see we don't call debugfs_remove*() - so, currently mac clear
debugfs for us - ieee80211_unregister_hw() -> wiphy_unregister I
think.
After that we deregister dfs_detector.


>> diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
>> index 46e640a..cde53d6 100644
>> --- a/drivers/net/wireless/ath/ath10k/debug.h
>> +++ b/drivers/net/wireless/ath/ath10k/debug.h
>> @@ -33,6 +33,7 @@ enum ath10k_debug_mask {
>>       ATH10K_DBG_MGMT         = 0x00000100,
>>       ATH10K_DBG_DATA         = 0x00000200,
>>       ATH10K_DBG_BMI          = 0x00000400,
>> +     ATH10K_DBG_REGULATORY   = 0x00000800,
>>       ATH10K_DBG_ANY          = 0xffffffff,
>>  };
>>
>> @@ -53,6 +54,7 @@ void ath10k_debug_read_service_map(struct ath10k *ar,
>>  void ath10k_debug_read_target_stats(struct ath10k *ar,
>>                                   struct wmi_stats_event *ev);
>>
>> +#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
>>  #else
>
> Empty line after #define
>
>>  static inline int ath10k_debug_start(struct ath10k *ar)
>>  {
>> @@ -82,6 +84,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
>>                                                 struct wmi_stats_event *ev)
>>  {
>>  }
>> +#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
>>  #endif /* CONFIG_ATH10K_DEBUGFS */
>
> Empty line before and after #define.
>
>>
>>  #ifdef CONFIG_ATH10K_DEBUG
>> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
>> index bbb0efa..79f8bfd 100644
>> --- a/drivers/net/wireless/ath/ath10k/mac.c
>> +++ b/drivers/net/wireless/ath/ath10k/mac.c
>> @@ -1438,9 +1438,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
>>  {
>>       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
>>       struct ath10k *ar = hw->priv;
>> +     bool result;
>>
>>       ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
>>
>> +     if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
>> +             ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%X\n",
>> +                        request->dfs_region);
>
> "0x%x" (also applies to elsewhere in the patch)
>
>> --- a/drivers/net/wireless/ath/ath10k/wmi.c
>> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
>> @@ -1383,9 +1383,251 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
>>       ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
>>  }
>>
>> +static void ath10k_dfs_radar_report(struct ath10k *ar,
>> +                                 struct wmi_single_phyerr_rx_event *event,
>> +                                 struct phyerr_radar_report *rr,
>> +                                 u64 tsf)
>> +{
>> +     u32 reg0, reg1, tsf32l;
>> +     struct pulse_event pe;
>> +     u64 tsf64;
>> +     u8 rssi, width;
>
> What about locking? Does this function assume that conf_mutex is held?
> If yes, please document that with lockdep_assert_held(). If no, we have
> a problem :)
>
> (Reads wmi.c)
>
> Ah, wmi events don't sleep anymore, forgot that. So we can't really use
> conf_mutex here. I guess our options are bring back worker for wmi
> events or use spinlock.
>
I think we can use here spin_lock_bh(&ar->data_lock) when setting
ar->debug.dfs_stats and when reading this from debugfs.
But, is that really needed (in worst case we will get older values via debugfs)?


>> +
>> +     reg0 = __le32_to_cpu(rr->reg0);
>> +     reg1 = __le32_to_cpu(rr->reg1);
>> +
>> +     ath10k_dbg(ATH10K_DBG_REGULATORY,
>> +                "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
>> +                MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
>> +                MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
>> +                MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
>> +                MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
>> +     ath10k_dbg(ATH10K_DBG_REGULATORY,
>> +                "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
>> +                MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
>> +                MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
>> +                MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
>> +                MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
>> +                MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
>> +     ath10k_dbg(ATH10K_DBG_REGULATORY,
>> +                "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
>> +                MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
>> +                MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
>> +
>> +     if (!ar->dfs_detector)
>> +             return;
>> +
>> +     /* report event to DFS pattern detector */
>> +     tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp);
>> +     tsf64 = tsf & (~0xFFFFFFFFULL);
>> +     tsf64 |= tsf32l;
>> +
>> +     width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR);
>> +     rssi = event->hdr.rssi_combined;
>> +
>> +     /*
>> +      * hardware store this as 8 bit signed value,
>> +      * set to zero if negative number
>> +      */
>
> to be consistent with rest of the comments in ath10k:
>
> "/* hardware...."
>
>> +     if (rssi & 0x80)
>> +             rssi = 0;
>> +
>> +     pe.ts = tsf64;
>> +     pe.freq = ar->hw->conf.chandef.chan->center_freq;
>> +     pe.width = width;
>> +     pe.rssi = rssi;
>> +
>> +     ath10k_dbg(ATH10K_DBG_REGULATORY,
>> +                "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
>> +                pe.freq, pe.width, pe.rssi, pe.ts);
>> +
>> +     ATH10K_DFS_STAT_INC(ar, pulses_detected);
>> +
>> +     if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
>> +             ath10k_dbg(ATH10K_DBG_REGULATORY,
>> +                        "dfs no pulse pattern detected, yet\n");
>> +             return;
>> +     }
>> +
>> +     ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
>> +     ATH10K_DFS_STAT_INC(ar, radar_detected);
>> +     ieee80211_radar_detected(ar->hw);
>> +}
>> +
>> +static int ath10k_dfs_fft_report(struct ath10k *ar,
>> +                              struct wmi_single_phyerr_rx_event *event,
>> +                              struct phyerr_fft_report *fftr,
>> +                              u64 tsf)
>> +{
>> +     u32 reg0, reg1;
>> +     u8 rssi, peak_mag;
>> +
>> +     reg0 = __le32_to_cpu(fftr->reg0);
>> +     reg1 = __le32_to_cpu(fftr->reg1);
>> +     rssi = event->hdr.rssi_combined;
>
> locking?
>
>> +     ath10k_dbg(ATH10K_DBG_REGULATORY,
>> +                "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
>> +                MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
>> +                MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
>> +                MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
>> +                MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
>> +     ath10k_dbg(ATH10K_DBG_REGULATORY,
>> +                "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
>> +                MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
>> +                MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
>> +                MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG),
>> +                MS(reg1, SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB));
>> +
>> +     peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
>> +
>> +     /* false event detection */
>> +     if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
>> +         peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
>> +             ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
>> +             ATH10K_DFS_STAT_INC(ar, pulses_discarded);
>> +             return -EINVAL;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static void ath10k_wmi_event_dfs(struct ath10k *ar,
>> +                              struct wmi_single_phyerr_rx_event *event,
>> +                              u64 tsf)
>> +{
>> +     int buf_len, tlv_len, res, i = 0;
>> +     struct phyerr_tlv *tlv;
>> +     struct phyerr_radar_report *rr;
>> +     struct phyerr_fft_report *fftr;
>> +     u8 *tlv_buf;
>
> locking?
>
> --
> Kalle Valo


From greearb at candelatech.com  Wed Nov  6 11:51:40 2013
From: greearb at candelatech.com (Ben Greear)
Date: Wed, 06 Nov 2013 08:51:40 -0800
Subject: What to do about hung firmware?
In-Reply-To: <87ob5yt1kp.fsf@kamboji.qca.qualcomm.com>
References: <52793E4B.20302@candelatech.com>
 <CA+BoTQk2EZddNywAMRLF2qpWafpD4OvyDrtvg+iTM4atcm44ig@mail.gmail.com>
 <87ob5yt1kp.fsf@kamboji.qca.qualcomm.com>
Message-ID: <527A739C.4060807@candelatech.com>

On 11/05/2013 11:46 PM, Kalle Valo wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
> 
>> You probably could try WMI_ECHO_CMDID to implement a keep alive when
>> idling (i.e. not sending WMI commands for a few seconds at least).
> 
> Sending something periodically would be bad from power consumption point
> of view. We would need to either disable it by default, only send it if
> there's a problem or something like that.

Ok, how about this:

If we hit the 3*HZ timeout, then we send a ping to the firmware
even if we are out of tickets.

If we get no response to that in 3*HZ or so, then consider firmware
hung and reset it.

Thanks,
Ben

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



From greearb at candelatech.com  Wed Nov  6 12:00:22 2013
From: greearb at candelatech.com (Ben Greear)
Date: Wed, 06 Nov 2013 09:00:22 -0800
Subject: [PATCH] ath10k:  Fix crash due to tasklet race.
In-Reply-To: <871u2tsmqe.fsf@kamboji.qca.qualcomm.com>
References: <1383082737-20728-1-git-send-email-greearb@candelatech.com>
 <871u2tsmqe.fsf@kamboji.qca.qualcomm.com>
Message-ID: <527A75A6.3020809@candelatech.com>

On 11/06/2013 05:06 AM, Kalle Valo wrote:
> greearb at candelatech.com writes:
> 
>> From: Ben Greear <greearb at candelatech.com>
>>
>> The tasklet can run after the rings have been cleaned up,
>> so check for NULL before de-referencing the ring.
>>
>> Signed-off-by: Ben Greear <greearb at candelatech.com>
> 
> I'll drop this as Michal's patch has a proper fix for this issue.

Ok, that sounds fine.  I'll rebase when you push his patches and
drop my patch for continued testing.

Thanks,
Ben

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



From greearb at candelatech.com  Wed Nov  6 12:05:40 2013
From: greearb at candelatech.com (Ben Greear)
Date: Wed, 06 Nov 2013 09:05:40 -0800
Subject: Cleanup of free_vdev_map and vif limits.
Message-ID: <527A76E4.3000509@candelatech.com>

Just FYI, I'm planning to clean up the free_vdev_map
logic.

Currently it does not deal well with the different VIF
limits in 10X firmware and earlier.  There are several places
where the vdev counts are hard-coded, etc.

I plan to have an ar->foo variable that holds the actual
max vdevs, and make the free_vdev_map 64-bit.

I also plan to add an IE to the firmware prefix so firmware can
advertise how many vdevs and stations it can support.

Thanks,
Ben

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



From kvalo at qca.qualcomm.com  Wed Nov  6 12:40:39 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 6 Nov 2013 19:40:39 +0200
Subject: What to do about hung firmware?
In-Reply-To: <527A739C.4060807@candelatech.com> (Ben Greear's message of "Wed, 
 6 Nov 2013 08:51:40 -0800")
References: <52793E4B.20302@candelatech.com>
 <CA+BoTQk2EZddNywAMRLF2qpWafpD4OvyDrtvg+iTM4atcm44ig@mail.gmail.com>
 <87ob5yt1kp.fsf@kamboji.qca.qualcomm.com>
 <527A739C.4060807@candelatech.com>
Message-ID: <87li11e8dk.fsf@kamboji.qca.qualcomm.com>

Ben Greear <greearb at candelatech.com> writes:

> On 11/05/2013 11:46 PM, Kalle Valo wrote:
>> Michal Kazior <michal.kazior at tieto.com> writes:
>> 
>>> You probably could try WMI_ECHO_CMDID to implement a keep alive when
>>> idling (i.e. not sending WMI commands for a few seconds at least).
>> 
>> Sending something periodically would be bad from power consumption point
>> of view. We would need to either disable it by default, only send it if
>> there's a problem or something like that.
>
> Ok, how about this:
>
> If we hit the 3*HZ timeout, then we send a ping to the firmware
> even if we are out of tickets.
>
> If we get no response to that in 3*HZ or so, then consider firmware
> hung and reset it.

Sounds good to me.

-- 
Kalle Valo


From joe at perches.com  Wed Nov  6 12:55:56 2013
From: joe at perches.com (Joe Perches)
Date: Wed, 06 Nov 2013 09:55:56 -0800
Subject: [PATCH] wcn36xx: Fix logging macro with unnecessary semicolon
In-Reply-To: <CAFSJ42YQy96Sko8CuG9BGjHzTV7TkRp2=NVt036APxSKpPB=Ag@mail.gmail.com>
References: <1383684000.4387.42.camel@joe-AO722>
 <CAFSJ42YQy96Sko8CuG9BGjHzTV7TkRp2=NVt036APxSKpPB=Ag@mail.gmail.com>
Message-ID: <1383760556.7940.28.camel@joe-AO722>

On Wed, 2013-11-06 at 07:49 +0000, Eugene Krasnikov wrote:
> Hm... when it comes to semicolon the patch seems to be good. When it
> comes to dynamic debugging i think we should have a separate
> discussion about that.
> I personally like the whole idea about dynamic debug but if you want
> to change it i would suggest to have some kind of framework for all
> ath drivers(or maybe all wireless drivers). Because obviously you can
> find common code in every driver that defines it's own debug
> functions/debug levels and so on. Why not to make a framework with
> standard API/levels?

You need to bring that up with the Atheros folk.
I've tried.  The view seemed to be it was more
trouble than it was worth.





From greearb at candelatech.com  Wed Nov  6 16:50:41 2013
From: greearb at candelatech.com (Ben Greear)
Date: Wed, 06 Nov 2013 13:50:41 -0800
Subject: BUG in wiphy_unregister (ath tree, 3.12.0-rc5)
Message-ID: <527AB9B1.7080909@candelatech.com>

Found this while hacking on ath10k, probably during module unload.

(gdb) l *(wiphy_unregister+0xcd)
0x748 is in wiphy_unregister (/mnt/sda/home/greearb/git/linux.ath/net/wireless/core.c:653).
648			rfkill_unregister(rdev->rfkill);
649	
650		rtnl_lock();
651		rdev->wiphy.registered = false;
652	
653		BUG_ON(!list_empty(&rdev->wdev_list));
654	
655		/*
656		 * First remove the hardware from everywhere, this makes
657		 * it impossible to find from userspace.


------------[ cut here ]------------
kernel BUG at /mnt/sda/home/greearb/git/linux.ath/net/wireless/core.c:653!
invalid opcode: 0000 [#1] PREEMPT SMP
Modules linked in: ath10k_pci(-) ath10k_core ath5k ath9k ath9k_common ath9k_hw nf_nat_ipv4 nf_nat veth 8021]
CPU: 3 PID: 12451 Comm: rmmod Tainted: G        WC   3.12.0-rc5-wl+ #2
Hardware name: To be filled by O.E.M. To be filled by O.E.M./HURONRIVER, BIOS 4.6.5 05/02/2012
task: ffff88020d478000 ti: ffff8800cb8b0000 task.ti: ffff8800cb8b0000
RIP: 0010:[<ffffffffa028b748>]  [<ffffffffa028b748>] wiphy_unregister+0xcd/0x1fc [cfg80211]
RSP: 0018:ffff8800cb8b1cf8  EFLAGS: 00010293
RAX: ffff8802153c8088 RBX: ffff8802153c8000 RCX: 0000000284142006
RDX: 0000000000000006 RSI: 0000000000000003 RDI: ffff8800cb8b0000
RBP: ffff8800cb8b1d58 R08: 0000000000000002 R09: 0000000000000000
R10: ffffffff814e7d11 R11: ffffffff81498427 R12: ffff8802153c8380
R13: 0000000000000000 R14: 000000000236a010 R15: 0000000000000002
FS:  00007f39b6285740(0000) GS:ffff88021fb80000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ffa10d6b000 CR3: 00000000cf2db000 CR4: 00000000000407e0
Stack:
 0000000000000200 ffff8800cf2016f8 ffff8800cb8b1d58 ffffffff810b4018
 0000000000000002 ffff880200000000 ffff8802153ca280 ffff8802153c88a0
 ffff8802153ca280 ffff880032d12520 000000000236a010 0000000000000002
Call Trace:
 [<ffffffff810b4018>] ? destroy_workqueue+0x174/0x1d1
 [<ffffffffa03291dd>] ieee80211_unregister_hw+0xdd/0x105 [mac80211]
 [<ffffffffa0830ade>] ath10k_mac_unregister+0x15/0x47 [ath10k_core]
 [<ffffffffa0832360>] ath10k_core_unregister+0xe/0x22 [ath10k_core]
 [<ffffffffa084e100>] ath10k_pci_remove+0x59/0x97 [ath10k_pci]
 [<ffffffff812e2fd6>] pci_device_remove+0x41/0x8f
 [<ffffffff8139fe79>] __device_release_driver+0x86/0xdc
 [<ffffffff813a0843>] driver_detach+0x79/0xa6
 [<ffffffff8139fd37>] bus_remove_driver+0xca/0xef
 [<ffffffffa0851f4c>] ? ath10k_ce_init+0x52b/0x52b [ath10k_pci]
 [<ffffffff813a0de9>] driver_unregister+0x42/0x49
 [<ffffffffa0851f4c>] ? ath10k_ce_init+0x52b/0x52b [ath10k_pci]
 [<ffffffff812e2af2>] pci_unregister_driver+0x1d/0x82
 [<ffffffffa0851f4c>] ? ath10k_ce_init+0x52b/0x52b [ath10k_pci]
 [<ffffffffa0851f5c>] ath10k_pci_exit+0x10/0x12 [ath10k_pci]
 [<ffffffff810f7a4f>] SyS_delete_module+0x1ee/0x260
 [<ffffffff810e4e66>] ? current_kernel_time+0xd/0x31
 [<ffffffff8118db16>] ? mntput_no_expire+0x1d/0x143
 [<ffffffff815967fd>] system_call_fastpath+0x1a/0x1f
Code: e0 48 8b 7b 30 48 85 ff 74 05 e8 58 d6 2e e1 e8 ce c5 25 e1 48 8d 83 88 00 00 00 48 39 83 88 00 00 00
RIP  [<ffffffffa028b748>] wiphy_unregister+0xcd/0x1fc [cfg80211]
 RSP <ffff8800cb8b1cf8>
---[ end trace 2c04c3e4cfaea150 ]---

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



From k.eugene.e at gmail.com  Thu Nov  7 02:32:37 2013
From: k.eugene.e at gmail.com (Eugene Krasnikov)
Date: Thu, 7 Nov 2013 07:32:37 +0000
Subject: [PATCH] wcn36xx: Fix logging macro with unnecessary semicolon
In-Reply-To: <1383760556.7940.28.camel@joe-AO722>
References: <1383684000.4387.42.camel@joe-AO722>
 <CAFSJ42YQy96Sko8CuG9BGjHzTV7TkRp2=NVt036APxSKpPB=Ag@mail.gmail.com>
 <1383760556.7940.28.camel@joe-AO722>
Message-ID: <CAFSJ42Y-3BZqj+JRNa8wdxjnm1fguD8ToH5Oj0m56yT5NexdVQ@mail.gmail.com>

Hi Joe,

I personally like the idea of making some kind of framework on top of
printing because all ath drivers are using the same printing approach
and combining all that code in one place will reduce amount of code in
each particular driver. As a true engineer i like when it's less code
= less work to do = less bugs:)

Suggestion is to send a patch with semicolon fix only and have a
second round of convincing ath guys to change printing code. How does
that sound?

On Wed, Nov 6, 2013 at 5:55 PM, Joe Perches <joe at perches.com> wrote:
> On Wed, 2013-11-06 at 07:49 +0000, Eugene Krasnikov wrote:
>> Hm... when it comes to semicolon the patch seems to be good. When it
>> comes to dynamic debugging i think we should have a separate
>> discussion about that.
>> I personally like the whole idea about dynamic debug but if you want
>> to change it i would suggest to have some kind of framework for all
>> ath drivers(or maybe all wireless drivers). Because obviously you can
>> find common code in every driver that defines it's own debug
>> functions/debug levels and so on. Why not to make a framework with
>> standard API/levels?
>
> You need to bring that up with the Atheros folk.
> I've tried.  The view seemed to be it was more
> trouble than it was worth.
>
>
>



-- 
Best regards,
Eugene


From joe at perches.com  Thu Nov  7 14:40:21 2013
From: joe at perches.com (Joe Perches)
Date: Thu, 07 Nov 2013 11:40:21 -0800
Subject: [PATCH] wcn36xx: Fix logging macro with unnecessary semicolon
In-Reply-To: <CAFSJ42Y-3BZqj+JRNa8wdxjnm1fguD8ToH5Oj0m56yT5NexdVQ@mail.gmail.com>
References: <1383684000.4387.42.camel@joe-AO722>
 <CAFSJ42YQy96Sko8CuG9BGjHzTV7TkRp2=NVt036APxSKpPB=Ag@mail.gmail.com>
 <1383760556.7940.28.camel@joe-AO722>
 <CAFSJ42Y-3BZqj+JRNa8wdxjnm1fguD8ToH5Oj0m56yT5NexdVQ@mail.gmail.com>
Message-ID: <1383853221.9263.14.camel@joe-AO722>

On Thu, 2013-11-07 at 07:32 +0000, Eugene Krasnikov wrote:
> Hi Joe,

Hi Eugene.

> I personally like the idea of making some kind of framework on top of
> printing because all ath drivers are using the same printing approach
> and combining all that code in one place will reduce amount of code in
> each particular driver. As a true engineer i like when it's less code
> = less work to do = less bugs:)
> 
> Suggestion is to send a patch with semicolon fix only

It's a one line fix, and pretty trivial to do yourself if you
want it.

I do think though the slightly odd wcn36xx_<level> uses of:

-#define wcn36xx_err(fmt, arg...)                               \
-       printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg);
-
-#define wcn36xx_warn(fmt, arg...)                              \
-       printk(KERN_WARNING pr_fmt("WARNING " fmt), ##arg)
-
-#define wcn36xx_info(fmt, arg...)              \
-       printk(KERN_INFO pr_fmt(fmt), ##arg)
-
[]
+#define wcn36xx_err(fmt, ...)                                  \
+       pr_err("ERROR " fmt, ##__VA_ARGS__)
+#define wcn36xx_warn(fmt, ...)                                 \
+       pr_warn("WARNING " fmt, ##__VA_ARGS__)
+#define wcn36xx_info(fmt, ...)                                 \
+       pr_info(fmt, ##__VA_ARGS__)

should still be converted to more normal pr_<level> like I did.

I don't believe that prefixing of "ERROR " and "WARNING " to
pr_err and pr_warn actually gain anything as the same level
information can be got already with dmesg -r via the "<3>" and
"<4>" prefixes or dmesg -l3 -l4

> have a
> second round of convincing ath guys to change printing code. How does
> that sound?

Luis?  Kalle?  Other Qualcomm/Atheros folk?

One of the nominal benefits of separating the ath_<level>
macros by subsystem was perf/tracing.  I believe some of the
ath subsystems have integrated the dmesg and tracing code.

I'm not sure how separable those may be here or if it's even
desirable to separate them.  I'd guess not.



From michal.kazior at tieto.com  Fri Nov  8 02:01:28 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:28 +0100
Subject: [PATCHv2 06/13] ath10k: fix ath10k_ce_init() failpath
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-7-git-send-email-michal.kazior@tieto.com>

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 at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:29 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:29 +0100
Subject: [PATCHv2 07/13] ath10k: remove meaningless check
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-8-git-send-email-michal.kazior@tieto.com>

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 at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:27 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:27 +0100
Subject: [PATCHv2 05/13] ath10k: make sure to mask all CE irqs
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-6-git-send-email-michal.kazior@tieto.com>

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 at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:24 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:24 +0100
Subject: [PATCHv2 02/13] ath10k: don't forget to kill fw error tasklet
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-3-git-send-email-michal.kazior@tieto.com>

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 at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:25 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:25 +0100
Subject: [PATCHv2 03/13] ath10k: split tasklet killing function
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-4-git-send-email-michal.kazior@tieto.com>

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

Signed-off-by: Michal Kazior <michal.kazior at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:23 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:23 +0100
Subject: [PATCHv2 01/13] ath10k: remove ar_pci->ce_count
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-2-git-send-email-michal.kazior@tieto.com>

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 at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:30 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:30 +0100
Subject: [PATCHv2 08/13] ath10k: use ath10k_do_pci_wake/sleep
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-9-git-send-email-michal.kazior@tieto.com>

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 at 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



From kvalo at qca.qualcomm.com  Fri Nov  8 02:06:19 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 8 Nov 2013 09:06:19 +0200
Subject: [PATCH] wcn36xx: Fix logging macro with unnecessary semicolon
In-Reply-To: <1383853221.9263.14.camel@joe-AO722> (Joe Perches's message of
 "Thu, 7 Nov 2013 11:40:21 -0800")
References: <1383684000.4387.42.camel@joe-AO722>
 <CAFSJ42YQy96Sko8CuG9BGjHzTV7TkRp2=NVt036APxSKpPB=Ag@mail.gmail.com>
 <1383760556.7940.28.camel@joe-AO722>
 <CAFSJ42Y-3BZqj+JRNa8wdxjnm1fguD8ToH5Oj0m56yT5NexdVQ@mail.gmail.com>
 <1383853221.9263.14.camel@joe-AO722>
Message-ID: <87bo1vcqz8.fsf@kamboji.qca.qualcomm.com>

Joe Perches <joe at perches.com> writes:

>> have a
>> second round of convincing ath guys to change printing code. How does
>> that sound?
>
> Luis?  Kalle?  Other Qualcomm/Atheros folk?

I didn't quite get what you are asking from me. But for me most
important is that the current debugging facilities from user's point of
view don't change. I don't care if the code is in ath10k.ko or ath.ko,
we are talking about ~100 lines of code anyway.

> One of the nominal benefits of separating the ath_<level>
> macros by subsystem was perf/tracing.

Nominal?

-- 
Kalle Valo


From michal.kazior at tieto.com  Fri Nov  8 02:05:18 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:05:18 +0100
Subject: [PATCH] ath10k: fix core init failpath
Message-ID: <1383894318-29455-1-git-send-email-michal.kazior@tieto.com>

HIF was not stopped properly in
ath10k_core_start() upon failure. This could cause
memory leaks of CE completions entries and
possibly other issues as well.

Move the HIF start/stop out of
ath10k_htc_wait_target(). The ctl_resp completion
is already prepared in ath10k_htc_init.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 16 +++++++++++++---
 drivers/net/wireless/ath/ath10k/htc.c  | 26 +++++---------------------
 2 files changed, 18 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 2a360ca..1d3040e 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -787,14 +787,22 @@ int ath10k_core_start(struct ath10k *ar)
 		goto err;
 	}
 
-	status = ath10k_htc_wait_target(&ar->htc);
-	if (status)
+	status = ath10k_hif_start(ar);
+	if (status) {
+		ath10k_err("could not start HIF: %d\n", status);
 		goto err_wmi_detach;
+	}
+
+	status = ath10k_htc_wait_target(&ar->htc);
+	if (status) {
+		ath10k_err("failed to connect to HTC: %d\n", status);
+		goto err_hif_stop;
+	}
 
 	status = ath10k_htt_attach(ar);
 	if (status) {
 		ath10k_err("could not attach htt (%d)\n", status);
-		goto err_wmi_detach;
+		goto err_hif_stop;
 	}
 
 	status = ath10k_init_connect_htc(ar);
@@ -833,6 +841,8 @@ err_disconnect_htc:
 	ath10k_htc_stop(&ar->htc);
 err_htt_detach:
 	ath10k_htt_detach(&ar->htt);
+err_hif_stop:
+	ath10k_hif_stop(ar);
 err_wmi_detach:
 	ath10k_wmi_detach(ar);
 err:
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 3118d75..d015911 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -534,14 +534,6 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
 	u16 credit_count;
 	u16 credit_size;
 
-	INIT_COMPLETION(htc->ctl_resp);
-
-	status = ath10k_hif_start(htc->ar);
-	if (status) {
-		ath10k_err("could not start HIF (%d)\n", status);
-		goto err_start;
-	}
-
 	status = wait_for_completion_timeout(&htc->ctl_resp,
 					     ATH10K_HTC_WAIT_TIMEOUT_HZ);
 	if (status <= 0) {
@@ -549,15 +541,13 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
 			status = -ETIMEDOUT;
 
 		ath10k_err("ctl_resp never came in (%d)\n", status);
-		goto err_target;
+		return status;
 	}
 
 	if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {
 		ath10k_err("Invalid HTC ready msg len:%d\n",
 			   htc->control_resp_len);
-
-		status = -ECOMM;
-		goto err_target;
+		return -ECOMM;
 	}
 
 	msg = (struct ath10k_htc_msg *)htc->control_resp_buffer;
@@ -567,8 +557,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
 
 	if (message_id != ATH10K_HTC_MSG_READY_ID) {
 		ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id);
-		status = -ECOMM;
-		goto err_target;
+		return -ECOMM;
 	}
 
 	htc->total_transmit_credits = credit_count;
@@ -581,9 +570,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
 
 	if ((htc->total_transmit_credits == 0) ||
 	    (htc->target_credit_size == 0)) {
-		status = -ECOMM;
 		ath10k_err("Invalid credit size received\n");
-		goto err_target;
+		return -ECOMM;
 	}
 
 	ath10k_htc_setup_target_buffer_assignments(htc);
@@ -600,14 +588,10 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
 	status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
 	if (status) {
 		ath10k_err("could not connect to htc service (%d)\n", status);
-		goto err_target;
+		return status;
 	}
 
 	return 0;
-err_target:
-	ath10k_hif_stop(htc->ar);
-err_start:
-	return status;
 }
 
 int ath10k_htc_connect_service(struct ath10k_htc *htc,
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov  8 02:01:22 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:22 +0100
Subject: [PATCHv2 00/13] ath10k: pci fixes 2013-10-30
In-Reply-To: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>

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



From michal.kazior at tieto.com  Fri Nov  8 02:01:31 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:31 +0100
Subject: [PATCHv2 09/13] ath10k: propagate ath10k_ce_disable_interrupts()
 errors
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-10-git-send-email-michal.kazior@tieto.com>

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

Signed-off-by: Michal Kazior <michal.kazior at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:32 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:32 +0100
Subject: [PATCHv2 10/13] ath10k: guard against CE corruption from firmware
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-11-git-send-email-michal.kazior@tieto.com>

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 at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:33 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:33 +0100
Subject: [PATCHv2 11/13] ath10k: re-arrange PCI init code
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-12-git-send-email-michal.kazior@tieto.com>

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 at candelatech.com>
Signed-off-by: Michal Kazior <michal.kazior at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:34 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:34 +0100
Subject: [PATCHv2 12/13] ath10k: add and fix some PCI prints
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-13-git-send-email-michal.kazior@tieto.com>

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

Signed-off-by: Michal Kazior <michal.kazior at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:35 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:35 +0100
Subject: [PATCHv2 13/13] ath10k: reset device upon stopping/power down
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-14-git-send-email-michal.kazior@tieto.com>

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 at candelatech.com>
Reported-By: Janusz Dziedzic <janusz.dziedzic at tieto.com>
Signed-off-by: Michal Kazior <michal.kazior at 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



From michal.kazior at tieto.com  Fri Nov  8 02:01:26 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri,  8 Nov 2013 08:01:26 +0100
Subject: [PATCHv2 04/13] ath10k: rename ath10k_pci_reset_target()
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1383894095-27998-5-git-send-email-michal.kazior@tieto.com>

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 at 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



From kvalo at qca.qualcomm.com  Fri Nov  8 04:44:51 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 8 Nov 2013 11:44:51 +0200
Subject: [PATCH] ath10k:  Fix un-initialized debug objects.
In-Reply-To: <1383585496-17580-1-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Mon, 4 Nov 2013 09:18:16
 -0800")
References: <1383585496-17580-1-git-send-email-greearb@candelatech.com>
Message-ID: <87txfnb52k.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> If the 'ar' registration fails early, the debug
> objects were not initialized, and trouble ensued when
> the object was later destroyed and the un-initialized
> objects were accessed.
>
> Per Kalle's suggestion, move the debug_destroy to the
> core_unregister method.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov  8 04:58:23 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 8 Nov 2013 11:58:23 +0200
Subject: [PATCH] ath10k: Add logging to better determine some VIF/STA
 creation failures.
In-Reply-To: <1383585574-17779-1-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Mon, 4 Nov 2013 09:19:34
 -0800")
References: <1383585574-17779-1-git-send-email-greearb@candelatech.com>
Message-ID: <87ppqbb4g0.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>

I did some changes to this patch:

https://github.com/kvalo/ath/commit/20c062b93a1addc863d15334dd1eb5892a759f78

The patch is still on ath-next-test branch. Please take a look and if
it's ok for you, send you S-o-b tag so that I can apply it (it was
missing).

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov  8 08:41:22 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 8 Nov 2013 15:41:22 +0200
Subject: [PATCH 1/3] ath10k: add phyerr/dfs handling
In-Reply-To: <CALhHN=oj2hg6zRf5rKyDBexWOdR08=aRXRJtD9gQQs7i_tjjMQ@mail.gmail.com>
 (Janusz Dziedzic's message of "Wed, 6 Nov 2013 14:52:09 +0100")
References: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
 <87bo1xuajk.fsf@kamboji.qca.qualcomm.com>
 <CALhHN=oj2hg6zRf5rKyDBexWOdR08=aRXRJtD9gQQs7i_tjjMQ@mail.gmail.com>
Message-ID: <87habnau4d.fsf@kamboji.qca.qualcomm.com>

Janusz Dziedzic <janusz.dziedzic at tieto.com> writes:

> On 6 November 2013 10:47, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
>> Marek Puzyniak <marek.puzyniak at tieto.com> writes:
>>
>>> +     struct ath10k *ar = file->private_data;
>>> +     char *buf;
>>> +
>>> +     buf = kzalloc(size, GFP_KERNEL);
>>> +     if (buf == NULL)
>>> +             return -ENOMEM;
>>> +
>>> +     if (!ar->dfs_detector) {
>>> +             len += scnprintf(buf + len, size - len, "DFS not enabled\n");
>>> +             goto exit;
>>> +     }
>>> +
>>> +     ar->debug.dfs_pool_stats = ar->dfs_detector->get_stats(ar->dfs_detector);
>>
>> I think we need to take conf_mutex to make sure ar->dfs_detector is not
>> destroyed while we use it.
>>
> We deregister dfs_detector in ath10k_mac_unregister() so we will first
> destroy debugfs, then we don't need any mutex here. BTW I see we don't
> call debugfs_remove*() - so, currently mac clear debugfs for us -
> ieee80211_unregister_hw() -> wiphy_unregister I think. After that we
> deregister dfs_detector.

I don't have the code at hand but yeah, that sounds sensible.

>>> +static void ath10k_dfs_radar_report(struct ath10k *ar,
>>> +                                 struct wmi_single_phyerr_rx_event *event,
>>> +                                 struct phyerr_radar_report *rr,
>>> +                                 u64 tsf)
>>> +{
>>> +     u32 reg0, reg1, tsf32l;
>>> +     struct pulse_event pe;
>>> +     u64 tsf64;
>>> +     u8 rssi, width;
>>
>> What about locking? Does this function assume that conf_mutex is held?
>> If yes, please document that with lockdep_assert_held(). If no, we have
>> a problem :)
>>
>> (Reads wmi.c)
>>
>> Ah, wmi events don't sleep anymore, forgot that. So we can't really use
>> conf_mutex here. I guess our options are bring back worker for wmi
>> events or use spinlock.
>
> I think we can use here spin_lock_bh(&ar->data_lock) when setting
> ar->debug.dfs_stats and when reading this from debugfs.
> But, is that really needed (in worst case we will get older values via debugfs)?

I would prefer not to have any race conditions in the driver, even if
it's just statistics. If there's only a race with statistics atomic
variables are also one option.

-- 
Kalle Valo


From greearb at candelatech.com  Fri Nov  8 11:53:24 2013
From: greearb at candelatech.com (Ben Greear)
Date: Fri, 08 Nov 2013 08:53:24 -0800
Subject: [PATCH] ath10k: Add logging to better determine some VIF/STA
 creation failures.
In-Reply-To: <87ppqbb4g0.fsf@kamboji.qca.qualcomm.com>
References: <1383585574-17779-1-git-send-email-greearb@candelatech.com>
 <87ppqbb4g0.fsf@kamboji.qca.qualcomm.com>
Message-ID: <527D1704.2000508@candelatech.com>

On 11/08/2013 01:58 AM, Kalle Valo wrote:
> greearb at candelatech.com writes:
> 
>> From: Ben Greear <greearb at candelatech.com>
>>
> 
> I did some changes to this patch:
> 
> https://github.com/kvalo/ath/commit/20c062b93a1addc863d15334dd1eb5892a759f78
> 
> The patch is still on ath-next-test branch. Please take a look and if
> it's ok for you, send you S-o-b tag so that I can apply it (it was
> missing).

This part has some grammar issues, it seems to say that the failure
is due to changed bssid.  Maybe make it instead:

Failed to add peer %pM for vdev %d when changing bssid, error: %i

-        ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
-              info->bssid, arvif->vdev_id);
+        ath10k_warn("Failed to add peer %pM for vdev %d due to changed bssid: %i\n",
+              info->bssid, arvif->vdev_id, ret);

Either way, it's better than what was there before, so:

Signed-off-by: Ben Greear <greearb at candelatech.com>

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



From kvalo at qca.qualcomm.com  Mon Nov 11 04:14:44 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 11 Nov 2013 11:14:44 +0200
Subject: [PATCH] ath10k: Add logging to better determine some VIF/STA
 creation failures.
In-Reply-To: <527D1704.2000508@candelatech.com> (Ben Greear's message of "Fri, 
 8 Nov 2013 08:53:24 -0800")
References: <1383585574-17779-1-git-send-email-greearb@candelatech.com>
 <87ppqbb4g0.fsf@kamboji.qca.qualcomm.com>
 <527D1704.2000508@candelatech.com>
Message-ID: <87d2m7b8qj.fsf@kamboji.qca.qualcomm.com>

Ben Greear <greearb at candelatech.com> writes:

> On 11/08/2013 01:58 AM, Kalle Valo wrote:
>> greearb at candelatech.com writes:
>> 
>>> From: Ben Greear <greearb at candelatech.com>
>>>
>> 
>> I did some changes to this patch:
>> 
>> https://github.com/kvalo/ath/commit/20c062b93a1addc863d15334dd1eb5892a759f78
>> 
>> The patch is still on ath-next-test branch. Please take a look and if
>> it's ok for you, send you S-o-b tag so that I can apply it (it was
>> missing).
>
> This part has some grammar issues, it seems to say that the failure
> is due to changed bssid.  Maybe make it instead:
>
> Failed to add peer %pM for vdev %d when changing bssid, error: %i
>
> -        ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
> -              info->bssid, arvif->vdev_id);
> +        ath10k_warn("Failed to add peer %pM for vdev %d due to changed bssid: %i\n",
> +              info->bssid, arvif->vdev_id, ret);
>
> Either way, it's better than what was there before, so:
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

Good point, thanks. I just didn't use the word error as I thought that
wasn't necessary. New version which I'll apply soon:

https://github.com/kvalo/ath/commit/ee309046323f2af1d2cd6f5c1361a6ce8dae5f87

-- 
Kalle Valo


From greearb at candelatech.com  Mon Nov 11 11:55:59 2013
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 11 Nov 2013 08:55:59 -0800
Subject: [PATCH] ath10k: Add logging to better determine some VIF/STA
 creation failures.
In-Reply-To: <87d2m7b8qj.fsf@kamboji.qca.qualcomm.com>
References: <1383585574-17779-1-git-send-email-greearb@candelatech.com>
 <87ppqbb4g0.fsf@kamboji.qca.qualcomm.com> <527D1704.2000508@candelatech.com>
 <87d2m7b8qj.fsf@kamboji.qca.qualcomm.com>
Message-ID: <52810C1F.3060600@candelatech.com>

On 11/11/2013 01:14 AM, Kalle Valo wrote:
> Ben Greear <greearb at candelatech.com> writes:
>
>> On 11/08/2013 01:58 AM, Kalle Valo wrote:
>>> greearb at candelatech.com writes:
>>>
>>>> From: Ben Greear <greearb at candelatech.com>
>>>>
>>>
>>> I did some changes to this patch:
>>>
>>> https://github.com/kvalo/ath/commit/20c062b93a1addc863d15334dd1eb5892a759f78
>>>
>>> The patch is still on ath-next-test branch. Please take a look and if
>>> it's ok for you, send you S-o-b tag so that I can apply it (it was
>>> missing).
>>
>> This part has some grammar issues, it seems to say that the failure
>> is due to changed bssid.  Maybe make it instead:
>>
>> Failed to add peer %pM for vdev %d when changing bssid, error: %i
>>
>> -        ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
>> -              info->bssid, arvif->vdev_id);
>> +        ath10k_warn("Failed to add peer %pM for vdev %d due to changed bssid: %i\n",
>> +              info->bssid, arvif->vdev_id, ret);
>>
>> Either way, it's better than what was there before, so:
>>
>> Signed-off-by: Ben Greear <greearb at candelatech.com>
>
> Good point, thanks. I just didn't use the word error as I thought that
> wasn't necessary. New version which I'll apply soon:
>
> https://github.com/kvalo/ath/commit/ee309046323f2af1d2cd6f5c1361a6ce8dae5f87
>

Looks good.

Thanks,
Ben


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



From kvalo at qca.qualcomm.com  Tue Nov 12 12:43:40 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 12 Nov 2013 19:43:40 +0200
Subject: [PATCH] ath10k: Add logging to better determine some VIF/STA
 creation failures.
In-Reply-To: <1383585574-17779-1-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Mon, 4 Nov 2013 09:19:34
 -0800")
References: <1383585574-17779-1-git-send-email-greearb@candelatech.com>
Message-ID: <87bo1pa52r.fsf@kamboji.qca.qualcomm.com>

Thanks, applied with these changes:

commit 479398b07048342c7fdca89fd3a6cdb739e48a86
Author: Ben Greear <greearb at candelatech.com>
Date:   Mon Nov 4 09:19:34 2013 -0800

    ath10k: add logging to better determine some VIF/STA creation failures
    
    Not all errors were properly notified, fix that.
    
    kvalo: use ath10k_warn() for all messages, cosmetic changes to some of the messages
    
    Signed-off-by: Ben Greear <greearb at candelatech.com>
    Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 12 13:07:45 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 12 Nov 2013 20:07:45 +0200
Subject: [PATCHv2 00/13] ath10k: pci fixes 2013-10-30
In-Reply-To: <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Fri, 8 Nov 2013 08:01:22 +0100")
References: <1383133346-8135-1-git-send-email-michal.kazior@tieto.com>
 <1383894095-27998-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <877gcda3ym.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at 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


From kvalo at qca.qualcomm.com  Wed Nov 13 03:59:27 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 13 Nov 2013 10:59:27 +0200
Subject: [PATCH 1/3] ath10k: add phyerr/dfs handling
In-Reply-To: <87habnau4d.fsf@kamboji.qca.qualcomm.com> (Kalle Valo's message
 of "Fri, 8 Nov 2013 15:41:22 +0200")
References: <1383048394-15256-1-git-send-email-marek.puzyniak@tieto.com>
 <87bo1xuajk.fsf@kamboji.qca.qualcomm.com>
 <CALhHN=oj2hg6zRf5rKyDBexWOdR08=aRXRJtD9gQQs7i_tjjMQ@mail.gmail.com>
 <87habnau4d.fsf@kamboji.qca.qualcomm.com>
Message-ID: <87r4ak8yog.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

>> I think we can use here spin_lock_bh(&ar->data_lock) when setting
>> ar->debug.dfs_stats and when reading this from debugfs.
>> But, is that really needed (in worst case we will get older values via debugfs)?
>
> I would prefer not to have any race conditions in the driver, even if
> it's just statistics. If there's only a race with statistics atomic
> variables are also one option.

I took a new look at these statistics and I think you are right. It
feels a bit overkill to use locking or atomic variables here.

-- 
Kalle Valo


From michal.kazior at tieto.com  Wed Nov 13 05:05:10 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 13 Nov 2013 11:05:10 +0100
Subject: [PATCH] ath10k: allow dynamic bandwidth in hw rate control
Message-ID: <1384337110-9417-1-git-send-email-michal.kazior@tieto.com>

Frames were never retransmitted with
different/lower bandwidths, e.g. only 80MHz
bandwidth was used when dealing with a VHT80
peer.

Allow HW rate control to try out different
bandwidths when retransmitting. This increases
robustness.

Also, document the parameter properly.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 2 +-
 drivers/net/wireless/ath/ath10k/wmi.h | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 56f030e..db81942 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1964,7 +1964,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
 		ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
 			    ret);
 
-	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 0);
+	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
 	if (ret)
 		ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
 			    ret);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 81e33a7..8b824f9 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -2234,7 +2234,12 @@ enum wmi_pdev_param {
 	 * 0: no protection 1:use CTS-to-self 2: use RTS/CTS
 	 */
 	WMI_PDEV_PARAM_PROTECTION_MODE,
-	/* Dynamic bandwidth 0: disable 1: enable */
+	/*
+	 * Dynamic bandwidth - 0: disable, 1: enable
+	 *
+	 * When enabled HW rate control tries different bandwidths when
+	 * retransmitting frames.
+	 */
 	WMI_PDEV_PARAM_DYNAMIC_BW,
 	/* Non aggregrate/ 11g sw retry threshold.0-disable */
 	WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
-- 
1.8.4.rc3



From kvalo at qca.qualcomm.com  Wed Nov 13 06:12:15 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 13 Nov 2013 13:12:15 +0200
Subject: TCP TSQ regression affecting ath10k throughput
Message-ID: <87ob5o7dyo.fsf@kamboji.qca.qualcomm.com>

Hi,

Sujith reported a regression in TCP which caused a major decrease in
ath9k and ath10k throughput:

http://thread.gmane.org/gmane.linux.network/290269

The commit which broke this is c9eeec26e32e ("tcp: TSQ can use a dynamic
limit") and this patch seems to fix it:

http://patchwork.ozlabs.org/patch/290672/

I have cherry picked the fix to ath.git master branch to make it easier
for ath10k developers.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 13 06:28:10 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 13 Nov 2013 13:28:10 +0200
Subject: [PATCH] ath10k: remove htt rx amsdu clear retry bit hack
Message-ID: <20131113112810.5221.69685.stgit@localhost6.localdomain6>

With commit 0cfcefef1 ("mac80211: support reporting A-MSDU subframes
individually") there's no need to have the hack to clear the retry bit in
ath10k_htt_rx_amsdu(), mac80211 can handle this properly now.

Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c |   17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 90d4f74..76c152b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -659,23 +659,6 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
 	memcpy(hdr_buf, hdr, hdr_len);
 	hdr = (struct ieee80211_hdr *)hdr_buf;
 
-	/* FIXME: Hopefully this is a temporary measure.
-	 *
-	 * Reporting individual A-MSDU subframes means each reported frame
-	 * shares the same sequence number.
-	 *
-	 * mac80211 drops frames it recognizes as duplicates, i.e.
-	 * retransmission flag is set and sequence number matches sequence
-	 * number from a previous frame (as per IEEE 802.11-2012: 9.3.2.10
-	 * "Duplicate detection and recovery")
-	 *
-	 * To avoid frames being dropped clear retransmission flag for all
-	 * received A-MSDUs.
-	 *
-	 * Worst case: actual duplicate frames will be reported but this should
-	 * still be handled gracefully by other OSI/ISO layers. */
-	hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_RETRY);
-
 	first = skb;
 	while (skb) {
 		void *decap_hdr;



From michal.kazior at tieto.com  Wed Nov 13 06:38:04 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 13 Nov 2013 12:38:04 +0100
Subject: [PATCH] ath10k: remove htt rx amsdu clear retry bit hack
In-Reply-To: <20131113112810.5221.69685.stgit@localhost6.localdomain6>
References: <20131113112810.5221.69685.stgit@localhost6.localdomain6>
Message-ID: <CA+BoTQkLsbwEAX6RomC_ZA-rtL6q1Q871=9n-Mgry=AZgrKs6Q@mail.gmail.com>

On 13 November 2013 12:28, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> With commit 0cfcefef1 ("mac80211: support reporting A-MSDU subframes
> individually") there's no need to have the hack to clear the retry bit in
> ath10k_htt_rx_amsdu(), mac80211 can handle this properly now.
>
> Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
> ---
>  drivers/net/wireless/ath/ath10k/htt_rx.c |   17 -----------------
>  1 file changed, 17 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
> index 90d4f74..76c152b 100644
> --- a/drivers/net/wireless/ath/ath10k/htt_rx.c
> +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
> @@ -659,23 +659,6 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
>         memcpy(hdr_buf, hdr, hdr_len);
>         hdr = (struct ieee80211_hdr *)hdr_buf;
>
> -       /* FIXME: Hopefully this is a temporary measure.
> -        *
> -        * Reporting individual A-MSDU subframes means each reported frame
> -        * shares the same sequence number.
> -        *
> -        * mac80211 drops frames it recognizes as duplicates, i.e.
> -        * retransmission flag is set and sequence number matches sequence
> -        * number from a previous frame (as per IEEE 802.11-2012: 9.3.2.10
> -        * "Duplicate detection and recovery")
> -        *
> -        * To avoid frames being dropped clear retransmission flag for all
> -        * received A-MSDUs.
> -        *
> -        * Worst case: actual duplicate frames will be reported but this should
> -        * still be handled gracefully by other OSI/ISO layers. */
> -       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_RETRY);
> -
>         first = skb;
>         while (skb) {
>                 void *decap_hdr;
>

You're missing RX_FLAG_AMSDU_MORE. All subframes (except the last one)
from an A-MSDU that are reported separately must have the bit set in
status->flag. Only then mac80211 can apply retransmission/duplication
check properly.


Micha?


From kvalo at qca.qualcomm.com  Wed Nov 13 08:23:18 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 13 Nov 2013 15:23:18 +0200
Subject: [PATCH] ath10k: remove htt rx amsdu clear retry bit hack
In-Reply-To: <CA+BoTQkLsbwEAX6RomC_ZA-rtL6q1Q871=9n-Mgry=AZgrKs6Q@mail.gmail.com>
 (Michal Kazior's message of "Wed, 13 Nov 2013 12:38:04 +0100")
References: <20131113112810.5221.69685.stgit@localhost6.localdomain6>
 <CA+BoTQkLsbwEAX6RomC_ZA-rtL6q1Q871=9n-Mgry=AZgrKs6Q@mail.gmail.com>
Message-ID: <87bo1o77w9.fsf@kamboji.qca.qualcomm.com>

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

>> -       /* FIXME: Hopefully this is a temporary measure.
>> -        *
>> -        * Reporting individual A-MSDU subframes means each reported frame
>> -        * shares the same sequence number.
>> -        *
>> -        * mac80211 drops frames it recognizes as duplicates, i.e.
>> -        * retransmission flag is set and sequence number matches sequence
>> -        * number from a previous frame (as per IEEE 802.11-2012: 9.3.2.10
>> -        * "Duplicate detection and recovery")
>> -        *
>> -        * To avoid frames being dropped clear retransmission flag for all
>> -        * received A-MSDUs.
>> -        *
>> -        * Worst case: actual duplicate frames will be reported but this should
>> -        * still be handled gracefully by other OSI/ISO layers. */
>> -       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_RETRY);
>> -
>>         first = skb;
>>         while (skb) {
>>                 void *decap_hdr;
>>
>
> You're missing RX_FLAG_AMSDU_MORE. All subframes (except the last one)
> from an A-MSDU that are reported separately must have the bit set in
> status->flag. Only then mac80211 can apply retransmission/duplication
> check properly.

I'll send v2, thanks for the review.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 13 08:23:30 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 13 Nov 2013 15:23:30 +0200
Subject: [PATCH v2] ath10k: remove htt rx amsdu clear retry bit hack
Message-ID: <20131113132330.25272.11354.stgit@localhost6.localdomain6>

With commit 0cfcefef1 ("mac80211: support reporting A-MSDU subframes
individually") there's no need to have the hack to clear the retry bit in
ath10k_htt_rx_amsdu(), mac80211 can handle this properly now.

Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/htt.h    |    1 +
 drivers/net/wireless/ath/ath10k/htt_rx.c |   20 +++-----------------
 drivers/net/wireless/ath/ath10k/txrx.c   |    3 +++
 3 files changed, 7 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 1a337e9..7fc7919 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1182,6 +1182,7 @@ struct htt_rx_info {
 		u32 info2;
 	} rate;
 	bool fcs_err;
+	bool amsdu_more;
 };
 
 struct ath10k_htt {
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 90d4f74..0335218 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -659,23 +659,6 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
 	memcpy(hdr_buf, hdr, hdr_len);
 	hdr = (struct ieee80211_hdr *)hdr_buf;
 
-	/* FIXME: Hopefully this is a temporary measure.
-	 *
-	 * Reporting individual A-MSDU subframes means each reported frame
-	 * shares the same sequence number.
-	 *
-	 * mac80211 drops frames it recognizes as duplicates, i.e.
-	 * retransmission flag is set and sequence number matches sequence
-	 * number from a previous frame (as per IEEE 802.11-2012: 9.3.2.10
-	 * "Duplicate detection and recovery")
-	 *
-	 * To avoid frames being dropped clear retransmission flag for all
-	 * received A-MSDUs.
-	 *
-	 * Worst case: actual duplicate frames will be reported but this should
-	 * still be handled gracefully by other OSI/ISO layers. */
-	hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_RETRY);
-
 	first = skb;
 	while (skb) {
 		void *decap_hdr;
@@ -746,6 +729,9 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
 		skb = skb->next;
 		info->skb->next = NULL;
 
+		if (skb)
+			info->amsdu_more = true;
+
 		ath10k_process_rx(htt->ar, info);
 	}
 
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index c511f91..df279a3 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -236,6 +236,9 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
 	if (info->fcs_err)
 		status->flag |= RX_FLAG_FAILED_FCS_CRC;
 
+	if (info->amsdu_more)
+		status->flag |= RX_FLAG_AMSDU_MORE;
+
 	status->signal = info->signal;
 
 	spin_lock_bh(&ar->data_lock);



From bartosz.markowski at tieto.com  Thu Nov 14 03:01:15 2013
From: bartosz.markowski at tieto.com (Bartosz Markowski)
Date: Thu, 14 Nov 2013 09:01:15 +0100
Subject: [PATCH] ath10k: expand the wmi mgmt queue limit to 128
Message-ID: <1384416075-13751-1-git-send-email-bartosz.markowski@tieto.com>

It was obseverd many times the short queue limit can be
easily exceeded in case of AP multiple BSSID scenarios.

"ath10k: wmi mgmt_tx queue limit reached."

This was leading to TX packets drops.

This patch expands the queue limit to 128. After many stress
experiments (high traffic and lot of management frames in
the air) the new value seems to fix the problem on platforms
with limited resources.

Reported-By: Tomasz Skapski <tomasz.skapski at tieto.com>
Signed-off-by: Bartosz Markowski <bartosz.markowski at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 0934f76..be35df2 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -43,7 +43,7 @@
 /* Antenna noise floor */
 #define ATH10K_DEFAULT_NOISE_FLOOR -95
 
-#define ATH10K_MAX_NUM_MGMT_PENDING 16
+#define ATH10K_MAX_NUM_MGMT_PENDING 128
 
 struct ath10k;
 
-- 
1.7.10



From marek.puzyniak at tieto.com  Thu Nov 14 03:33:36 2013
From: marek.puzyniak at tieto.com (Marek Puzyniak)
Date: Thu, 14 Nov 2013 09:33:36 +0100
Subject: [PATCH v2 1/3] ath10k: add phyerr/dfs handling
Message-ID: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>

From: Janusz Dziedzic <janusz.dziedzic at tieto.com>

Handle phyerr, dfs event, radar_report and fft_report.
Add also debugfs dfs_simulate_radar and dfs_stats files.
Use ath dfs pattern detector.

Signed-off-by: Janusz Dziedzic <janusz.dziedzic at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |  13 ++
 drivers/net/wireless/ath/ath10k/debug.c |  90 ++++++++++++
 drivers/net/wireless/ath/ath10k/debug.h |   6 +
 drivers/net/wireless/ath/ath10k/mac.c   |  24 ++++
 drivers/net/wireless/ath/ath10k/wmi.c   | 244 +++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/wmi.h   |  85 +++++++++++
 6 files changed, 461 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 0934f76..671dbe3 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -30,6 +30,7 @@
 #include "wmi.h"
 #include "../ath.h"
 #include "../regd.h"
+#include "../dfs_pattern_detector.h"
 
 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -192,6 +193,14 @@ struct ath10k_target_stats {
 
 };
 
+struct ath10k_dfs_stats {
+	u32 phy_errors;
+	u32 pulses_total;
+	u32 pulses_detected;
+	u32 pulses_discarded;
+	u32 radar_detected;
+};
+
 #define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */
 
 struct ath10k_peer {
@@ -261,6 +270,8 @@ struct ath10k_debug {
 
 	unsigned long htt_stats_mask;
 	struct delayed_work htt_stats_dwork;
+	struct ath10k_dfs_stats dfs_stats;
+	struct ath_dfs_pool_stats dfs_pool_stats;
 };
 
 enum ath10k_state {
@@ -428,6 +439,8 @@ struct ath10k {
 	u32 survey_last_cycle_count;
 	struct survey_info survey[ATH10K_NUM_CHANS];
 
+	struct dfs_pattern_detector *dfs_detector;
+
 #ifdef CONFIG_ATH10K_DEBUGFS
 	struct ath10k_debug debug;
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 760ff22..13705d4 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -639,6 +639,86 @@ void ath10k_debug_stop(struct ath10k *ar)
 		cancel_delayed_work(&ar->debug.htt_stats_dwork);
 }
 
+static ssize_t ath10k_write_simulate_radar(struct file *file,
+					   const char __user *user_buf,
+					   size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+
+	ieee80211_radar_detected(ar->hw);
+
+	return count;
+}
+
+static const struct file_operations fops_simulate_radar = {
+	.write = ath10k_write_simulate_radar,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+#define ATH10K_DFS_STAT(s, p) (\
+	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
+			 ar->debug.dfs_stats.p))
+
+#define ATH10K_DFS_POOL_STAT(s, p) (\
+	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
+			 ar->debug.dfs_pool_stats.p))
+
+static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	int retval = 0, len = 0;
+	const int size = 8000;
+	struct ath10k *ar = file->private_data;
+	char *buf;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	if (!ar->dfs_detector) {
+		len += scnprintf(buf + len, size - len, "DFS not enabled\n");
+		goto exit;
+	}
+
+	ar->debug.dfs_pool_stats =
+			ar->dfs_detector->get_stats(ar->dfs_detector);
+
+	len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
+
+	ATH10K_DFS_STAT("reported phy errors", phy_errors);
+	ATH10K_DFS_STAT("pulse events reported", pulses_total);
+	ATH10K_DFS_STAT("DFS pulses detected", pulses_detected);
+	ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded);
+	ATH10K_DFS_STAT("Radars detected", radar_detected);
+
+	len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
+	ATH10K_DFS_POOL_STAT("Pool references", pool_reference);
+	ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated);
+	ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error);
+	ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used);
+	ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated);
+	ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error);
+	ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used);
+
+exit:
+	if (len > size)
+		len = size;
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+}
+
+static const struct file_operations fops_dfs_stats = {
+	.read = ath10k_read_dfs_stats,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath10k_debug_create(struct ath10k *ar)
 {
 	ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
@@ -667,6 +747,16 @@ int ath10k_debug_create(struct ath10k *ar)
 	debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_htt_stats_mask);
 
+	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
+		debugfs_create_file("dfs_simulate_radar", S_IWUSR,
+				    ar->debug.debugfs_phy, ar,
+				    &fops_simulate_radar);
+
+		debugfs_create_file("dfs_stats", S_IRUSR,
+				    ar->debug.debugfs_phy, ar,
+				    &fops_dfs_stats);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 46e640a..92f1a5e 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -33,6 +33,7 @@ enum ath10k_debug_mask {
 	ATH10K_DBG_MGMT		= 0x00000100,
 	ATH10K_DBG_DATA		= 0x00000200,
 	ATH10K_DBG_BMI		= 0x00000400,
+	ATH10K_DBG_REGULATORY	= 0x00000800,
 	ATH10K_DBG_ANY		= 0xffffffff,
 };
 
@@ -53,6 +54,8 @@ void ath10k_debug_read_service_map(struct ath10k *ar,
 void ath10k_debug_read_target_stats(struct ath10k *ar,
 				    struct wmi_stats_event *ev);
 
+#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
+
 #else
 static inline int ath10k_debug_start(struct ath10k *ar)
 {
@@ -82,6 +85,9 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
 						  struct wmi_stats_event *ev)
 {
 }
+
+#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
+
 #endif /* CONFIG_ATH10K_DEBUGFS */
 
 #ifdef CONFIG_ATH10K_DEBUG
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 56f030e..1a70d0c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1442,9 +1442,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ath10k *ar = hw->priv;
+	bool result;
 
 	ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
 
+	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
+		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
+			   request->dfs_region);
+		result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
+							  request->dfs_region);
+		if (!result)
+			ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n",
+				    request->dfs_region);
+	}
+
 	mutex_lock(&ar->conf_mutex);
 	if (ar->state == ATH10K_STATE_ON)
 		ath10k_regd_update(ar);
@@ -3531,6 +3542,16 @@ int ath10k_mac_register(struct ath10k *ar)
 
 	ar->hw->netdev_features = NETIF_F_HW_CSUM;
 
+	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
+		/* Init ath dfs pattern detector */
+		ar->ath_common.debug_mask = ATH_DBG_DFS;
+		ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common,
+							     NL80211_DFS_UNSET);
+
+		if (!ar->dfs_detector)
+			ath10k_warn("dfs pattern detector init failed\n");
+	}
+
 	ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
 			    ath10k_reg_notifier);
 	if (ret) {
@@ -3566,6 +3587,9 @@ void ath10k_mac_unregister(struct ath10k *ar)
 {
 	ieee80211_unregister_hw(ar->hw);
 
+	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
+		ar->dfs_detector->exit(ar->dfs_detector);
+
 	kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels);
 	kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels);
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index f79f17c..f0bc94a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1381,9 +1381,251 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
 	ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
 }
 
+static void ath10k_dfs_radar_report(struct ath10k *ar,
+				    struct wmi_single_phyerr_rx_event *event,
+				    struct phyerr_radar_report *rr,
+				    u64 tsf)
+{
+	u32 reg0, reg1, tsf32l;
+	struct pulse_event pe;
+	u64 tsf64;
+	u8 rssi, width;
+
+	reg0 = __le32_to_cpu(rr->reg0);
+	reg1 = __le32_to_cpu(rr->reg1);
+
+	ath10k_dbg(ATH10K_DBG_REGULATORY,
+		   "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
+		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
+		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
+		   MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
+		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
+	ath10k_dbg(ATH10K_DBG_REGULATORY,
+		   "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
+		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
+		   MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
+		   MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
+		   MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
+		   MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
+	ath10k_dbg(ATH10K_DBG_REGULATORY,
+		   "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
+		   MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
+		   MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
+
+	if (!ar->dfs_detector)
+		return;
+
+	/* report event to DFS pattern detector */
+	tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp);
+	tsf64 = tsf & (~0xFFFFFFFFULL);
+	tsf64 |= tsf32l;
+
+	width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR);
+	rssi = event->hdr.rssi_combined;
+
+	/* hardware store this as 8 bit signed value,
+	 * set to zero if negative number
+	 */
+	if (rssi & 0x80)
+		rssi = 0;
+
+	pe.ts = tsf64;
+	pe.freq = ar->hw->conf.chandef.chan->center_freq;
+	pe.width = width;
+	pe.rssi = rssi;
+
+	ath10k_dbg(ATH10K_DBG_REGULATORY,
+		   "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
+		   pe.freq, pe.width, pe.rssi, pe.ts);
+
+	ATH10K_DFS_STAT_INC(ar, pulses_detected);
+
+	if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
+		ath10k_dbg(ATH10K_DBG_REGULATORY,
+			   "dfs no pulse pattern detected, yet\n");
+		return;
+	}
+
+	ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
+	ATH10K_DFS_STAT_INC(ar, radar_detected);
+	ieee80211_radar_detected(ar->hw);
+}
+
+static int ath10k_dfs_fft_report(struct ath10k *ar,
+				 struct wmi_single_phyerr_rx_event *event,
+				 struct phyerr_fft_report *fftr,
+				 u64 tsf)
+{
+	u32 reg0, reg1;
+	u8 rssi, peak_mag;
+
+	reg0 = __le32_to_cpu(fftr->reg0);
+	reg1 = __le32_to_cpu(fftr->reg1);
+	rssi = event->hdr.rssi_combined;
+
+	ath10k_dbg(ATH10K_DBG_REGULATORY,
+		   "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
+		   MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
+		   MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
+		   MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
+		   MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
+	ath10k_dbg(ATH10K_DBG_REGULATORY,
+		   "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
+		   MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
+		   MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
+		   MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG),
+		   MS(reg1, SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB));
+
+	peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
+
+	/* false event detection */
+	if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
+	    peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
+		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
+		ATH10K_DFS_STAT_INC(ar, pulses_discarded);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ath10k_wmi_event_dfs(struct ath10k *ar,
+				 struct wmi_single_phyerr_rx_event *event,
+				 u64 tsf)
+{
+	int buf_len, tlv_len, res, i = 0;
+	struct phyerr_tlv *tlv;
+	struct phyerr_radar_report *rr;
+	struct phyerr_fft_report *fftr;
+	u8 *tlv_buf;
+
+	buf_len = __le32_to_cpu(event->hdr.buf_len);
+	ath10k_dbg(ATH10K_DBG_REGULATORY,
+		   "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
+		   event->hdr.phy_err_code, event->hdr.rssi_combined,
+		   __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
+
+	/* Skip event if DFS disabled */
+	if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED))
+		return;
+
+	ATH10K_DFS_STAT_INC(ar, pulses_total);
+
+	while (i < buf_len) {
+		if (i + sizeof(*tlv) > buf_len) {
+			ath10k_warn("too short buf for tlv header (%d)\n", i);
+			return;
+		}
+
+		tlv = (struct phyerr_tlv *)&event->bufp[i];
+		tlv_len = __le16_to_cpu(tlv->len);
+		tlv_buf = &event->bufp[i + sizeof(*tlv)];
+		ath10k_dbg(ATH10K_DBG_REGULATORY,
+			   "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
+			   tlv_len, tlv->tag, tlv->sig);
+
+		switch (tlv->tag) {
+		case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY:
+			if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) {
+				ath10k_warn("too short radar pulse summary (%d)\n",
+					    i);
+				return;
+			}
+
+			rr = (struct phyerr_radar_report *)tlv_buf;
+			ath10k_dfs_radar_report(ar, event, rr, tsf);
+			break;
+		case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
+			if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
+				ath10k_warn("too short fft report (%d)\n", i);
+				return;
+			}
+
+			fftr = (struct phyerr_fft_report *)tlv_buf;
+			res = ath10k_dfs_fft_report(ar, event, fftr, tsf);
+			if (res)
+				return;
+			break;
+		}
+
+		i += sizeof(*tlv) + tlv_len;
+	}
+}
+
+static void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
+				struct wmi_single_phyerr_rx_event *event,
+				u64 tsf)
+{
+	ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n");
+}
+
 static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_PHYERR_EVENTID\n");
+	struct wmi_comb_phyerr_rx_event *comb_event;
+	struct wmi_single_phyerr_rx_event *event;
+	u32 count, i, buf_len, phy_err_code;
+	u64 tsf;
+	int left_len = skb->len;
+
+	ATH10K_DFS_STAT_INC(ar, phy_errors);
+
+	/* Check if combined event available */
+	if (left_len < sizeof(*comb_event)) {
+		ath10k_warn("wmi phyerr combined event wrong len\n");
+		return;
+	}
+
+	left_len -= sizeof(*comb_event);
+
+	/* Check number of included events */
+	comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data;
+	count = __le32_to_cpu(comb_event->hdr.num_phyerr_events);
+
+	tsf = __le32_to_cpu(comb_event->hdr.tsf_u32);
+	tsf <<= 32;
+	tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
+
+	ath10k_dbg(ATH10K_DBG_WMI,
+		   "wmi event phyerr count %d tsf64 0x%llX\n",
+		   count, tsf);
+
+	event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp;
+	for (i = 0; i < count; i++) {
+		/* Check if we can read event header */
+		if (left_len < sizeof(*event)) {
+			ath10k_warn("single event (%d) wrong head len\n", i);
+			return;
+		}
+
+		left_len -= sizeof(*event);
+
+		buf_len = __le32_to_cpu(event->hdr.buf_len);
+		phy_err_code = event->hdr.phy_err_code;
+
+		if (left_len < buf_len) {
+			ath10k_warn("single event (%d) wrong buf len\n", i);
+			return;
+		}
+
+		left_len -= buf_len;
+
+		switch (phy_err_code) {
+		case PHY_ERROR_RADAR:
+			ath10k_wmi_event_dfs(ar, event, tsf);
+			break;
+		case PHY_ERROR_SPECTRAL_SCAN:
+			ath10k_wmi_event_spectral_scan(ar, event, tsf);
+			break;
+		case PHY_ERROR_FALSE_RADAR_EXT:
+			ath10k_wmi_event_dfs(ar, event, tsf);
+			ath10k_wmi_event_spectral_scan(ar, event, tsf);
+			break;
+		default:
+			break;
+		}
+
+		event += sizeof(*event) + buf_len;
+	}
 }
 
 static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 81e33a7..ad53333 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -1978,6 +1978,10 @@ struct wmi_mgmt_rx_event_v2 {
 #define WMI_RX_STATUS_ERR_MIC			0x10
 #define WMI_RX_STATUS_ERR_KEY_CACHE_MISS	0x20
 
+#define PHY_ERROR_SPECTRAL_SCAN		0x26
+#define PHY_ERROR_FALSE_RADAR_EXT		0x24
+#define PHY_ERROR_RADAR				0x05
+
 struct wmi_single_phyerr_rx_hdr {
 	/* TSF timestamp */
 	__le32 tsf_timestamp;
@@ -2069,6 +2073,87 @@ struct wmi_comb_phyerr_rx_event {
 	u8 bufp[0];
 } __packed;
 
+#define PHYERR_TLV_SIG				0xBB
+#define PHYERR_TLV_TAG_SEARCH_FFT_REPORT	0xFB
+#define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY	0xF8
+
+struct phyerr_radar_report {
+	__le32 reg0; /* RADAR_REPORT_REG0_* */
+	__le32 reg1; /* REDAR_REPORT_REG1_* */
+} __packed;
+
+#define RADAR_REPORT_REG0_PULSE_IS_CHIRP_MASK		0x80000000
+#define RADAR_REPORT_REG0_PULSE_IS_CHIRP_LSB		31
+
+#define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_MASK	0x40000000
+#define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_LSB	30
+
+#define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_MASK		0x3FF00000
+#define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_LSB		20
+
+#define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_MASK		0x000F0000
+#define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_LSB		16
+
+#define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_MASK		0x0000FC00
+#define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_LSB		10
+
+#define RADAR_REPORT_REG0_PULSE_SIDX_MASK		0x000003FF
+#define RADAR_REPORT_REG0_PULSE_SIDX_LSB		0
+
+#define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_MASK	0x80000000
+#define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_LSB	31
+
+#define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_MASK	0x7F000000
+#define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_LSB		24
+
+#define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_MASK	0x00FF0000
+#define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_LSB	16
+
+#define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_MASK		0x0000FF00
+#define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_LSB		8
+
+#define RADAR_REPORT_REG1_PULSE_DUR_MASK		0x000000FF
+#define RADAR_REPORT_REG1_PULSE_DUR_LSB			0
+
+struct phyerr_fft_report {
+	__le32 reg0; /* SEARCH_FFT_REPORT_REG0_ * */
+	__le32 reg1; /* SEARCH_FFT_REPORT_REG1_ * */
+} __packed;
+
+#define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_MASK	0xFF800000
+#define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_LSB	23
+
+#define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_MASK		0x007FC000
+#define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_LSB		14
+
+#define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_MASK		0x00003000
+#define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_LSB		12
+
+#define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_MASK		0x00000FFF
+#define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_LSB		0
+
+#define SEARCH_FFT_REPORT_REG1_RELPWR_DB_MASK		0xFC000000
+#define SEARCH_FFT_REPORT_REG1_RELPWR_DB_LSB		26
+
+#define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_MASK		0x03FC0000
+#define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_LSB		18
+
+#define SEARCH_FFT_REPORT_REG1_PEAK_MAG_MASK		0x0003FF00
+#define SEARCH_FFT_REPORT_REG1_PEAK_MAG_LSB		8
+
+#define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_MASK	0x000000FF
+#define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_LSB	0
+
+
+struct phyerr_tlv {
+	__le16 len;
+	u8 tag;
+	u8 sig;
+} __packed;
+
+#define DFS_RSSI_POSSIBLY_FALSE			50
+#define DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE	40
+
 struct wmi_mgmt_tx_hdr {
 	__le32 vdev_id;
 	struct wmi_mac_addr peer_macaddr;
-- 
1.8.1.2



From marek.puzyniak at tieto.com  Thu Nov 14 03:33:37 2013
From: marek.puzyniak at tieto.com (Marek Puzyniak)
Date: Thu, 14 Nov 2013 09:33:37 +0100
Subject: [PATCH v2 2/3] ath10k: introduce DFS implementation
In-Reply-To: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>
References: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>
Message-ID: <1384418018-4973-2-git-send-email-marek.puzyniak@tieto.com>

Configure interface combination for AP running on channels
where radar detection is required. It allows only one type
of interface - AP on DFS channel and limits number of AP
interfaces to 8. Setup WMI channel flags accordingly to mac
channel configuration. CAC based on additional monitor vdev
is started if required for current channel.

Signed-off-by: Marek Puzyniak <marek.puzyniak at tieto.com>
Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/Kconfig  |   7 ++
 drivers/net/wireless/ath/ath10k/core.h   |   6 ++
 drivers/net/wireless/ath/ath10k/htt_rx.c |   5 +
 drivers/net/wireless/ath/ath10k/mac.c    | 160 +++++++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath10k/wmi.c    |  23 ++++-
 drivers/net/wireless/ath/ath10k/wmi.h    |   1 +
 6 files changed, 189 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 82e8088..f51b8e9 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -37,3 +37,10 @@ config ATH10K_TRACING
 	---help---
 	  Select this to ath10k use tracing infrastructure.
 
+config ATH10K_DFS_CERTIFIED
+	bool "Atheros DFS support for certified platforms"
+	depends on ATH10K && CFG80211_CERTIFICATION_ONUS
+	default n
+	---help---
+	  This option enables DFS support for initiating radiation on
+	  ath10k.
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 671dbe3..d5fd74b 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -310,6 +310,11 @@ enum ath10k_fw_features {
 	ATH10K_FW_FEATURE_COUNT,
 };
 
+enum ath10k_dev_flags {
+	/* Indicates that ath10k device is during CAC phase of DFS */
+	ATH10K_CAC_RUNNING,
+};
+
 struct ath10k {
 	struct ath_common ath_common;
 	struct ieee80211_hw *hw;
@@ -403,6 +408,7 @@ struct ath10k {
 	bool monitor_enabled;
 	bool monitor_present;
 	unsigned int filter_flags;
+	unsigned long dev_flags;
 
 	struct wmi_pdev_set_wmm_params_arg wmm_params;
 	struct completion install_key_done;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 90d4f74..d619291 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -959,6 +959,11 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 				continue;
 			}
 
+			if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
+				ath10k_htt_rx_free_msdu_chain(msdu_head);
+				continue;
+			}
+
 			/* FIXME: we do not support chaining yet.
 			 * this needs investigation */
 			if (msdu_chaining) {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1a70d0c..a1bc8a8 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -463,6 +463,10 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
 		arg.ssid = arvif->u.ap.ssid;
 		arg.ssid_len = arvif->u.ap.ssid_len;
 		arg.hidden_ssid = arvif->u.ap.hidden_ssid;
+
+		/* For now allow DFS for AP mode */
+		arg.channel.chan_radar =
+			!!(channel->flags & IEEE80211_CHAN_RADAR);
 	} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
 		arg.ssid = arvif->vif->bss_conf.ssid;
 		arg.ssid_len = arvif->vif->bss_conf.ssid_len;
@@ -532,6 +536,8 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 	/* TODO setup this dynamically, what in case we
 	   don't have any vifs? */
 	arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef);
+	arg.channel.chan_radar =
+			!!(channel->flags & IEEE80211_CHAN_RADAR);
 
 	arg.channel.min_power = 0;
 	arg.channel.max_power = channel->max_power * 2;
@@ -666,6 +672,107 @@ static int ath10k_monitor_destroy(struct ath10k *ar)
 	return ret;
 }
 
+static int ath10k_start_cac(struct ath10k *ar)
+{
+	int ret;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+	ret = ath10k_monitor_create(ar);
+	if (ret) {
+		clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+		return ret;
+	}
+
+	ret = ath10k_monitor_start(ar, ar->monitor_vdev_id);
+	if (ret) {
+		clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+		ath10k_monitor_destroy(ar);
+		return ret;
+	}
+
+	ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
+		   ar->monitor_vdev_id);
+
+	return 0;
+}
+
+static int ath10k_stop_cac(struct ath10k *ar)
+{
+	lockdep_assert_held(&ar->conf_mutex);
+
+	/* CAC is not running - do nothing */
+	if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags))
+		return 0;
+
+	ath10k_monitor_stop(ar);
+	ath10k_monitor_destroy(ar);
+	clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+	ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
+
+	return 0;
+}
+
+static const char *ath10k_dfs_state(enum nl80211_dfs_state dfs_state)
+{
+	switch (dfs_state) {
+	case NL80211_DFS_USABLE:
+		return "USABLE";
+	case NL80211_DFS_UNAVAILABLE:
+		return "UNAVAILABLE";
+	case NL80211_DFS_AVAILABLE:
+		return "AVAILABLE";
+	default:
+		WARN_ON(1);
+		return "bug";
+	}
+}
+
+static void ath10k_config_radar_detection(struct ath10k *ar)
+{
+	struct ieee80211_channel *chan = ar->hw->conf.chandef.chan;
+	bool radar = ar->hw->conf.radar_enabled;
+	bool chan_radar = !!(chan->flags & IEEE80211_CHAN_RADAR);
+	enum nl80211_dfs_state dfs_state = chan->dfs_state;
+	int ret;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	ath10k_dbg(ATH10K_DBG_MAC,
+		   "mac radar config update: chan %dMHz radar %d chan radar %d chan state %s\n",
+		   chan->center_freq, radar, chan_radar,
+		   ath10k_dfs_state(dfs_state));
+
+	/*
+	 * It's safe to call it even if CAC is not started.
+	 * This call here guarantees changing channel, etc. will stop CAC.
+	 */
+	ath10k_stop_cac(ar);
+
+	if (!radar)
+		return;
+
+	if (!chan_radar)
+		return;
+
+	if (dfs_state != NL80211_DFS_USABLE)
+		return;
+
+	ret = ath10k_start_cac(ar);
+	if (ret) {
+		/*
+		 * Not possible to start CAC on current channel so starting
+		 * radiation is not allowed, make this channel DFS_UNAVAILABLE
+		 * by indicating that radar was detected.
+		 */
+		ath10k_warn("failed to start CAC (%d)\n", ret);
+		ieee80211_radar_detected(ar->hw);
+	}
+}
+
 static void ath10k_control_beaconing(struct ath10k_vif *arvif,
 				struct ieee80211_bss_conf *info)
 {
@@ -1375,6 +1482,9 @@ static int ath10k_update_channel_list(struct ath10k *ar)
 			ch->ht40plus =
 				!(channel->flags & IEEE80211_CHAN_NO_HT40PLUS);
 
+			ch->chan_radar =
+				!!(channel->flags & IEEE80211_CHAN_RADAR);
+
 			passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN;
 			ch->passive = passive;
 
@@ -1921,6 +2031,7 @@ void ath10k_halt(struct ath10k *ar)
 {
 	lockdep_assert_held(&ar->conf_mutex);
 
+	ath10k_stop_cac(ar);
 	del_timer_sync(&ar->scan.timeout);
 	ath10k_offchan_tx_purge(ar);
 	ath10k_mgmt_over_wmi_tx_purge(ar);
@@ -2035,11 +2146,16 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 	mutex_lock(&ar->conf_mutex);
 
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac config channel %d mhz\n",
-			   conf->chandef.chan->center_freq);
+		ath10k_dbg(ATH10K_DBG_MAC,
+			   "mac config channel %d mhz flags 0x%x\n",
+			   conf->chandef.chan->center_freq,
+			   conf->chandef.chan->flags);
+
 		spin_lock_bh(&ar->data_lock);
 		ar->rx_channel = conf->chandef.chan;
 		spin_unlock_bh(&ar->data_lock);
+
+		ath10k_config_radar_detection(ar);
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -3308,12 +3424,36 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
 	},
 };
 
-static const struct ieee80211_iface_combination ath10k_if_comb = {
-	.limits = ath10k_if_limits,
-	.n_limits = ARRAY_SIZE(ath10k_if_limits),
-	.max_interfaces = 8,
-	.num_different_channels = 1,
-	.beacon_int_infra_match = true,
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+static const struct ieee80211_iface_limit ath10k_if_dfs_limits[] = {
+	{
+	.max	= 8,
+	.types	= BIT(NL80211_IFTYPE_AP)
+	},
+};
+#endif
+
+static const struct ieee80211_iface_combination ath10k_if_comb[] = {
+	{
+		.limits = ath10k_if_limits,
+		.n_limits = ARRAY_SIZE(ath10k_if_limits),
+		.max_interfaces = 8,
+		.num_different_channels = 1,
+		.beacon_int_infra_match = true,
+	},
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+	{
+		.limits = ath10k_if_dfs_limits,
+		.n_limits = ARRAY_SIZE(ath10k_if_dfs_limits),
+		.max_interfaces = 8,
+		.num_different_channels = 1,
+		.beacon_int_infra_match = true,
+		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+					BIT(NL80211_CHAN_WIDTH_20) |
+					BIT(NL80211_CHAN_WIDTH_40) |
+					BIT(NL80211_CHAN_WIDTH_80),
+	}
+#endif
 };
 
 static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
@@ -3537,8 +3677,8 @@ int ath10k_mac_register(struct ath10k *ar)
 	 */
 	ar->hw->queues = 4;
 
-	ar->hw->wiphy->iface_combinations = &ath10k_if_comb;
-	ar->hw->wiphy->n_iface_combinations = 1;
+	ar->hw->wiphy->iface_combinations = ath10k_if_comb;
+	ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb);
 
 	ar->hw->netdev_features = NETIF_F_HW_CSUM;
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index f0bc94a..aea81d9 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -907,6 +907,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 	ath10k_dbg(ATH10K_DBG_MGMT,
 		   "event mgmt rx status %08x\n", rx_status);
 
+	if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
 	if (rx_status & WMI_RX_STATUS_ERR_DECRYPT) {
 		dev_kfree_skb(skb);
 		return 0;
@@ -2302,6 +2307,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
 {
 	struct wmi_set_channel_cmd *cmd;
 	struct sk_buff *skb;
+	u32 ch_flags = 0;
 
 	if (arg->passive)
 		return -EINVAL;
@@ -2310,10 +2316,14 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
 	if (!skb)
 		return -ENOMEM;
 
+	if (arg->chan_radar)
+		ch_flags |= WMI_CHAN_FLAG_DFS;
+
 	cmd = (struct wmi_set_channel_cmd *)skb->data;
 	cmd->chan.mhz               = __cpu_to_le32(arg->freq);
 	cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq);
 	cmd->chan.mode              = arg->mode;
+	cmd->chan.flags		   |= __cpu_to_le32(ch_flags);
 	cmd->chan.min_power         = arg->min_power;
 	cmd->chan.max_power         = arg->max_power;
 	cmd->chan.reg_power         = arg->max_reg_power;
@@ -2862,6 +2872,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
 	struct sk_buff *skb;
 	const char *cmdname;
 	u32 flags = 0;
+	u32 ch_flags = 0;
 
 	if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid &&
 	    cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)
@@ -2888,6 +2899,8 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
 		flags |= WMI_VDEV_START_HIDDEN_SSID;
 	if (arg->pmf_enabled)
 		flags |= WMI_VDEV_START_PMF_ENABLED;
+	if (arg->channel.chan_radar)
+		ch_flags |= WMI_CHAN_FLAG_DFS;
 
 	cmd = (struct wmi_vdev_start_request_cmd *)skb->data;
 	cmd->vdev_id         = __cpu_to_le32(arg->vdev_id);
@@ -2909,6 +2922,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
 		__cpu_to_le32(arg->channel.band_center_freq1);
 
 	cmd->chan.mode = arg->channel.mode;
+	cmd->chan.flags |= __cpu_to_le32(ch_flags);
 	cmd->chan.min_power = arg->channel.min_power;
 	cmd->chan.max_power = arg->channel.max_power;
 	cmd->chan.reg_power = arg->channel.max_reg_power;
@@ -2916,9 +2930,10 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
 	cmd->chan.antenna_max = arg->channel.max_antenna_gain;
 
 	ath10k_dbg(ATH10K_DBG_WMI,
-		   "wmi vdev %s id 0x%x freq %d, mode %d, ch_flags: 0x%0X,"
-		   "max_power: %d\n", cmdname, arg->vdev_id, arg->channel.freq,
-		   arg->channel.mode, flags, arg->channel.max_power);
+		   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, "
+		   "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id,
+		   flags, arg->channel.freq, arg->channel.mode,
+		   cmd->chan.flags, arg->channel.max_power);
 
 	return ath10k_wmi_cmd_send(ar, skb, cmd_id);
 }
@@ -3252,6 +3267,8 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
 			flags |= WMI_CHAN_FLAG_ALLOW_VHT;
 		if (ch->ht40plus)
 			flags |= WMI_CHAN_FLAG_HT40_PLUS;
+		if (ch->chan_radar)
+			flags |= WMI_CHAN_FLAG_DFS;
 
 		ci->mhz               = __cpu_to_le32(ch->freq);
 		ci->band_center_freq1 = __cpu_to_le32(ch->freq);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index ad53333..b47a301 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -916,6 +916,7 @@ struct wmi_channel_arg {
 	bool allow_ht;
 	bool allow_vht;
 	bool ht40plus;
+	bool chan_radar;
 	/* note: power unit is 0.5 dBm */
 	u32 min_power;
 	u32 max_power;
-- 
1.8.1.2



From marek.puzyniak at tieto.com  Thu Nov 14 03:33:38 2013
From: marek.puzyniak at tieto.com (Marek Puzyniak)
Date: Thu, 14 Nov 2013 09:33:38 +0100
Subject: [PATCH v2 3/3] ath10k: add debugfs file to control radar events
 blocking
In-Reply-To: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>
References: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>
Message-ID: <1384418018-4973-3-git-send-email-marek.puzyniak@tieto.com>

Sometimes for DFS testing is required to stay on current channel even after
radar detected. This patch allows to enable/disable radar detected event to be
passed to mac80211.

By default radar detected event in not blocked.

To block it:
echo 1 > /sys/kernel/debug/ieee80211/phyX/ath10k/dfs_block_radar_events

To unblock again:
echo 0 > /sys/kernel/debug/ieee80211/phyX/ath10k/dfs_block_radar_events

Inform about blocking radar detected event even when logs are disabled
for throughput/performance reasons.

Signed-off-by: Marek Puzyniak <marek.puzyniak at tieto.com>
Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h  | 1 +
 drivers/net/wireless/ath/ath10k/debug.c | 4 ++++
 drivers/net/wireless/ath/ath10k/wmi.c   | 8 ++++++++
 3 files changed, 13 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index d5fd74b..cdedcbf 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -409,6 +409,7 @@ struct ath10k {
 	bool monitor_present;
 	unsigned int filter_flags;
 	unsigned long dev_flags;
+	u32 dfs_block_radar_events;
 
 	struct wmi_pdev_set_wmm_params_arg wmm_params;
 	struct completion install_key_done;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 13705d4..6bdfad3 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -752,6 +752,10 @@ int ath10k_debug_create(struct ath10k *ar)
 				    ar->debug.debugfs_phy, ar,
 				    &fops_simulate_radar);
 
+		debugfs_create_bool("dfs_block_radar_events", S_IWUSR,
+				    ar->debug.debugfs_phy,
+				    &ar->dfs_block_radar_events);
+
 		debugfs_create_file("dfs_stats", S_IRUSR,
 				    ar->debug.debugfs_phy, ar,
 				    &fops_dfs_stats);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index aea81d9..c654137 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1453,6 +1453,14 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
 
 	ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
 	ATH10K_DFS_STAT_INC(ar, radar_detected);
+
+	/* Control radar events reporting in debugfs file
+	   dfs_block_radar_events */
+	if (ar->dfs_block_radar_events) {
+		ath10k_info("DFS Radar detected, but ignored as requested\n");
+		return;
+	}
+
 	ieee80211_radar_detected(ar->hw);
 }
 
-- 
1.8.1.2



From michal.kazior at tieto.com  Thu Nov 14 04:34:18 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 14 Nov 2013 10:34:18 +0100
Subject: [PATCH] ath10k: clear tx status before submitting to mac80211
Message-ID: <1384421658-7295-1-git-send-email-michal.kazior@tieto.com>

Garbage was reported in ieee80211_tx_info. This
led to a WARN_ON in cfg80211_calculate_bitrate().

This also fixes some random tx bitrate values
reported through `iw` command.

Reported-By: Kalle Valo <kvalo at qca.qualcomm.com>
Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/txrx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index c511f91..3bc86f1 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -75,6 +75,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 	ath10k_report_offchan_tx(htt->ar, msdu);
 
 	info = IEEE80211_SKB_CB(msdu);
+	memset(info, 0, sizeof(*info));
 
 	if (tx_done->discard) {
 		ieee80211_free_txskb(htt->ar->hw, msdu);
-- 
1.8.4.rc3



From kvalo at qca.qualcomm.com  Fri Nov 15 04:01:03 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 15 Nov 2013 11:01:03 +0200
Subject: [PATCH v2] ath10k: remove htt rx amsdu clear retry bit hack
In-Reply-To: <20131113132330.25272.11354.stgit@localhost6.localdomain6> (Kalle
 Valo's message of "Wed, 13 Nov 2013 15:23:30 +0200")
References: <20131113132330.25272.11354.stgit@localhost6.localdomain6>
Message-ID: <87mwl63upc.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

> With commit 0cfcefef1 ("mac80211: support reporting A-MSDU subframes
> individually") there's no need to have the hack to clear the retry bit in
> ath10k_htt_rx_amsdu(), mac80211 can handle this properly now.
>
> Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>

Applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov 15 04:01:50 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 15 Nov 2013 11:01:50 +0200
Subject: [PATCH] ath10k: expand the wmi mgmt queue limit to 128
In-Reply-To: <1384416075-13751-1-git-send-email-bartosz.markowski@tieto.com>
 (Bartosz Markowski's message of "Thu, 14 Nov 2013 09:01:15 +0100")
References: <1384416075-13751-1-git-send-email-bartosz.markowski@tieto.com>
Message-ID: <87iovu3uo1.fsf@kamboji.qca.qualcomm.com>

Bartosz Markowski <bartosz.markowski at tieto.com> writes:

> It was obseverd many times the short queue limit can be
> easily exceeded in case of AP multiple BSSID scenarios.
>
> "ath10k: wmi mgmt_tx queue limit reached."
>
> This was leading to TX packets drops.
>
> This patch expands the queue limit to 128. After many stress
> experiments (high traffic and lot of management frames in
> the air) the new value seems to fix the problem on platforms
> with limited resources.
>
> Reported-By: Tomasz Skapski <tomasz.skapski at tieto.com>
> Signed-off-by: Bartosz Markowski <bartosz.markowski at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov 15 04:06:55 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 15 Nov 2013 11:06:55 +0200
Subject: [PATCH] ath10k: clear tx status before submitting to mac80211
In-Reply-To: <1384421658-7295-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 14 Nov 2013 10:34:18 +0100")
References: <1384421658-7295-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87eh6i3ufk.fsf@kamboji.qca.qualcomm.com>

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

> Garbage was reported in ieee80211_tx_info. This
> led to a WARN_ON in cfg80211_calculate_bitrate().
>
> This also fixes some random tx bitrate values
> reported through `iw` command.
>
> Reported-By: Kalle Valo <kvalo at qca.qualcomm.com>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov 15 03:59:57 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 15 Nov 2013 10:59:57 +0200
Subject: [PATCH] ath10k: allow dynamic bandwidth in hw rate control
In-Reply-To: <1384337110-9417-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Wed, 13 Nov 2013 11:05:10 +0100")
References: <1384337110-9417-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87r4ai3ur6.fsf@kamboji.qca.qualcomm.com>

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

> Frames were never retransmitted with
> different/lower bandwidths, e.g. only 80MHz
> bandwidth was used when dealing with a VHT80
> peer.
>
> Allow HW rate control to try out different
> bandwidths when retransmitting. This increases
> robustness.
>
> Also, document the parameter properly.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov 15 12:25:26 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 15 Nov 2013 19:25:26 +0200
Subject: [PATCH 1/3] ath10k: don't show MSI registration warnings
Message-ID: <20131115172526.10646.35233.stgit@localhost6.localdomain6>

Convert the MSI failure warnings to a debug message to make them less spammy.
Also convert the irq mode printout to a single print to make it easier to
show it only once.

Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/pci.c |   26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 46c94ce..a3cdd72 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1851,6 +1851,7 @@ static void ath10k_pci_start_bmi(struct ath10k *ar)
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	const char *irq_mode;
 	int ret;
 
 	/*
@@ -1916,6 +1917,16 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	}
 
 	ath10k_pci_start_bmi(ar);
+
+	if (ar_pci->num_msi_intrs > 1)
+		irq_mode = "MSI-X";
+	else if (ar_pci->num_msi_intrs == 1)
+		irq_mode = "MSI";
+	else
+		irq_mode = "legacy";
+
+	ath10k_info("pci irq %s\n", irq_mode);
+
 	return 0;
 
 err_irq:
@@ -2161,7 +2172,8 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)
 		}
 	}
 
-	ath10k_info("MSI-X interrupt handling (%d intrs)\n", num);
+	ath10k_dbg(ATH10K_DBG_BOOT,
+		   "MSI-X interrupt handling (%d intrs)\n", num);
 	return 0;
 }
 
@@ -2182,7 +2194,7 @@ static int ath10k_pci_start_intr_msi(struct ath10k *ar)
 		return ret;
 	}
 
-	ath10k_info("MSI interrupt handling\n");
+	ath10k_dbg(ATH10K_DBG_BOOT, "MSI interrupt handling\n");
 	return 0;
 }
 
@@ -2218,7 +2230,7 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 				 PCIE_INTR_ENABLE_ADDRESS));
 
 	ath10k_pci_sleep(ar);
-	ath10k_info("legacy interrupt handling\n");
+	ath10k_dbg(ATH10K_DBG_BOOT, "legacy interrupt handling\n");
 	return 0;
 }
 
@@ -2248,7 +2260,8 @@ static int ath10k_pci_start_intr(struct ath10k *ar)
 		if (ret == 0)
 			goto exit;
 
-		ath10k_warn("MSI-X didn't succeed (%d), trying MSI\n", ret);
+		ath10k_dbg(ATH10K_DBG_BOOT,
+			   "MSI-X didn't succeed (%d), trying MSI\n", ret);
 		num = 1;
 	}
 
@@ -2257,8 +2270,9 @@ static int ath10k_pci_start_intr(struct ath10k *ar)
 		if (ret == 0)
 			goto exit;
 
-		ath10k_warn("MSI didn't succeed (%d), trying legacy INTR\n",
-			    ret);
+		ath10k_dbg(ATH10K_DBG_BOOT,
+			   "MSI didn't succeed (%d), trying legacy INTR\n",
+			   ret);
 		num = 0;
 	}
 



From kvalo at qca.qualcomm.com  Fri Nov 15 12:25:33 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 15 Nov 2013 19:25:33 +0200
Subject: [PATCH 2/3] ath10k: make core boot messages more compact
In-Reply-To: <20131115172526.10646.35233.stgit@localhost6.localdomain6>
References: <20131115172526.10646.35233.stgit@localhost6.localdomain6>
Message-ID: <20131115172533.10646.28979.stgit@localhost6.localdomain6>

We can show the same amount of information in one line. And then
it's easier to show this information only during first firmware boot
(see next patch).

For UART printouts there's already a message when they are enabled so
no need to have a print when they are disabled, that's the default
anyway.

Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c |   16 ++++++++++------
 drivers/net/wireless/ath/ath10k/htt.c  |    4 ++--
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index be5b17e..e6c468b 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -597,10 +597,8 @@ static int ath10k_init_uart(struct ath10k *ar)
 		return ret;
 	}
 
-	if (!uart_print) {
-		ath10k_info("UART prints disabled\n");
+	if (!uart_print)
 		return 0;
-	}
 
 	ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
 	if (ret) {
@@ -645,8 +643,8 @@ static int ath10k_init_hw_params(struct ath10k *ar)
 
 	ar->hw_params = *hw_params;
 
-	ath10k_info("Hardware name %s version 0x%x\n",
-		    ar->hw_params.name, ar->target_version);
+	ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
+		   ar->hw_params.name, ar->target_version);
 
 	return 0;
 }
@@ -807,7 +805,8 @@ int ath10k_core_start(struct ath10k *ar)
 	if (status)
 		goto err_htt_detach;
 
-	ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version);
+	ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
+		   ar->hw->wiphy->fw_version);
 
 	status = ath10k_wmi_cmd_init(ar);
 	if (status) {
@@ -833,6 +832,11 @@ int ath10k_core_start(struct ath10k *ar)
 	ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
 	INIT_LIST_HEAD(&ar->arvifs);
 
+	ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n",
+		    ar->hw_params.name, ar->target_version,
+		    ar->hw->wiphy->fw_version, ar->fw_api,
+		    ar->htt.target_version_major, ar->htt.target_version_minor);
+
 	return 0;
 
 err_disconnect_htc:
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 5f7eeeb..69697af5 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -104,8 +104,8 @@ err_htc_attach:
 
 static int ath10k_htt_verify_version(struct ath10k_htt *htt)
 {
-	ath10k_info("htt target version %d.%d\n",
-		    htt->target_version_major, htt->target_version_minor);
+	ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n",
+		   htt->target_version_major, htt->target_version_minor);
 
 	if (htt->target_version_major != 2 &&
 	    htt->target_version_major != 3) {



From kvalo at qca.qualcomm.com  Fri Nov 15 12:25:39 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 15 Nov 2013 19:25:39 +0200
Subject: [PATCH 3/3] ath10k: show hardware and firmware info prints only once
In-Reply-To: <20131115172526.10646.35233.stgit@localhost6.localdomain6>
References: <20131115172526.10646.35233.stgit@localhost6.localdomain6>
Message-ID: <20131115172539.10646.6643.stgit@localhost6.localdomain6>

This makes ath10k a lot less spammy by default.

Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c |   12 ++++++++----
 drivers/net/wireless/ath/ath10k/core.h |    1 +
 drivers/net/wireless/ath/ath10k/pci.c  |    4 +++-
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index e6c468b..3b59af3 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -832,10 +832,14 @@ int ath10k_core_start(struct ath10k *ar)
 	ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
 	INIT_LIST_HEAD(&ar->arvifs);
 
-	ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n",
-		    ar->hw_params.name, ar->target_version,
-		    ar->hw->wiphy->fw_version, ar->fw_api,
-		    ar->htt.target_version_major, ar->htt.target_version_minor);
+	if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
+		ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n",
+			    ar->hw_params.name, ar->target_version,
+			    ar->hw->wiphy->fw_version, ar->fw_api,
+			    ar->htt.target_version_major,
+			    ar->htt.target_version_minor);
+
+	__set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);
 
 	return 0;
 
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 7721e3b..79726e0 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -313,6 +313,7 @@ enum ath10k_fw_features {
 enum ath10k_dev_flags {
 	/* Indicates that ath10k device is during CAC phase of DFS */
 	ATH10K_CAC_RUNNING,
+	ATH10K_FLAG_FIRST_BOOT_DONE,
 };
 
 struct ath10k {
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index a3cdd72..2457c8b 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/bitops.h>
 
 #include "core.h"
 #include "debug.h"
@@ -1925,7 +1926,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 	else
 		irq_mode = "legacy";
 
-	ath10k_info("pci irq %s\n", irq_mode);
+	if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
+		ath10k_info("pci irq %s\n", irq_mode);
 
 	return 0;
 



From kvalo at qca.qualcomm.com  Tue Nov 19 09:49:30 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 19 Nov 2013 16:49:30 +0200
Subject: [PATCH v2 1/3] ath10k: add phyerr/dfs handling
In-Reply-To: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>
 (Marek Puzyniak's message of "Thu, 14 Nov 2013 09:33:36 +0100")
References: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>
Message-ID: <87vbzo1m6d.fsf@kamboji.qca.qualcomm.com>

Marek Puzyniak <marek.puzyniak at tieto.com> writes:

> From: Janusz Dziedzic <janusz.dziedzic at tieto.com>
>
> Handle phyerr, dfs event, radar_report and fft_report.
> Add also debugfs dfs_simulate_radar and dfs_stats files.
> Use ath dfs pattern detector.
>
> Signed-off-by: Janusz Dziedzic <janusz.dziedzic at tieto.com>

Thanks, all three applied.

In the future please add a changelog when you change something in the
patches. It's very difficult to review otherwise.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 20 03:59:21 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 20 Nov 2013 10:59:21 +0200
Subject: [PATCH v2 1/3] ath10k: add phyerr/dfs handling
In-Reply-To: <87vbzo1m6d.fsf@kamboji.qca.qualcomm.com> (Kalle Valo's message
 of "Tue, 19 Nov 2013 16:49:30 +0200")
References: <1384418018-4973-1-git-send-email-marek.puzyniak@tieto.com>
 <87vbzo1m6d.fsf@kamboji.qca.qualcomm.com>
Message-ID: <87wqk3zbx2.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

> Marek Puzyniak <marek.puzyniak at tieto.com> writes:
>
>> From: Janusz Dziedzic <janusz.dziedzic at tieto.com>
>>
>> Handle phyerr, dfs event, radar_report and fft_report.
>> Add also debugfs dfs_simulate_radar and dfs_stats files.
>> Use ath dfs pattern detector.
>>
>> Signed-off-by: Janusz Dziedzic <janusz.dziedzic at tieto.com>
>
> Thanks, all three applied.
>
> In the future please add a changelog when you change something in the
> patches. It's very difficult to review otherwise.

I found out _afterwards_ that these patches actually depend on some
functionality which is only in mac80211-next.git. As I do not want to
submit broken functionality to John I had to rebase ath.git and change
the patch 2:

commit e8a50f8ba44b6933b2a39b6a65528b9a4e8ba5f3
Author: Marek Puzyniak <marek.puzyniak at tieto.com>
Date:   Wed Nov 20 09:59:47 2013 +0200

    ath10k: introduce DFS implementation
    
    Configure interface combination for AP running on channels
    where radar detection is required. It allows only one type
    of interface - AP on DFS channel and limits number of AP
    interfaces to 8. Setup WMI channel flags accordingly to mac
    channel configuration. CAC based on additional monitor vdev
    is started if required for current channel.
    
    kvalo: dropped ATH10K_DFS_CERTIFIED config option as this
    the DFS still depends on few mac80211 and cfg80211 patches
    which are on mac80211-next.git right now. The config option
    will be added later once all dependencies are available.
    
    Signed-off-by: Marek Puzyniak <marek.puzyniak at tieto.com>
    Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
    Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>


-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 20 04:03:40 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 20 Nov 2013 11:03:40 +0200
Subject: ath.git rebased
Message-ID: <87siurzbpv.fsf@kamboji.qca.qualcomm.com>

Hi,

due to problems with the ath10k DFS patches I had to rebase both master
and ath-next branches and everyone using these branches need to reset
their local branches. Make sure that the branch the commit below is the
head commit ('git show').

I apologize for the inconvenience but I didn't have any other way to fix
this.

commit dd34375ace70d9bd714c040cf25860454ec5c31b
Merge: 57021ab 650b91f
Author: Kalle Valo <kvalo at qca.qualcomm.com>
Date:   Wed Nov 20 10:39:58 2013 +0200

    Merge branch 'ath-next'

-- 
Kalle Valo


From malaakso at elisanet.fi  Wed Nov 20 16:38:13 2013
From: malaakso at elisanet.fi (Matti Laakso)
Date: Wed, 20 Nov 2013 22:38:13 +0100
Subject: [PATCH] ath10k: clear tx status before submitting to mac80211
In-Reply-To: <87eh6i3ufk.fsf@kamboji.qca.qualcomm.com>
References: <87eh6i3ufk.fsf@kamboji.qca.qualcomm.com>
Message-ID: <528D2BC5.7050902@elisanet.fi>

> Michal Kazior <michal.kazior at tieto.com <http://lists.infradead.org/mailman/listinfo/ath10k>> writes:
>
> >/ Garbage was reported in ieee80211_tx_info. This
> />/ led to a WARN_ON in cfg80211_calculate_bitrate().
> />/
> />/ This also fixes some random tx bitrate values
> />/ reported through `iw` command.
> />/
> />/ Reported-By: Kalle Valo <kvalo at qca.qualcomm.com <http://lists.infradead.org/mailman/listinfo/ath10k>>
> />/ Signed-off-by: Michal Kazior <michal.kazior at tieto.com <http://lists.infradead.org/mailman/listinfo/ath10k>>
> /
> Thanks, applied.
>
> -- 
> Kalle Valo

I'm running ath10k on a router, and cherry-picking this to current
OpenWrt (3.10.18 with backports from linux-next and some
OpenWrt-specific patches) prevents all stations from associating to the
access point. As far as I can see this patch doesn't depend on anything
else pushed in between?

Matti Laakso


From michal.kazior at tieto.com  Thu Nov 21 02:21:16 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 21 Nov 2013 08:21:16 +0100
Subject: [PATCH] ath10k: clear tx status before submitting to mac80211
In-Reply-To: <528D2BC5.7050902@elisanet.fi>
References: <87eh6i3ufk.fsf@kamboji.qca.qualcomm.com>
 <528D2BC5.7050902@elisanet.fi>
Message-ID: <CA+BoTQkwQ08_xTcQ2XiBq1LYgL4u=8+qVSvMcOA_RatueUBgQQ@mail.gmail.com>

On 20 November 2013 22:38, Matti Laakso <malaakso at elisanet.fi> wrote:
>> Michal Kazior <michal.kazior at tieto.com <http://lists.infradead.org/mailman/listinfo/ath10k>> writes:
>>
>> >/ Garbage was reported in ieee80211_tx_info. This
>> />/ led to a WARN_ON in cfg80211_calculate_bitrate().
>> />/
>> />/ This also fixes some random tx bitrate values
>> />/ reported through `iw` command.
>> />/
>> />/ Reported-By: Kalle Valo <kvalo at qca.qualcomm.com <http://lists.infradead.org/mailman/listinfo/ath10k>>
>> />/ Signed-off-by: Michal Kazior <michal.kazior at tieto.com <http://lists.infradead.org/mailman/listinfo/ath10k>>
>> /
>> Thanks, applied.
>>
>> --
>> Kalle Valo
>
> I'm running ath10k on a router, and cherry-picking this to current
> OpenWrt (3.10.18 with backports from linux-next and some
> OpenWrt-specific patches) prevents all stations from associating to the
> access point. As far as I can see this patch doesn't depend on anything
> else pushed in between?

Ah, my mistake. Thank you for testing and reporting back. I'll post a
fix for that.


Micha?


From phil.moora at gmail.com  Thu Nov 21 21:09:36 2013
From: phil.moora at gmail.com (Phil Moora)
Date: Thu, 21 Nov 2013 18:09:36 -0800
Subject: active/idle time from ath10k
Message-ID: <CAPqRyK8aiF4cnz+V9bDyPKPakjZ5ee3e+OFxmsnTaTMhh8An5g@mail.gmail.com>

Hi all,

Is there a way to get radio active time or idle time from ath10k? By
active time, I mean that the radio was transmitting or receiving
something.

I looked at ath10k_get_survey function but
(1) I don't want/need to hop across channels, just need the statistics
for my radio's current channel,
(2) I want the statistics periodically, as opposed to survey dump
which is only available at request.

Any pointers?


From moon.linux at yahoo.com  Fri Nov 22 00:05:14 2013
From: moon.linux at yahoo.com (Anand Moon)
Date: Thu, 21 Nov 2013 21:05:14 -0800 (PST)
Subject: Ath10k router
Message-ID: <1385096714.41414.YahooMailNeo@web122305.mail.ne1.yahoo.com>

Hi All,

I am looking to work on development router with support Ath10k, my guess is that compex.sg provide development routers.
Are there any other free development router which can be use for development as well as testing.

Please share the details and please guide me.
-Anand Moon


From michal.kazior at tieto.com  Fri Nov 22 08:05:11 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:11 +0100
Subject: [PATCH 1/8] ath10k: don't consume other's shared interrupts
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-2-git-send-email-michal.kazior@tieto.com>

ath10k assumed all interrupts were directed to it.
This isn't the case for legacy shared interrupts.
ath10k consumed interrupts for other devices.

Check device irq status and return IRQ_NONE when
appropriate.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/hw.h  |  1 +
 drivers/net/wireless/ath/ath10k/pci.c | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 8aeb46d..9535eaa 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -269,6 +269,7 @@ enum ath10k_mcast2ucast_mode {
 #define CORE_CTRL_CPU_INTR_MASK			0x00002000
 #define CORE_CTRL_ADDRESS			0x0000
 #define PCIE_INTR_ENABLE_ADDRESS		0x0008
+#define PCIE_INTR_CAUSE_ADDRESS			0x000c
 #define PCIE_INTR_CLR_ADDRESS			0x0014
 #define SCRATCH_3_ADDRESS			0x0030
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 2457c8b..ed752d6 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2075,6 +2075,24 @@ static irqreturn_t ath10k_pci_msi_fw_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+static bool ath10k_pci_irq_pending(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	u32 cause;
+
+	/* MSIs are always exclusive */
+	if (ar_pci->num_msi_intrs > 0)
+		return true;
+
+	/* Check if the shared legacy irq is for us */
+	cause = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				  PCIE_INTR_CAUSE_ADDRESS);
+	if (cause & (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL))
+		return true;
+
+	return false;
+}
+
 /*
  * Top-level interrupt handler for all PCI interrupts from a Target.
  * When a block of MSI interrupts is allocated, this top-level handler
@@ -2085,6 +2103,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 	struct ath10k *ar = arg;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
+	if (!ath10k_pci_irq_pending(ar))
+		return IRQ_NONE;
+
 	if (ar_pci->num_msi_intrs == 0) {
 		/*
 		 * IMPORTANT: INTR_CLR regiser has to be set after
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:14 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:14 +0100
Subject: [PATCH 4/8] ath10k: don't use interrupts for BMI
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-5-git-send-email-michal.kazior@tieto.com>

It's not really necessary for interrupts to be
used for BMI. BMI already assumes there's only one
caller at a time and it works directly with CE.

Make BMI poll for CE completions instead of
waiting for interrupts. This makes disabling
interrupts during early boot possible.

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 4067890..1b12db8 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -59,6 +59,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar);
 static int ath10k_pci_deinit_irq(struct ath10k *ar);
 static int ath10k_pci_request_irq(struct ath10k *ar);
 static void ath10k_pci_free_irq(struct ath10k *ar);
+static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
+			       struct ath10k_ce_pipe *rx_pipe,
+			       struct bmi_xfer *xfer);
 
 static const struct ce_attr host_ce_config_wlan[] = {
 	/* CE0: host->target HTC control and raw streams */
@@ -1382,6 +1385,8 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
 	void *treq, *tresp = NULL;
 	int ret = 0;
 
+	might_sleep();
+
 	if (resp && !resp_len)
 		return -EINVAL;
 
@@ -1422,14 +1427,12 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
 	if (ret)
 		goto err_resp;
 
-	ret = wait_for_completion_timeout(&xfer.done,
-					  BMI_COMMUNICATION_TIMEOUT_HZ);
-	if (ret <= 0) {
+	ret = ath10k_pci_bmi_wait(ce_tx, ce_rx, &xfer);
+	if (ret) {
 		u32 unused_buffer;
 		unsigned int unused_nbytes;
 		unsigned int unused_id;
 
-		ret = -ETIMEDOUT;
 		ath10k_ce_cancel_send_next(ce_tx, NULL, &unused_buffer,
 					   &unused_nbytes, &unused_id);
 	} else {
@@ -1497,6 +1500,25 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
 	complete(&xfer->done);
 }
 
+static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
+			       struct ath10k_ce_pipe *rx_pipe,
+			       struct bmi_xfer *xfer)
+{
+	unsigned long timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ;
+
+	while (time_before_eq(jiffies, timeout)) {
+		ath10k_pci_bmi_send_done(tx_pipe);
+		ath10k_pci_bmi_recv_data(rx_pipe);
+
+		if (completion_done(&xfer->done))
+			return 0;
+
+		schedule();
+	}
+
+	return -ETIMEDOUT;
+}
+
 /*
  * Map from service/endpoint to Copy Engine.
  * This table is derived from the CE_PCI TABLE, above.
@@ -1834,24 +1856,6 @@ 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);
-
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot start bmi\n");
-}
-
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -1926,8 +1930,6 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_free_irq;
 	}
 
-	ath10k_pci_start_bmi(ar);
-
 	if (ar_pci->num_msi_intrs > 1)
 		irq_mode = "MSI-X";
 	else if (ar_pci->num_msi_intrs == 1)
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:17 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:17 +0100
Subject: [PATCH 7/8] ath10k: re-add support for early fw indication
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-8-git-send-email-michal.kazior@tieto.com>

It's possible for FW to panic during early boot or
at driver teardown in some rare cases.

The patch re-introduces support to detect and
print those crashes.

This introduces an additional irq handler that is
set for the duration of early boot and shutdown.
The handler is then overriden with regular
handlers upon hif start().

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 107 ++++++++++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath10k/pci.h |   1 +
 2 files changed, 102 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index a9bc290..47d9b6e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -59,6 +59,8 @@ static int ath10k_pci_init_irq(struct ath10k *ar);
 static int ath10k_pci_deinit_irq(struct ath10k *ar);
 static int ath10k_pci_request_irq(struct ath10k *ar);
 static void ath10k_pci_free_irq(struct ath10k *ar);
+static int ath10k_pci_request_early_irq(struct ath10k *ar);
+static void ath10k_pci_free_early_irq(struct ath10k *ar);
 static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
 			       struct ath10k_ce_pipe *rx_pipe,
 			       struct bmi_xfer *xfer);
@@ -876,6 +878,7 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 
 	tasklet_kill(&ar_pci->intr_tq);
 	tasklet_kill(&ar_pci->msi_fw_err);
+	tasklet_kill(&ar_pci->early_irq_tasklet);
 
 	for (i = 0; i < CE_COUNT; i++)
 		tasklet_kill(&ar_pci->pipe_info[i].intr);
@@ -1188,12 +1191,15 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
 static int ath10k_pci_hif_start(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int ret;
+	int ret, ret2;
+
+	ath10k_pci_free_early_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
 
 	ret = ath10k_pci_start_ce(ar);
 	if (ret) {
 		ath10k_warn("failed to start CE: %d\n", ret);
-		return ret;
+		goto err_early_irq;
 	}
 
 	ret = ath10k_pci_request_irq(ar);
@@ -1219,6 +1225,11 @@ err_free_irq:
 	ath10k_pci_kill_tasklet(ar);
 err_stop_ce:
 	ath10k_pci_stop_ce(ar);
+err_early_irq:
+	ret2 = ath10k_pci_request_early_irq(ar);
+	if (ret2)
+		ath10k_warn("failed to re-enable early irq: %d\n", ret2);
+
 	return ret;
 }
 
@@ -1352,6 +1363,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
 	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_stop_ce(ar);
 
+	ret = ath10k_pci_request_early_irq(ar);
+	if (ret)
+		ath10k_warn("failed to re-enable early irq: %d\n", ret);
+
 	/* At this point, asynchronous threads are stopped, the target should
 	 * not DMA nor interrupt. We process the leftovers and then free
 	 * everything else up. */
@@ -1900,28 +1915,34 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_ce;
 	}
 
+	ret = ath10k_pci_request_early_irq(ar);
+	if (ret) {
+		ath10k_err("failed to request early irq: %d\n", ret);
+		goto err_deinit_irq;
+	}
+
 	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret) {
 		ath10k_err("failed to wait for target to init: %d\n", ret);
-		goto err_deinit_irq;
+		goto err_free_early_irq;
 	}
 
 	ret = ath10k_ce_enable_err_irq(ar);
 	if (ret) {
 		ath10k_err("failed to enable CE error irq: %d\n", ret);
-		goto err_deinit_irq;
+		goto err_free_early_irq;
 	}
 
 	ret = ath10k_pci_init_config(ar);
 	if (ret) {
 		ath10k_err("failed to setup init config: %d\n", ret);
-		goto err_deinit_irq;
+		goto err_free_early_irq;
 	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU: %d\n", ret);
-		goto err_deinit_irq;
+		goto err_free_early_irq;
 	}
 
 	if (ar_pci->num_msi_intrs > 1)
@@ -1936,6 +1957,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 	return 0;
 
+err_free_early_irq:
+	ath10k_pci_free_early_irq(ar);
 err_deinit_irq:
 	ath10k_pci_deinit_irq(ar);
 err_ce:
@@ -1952,6 +1975,9 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
+	ath10k_ce_disable_interrupts(ar);
+	ath10k_pci_free_early_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_deinit_irq(ar);
 	ath10k_pci_device_reset(ar);
 
@@ -2145,6 +2171,50 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
+{
+	struct ath10k *ar = arg;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+	if (!ath10k_pci_irq_pending(ar))
+		return IRQ_NONE;
+
+	if (ar_pci->num_msi_intrs == 0)
+		ath10k_pci_disable_and_clear_legacy_irq(ar);
+
+	tasklet_schedule(&ar_pci->early_irq_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+static void ath10k_pci_early_irq_tasklet(unsigned long data)
+{
+	struct ath10k *ar = (struct ath10k *)data;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	u32 fw_ind;
+	int ret;
+
+	ret = ath10k_pci_wake(ar);
+	if (ret) {
+		ath10k_warn("failed to wake target in early irq tasklet: %d\n",
+			    ret);
+		return;
+	}
+
+	fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address);
+	if (fw_ind & FW_IND_EVENT_PENDING) {
+		ath10k_pci_write32(ar, ar_pci->fw_indicator_address,
+				   fw_ind & ~FW_IND_EVENT_PENDING);
+
+		/* Some structures are unavailable during early boot or at
+		 * driver teardown so just print that the device has crashed. */
+		ath10k_warn("device crashed - no diagnostics available\n");
+	}
+
+	ath10k_pci_sleep(ar);
+	ath10k_pci_enable_legacy_irq(ar);
+}
+
 static void ath10k_pci_tasklet(unsigned long data)
 {
 	struct ath10k *ar = (struct ath10k *)data;
@@ -2253,6 +2323,29 @@ static void ath10k_pci_free_irq(struct ath10k *ar)
 		free_irq(ar_pci->pdev->irq + i, ar);
 }
 
+static int ath10k_pci_request_early_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int ret;
+
+	/* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
+	 * interrupt from irq vector is triggered in all cases for FW
+	 * indication/errors */
+	ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
+			  IRQF_SHARED, "ath10k_pci (early)", ar);
+	if (ret) {
+		ath10k_warn("failed to request early irq: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void ath10k_pci_free_early_irq(struct ath10k *ar)
+{
+	free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
+}
+
 static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -2261,6 +2354,8 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
 	tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
 		     (unsigned long)ar);
+	tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
+		     (unsigned long)ar);
 
 	for (i = 0; i < CE_COUNT; i++) {
 		ar_pci->pipe_info[i].ar_pci = ar_pci;
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 73a3d4e..a4f3203 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -198,6 +198,7 @@ struct ath10k_pci {
 
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct msi_fw_err;
+	struct tasklet_struct early_irq_tasklet;
 
 	int started;
 
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:10 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:10 +0100
Subject: [PATCH 0/8] ath10k: pci fixes 2013-11-22
Message-ID: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>

Hi,

ath10k didn't play well with other devices on a
shared irq line. This patchset fixes support for
shared legacy interrupts. 

Some rework was necessary because ath10k was using
disable_irq and CE irq masking (which is not
sufficient for shared interrupts).

Since main irq handlers are now registered after
boot, BMI is now polling for CE updates. I haven't
observed any differences in boot speed.

Also this plugs a leak I spotted during rework and
adds an option for testing different irq modes.


Michal Kazior (8):
  ath10k: don't consume other's shared interrupts
  ath10k: split up pci irq code
  ath10k: fix memory leak on hif_start failpath
  ath10k: don't use interrupts for BMI
  ath10k: defer irq registration until hif start()
  ath10k: extract functions for legacy irq handling
  ath10k: re-add support for early fw indication
  ath10k: allow explicit MSI/MSI-X disabling

 drivers/net/wireless/ath/ath10k/hw.h  |   1 +
 drivers/net/wireless/ath/ath10k/pci.c | 503 ++++++++++++++++++++++------------
 drivers/net/wireless/ath/ath10k/pci.h |   1 +
 3 files changed, 333 insertions(+), 172 deletions(-)

-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:12 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:12 +0100
Subject: [PATCH 2/8] ath10k: split up pci irq code
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-3-git-send-email-michal.kazior@tieto.com>

Hardware waits until host signals whether it has
chosen MSI(-X) or shared legacy interrupts. It is
not required for the driver to register interrupt
handlers immediately.

This patch prepares the pci irq code for more
changes.

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index ed752d6..d4536cb 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -55,8 +55,10 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(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);
+static int ath10k_pci_init_irq(struct ath10k *ar);
+static int ath10k_pci_deinit_irq(struct ath10k *ar);
+static int ath10k_pci_request_irq(struct ath10k *ar);
+static void ath10k_pci_free_irq(struct ath10k *ar);
 
 static const struct ce_attr host_ce_config_wlan[] = {
 	/* CE0: host->target HTC control and raw streams */
@@ -1341,7 +1343,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
 	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
 
 	/* Irqs are never explicitly re-enabled. They are implicitly re-enabled
-	 * by ath10k_pci_start_intr(). */
+	 * by upon power_up. */
 	ath10k_pci_disable_irqs(ar);
 
 	ath10k_pci_stop_ce(ar);
@@ -1887,34 +1889,40 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_ce;
 	}
 
-	ret = ath10k_pci_start_intr(ar);
+	ret = ath10k_pci_init_irq(ar);
 	if (ret) {
-		ath10k_err("failed to start interrupt handling: %d\n", ret);
+		ath10k_err("failed to init irqs: %d\n", ret);
 		goto err_ce;
 	}
 
+	ret = ath10k_pci_request_irq(ar);
+	if (ret) {
+		ath10k_err("failed to request irqs: %d\n", ret);
+		goto err_deinit_irq;
+	}
+
 	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;
+		goto err_free_irq;
 	}
 
 	ret = ath10k_ce_enable_err_irq(ar);
 	if (ret) {
 		ath10k_err("failed to enable CE error irq: %d\n", ret);
-		goto err_irq;
+		goto err_free_irq;
 	}
 
 	ret = ath10k_pci_init_config(ar);
 	if (ret) {
 		ath10k_err("failed to setup init config: %d\n", ret);
-		goto err_irq;
+		goto err_free_irq;
 	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU: %d\n", ret);
-		goto err_irq;
+		goto err_free_irq;
 	}
 
 	ath10k_pci_start_bmi(ar);
@@ -1931,11 +1939,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 	return 0;
 
-err_irq:
-	ath10k_ce_disable_interrupts(ar);
-	ath10k_pci_stop_intr(ar);
+err_free_irq:
+	ath10k_pci_free_irq(ar);
 	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_device_reset(ar);
+err_deinit_irq:
+	ath10k_pci_deinit_irq(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
 err_ps:
@@ -1949,7 +1958,8 @@ 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_free_irq(ar);
+	ath10k_pci_deinit_irq(ar);
 	ath10k_pci_device_reset(ar);
 
 	ath10k_pci_ce_deinit(ar);
@@ -2157,24 +2167,17 @@ static void ath10k_pci_tasklet(unsigned long data)
 	}
 }
 
-static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)
+static int ath10k_pci_request_irq_msix(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int ret;
-	int i;
-
-	ret = pci_enable_msi_block(ar_pci->pdev, num);
-	if (ret)
-		return ret;
+	int ret, i;
 
 	ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,
 			  ath10k_pci_msi_fw_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
 	if (ret) {
-		ath10k_warn("request_irq(%d) failed %d\n",
+		ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
 			    ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
-
-		pci_disable_msi(ar_pci->pdev);
 		return ret;
 	}
 
@@ -2183,45 +2186,38 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)
 				  ath10k_pci_per_engine_handler,
 				  IRQF_SHARED, "ath10k_pci", ar);
 		if (ret) {
-			ath10k_warn("request_irq(%d) failed %d\n",
+			ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
 				    ar_pci->pdev->irq + i, ret);
 
 			for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
 				free_irq(ar_pci->pdev->irq + i, ar);
 
 			free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar);
-			pci_disable_msi(ar_pci->pdev);
 			return ret;
 		}
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT,
-		   "MSI-X interrupt handling (%d intrs)\n", num);
 	return 0;
 }
 
-static int ath10k_pci_start_intr_msi(struct ath10k *ar)
+static int ath10k_pci_request_irq_msi(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
 
-	ret = pci_enable_msi(ar_pci->pdev);
-	if (ret < 0)
-		return ret;
-
 	ret = request_irq(ar_pci->pdev->irq,
 			  ath10k_pci_interrupt_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
-	if (ret < 0) {
-		pci_disable_msi(ar_pci->pdev);
+	if (ret) {
+		ath10k_warn("failed to request MSI irq %d: %d\n",
+			    ar_pci->pdev->irq, ret);
 		return ret;
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "MSI interrupt handling\n");
 	return 0;
 }
 
-static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
+static int ath10k_pci_request_irq_legacy(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
@@ -2229,99 +2225,140 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 	ret = request_irq(ar_pci->pdev->irq,
 			  ath10k_pci_interrupt_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
-	if (ret < 0)
-		return ret;
-
-	ret = ath10k_pci_wake(ar);
 	if (ret) {
-		free_irq(ar_pci->pdev->irq, ar);
-		ath10k_err("failed to wake up target: %d\n", ret);
+		ath10k_warn("failed to request legacy irq %d: %d\n",
+			    ar_pci->pdev->irq, ret);
 		return ret;
 	}
 
-	/*
-	 * A potential race occurs here: The CORE_BASE write
-	 * depends on target correctly decoding AXI address but
-	 * host won't know when target writes BAR to CORE_CTRL.
-	 * This write might get lost if target has NOT written BAR.
-	 * For now, fix the race by repeating the write in below
-	 * synchronization checking.
-	 */
-	iowrite32(PCIE_INTR_FIRMWARE_MASK |
-		  PCIE_INTR_CE_MASK_ALL,
-		  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
-				 PCIE_INTR_ENABLE_ADDRESS));
-
-	ath10k_pci_sleep(ar);
-	ath10k_dbg(ATH10K_DBG_BOOT, "legacy interrupt handling\n");
 	return 0;
 }
 
-static int ath10k_pci_start_intr(struct ath10k *ar)
+static int ath10k_pci_request_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+	switch (ar_pci->num_msi_intrs) {
+	case 0:
+		return ath10k_pci_request_irq_legacy(ar);
+	case 1:
+		return ath10k_pci_request_irq_msi(ar);
+	case MSI_NUM_REQUEST:
+		return ath10k_pci_request_irq_msix(ar);
+	}
+
+	ath10k_warn("unknown irq configuration upon request\n");
+	return -EINVAL;
+}
+
+static void ath10k_pci_free_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int i;
+
+	/* There's at least one interrupt irregardless whether its legacy INTR
+	 * or MSI or MSI-X */
+	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
+		free_irq(ar_pci->pdev->irq + i, ar);
+}
+
+static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int num = MSI_NUM_REQUEST;
-	int ret;
 	int i;
 
-	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long) ar);
+	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
 	tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
-		     (unsigned long) ar);
+		     (unsigned long)ar);
 
 	for (i = 0; i < CE_COUNT; i++) {
 		ar_pci->pipe_info[i].ar_pci = ar_pci;
-		tasklet_init(&ar_pci->pipe_info[i].intr,
-			     ath10k_pci_ce_tasklet,
+		tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet,
 			     (unsigned long)&ar_pci->pipe_info[i]);
 	}
+}
+
+static int ath10k_pci_init_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int ret;
+
+	ath10k_pci_init_irq_tasklets(ar);
 
 	if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features))
-		num = 1;
+		goto msi;
 
-	if (num > 1) {
-		ret = ath10k_pci_start_intr_msix(ar, num);
-		if (ret == 0)
-			goto exit;
+	/* Try MSI-X */
+	ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
+	ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
+	if (ret == 0)
+		return 0;
+	if (ret > 0)
+		pci_disable_msi(ar_pci->pdev);
 
-		ath10k_dbg(ATH10K_DBG_BOOT,
-			   "MSI-X didn't succeed (%d), trying MSI\n", ret);
-		num = 1;
-	}
+msi:
+	/* Try MSI */
+	ar_pci->num_msi_intrs = 1;
+	ret = pci_enable_msi(ar_pci->pdev);
+	if (ret == 0)
+		return 0;
 
-	if (num == 1) {
-		ret = ath10k_pci_start_intr_msi(ar);
-		if (ret == 0)
-			goto exit;
+	/* Try legacy irq
+	 *
+	 * A potential race occurs here: The CORE_BASE write
+	 * depends on target correctly decoding AXI address but
+	 * host won't know when target writes BAR to CORE_CTRL.
+	 * This write might get lost if target has NOT written BAR.
+	 * For now, fix the race by repeating the write in below
+	 * synchronization checking. */
+	ar_pci->num_msi_intrs = 0;
 
-		ath10k_dbg(ATH10K_DBG_BOOT,
-			   "MSI didn't succeed (%d), trying legacy INTR\n",
-			   ret);
-		num = 0;
+	ret = ath10k_pci_wake(ar);
+	if (ret) {
+		ath10k_warn("failed to wake target: %d\n", ret);
+		return ret;
 	}
 
-	ret = ath10k_pci_start_intr_legacy(ar);
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
+			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
+	ath10k_pci_sleep(ar);
+
+	return 0;
+}
+
+static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
+{
+	int ret;
+
+	ret = ath10k_pci_wake(ar);
 	if (ret) {
-		ath10k_warn("Failed to start legacy interrupts: %d\n", ret);
+		ath10k_warn("failed to wake target: %d\n", ret);
 		return ret;
 	}
 
-exit:
-	ar_pci->num_msi_intrs = num;
-	return ret;
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
+			   0);
+	ath10k_pci_sleep(ar);
+
+	return 0;
 }
 
-static void ath10k_pci_stop_intr(struct ath10k *ar)
+static int ath10k_pci_deinit_irq(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int i;
 
-	/* There's at least one interrupt irregardless whether its legacy INTR
-	 * or MSI or MSI-X */
-	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
-		free_irq(ar_pci->pdev->irq + i, ar);
-
-	if (ar_pci->num_msi_intrs > 0)
+	switch (ar_pci->num_msi_intrs) {
+	case 0:
+		return ath10k_pci_deinit_irq_legacy(ar);
+	case 1:
+		/* fall-through */
+	case MSI_NUM_REQUEST:
 		pci_disable_msi(ar_pci->pdev);
+		return 0;
+	}
+
+	ath10k_warn("unknown irq configuration upon deinit\n");
+	return -EINVAL;
 }
 
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:15 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:15 +0100
Subject: [PATCH 5/8] ath10k: defer irq registration until hif start()
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-6-git-send-email-michal.kazior@tieto.com>

It's impossible to rely on disable_irq() and/or CE
interrupt masking with legacy shared interrupts.
Other devices sharing the same irq line may assert
it while ath10k is doing something that requires
no interrupts.

Irq handlers are now registered after all
preparations are complete so spurious/foreign
interrupts won't do any harm. The handlers are
unregistered when no interrupts are required (i.e.
during driver teardown).

This also removes the ability to receive FW early
indication (since interrupts are not registered
until early boot is complete). This is not mission
critical (it's more of a hint that early boot
failed due to unexpected FW crash) and will be
re-added in a follow up patch.

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 1b12db8..fa1162e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -886,13 +886,6 @@ 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_pci_kill_tasklet(ar);
 
 	/* Mark pending completions as aborted, so that upper layers free up
 	 * their associated resources */
@@ -1203,17 +1196,30 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 		return ret;
 	}
 
+	ret = ath10k_pci_request_irq(ar);
+	if (ret) {
+		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
+			    ret);
+		goto err_stop_ce;
+	}
+
 	/* Post buffers once to start things off. */
 	ret = ath10k_pci_post_rx(ar);
 	if (ret) {
 		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
 			    ret);
-		ath10k_pci_stop_ce(ar);
-		return ret;
+		goto err_free_irq;
 	}
 
 	ar_pci->started = 1;
 	return 0;
+
+err_free_irq:
+	ath10k_pci_free_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
+err_stop_ce:
+	ath10k_pci_stop_ce(ar);
+	return ret;
 }
 
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
@@ -1331,25 +1337,19 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
 	}
 }
 
-static void ath10k_pci_disable_irqs(struct ath10k *ar)
-{
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int i;
-
-	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
-		disable_irq(ar_pci->pdev->irq + i);
-}
-
 static void ath10k_pci_hif_stop(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int ret;
 
 	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
 
-	/* Irqs are never explicitly re-enabled. They are implicitly re-enabled
-	 * by upon power_up. */
-	ath10k_pci_disable_irqs(ar);
+	ret = ath10k_ce_disable_interrupts(ar);
+	if (ret)
+		ath10k_warn("failed to disable CE interrupts: %d\n", ret);
 
+	ath10k_pci_free_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_stop_ce(ar);
 
 	/* At this point, asynchronous threads are stopped, the target should
@@ -1900,34 +1900,28 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_ce;
 	}
 
-	ret = ath10k_pci_request_irq(ar);
-	if (ret) {
-		ath10k_err("failed to request irqs: %d\n", ret);
-		goto err_deinit_irq;
-	}
-
 	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret) {
 		ath10k_err("failed to wait for target to init: %d\n", ret);
-		goto err_free_irq;
+		goto err_deinit_irq;
 	}
 
 	ret = ath10k_ce_enable_err_irq(ar);
 	if (ret) {
 		ath10k_err("failed to enable CE error irq: %d\n", ret);
-		goto err_free_irq;
+		goto err_deinit_irq;
 	}
 
 	ret = ath10k_pci_init_config(ar);
 	if (ret) {
 		ath10k_err("failed to setup init config: %d\n", ret);
-		goto err_free_irq;
+		goto err_deinit_irq;
 	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU: %d\n", ret);
-		goto err_free_irq;
+		goto err_deinit_irq;
 	}
 
 	if (ar_pci->num_msi_intrs > 1)
@@ -1942,14 +1936,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 	return 0;
 
-err_free_irq:
-	ath10k_pci_free_irq(ar);
-	ath10k_pci_kill_tasklet(ar);
-	ath10k_pci_device_reset(ar);
 err_deinit_irq:
 	ath10k_pci_deinit_irq(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
+	ath10k_pci_device_reset(ar);
 err_ps:
 	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
 		ath10k_do_pci_sleep(ar);
@@ -1961,7 +1952,6 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	ath10k_pci_free_irq(ar);
 	ath10k_pci_deinit_irq(ar);
 	ath10k_pci_device_reset(ar);
 
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:13 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:13 +0100
Subject: [PATCH 3/8] ath10k: fix memory leak on hif_start failpath
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-4-git-send-email-michal.kazior@tieto.com>

If post_rx failed then completions were not freed.

Signed-off-by: Michal Kazior <michal.kazior at 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 d4536cb..4067890 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1205,6 +1205,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 	if (ret) {
 		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
 			    ret);
+		ath10k_pci_stop_ce(ar);
 		return ret;
 	}
 
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:18 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:18 +0100
Subject: [PATCH 8/8] ath10k: allow explicit MSI/MSI-X disabling
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-9-git-send-email-michal.kazior@tieto.com>

This can be useful for testing and debugging.

Two new ath10k_pci module options are now available:

 disable_msix - disable just MSI-X
 disable_msi - disable MSI (along with MSI-X)

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 47d9b6e..b89fd7b 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -34,9 +34,18 @@
 #include "pci.h"
 
 static unsigned int ath10k_target_ps;
+static bool ath10k_disable_msix;
+static bool ath10k_disable_msi;
+
 module_param(ath10k_target_ps, uint, 0644);
 MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option");
 
+module_param_named(disable_msix, ath10k_disable_msix, bool, 0644);
+MODULE_PARM_DESC(disable_msix, "Disable MSI-X support");
+
+module_param_named(disable_msi, ath10k_disable_msi, bool, 0644);
+MODULE_PARM_DESC(disable_msi, "Disable MSI support");
+
 #define QCA988X_2_0_DEVICE_ID	(0x003c)
 
 static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
@@ -2367,27 +2376,33 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 static int ath10k_pci_init_irq(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X,
+				       ar_pci->features);
 	int ret;
 
 	ath10k_pci_init_irq_tasklets(ar);
 
-	if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features))
-		goto msi;
-
 	/* Try MSI-X */
-	ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
-	ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
-	if (ret == 0)
-		return 0;
-	if (ret > 0)
-		pci_disable_msi(ar_pci->pdev);
+	if (msix_supported && !ath10k_disable_msix && !ath10k_disable_msi) {
+		ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
+		ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
+		if (ret == 0)
+			return 0;
+		if (ret > 0)
+			pci_disable_msi(ar_pci->pdev);
+
+		/* fall-through */
+	}
 
-msi:
 	/* Try MSI */
-	ar_pci->num_msi_intrs = 1;
-	ret = pci_enable_msi(ar_pci->pdev);
-	if (ret == 0)
-		return 0;
+	if (!ath10k_disable_msi) {
+		ar_pci->num_msi_intrs = 1;
+		ret = pci_enable_msi(ar_pci->pdev);
+		if (ret == 0)
+			return 0;
+
+		/* fall-through */
+	}
 
 	/* Try legacy irq
 	 *
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:05:16 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:05:16 +0100
Subject: [PATCH 6/8] ath10k: extract functions for legacy irq handling
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385125518-13461-7-git-send-email-michal.kazior@tieto.com>

Preparation for code re-use. Also use ioread/write
wrappers.

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index fa1162e..a9bc290 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2096,6 +2096,34 @@ static bool ath10k_pci_irq_pending(struct ath10k *ar)
 	return false;
 }
 
+static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
+{
+	/* IMPORTANT: INTR_CLR register has to be set after
+	 * INTR_ENABLE is set to 0, otherwise interrupt can not be
+	 * really cleared. */
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
+			   0);
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS,
+			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
+
+	/* IMPORTANT: this extra read transaction is required to
+	 * flush the posted write buffer. */
+	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				 PCIE_INTR_ENABLE_ADDRESS);
+}
+
+static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
+{
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+			   PCIE_INTR_ENABLE_ADDRESS,
+			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
+
+	/* IMPORTANT: this extra read transaction is required to
+	 * flush the posted write buffer. */
+	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				 PCIE_INTR_ENABLE_ADDRESS);
+}
+
 /*
  * Top-level interrupt handler for all PCI interrupts from a Target.
  * When a block of MSI interrupts is allocated, this top-level handler
@@ -2109,27 +2137,8 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 	if (!ath10k_pci_irq_pending(ar))
 		return IRQ_NONE;
 
-	if (ar_pci->num_msi_intrs == 0) {
-		/*
-		 * IMPORTANT: INTR_CLR regiser has to be set after
-		 * INTR_ENABLE is set to 0, otherwise interrupt can not be
-		 * really cleared.
-		 */
-		iowrite32(0, ar_pci->mem +
-			  (SOC_CORE_BASE_ADDRESS |
-			   PCIE_INTR_ENABLE_ADDRESS));
-		iowrite32(PCIE_INTR_FIRMWARE_MASK |
-			  PCIE_INTR_CE_MASK_ALL,
-			  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
-					 PCIE_INTR_CLR_ADDRESS));
-		/*
-		 * IMPORTANT: this extra read transaction is required to
-		 * flush the posted write buffer.
-		 */
-		(void) ioread32(ar_pci->mem +
-				(SOC_CORE_BASE_ADDRESS |
-				 PCIE_INTR_ENABLE_ADDRESS));
-	}
+	if (ar_pci->num_msi_intrs == 0)
+		ath10k_pci_disable_and_clear_legacy_irq(ar);
 
 	tasklet_schedule(&ar_pci->intr_tq);
 
@@ -2144,20 +2153,9 @@ static void ath10k_pci_tasklet(unsigned long data)
 	ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */
 	ath10k_ce_per_engine_service_any(ar);
 
-	if (ar_pci->num_msi_intrs == 0) {
-		/* Enable Legacy PCI line interrupts */
-		iowrite32(PCIE_INTR_FIRMWARE_MASK |
-			  PCIE_INTR_CE_MASK_ALL,
-			  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
-					 PCIE_INTR_ENABLE_ADDRESS));
-		/*
-		 * IMPORTANT: this extra read transaction is required to
-		 * flush the posted write buffer
-		 */
-		(void) ioread32(ar_pci->mem +
-				(SOC_CORE_BASE_ADDRESS |
-				 PCIE_INTR_ENABLE_ADDRESS));
-	}
+	/* Re-enable legacy irq that was disabled in the irq handler */
+	if (ar_pci->num_msi_intrs == 0)
+		ath10k_pci_enable_legacy_irq(ar);
 }
 
 static int ath10k_pci_request_irq_msix(struct ath10k *ar)
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:26:56 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:26:56 +0100
Subject: [PATCH 0/3] ath10k: fixes 2013-11-22
Message-ID: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>

Hi,

This has some fixes I've stacked in my local repo.
There are no dependencies between them.

Michal Kazior (3):
  ath10k: use nss provided by mac80211
  ath10k: implement sta_rc_update()
  ath10k: fix Tx status clearing

 drivers/net/wireless/ath/ath10k/mac.c  | 88 +++++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/txrx.c |  2 +-
 drivers/net/wireless/ath/ath10k/wmi.h  |  6 +++
 3 files changed, 93 insertions(+), 3 deletions(-)

-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:26:57 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:26:57 +0100
Subject: [PATCH 1/3] ath10k: use nss provided by mac80211
In-Reply-To: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385126819-15311-2-git-send-email-michal.kazior@tieto.com>

Calculating STA NSS just from the rateset is not
the greatest idea. The NSS could be possibly
influenced by other things that only mac80211
knows about.

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

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b70a3b2..15eda44 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -925,7 +925,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
 	else
 		arg->peer_listen_intval = ar->hw->conf.listen_interval;
 
-	arg->peer_num_spatial_streams = 1;
+	arg->peer_num_spatial_streams = max_t(u32, 1, sta->rx_nss);
 
 	/*
 	 * The assoc capabilities are available only in managed mode.
@@ -1075,7 +1075,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 			arg->peer_ht_rates.rates[n++] = i;
 
 	arg->peer_ht_rates.num_rates = n;
-	arg->peer_num_spatial_streams = max((n+7) / 8, 1);
 
 	ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
 		   arg->addr,
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:26:58 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:26:58 +0100
Subject: [PATCH 2/3] ath10k: implement sta_rc_update()
In-Reply-To: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385126819-15311-3-git-send-email-michal.kazior@tieto.com>

This allows dynamic changes of bandwidth/nss, e.g.
via ht/vht operation mode change notification.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 85 +++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h |  6 +++
 2 files changed, 91 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 15eda44..65cb63d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3269,6 +3269,90 @@ exit:
 	return ret;
 }
 
+static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_sta *sta,
+				 u32 changed)
+{
+	struct ath10k *ar = hw->priv;
+	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+	u32 chwidth, smps;
+	int ret;
+
+	if (changed & IEEE80211_RC_BW_CHANGED) {
+		switch (sta->bandwidth) {
+		default:
+			ath10k_warn("unsupported STA BW: %d\n", sta->bandwidth);
+		case IEEE80211_STA_RX_BW_20:
+			chwidth = WMI_PEER_CHWIDTH_20MHZ;
+			break;
+		case IEEE80211_STA_RX_BW_40:
+			chwidth = WMI_PEER_CHWIDTH_40MHZ;
+			break;
+		case IEEE80211_STA_RX_BW_80:
+			chwidth = WMI_PEER_CHWIDTH_80MHZ;
+			break;
+		}
+
+		ath10k_dbg(ATH10K_DBG_MAC,
+			   "mac update sta %pM bandwidth (peer chwidth %d) to %d\n",
+			   sta->addr, chwidth, sta->bandwidth);
+
+		ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+						WMI_PEER_CHAN_WIDTH, chwidth);
+		if (ret)
+			ath10k_warn("failed to update STA %pM bandwidth (peer chwidth %d) to %d: %d\n",
+				    sta->addr, chwidth, sta->bandwidth, ret);
+	}
+
+	if (changed & IEEE80211_RC_NSS_CHANGED) {
+		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss to %d\n",
+			   sta->addr, sta->rx_nss);
+
+		ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+						WMI_PEER_NSS, sta->rx_nss);
+		if (ret)
+			ath10k_warn("failed to update STA %pM nss to %d: %d\n",
+				    sta->addr, sta->rx_nss, ret);
+	}
+
+	if (changed & IEEE80211_RC_SMPS_CHANGED) {
+		smps = WMI_PEER_SMPS_PS_NONE;
+
+		switch (sta->smps_mode) {
+		case IEEE80211_SMPS_NUM_MODES:
+			ath10k_warn("invalid smps mode: %d\n", sta->smps_mode);
+		case IEEE80211_SMPS_AUTOMATIC:
+		case IEEE80211_SMPS_OFF:
+			smps = WMI_PEER_SMPS_PS_NONE;
+			break;
+		case IEEE80211_SMPS_STATIC:
+			smps = WMI_PEER_SMPS_STATIC;
+			break;
+		case IEEE80211_SMPS_DYNAMIC:
+			smps = WMI_PEER_SMPS_DYNAMIC;
+			break;
+		}
+
+		ath10k_dbg(ATH10K_DBG_MAC,
+			   "mac update sta %pM smps (peer smps %d) to %d\n",
+			   sta->addr, smps, sta->smps_mode);
+
+		ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+						WMI_PEER_SMPS_STATE, smps);
+		if (ret)
+			ath10k_warn("failed to update STA %pM smps (peer smps %d) to %d: %d\n",
+				    sta->addr, smps, sta->smps_mode, ret);
+	}
+
+	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+		/* FIXME: Not implemented. Not really sure if it's possible to
+		 * influence HW rate control so much. */
+		ath10k_dbg(ATH10K_DBG_MAC,
+			   "mac sta rc update - supp rates changed - not implemented\n");
+	}
+}
+
 static const struct ieee80211_ops ath10k_ops = {
 	.tx				= ath10k_tx,
 	.start				= ath10k_start,
@@ -3291,6 +3375,7 @@ static const struct ieee80211_ops ath10k_ops = {
 	.tx_last_beacon			= ath10k_tx_last_beacon,
 	.restart_complete		= ath10k_restart_complete,
 	.get_survey			= ath10k_get_survey,
+	.sta_rc_update			= ath10k_sta_rc_update,
 #ifdef CONFIG_PM
 	.suspend			= ath10k_suspend,
 	.resume				= ath10k_resume,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 0087d69..e8c4bb7 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -3847,6 +3847,12 @@ enum wmi_peer_smps_state {
 	WMI_PEER_SMPS_DYNAMIC = 0x2
 };
 
+enum wmi_peer_chwidth {
+	WMI_PEER_CHWIDTH_20MHZ = 0,
+	WMI_PEER_CHWIDTH_40MHZ = 1,
+	WMI_PEER_CHWIDTH_80MHZ = 2,
+};
+
 enum wmi_peer_param {
 	WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */
 	WMI_PEER_AMPDU      = 0x2,
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Fri Nov 22 08:26:59 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 22 Nov 2013 14:26:59 +0100
Subject: [PATCH 3/3] ath10k: fix Tx status clearing
In-Reply-To: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385126819-15311-4-git-send-email-michal.kazior@tieto.com>

Too much of tx info was being cleared. This caused
issues in some setups.

Reported-By: Matti Laakso <malaakso at elisanet.fi>
Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/txrx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index d476b2c..2282980 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -75,7 +75,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 	ath10k_report_offchan_tx(htt->ar, msdu);
 
 	info = IEEE80211_SKB_CB(msdu);
-	memset(info, 0, sizeof(*info));
+	memset(&info->status, 0, sizeof(info->status));
 
 	if (tx_done->discard) {
 		ieee80211_free_txskb(htt->ar->hw, msdu);
-- 
1.8.4.rc3



From kvalo at qca.qualcomm.com  Sun Nov 24 08:50:07 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Sun, 24 Nov 2013 15:50:07 +0200
Subject: [PATCH 1/3] ath10k: use nss provided by mac80211
In-Reply-To: <1385126819-15311-2-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Fri, 22 Nov 2013 14:26:57 +0100")
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385126819-15311-2-git-send-email-michal.kazior@tieto.com>
Message-ID: <87k3fxsycw.fsf@kamboji.qca.qualcomm.com>

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

> Calculating STA NSS just from the rateset is not
> the greatest idea. The NSS could be possibly
> influenced by other things that only mac80211
> knows about.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Is there a bug which this patch fixes or what motivated you to do this?

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sun Nov 24 08:51:58 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Sun, 24 Nov 2013 15:51:58 +0200
Subject: [PATCH 3/3] ath10k: fix Tx status clearing
In-Reply-To: <1385126819-15311-4-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Fri, 22 Nov 2013 14:26:59 +0100")
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385126819-15311-4-git-send-email-michal.kazior@tieto.com>
Message-ID: <87fvqlsy9t.fsf@kamboji.qca.qualcomm.com>

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

> Too much of tx info was being cleared. This caused
> issues in some setups.
>
> Reported-By: Matti Laakso <malaakso at elisanet.fi>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Please describe the issues (or at least some of them) in the commit log.
The idea is that an advanced ath10k user will understand what kind of
bug (from user's point of view) this patch is fixing.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sun Nov 24 08:59:49 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Sun, 24 Nov 2013 15:59:49 +0200
Subject: [PATCH 1/8] ath10k: don't consume other's shared interrupts
In-Reply-To: <1385125518-13461-2-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Fri, 22 Nov 2013 14:05:11 +0100")
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385125518-13461-2-git-send-email-michal.kazior@tieto.com>
Message-ID: <87bo19sxwq.fsf@kamboji.qca.qualcomm.com>

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

> ath10k assumed all interrupts were directed to it.
> This isn't the case for legacy shared interrupts.
> ath10k consumed interrupts for other devices.
>
> Check device irq status and return IRQ_NONE when
> appropriate.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

[...]

> @@ -2085,6 +2103,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
>  	struct ath10k *ar = arg;
>  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
>  
> +	if (!ath10k_pci_irq_pending(ar))
> +		return IRQ_NONE;
> +
>  	if (ar_pci->num_msi_intrs == 0) {
>  		/*
>  		 * IMPORTANT: INTR_CLR regiser has to be set after

What if you move ath10k_pci_irq_pending() call after
ar_pci->num_msi_intrs == 0 check? That way you could remove the
"ar_pci->num_msi_intrs == 0" check from irq_pending() function.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 25 03:48:39 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 25 Nov 2013 10:48:39 +0200
Subject: Ath10k router
In-Reply-To: <1385096714.41414.YahooMailNeo@web122305.mail.ne1.yahoo.com>
 (Anand Moon's message of "Thu, 21 Nov 2013 21:05:14 -0800 (PST)")
References: <1385096714.41414.YahooMailNeo@web122305.mail.ne1.yahoo.com>
Message-ID: <87txf0q32w.fsf@kamboji.qca.qualcomm.com>

Anand Moon <moon.linux at yahoo.com> writes:

> I am looking to work on development router with support Ath10k, my
> guess is that compex.sg provide development routers. Are there any
> other free development router which can be use for development as well
> as testing.

I'm not familiar with development routers. But if you get one, make sure
it's has QCA988x hw2.0 chip. ath10k does not support hw1.0.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 25 03:54:30 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 25 Nov 2013 10:54:30 +0200
Subject: active/idle time from ath10k
In-Reply-To: <CAPqRyK8aiF4cnz+V9bDyPKPakjZ5ee3e+OFxmsnTaTMhh8An5g@mail.gmail.com>
 (Phil Moora's message of "Thu, 21 Nov 2013 18:09:36 -0800")
References: <CAPqRyK8aiF4cnz+V9bDyPKPakjZ5ee3e+OFxmsnTaTMhh8An5g@mail.gmail.com>
Message-ID: <87mwksq2t5.fsf@kamboji.qca.qualcomm.com>

Phil Moora <phil.moora at gmail.com> writes:

> Is there a way to get radio active time or idle time from ath10k? By
> active time, I mean that the radio was transmitting or receiving
> something.
>
> I looked at ath10k_get_survey function but
> (1) I don't want/need to hop across channels, just need the statistics
> for my radio's current channel,
> (2) I want the statistics periodically, as opposed to survey dump
> which is only available at request.

I haven't noticed firmware supporting anything like this.

-- 
Kalle Valo


From michal.kazior at tieto.com  Mon Nov 25 05:11:46 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 11:11:46 +0100
Subject: [PATCH 1/3] ath10k: use nss provided by mac80211
In-Reply-To: <87k3fxsycw.fsf@kamboji.qca.qualcomm.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385126819-15311-2-git-send-email-michal.kazior@tieto.com>
 <87k3fxsycw.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQnFJzGNK7605M9XUhQK=sxhqHW=9h-ytvgcCci4Knj1ww@mail.gmail.com>

On 24 November 2013 14:50, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> Calculating STA NSS just from the rateset is not
>> the greatest idea. The NSS could be possibly
>> influenced by other things that only mac80211
>> knows about.
>>
>> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
>
> Is there a bug which this patch fixes or what motivated you to do this?

This doesn't fix any bug that I know of. It just seems like probably
should use rx_nss instead of calculating it on our own (in case
something changes in the future).

A station may actually include operation mode change notification in
assoc request declaring it wants to use a different number of streams
than it actually supports as per its mcs map. That's not supported in
mac80211 though yet. Marek has posted some patches a few days ago but
it actually uses a different codepath from what I understand.


Micha?


From moon.linux at yahoo.com  Mon Nov 25 06:48:48 2013
From: moon.linux at yahoo.com (Anand Moon)
Date: Mon, 25 Nov 2013 03:48:48 -0800 (PST)
Subject: Ath10k router
In-Reply-To: <87txf0q32w.fsf@kamboji.qca.qualcomm.com>
References: <1385096714.41414.YahooMailNeo@web122305.mail.ne1.yahoo.com>
 <87txf0q32w.fsf@kamboji.qca.qualcomm.com>
Message-ID: <1385380128.81718.YahooMailNeo@web122304.mail.ne1.yahoo.com>

Hi Kalle Valo,

Thanks for the input.

-Anand Moon


On Monday, November 25, 2013 2:19 PM, Kalle Valo <kvalo at qca.qualcomm.com> wrote:

Anand Moon <moon.linux at yahoo.com> writes:


> I am looking to work on development router with support Ath10k, my
> guess is that compex.sg provide development routers. Are there any
> other free development router which can be use for development as well
> as testing.

I'm not familiar with development routers. But if you get one, make sure
it's has QCA988x hw2.0 chip. ath10k does not support hw1.0.

-- 
Kalle Valo

_______________________________________________
ath10k mailing list
ath10k at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k??


From kvalo at qca.qualcomm.com  Mon Nov 25 07:01:53 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 25 Nov 2013 14:01:53 +0200
Subject: [PATCH 8/8] ath10k: allow explicit MSI/MSI-X disabling
In-Reply-To: <1385125518-13461-9-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Fri, 22 Nov 2013 14:05:18 +0100")
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385125518-13461-9-git-send-email-michal.kazior@tieto.com>
Message-ID: <871u24ofke.fsf@kamboji.qca.qualcomm.com>

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

> This can be useful for testing and debugging.
>
> Two new ath10k_pci module options are now available:
>
>  disable_msix - disable just MSI-X
>  disable_msi - disable MSI (along with MSI-X)
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

This is useful but I think it's a bit too much to have two more options,
it would be simpler to have just one. Few quick ideas how to do this a
bit differently:

irq_mode: 0 = automatic, 2 = MSI, 1 = legacy

Here the problem is of course that we can't force use of MSI if the host
only supports legacy interrupts, but IMHO that's a minor nuisance and in
that case we should just enable legacy interrupts.

disable_msi: 0x1 = disable MSI-X, 0x2 = disable MSI

Basically this is just your booleans converted to a bitfield.

I vote for irq_mode because I think that's easier for the user to
understand. But I'm sure there is a better way to do this.

> +	if (msix_supported && !ath10k_disable_msix && !ath10k_disable_msi) {
> +		ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
> +		ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
> +		if (ret == 0)
> +			return 0;
> +		if (ret > 0)
> +			pci_disable_msi(ar_pci->pdev);
> +
> +		/* fall-through */
> +	}

If we force some other irq mode than the default it would be good to
have an info print for that.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 25 07:20:00 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 25 Nov 2013 14:20:00 +0200
Subject: [PATCH 7/8] ath10k: re-add support for early fw indication
In-Reply-To: <1385125518-13461-8-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Fri, 22 Nov 2013 14:05:17 +0100")
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385125518-13461-8-git-send-email-michal.kazior@tieto.com>
Message-ID: <87siukn05r.fsf@kamboji.qca.qualcomm.com>

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

> It's possible for FW to panic during early boot or
> at driver teardown in some rare cases.
>
> The patch re-introduces support to detect and
> print those crashes.
>
> This introduces an additional irq handler that is
> set for the duration of early boot and shutdown.
> The handler is then overriden with regular
> handlers upon hif start().
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

[...]

> --- a/drivers/net/wireless/ath/ath10k/pci.c
> +++ b/drivers/net/wireless/ath/ath10k/pci.c
> @@ -59,6 +59,8 @@ static int ath10k_pci_init_irq(struct ath10k *ar);
>  static int ath10k_pci_deinit_irq(struct ath10k *ar);
>  static int ath10k_pci_request_irq(struct ath10k *ar);
>  static void ath10k_pci_free_irq(struct ath10k *ar);
> +static int ath10k_pci_request_early_irq(struct ath10k *ar);
> +static void ath10k_pci_free_early_irq(struct ath10k *ar);

We should always try to avoid using forward declarations. If I
understood correctly these are not needed.

>  static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
>  			       struct ath10k_ce_pipe *rx_pipe,
>  			       struct bmi_xfer *xfer);
> @@ -876,6 +878,7 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
>  
>  	tasklet_kill(&ar_pci->intr_tq);
>  	tasklet_kill(&ar_pci->msi_fw_err);
> +	tasklet_kill(&ar_pci->early_irq_tasklet);
>  
>  	for (i = 0; i < CE_COUNT; i++)
>  		tasklet_kill(&ar_pci->pipe_info[i].intr);
> @@ -1188,12 +1191,15 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
>  static int ath10k_pci_hif_start(struct ath10k *ar)
>  {
>  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
> -	int ret;
> +	int ret, ret2;
> +
> +	ath10k_pci_free_early_irq(ar);
> +	ath10k_pci_kill_tasklet(ar);

Calling kill_tasklet() looks a bit odd here when you only want to kill
early_irq_tasklet. But I guess that's ok.

>  	ret = ath10k_pci_start_ce(ar);
>  	if (ret) {
>  		ath10k_warn("failed to start CE: %d\n", ret);
> -		return ret;
> +		goto err_early_irq;
>  	}
>  
>  	ret = ath10k_pci_request_irq(ar);
> @@ -1219,6 +1225,11 @@ err_free_irq:
>  	ath10k_pci_kill_tasklet(ar);
>  err_stop_ce:
>  	ath10k_pci_stop_ce(ar);
> +err_early_irq:
> +	ret2 = ath10k_pci_request_early_irq(ar);
> +	if (ret2)
> +		ath10k_warn("failed to re-enable early irq: %d\n", ret2);

ret_early or something like that would be a nicer name.

> @@ -1952,6 +1975,9 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
>  {
>  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
>  
> +	ath10k_ce_disable_interrupts(ar);
> +	ath10k_pci_free_early_irq(ar);
> +	ath10k_pci_kill_tasklet(ar);

Should disable_interrupts() and kill_tasklet() be in an earlier patch?

-- 
Kalle Valo


From michal.kazior at tieto.com  Mon Nov 25 07:46:23 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 13:46:23 +0100
Subject: [PATCH 7/8] ath10k: re-add support for early fw indication
In-Reply-To: <87siukn05r.fsf@kamboji.qca.qualcomm.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385125518-13461-8-git-send-email-michal.kazior@tieto.com>
 <87siukn05r.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQnQWEy6QzKb9Ts6UokyC7yhY829PB42kUpZwLP4dqj+nQ@mail.gmail.com>

On 25 November 2013 13:20, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> It's possible for FW to panic during early boot or
>> at driver teardown in some rare cases.
>>
>> The patch re-introduces support to detect and
>> print those crashes.
>>
>> This introduces an additional irq handler that is
>> set for the duration of early boot and shutdown.
>> The handler is then overriden with regular
>> handlers upon hif start().
>>
>> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

[...]

>> @@ -1952,6 +1975,9 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
>>  {
>>       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
>>
>> +     ath10k_ce_disable_interrupts(ar);
>> +     ath10k_pci_free_early_irq(ar);
>> +     ath10k_pci_kill_tasklet(ar);
>
> Should disable_interrupts() and kill_tasklet() be in an earlier patch?

No. Before this patch there are no interrupt handlers registered by
power_up, so there are no interrupts to be cleaned up in power_down.

Since this patch introduces early irq handling in power_up, then
power_down must shut everything down. Now that I think about the
ath10k_ce_disable_interrupts() isn't necessary here. The other two
functions are though.


Micha?


From michal.kazior at tieto.com  Mon Nov 25 08:06:20 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:20 +0100
Subject: [PATCH v2 1/8] ath10k: don't consume other's shared interrupts
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-2-git-send-email-michal.kazior@tieto.com>

ath10k assumed all interrupts were directed to it.
This isn't the case for legacy shared interrupts.
ath10k consumed interrupts for other devices.

Check device irq status and return IRQ_NONE when
appropriate.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
v2:
 * move function definition up to avoid forward
   declaration in subsequent patches
 * remove check for legacy interrupts inside the
   irq_pending() by guaranteeing it is called
   only for legacy interrupts


 drivers/net/wireless/ath/ath10k/hw.h  |  1 +
 drivers/net/wireless/ath/ath10k/pci.c | 16 ++++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 8aeb46d..9535eaa 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -269,6 +269,7 @@ enum ath10k_mcast2ucast_mode {
 #define CORE_CTRL_CPU_INTR_MASK			0x00002000
 #define CORE_CTRL_ADDRESS			0x0000
 #define PCIE_INTR_ENABLE_ADDRESS		0x0008
+#define PCIE_INTR_CAUSE_ADDRESS			0x000c
 #define PCIE_INTR_CLR_ADDRESS			0x0014
 #define SCRATCH_3_ADDRESS			0x0030
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 2457c8b..12fb12e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -201,6 +201,19 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
 	/* CE7 used only by Host */
 };
 
+static bool ath10k_pci_irq_pending(struct ath10k *ar)
+{
+	u32 cause;
+
+	/* Check if the shared legacy irq is for us */
+	cause = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				  PCIE_INTR_CAUSE_ADDRESS);
+	if (cause & (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL))
+		return true;
+
+	return false;
+}
+
 /*
  * Diagnostic read/write access is provided for startup/config/debug usage.
  * Caller must guarantee proper alignment, when applicable, and single user
@@ -2086,6 +2099,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
 	if (ar_pci->num_msi_intrs == 0) {
+		if (!ath10k_pci_irq_pending(ar))
+			return IRQ_NONE;
+
 		/*
 		 * IMPORTANT: INTR_CLR regiser has to be set after
 		 * INTR_ENABLE is set to 0, otherwise interrupt can not be
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:19 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:19 +0100
Subject: [PATCH v2 0/8] ath10k: pci fixes 2013-11-22
In-Reply-To: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>

Hi,

ath10k didn't play well with other devices on a
shared irq line. This patchset fixes support for
shared legacy interrupts. 

Some rework was necessary because ath10k was using
disable_irq and CE irq masking (which is not
sufficient for shared interrupts).

Since main irq handlers are now registered after
boot, BMI is now polling for CE updates. I haven't
observed any differences in boot speed.

Also this plugs a leak I spotted during rework and
adds an option for testing different irq modes.

v2:
 * simplify ath10k_pci_irq_pending()
 * combine memory leak fix patch with a
   functionality decoupling (it's very closely
   related)
 * fix 'irq: nobody cared'
 * change MSI/MSI-X disabling parameters
 * some minor fixes & code shuffling to avoid
   forward declarations


Michal Kazior (8):
  ath10k: don't consume other's shared interrupts
  ath10k: split up pci irq code
  ath10k: don't use interrupts for BMI
  ath10k: decouple ath10k_pci_start_ce()
  ath10k: defer irq registration until hif start()
  ath10k: extract functions for legacy irq handling
  ath10k: re-add support for early fw indication
  ath10k: allow explicit MSI/MSI-X disabling

 drivers/net/wireless/ath/ath10k/ce.c  |  15 -
 drivers/net/wireless/ath/ath10k/ce.h  |   1 -
 drivers/net/wireless/ath/ath10k/hw.h  |   1 +
 drivers/net/wireless/ath/ath10k/pci.c | 577 ++++++++++++++++++++++------------
 drivers/net/wireless/ath/ath10k/pci.h |   1 +
 5 files changed, 383 insertions(+), 212 deletions(-)

-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:25 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:25 +0100
Subject: [PATCH v2 6/8] ath10k: extract functions for legacy irq handling
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-7-git-send-email-michal.kazior@tieto.com>

Preparation for code re-use. Also use ioread/write
wrappers.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
v2:
 * move function definitions up to avoid forward
   declarations in subsequent patches

 drivers/net/wireless/ath/ath10k/pci.c | 65 +++++++++++++++++------------------
 1 file changed, 32 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index bd67311..1d2939c 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -220,6 +220,34 @@ static bool ath10k_pci_irq_pending(struct ath10k *ar)
 	return false;
 }
 
+static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
+{
+	/* IMPORTANT: INTR_CLR register has to be set after
+	 * INTR_ENABLE is set to 0, otherwise interrupt can not be
+	 * really cleared. */
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
+			   0);
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS,
+			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
+
+	/* IMPORTANT: this extra read transaction is required to
+	 * flush the posted write buffer. */
+	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				 PCIE_INTR_ENABLE_ADDRESS);
+}
+
+static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
+{
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+			   PCIE_INTR_ENABLE_ADDRESS,
+			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
+
+	/* IMPORTANT: this extra read transaction is required to
+	 * flush the posted write buffer. */
+	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				 PCIE_INTR_ENABLE_ADDRESS);
+}
+
 /*
  * Diagnostic read/write access is provided for startup/config/debug usage.
  * Caller must guarantee proper alignment, when applicable, and single user
@@ -2128,25 +2156,7 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 		if (!ath10k_pci_irq_pending(ar))
 			return IRQ_NONE;
 
-		/*
-		 * IMPORTANT: INTR_CLR regiser has to be set after
-		 * INTR_ENABLE is set to 0, otherwise interrupt can not be
-		 * really cleared.
-		 */
-		iowrite32(0, ar_pci->mem +
-			  (SOC_CORE_BASE_ADDRESS |
-			   PCIE_INTR_ENABLE_ADDRESS));
-		iowrite32(PCIE_INTR_FIRMWARE_MASK |
-			  PCIE_INTR_CE_MASK_ALL,
-			  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
-					 PCIE_INTR_CLR_ADDRESS));
-		/*
-		 * IMPORTANT: this extra read transaction is required to
-		 * flush the posted write buffer.
-		 */
-		(void) ioread32(ar_pci->mem +
-				(SOC_CORE_BASE_ADDRESS |
-				 PCIE_INTR_ENABLE_ADDRESS));
+		ath10k_pci_disable_and_clear_legacy_irq(ar);
 	}
 
 	tasklet_schedule(&ar_pci->intr_tq);
@@ -2162,20 +2172,9 @@ static void ath10k_pci_tasklet(unsigned long data)
 	ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */
 	ath10k_ce_per_engine_service_any(ar);
 
-	if (ar_pci->num_msi_intrs == 0) {
-		/* Enable Legacy PCI line interrupts */
-		iowrite32(PCIE_INTR_FIRMWARE_MASK |
-			  PCIE_INTR_CE_MASK_ALL,
-			  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
-					 PCIE_INTR_ENABLE_ADDRESS));
-		/*
-		 * IMPORTANT: this extra read transaction is required to
-		 * flush the posted write buffer
-		 */
-		(void) ioread32(ar_pci->mem +
-				(SOC_CORE_BASE_ADDRESS |
-				 PCIE_INTR_ENABLE_ADDRESS));
-	}
+	/* Re-enable legacy irq that was disabled in the irq handler */
+	if (ar_pci->num_msi_intrs == 0)
+		ath10k_pci_enable_legacy_irq(ar);
 }
 
 static int ath10k_pci_request_irq_msix(struct ath10k *ar)
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:22 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:22 +0100
Subject: [PATCH v2 3/8] ath10k: don't use interrupts for BMI
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-4-git-send-email-michal.kazior@tieto.com>

It's not really necessary for interrupts to be
used for BMI. BMI already assumes there's only one
caller at a time and it works directly with CE.

Make BMI poll for CE completions instead of
waiting for interrupts. This makes disabling
interrupts during early boot possible.

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 957fc59..327afbc 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -59,6 +59,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar);
 static int ath10k_pci_deinit_irq(struct ath10k *ar);
 static int ath10k_pci_request_irq(struct ath10k *ar);
 static void ath10k_pci_free_irq(struct ath10k *ar);
+static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
+			       struct ath10k_ce_pipe *rx_pipe,
+			       struct bmi_xfer *xfer);
 
 static const struct ce_attr host_ce_config_wlan[] = {
 	/* CE0: host->target HTC control and raw streams */
@@ -1394,6 +1397,8 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
 	void *treq, *tresp = NULL;
 	int ret = 0;
 
+	might_sleep();
+
 	if (resp && !resp_len)
 		return -EINVAL;
 
@@ -1434,14 +1439,12 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
 	if (ret)
 		goto err_resp;
 
-	ret = wait_for_completion_timeout(&xfer.done,
-					  BMI_COMMUNICATION_TIMEOUT_HZ);
-	if (ret <= 0) {
+	ret = ath10k_pci_bmi_wait(ce_tx, ce_rx, &xfer);
+	if (ret) {
 		u32 unused_buffer;
 		unsigned int unused_nbytes;
 		unsigned int unused_id;
 
-		ret = -ETIMEDOUT;
 		ath10k_ce_cancel_send_next(ce_tx, NULL, &unused_buffer,
 					   &unused_nbytes, &unused_id);
 	} else {
@@ -1509,6 +1512,25 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
 	complete(&xfer->done);
 }
 
+static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
+			       struct ath10k_ce_pipe *rx_pipe,
+			       struct bmi_xfer *xfer)
+{
+	unsigned long timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ;
+
+	while (time_before_eq(jiffies, timeout)) {
+		ath10k_pci_bmi_send_done(tx_pipe);
+		ath10k_pci_bmi_recv_data(rx_pipe);
+
+		if (completion_done(&xfer->done))
+			return 0;
+
+		schedule();
+	}
+
+	return -ETIMEDOUT;
+}
+
 /*
  * Map from service/endpoint to Copy Engine.
  * This table is derived from the CE_PCI TABLE, above.
@@ -1846,24 +1868,6 @@ 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);
-
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot start bmi\n");
-}
-
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -1938,8 +1942,6 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_free_irq;
 	}
 
-	ath10k_pci_start_bmi(ar);
-
 	if (ar_pci->num_msi_intrs > 1)
 		irq_mode = "MSI-X";
 	else if (ar_pci->num_msi_intrs == 1)
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:21 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:21 +0100
Subject: [PATCH v2 2/8] ath10k: split up pci irq code
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-3-git-send-email-michal.kazior@tieto.com>

Hardware waits until host signals whether it has
chosen MSI(-X) or shared legacy interrupts. It is
not required for the driver to register interrupt
handlers immediately.

This patch prepares the pci irq code for more
changes.

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 12fb12e..957fc59 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -55,8 +55,10 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(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);
+static int ath10k_pci_init_irq(struct ath10k *ar);
+static int ath10k_pci_deinit_irq(struct ath10k *ar);
+static int ath10k_pci_request_irq(struct ath10k *ar);
+static void ath10k_pci_free_irq(struct ath10k *ar);
 
 static const struct ce_attr host_ce_config_wlan[] = {
 	/* CE0: host->target HTC control and raw streams */
@@ -1354,7 +1356,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
 	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
 
 	/* Irqs are never explicitly re-enabled. They are implicitly re-enabled
-	 * by ath10k_pci_start_intr(). */
+	 * by upon power_up. */
 	ath10k_pci_disable_irqs(ar);
 
 	ath10k_pci_stop_ce(ar);
@@ -1900,34 +1902,40 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_ce;
 	}
 
-	ret = ath10k_pci_start_intr(ar);
+	ret = ath10k_pci_init_irq(ar);
 	if (ret) {
-		ath10k_err("failed to start interrupt handling: %d\n", ret);
+		ath10k_err("failed to init irqs: %d\n", ret);
 		goto err_ce;
 	}
 
+	ret = ath10k_pci_request_irq(ar);
+	if (ret) {
+		ath10k_err("failed to request irqs: %d\n", ret);
+		goto err_deinit_irq;
+	}
+
 	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;
+		goto err_free_irq;
 	}
 
 	ret = ath10k_ce_enable_err_irq(ar);
 	if (ret) {
 		ath10k_err("failed to enable CE error irq: %d\n", ret);
-		goto err_irq;
+		goto err_free_irq;
 	}
 
 	ret = ath10k_pci_init_config(ar);
 	if (ret) {
 		ath10k_err("failed to setup init config: %d\n", ret);
-		goto err_irq;
+		goto err_free_irq;
 	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU: %d\n", ret);
-		goto err_irq;
+		goto err_free_irq;
 	}
 
 	ath10k_pci_start_bmi(ar);
@@ -1944,11 +1952,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 	return 0;
 
-err_irq:
-	ath10k_ce_disable_interrupts(ar);
-	ath10k_pci_stop_intr(ar);
+err_free_irq:
+	ath10k_pci_free_irq(ar);
 	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_device_reset(ar);
+err_deinit_irq:
+	ath10k_pci_deinit_irq(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
 err_ps:
@@ -1962,7 +1971,8 @@ 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_free_irq(ar);
+	ath10k_pci_deinit_irq(ar);
 	ath10k_pci_device_reset(ar);
 
 	ath10k_pci_ce_deinit(ar);
@@ -2152,24 +2162,17 @@ static void ath10k_pci_tasklet(unsigned long data)
 	}
 }
 
-static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)
+static int ath10k_pci_request_irq_msix(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int ret;
-	int i;
-
-	ret = pci_enable_msi_block(ar_pci->pdev, num);
-	if (ret)
-		return ret;
+	int ret, i;
 
 	ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,
 			  ath10k_pci_msi_fw_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
 	if (ret) {
-		ath10k_warn("request_irq(%d) failed %d\n",
+		ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
 			    ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
-
-		pci_disable_msi(ar_pci->pdev);
 		return ret;
 	}
 
@@ -2178,45 +2181,38 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)
 				  ath10k_pci_per_engine_handler,
 				  IRQF_SHARED, "ath10k_pci", ar);
 		if (ret) {
-			ath10k_warn("request_irq(%d) failed %d\n",
+			ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
 				    ar_pci->pdev->irq + i, ret);
 
 			for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
 				free_irq(ar_pci->pdev->irq + i, ar);
 
 			free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar);
-			pci_disable_msi(ar_pci->pdev);
 			return ret;
 		}
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT,
-		   "MSI-X interrupt handling (%d intrs)\n", num);
 	return 0;
 }
 
-static int ath10k_pci_start_intr_msi(struct ath10k *ar)
+static int ath10k_pci_request_irq_msi(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
 
-	ret = pci_enable_msi(ar_pci->pdev);
-	if (ret < 0)
-		return ret;
-
 	ret = request_irq(ar_pci->pdev->irq,
 			  ath10k_pci_interrupt_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
-	if (ret < 0) {
-		pci_disable_msi(ar_pci->pdev);
+	if (ret) {
+		ath10k_warn("failed to request MSI irq %d: %d\n",
+			    ar_pci->pdev->irq, ret);
 		return ret;
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "MSI interrupt handling\n");
 	return 0;
 }
 
-static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
+static int ath10k_pci_request_irq_legacy(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
@@ -2224,99 +2220,140 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)
 	ret = request_irq(ar_pci->pdev->irq,
 			  ath10k_pci_interrupt_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
-	if (ret < 0)
-		return ret;
-
-	ret = ath10k_pci_wake(ar);
 	if (ret) {
-		free_irq(ar_pci->pdev->irq, ar);
-		ath10k_err("failed to wake up target: %d\n", ret);
+		ath10k_warn("failed to request legacy irq %d: %d\n",
+			    ar_pci->pdev->irq, ret);
 		return ret;
 	}
 
-	/*
-	 * A potential race occurs here: The CORE_BASE write
-	 * depends on target correctly decoding AXI address but
-	 * host won't know when target writes BAR to CORE_CTRL.
-	 * This write might get lost if target has NOT written BAR.
-	 * For now, fix the race by repeating the write in below
-	 * synchronization checking.
-	 */
-	iowrite32(PCIE_INTR_FIRMWARE_MASK |
-		  PCIE_INTR_CE_MASK_ALL,
-		  ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
-				 PCIE_INTR_ENABLE_ADDRESS));
-
-	ath10k_pci_sleep(ar);
-	ath10k_dbg(ATH10K_DBG_BOOT, "legacy interrupt handling\n");
 	return 0;
 }
 
-static int ath10k_pci_start_intr(struct ath10k *ar)
+static int ath10k_pci_request_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+	switch (ar_pci->num_msi_intrs) {
+	case 0:
+		return ath10k_pci_request_irq_legacy(ar);
+	case 1:
+		return ath10k_pci_request_irq_msi(ar);
+	case MSI_NUM_REQUEST:
+		return ath10k_pci_request_irq_msix(ar);
+	}
+
+	ath10k_warn("unknown irq configuration upon request\n");
+	return -EINVAL;
+}
+
+static void ath10k_pci_free_irq(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int num = MSI_NUM_REQUEST;
-	int ret;
 	int i;
 
-	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long) ar);
+	/* There's at least one interrupt irregardless whether its legacy INTR
+	 * or MSI or MSI-X */
+	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
+		free_irq(ar_pci->pdev->irq + i, ar);
+}
+
+static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int i;
+
+	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
 	tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
-		     (unsigned long) ar);
+		     (unsigned long)ar);
 
 	for (i = 0; i < CE_COUNT; i++) {
 		ar_pci->pipe_info[i].ar_pci = ar_pci;
-		tasklet_init(&ar_pci->pipe_info[i].intr,
-			     ath10k_pci_ce_tasklet,
+		tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet,
 			     (unsigned long)&ar_pci->pipe_info[i]);
 	}
+}
+
+static int ath10k_pci_init_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int ret;
+
+	ath10k_pci_init_irq_tasklets(ar);
 
 	if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features))
-		num = 1;
+		goto msi;
 
-	if (num > 1) {
-		ret = ath10k_pci_start_intr_msix(ar, num);
-		if (ret == 0)
-			goto exit;
+	/* Try MSI-X */
+	ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
+	ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
+	if (ret == 0)
+		return 0;
+	if (ret > 0)
+		pci_disable_msi(ar_pci->pdev);
 
-		ath10k_dbg(ATH10K_DBG_BOOT,
-			   "MSI-X didn't succeed (%d), trying MSI\n", ret);
-		num = 1;
-	}
+msi:
+	/* Try MSI */
+	ar_pci->num_msi_intrs = 1;
+	ret = pci_enable_msi(ar_pci->pdev);
+	if (ret == 0)
+		return 0;
 
-	if (num == 1) {
-		ret = ath10k_pci_start_intr_msi(ar);
-		if (ret == 0)
-			goto exit;
+	/* Try legacy irq
+	 *
+	 * A potential race occurs here: The CORE_BASE write
+	 * depends on target correctly decoding AXI address but
+	 * host won't know when target writes BAR to CORE_CTRL.
+	 * This write might get lost if target has NOT written BAR.
+	 * For now, fix the race by repeating the write in below
+	 * synchronization checking. */
+	ar_pci->num_msi_intrs = 0;
 
-		ath10k_dbg(ATH10K_DBG_BOOT,
-			   "MSI didn't succeed (%d), trying legacy INTR\n",
-			   ret);
-		num = 0;
+	ret = ath10k_pci_wake(ar);
+	if (ret) {
+		ath10k_warn("failed to wake target: %d\n", ret);
+		return ret;
 	}
 
-	ret = ath10k_pci_start_intr_legacy(ar);
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
+			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
+	ath10k_pci_sleep(ar);
+
+	return 0;
+}
+
+static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
+{
+	int ret;
+
+	ret = ath10k_pci_wake(ar);
 	if (ret) {
-		ath10k_warn("Failed to start legacy interrupts: %d\n", ret);
+		ath10k_warn("failed to wake target: %d\n", ret);
 		return ret;
 	}
 
-exit:
-	ar_pci->num_msi_intrs = num;
-	return ret;
+	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
+			   0);
+	ath10k_pci_sleep(ar);
+
+	return 0;
 }
 
-static void ath10k_pci_stop_intr(struct ath10k *ar)
+static int ath10k_pci_deinit_irq(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int i;
 
-	/* There's at least one interrupt irregardless whether its legacy INTR
-	 * or MSI or MSI-X */
-	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
-		free_irq(ar_pci->pdev->irq + i, ar);
-
-	if (ar_pci->num_msi_intrs > 0)
+	switch (ar_pci->num_msi_intrs) {
+	case 0:
+		return ath10k_pci_deinit_irq_legacy(ar);
+	case 1:
+		/* fall-through */
+	case MSI_NUM_REQUEST:
 		pci_disable_msi(ar_pci->pdev);
+		return 0;
+	}
+
+	ath10k_warn("unknown irq configuration upon deinit\n");
+	return -EINVAL;
 }
 
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:26 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:26 +0100
Subject: [PATCH v2 7/8] ath10k: re-add support for early fw indication
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-8-git-send-email-michal.kazior@tieto.com>

It's possible for FW to panic during early boot.

The patch re-introduces support to detect and
print those crashes.

This introduces an additional irq handler that is
set for the duration of early boot and shutdown.
The handler is then overriden with regular
handlers upon hif start().

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
v2:
 * move function definitions up to avoid forward
   declarations
 * forward declarations are gone now
 * rename ret2 to ret_early

 drivers/net/wireless/ath/ath10k/pci.c | 106 ++++++++++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath10k/pci.h |   1 +
 2 files changed, 102 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 1d2939c..0a2d1c2 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -248,6 +248,46 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
 				 PCIE_INTR_ENABLE_ADDRESS);
 }
 
+static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
+{
+	struct ath10k *ar = arg;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+	if (ar_pci->num_msi_intrs == 0) {
+		if (!ath10k_pci_irq_pending(ar))
+			return IRQ_NONE;
+
+		ath10k_pci_disable_and_clear_legacy_irq(ar);
+	}
+
+	tasklet_schedule(&ar_pci->early_irq_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+static int ath10k_pci_request_early_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int ret;
+
+	/* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
+	 * interrupt from irq vector is triggered in all cases for FW
+	 * indication/errors */
+	ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
+			  IRQF_SHARED, "ath10k_pci (early)", ar);
+	if (ret) {
+		ath10k_warn("failed to request early irq: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void ath10k_pci_free_early_irq(struct ath10k *ar)
+{
+	free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
+}
+
 /*
  * Diagnostic read/write access is provided for startup/config/debug usage.
  * Caller must guarantee proper alignment, when applicable, and single user
@@ -937,6 +977,7 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 
 	tasklet_kill(&ar_pci->intr_tq);
 	tasklet_kill(&ar_pci->msi_fw_err);
+	tasklet_kill(&ar_pci->early_irq_tasklet);
 
 	for (i = 0; i < CE_COUNT; i++)
 		tasklet_kill(&ar_pci->pipe_info[i].intr);
@@ -1249,12 +1290,15 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
 static int ath10k_pci_hif_start(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int ret;
+	int ret, ret_early;
+
+	ath10k_pci_free_early_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
 
 	ret = ath10k_pci_alloc_compl(ar);
 	if (ret) {
 		ath10k_warn("failed to allocate CE completions: %d\n", ret);
-		return ret;
+		goto err_early_irq;
 	}
 
 	ret = ath10k_pci_request_irq(ar);
@@ -1289,6 +1333,14 @@ err_stop:
 	ath10k_pci_process_ce(ar);
 err_free_compl:
 	ath10k_pci_cleanup_ce(ar);
+err_early_irq:
+	/* Though there should be no interrupts (device was reset)
+	 * power_down() expects the early IRQ to be installed as per the
+	 * driver lifecycle. */
+	ret_early = ath10k_pci_request_early_irq(ar);
+	if (ret_early)
+		ath10k_warn("failed to re-enable early irq: %d\n", ret_early);
+
 	return ret;
 }
 
@@ -1422,6 +1474,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
 	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_stop_ce(ar);
 
+	ret = ath10k_pci_request_early_irq(ar);
+	if (ret)
+		ath10k_warn("failed to re-enable early irq: %d\n", ret);
+
 	/* At this point, asynchronous threads are stopped, the target should
 	 * not DMA nor interrupt. We process the leftovers and then free
 	 * everything else up. */
@@ -1970,22 +2026,28 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_ce;
 	}
 
+	ret = ath10k_pci_request_early_irq(ar);
+	if (ret) {
+		ath10k_err("failed to request early irq: %d\n", ret);
+		goto err_deinit_irq;
+	}
+
 	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret) {
 		ath10k_err("failed to wait for target to init: %d\n", ret);
-		goto err_deinit_irq;
+		goto err_free_early_irq;
 	}
 
 	ret = ath10k_pci_init_config(ar);
 	if (ret) {
 		ath10k_err("failed to setup init config: %d\n", ret);
-		goto err_deinit_irq;
+		goto err_free_early_irq;
 	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU: %d\n", ret);
-		goto err_deinit_irq;
+		goto err_free_early_irq;
 	}
 
 	if (ar_pci->num_msi_intrs > 1)
@@ -2000,6 +2062,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 	return 0;
 
+err_free_early_irq:
+	ath10k_pci_free_early_irq(ar);
 err_deinit_irq:
 	ath10k_pci_deinit_irq(ar);
 err_ce:
@@ -2016,6 +2080,8 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
+	ath10k_pci_free_early_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_deinit_irq(ar);
 	ath10k_pci_device_reset(ar);
 
@@ -2164,6 +2230,34 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+static void ath10k_pci_early_irq_tasklet(unsigned long data)
+{
+	struct ath10k *ar = (struct ath10k *)data;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	u32 fw_ind;
+	int ret;
+
+	ret = ath10k_pci_wake(ar);
+	if (ret) {
+		ath10k_warn("failed to wake target in early irq tasklet: %d\n",
+			    ret);
+		return;
+	}
+
+	fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address);
+	if (fw_ind & FW_IND_EVENT_PENDING) {
+		ath10k_pci_write32(ar, ar_pci->fw_indicator_address,
+				   fw_ind & ~FW_IND_EVENT_PENDING);
+
+		/* Some structures are unavailable during early boot or at
+		 * driver teardown so just print that the device has crashed. */
+		ath10k_warn("device crashed - no diagnostics available\n");
+	}
+
+	ath10k_pci_sleep(ar);
+	ath10k_pci_enable_legacy_irq(ar);
+}
+
 static void ath10k_pci_tasklet(unsigned long data)
 {
 	struct ath10k *ar = (struct ath10k *)data;
@@ -2280,6 +2374,8 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
 	tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
 		     (unsigned long)ar);
+	tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
+		     (unsigned long)ar);
 
 	for (i = 0; i < CE_COUNT; i++) {
 		ar_pci->pipe_info[i].ar_pci = ar_pci;
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 73a3d4e..a4f3203 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -198,6 +198,7 @@ struct ath10k_pci {
 
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct msi_fw_err;
+	struct tasklet_struct early_irq_tasklet;
 
 	int started;
 
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:24 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:24 +0100
Subject: [PATCH v2 5/8] ath10k: defer irq registration until hif start()
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-6-git-send-email-michal.kazior@tieto.com>

It's impossible to rely on disable_irq() and/or CE
interrupt masking with legacy shared interrupts.
Other devices sharing the same irq line may assert
it while ath10k is doing something that requires
no interrupts.

Irq handlers are now registered after all
preparations are complete so spurious/foreign
interrupts won't do any harm. The handlers are
unregistered when no interrupts are required (i.e.
during driver teardown).

This also removes the ability to receive FW early
indication (since interrupts are not registered
until early boot is complete). This is not mission
critical (it's more of a hint that early boot
failed due to unexpected FW crash) and will be
re-added in a follow up patch.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
v2:
 * remove ce_enable_err_irq() - dont enable device
   interrupts before irq handlers are registered
 * with the earlier pci_start_ce() decoupling
   patch, irq handlers are now registered after CE
   completions are allocated but before CE
   interrupts are enabled via HW registers
   (fixes 'irq: nobody cared')

 drivers/net/wireless/ath/ath10k/ce.c  | 15 --------
 drivers/net/wireless/ath/ath10k/ce.h  |  1 -
 drivers/net/wireless/ath/ath10k/pci.c | 65 +++++++++++++----------------------
 3 files changed, 23 insertions(+), 58 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 476928f..d44d618 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -792,21 +792,6 @@ 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;
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 8a58bac..67dbde6 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -235,7 +235,6 @@ 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 05e6f8b..bd67311 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -919,13 +919,6 @@ 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_pci_kill_tasklet(ar);
 
 	/* Mark pending completions as aborted, so that upper layers free up
 	 * their associated resources */
@@ -1236,10 +1229,17 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 		return ret;
 	}
 
+	ret = ath10k_pci_request_irq(ar);
+	if (ret) {
+		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
+			    ret);
+		goto err_free_compl;
+	}
+
 	ret = ath10k_pci_setup_ce_irq(ar);
 	if (ret) {
 		ath10k_warn("failed to setup CE interrupts: %d\n", ret);
-		goto err_free_compl;
+		goto err_stop;
 	}
 
 	/* Post buffers once to start things off. */
@@ -1247,13 +1247,16 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 	if (ret) {
 		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
 			    ret);
-		goto err_stop_ce;
+		goto err_stop;
 	}
 
 	ar_pci->started = 1;
 	return 0;
 
-err_stop_ce:
+err_stop:
+	ath10k_ce_disable_interrupts(ar);
+	ath10k_pci_free_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_stop_ce(ar);
 	ath10k_pci_process_ce(ar);
 err_free_compl:
@@ -1376,25 +1379,19 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
 	}
 }
 
-static void ath10k_pci_disable_irqs(struct ath10k *ar)
-{
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int i;
-
-	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
-		disable_irq(ar_pci->pdev->irq + i);
-}
-
 static void ath10k_pci_hif_stop(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int ret;
 
 	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
 
-	/* Irqs are never explicitly re-enabled. They are implicitly re-enabled
-	 * by upon power_up. */
-	ath10k_pci_disable_irqs(ar);
+	ret = ath10k_ce_disable_interrupts(ar);
+	if (ret)
+		ath10k_warn("failed to disable CE interrupts: %d\n", ret);
 
+	ath10k_pci_free_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
 	ath10k_pci_stop_ce(ar);
 
 	/* At this point, asynchronous threads are stopped, the target should
@@ -1945,34 +1942,22 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 		goto err_ce;
 	}
 
-	ret = ath10k_pci_request_irq(ar);
-	if (ret) {
-		ath10k_err("failed to request irqs: %d\n", ret);
-		goto err_deinit_irq;
-	}
-
 	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret) {
 		ath10k_err("failed to wait for target to init: %d\n", ret);
-		goto err_free_irq;
-	}
-
-	ret = ath10k_ce_enable_err_irq(ar);
-	if (ret) {
-		ath10k_err("failed to enable CE error irq: %d\n", ret);
-		goto err_free_irq;
+		goto err_deinit_irq;
 	}
 
 	ret = ath10k_pci_init_config(ar);
 	if (ret) {
 		ath10k_err("failed to setup init config: %d\n", ret);
-		goto err_free_irq;
+		goto err_deinit_irq;
 	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
 		ath10k_err("could not wake up target CPU: %d\n", ret);
-		goto err_free_irq;
+		goto err_deinit_irq;
 	}
 
 	if (ar_pci->num_msi_intrs > 1)
@@ -1987,14 +1972,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 	return 0;
 
-err_free_irq:
-	ath10k_pci_free_irq(ar);
-	ath10k_pci_kill_tasklet(ar);
-	ath10k_pci_device_reset(ar);
 err_deinit_irq:
 	ath10k_pci_deinit_irq(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
+	ath10k_pci_device_reset(ar);
 err_ps:
 	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
 		ath10k_do_pci_sleep(ar);
@@ -2006,7 +1988,6 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	ath10k_pci_free_irq(ar);
 	ath10k_pci_deinit_irq(ar);
 	ath10k_pci_device_reset(ar);
 
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:23 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:23 +0100
Subject: [PATCH v2 4/8] ath10k: decouple ath10k_pci_start_ce()
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-5-git-send-email-michal.kazior@tieto.com>

The function did a couple of things: it allocated
CE completions, registered CE callbacks and
enabled CE interrupts through HW registers.

This cannot be so. Split the function into one
that allocates CE completions and the other one
that starts off CE operation.

This is required for future legacy shared
interrupt handling.

This also fixes possible memory leak if post rx
failed.

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

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 327afbc..05e6f8b 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -62,6 +62,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar);
 static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
 			       struct ath10k_ce_pipe *rx_pipe,
 			       struct bmi_xfer *xfer);
+static void ath10k_pci_cleanup_ce(struct ath10k *ar);
 
 static const struct ce_attr host_ce_config_wlan[] = {
 	/* CE0: host->target HTC control and raw streams */
@@ -824,14 +825,13 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
 	       sizeof(ar_pci->msg_callbacks_current));
 }
 
-static int ath10k_pci_start_ce(struct ath10k *ar)
+static int ath10k_pci_alloc_compl(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	struct ath10k_ce_pipe *ce_diag = ar_pci->ce_diag;
 	const struct ce_attr *attr;
 	struct ath10k_pci_pipe *pipe_info;
 	struct ath10k_pci_compl *compl;
-	int i, pipe_num, completions, disable_interrupts;
+	int i, pipe_num, completions;
 
 	spin_lock_init(&ar_pci->compl_lock);
 	INIT_LIST_HEAD(&ar_pci->compl_process);
@@ -843,34 +843,23 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
 		INIT_LIST_HEAD(&pipe_info->compl_free);
 
 		/* Handle Diagnostic CE specially */
-		if (pipe_info->ce_hdl == ce_diag)
+		if (pipe_info->ce_hdl == ar_pci->ce_diag)
 			continue;
 
 		attr = &host_ce_config_wlan[pipe_num];
 		completions = 0;
 
-		if (attr->src_nentries) {
-			disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;
-			ath10k_ce_send_cb_register(pipe_info->ce_hdl,
-						   ath10k_pci_ce_send_done,
-						   disable_interrupts);
+		if (attr->src_nentries)
 			completions += attr->src_nentries;
-		}
 
-		if (attr->dest_nentries) {
-			ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
-						   ath10k_pci_ce_recv_data);
+		if (attr->dest_nentries)
 			completions += attr->dest_nentries;
-		}
-
-		if (completions == 0)
-			continue;
 
 		for (i = 0; i < completions; i++) {
 			compl = kmalloc(sizeof(*compl), GFP_KERNEL);
 			if (!compl) {
 				ath10k_warn("No memory for completion state\n");
-				ath10k_pci_stop_ce(ar);
+				ath10k_pci_cleanup_ce(ar);
 				return -ENOMEM;
 			}
 
@@ -882,6 +871,37 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
 	return 0;
 }
 
+static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	const struct ce_attr *attr;
+	struct ath10k_pci_pipe *pipe_info;
+	int pipe_num, disable_interrupts;
+
+	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
+		pipe_info = &ar_pci->pipe_info[pipe_num];
+
+		/* Handle Diagnostic CE specially */
+		if (pipe_info->ce_hdl == ar_pci->ce_diag)
+			continue;
+
+		attr = &host_ce_config_wlan[pipe_num];
+
+		if (attr->src_nentries) {
+			disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;
+			ath10k_ce_send_cb_register(pipe_info->ce_hdl,
+						   ath10k_pci_ce_send_done,
+						   disable_interrupts);
+		}
+
+		if (attr->dest_nentries)
+			ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
+						   ath10k_pci_ce_recv_data);
+	}
+
+	return 0;
+}
+
 static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -1210,22 +1230,35 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
 
-	ret = ath10k_pci_start_ce(ar);
+	ret = ath10k_pci_alloc_compl(ar);
 	if (ret) {
-		ath10k_warn("failed to start CE: %d\n", ret);
+		ath10k_warn("failed to allocate CE completions: %d\n", ret);
 		return ret;
 	}
 
+	ret = ath10k_pci_setup_ce_irq(ar);
+	if (ret) {
+		ath10k_warn("failed to setup CE interrupts: %d\n", ret);
+		goto err_free_compl;
+	}
+
 	/* Post buffers once to start things off. */
 	ret = ath10k_pci_post_rx(ar);
 	if (ret) {
 		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
 			    ret);
-		return ret;
+		goto err_stop_ce;
 	}
 
 	ar_pci->started = 1;
 	return 0;
+
+err_stop_ce:
+	ath10k_pci_stop_ce(ar);
+	ath10k_pci_process_ce(ar);
+err_free_compl:
+	ath10k_pci_cleanup_ce(ar);
+	return ret;
 }
 
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Mon Nov 25 08:06:27 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 25 Nov 2013 14:06:27 +0100
Subject: [PATCH v2 8/8] ath10k: allow explicit MSI/MSI-X disabling
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385384787-12470-9-git-send-email-michal.kazior@tieto.com>

This can be useful for testing and debugging.

This introduces new ath10k_pci module parameter
`irq_mode`. By default it is 0, meaning automatic
irq mode (MSI-X as long as both target HW and host
platform supports it). The parameter works on a
best effort basis.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
v2:
 * merge 2 parameters into 1
 * add info print if the mode is != auto

 drivers/net/wireless/ath/ath10k/pci.c | 47 +++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 0a2d1c2..9606b9b 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -33,10 +33,21 @@
 #include "ce.h"
 #include "pci.h"
 
+enum ath10k_pci_irq_mode {
+	ATH10K_PCI_IRQ_AUTO = 0,
+	ATH10K_PCI_IRQ_LEGACY = 1,
+	ATH10K_PCI_IRQ_MSI = 2,
+};
+
 static unsigned int ath10k_target_ps;
+static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
+
 module_param(ath10k_target_ps, uint, 0644);
 MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option");
 
+module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
+MODULE_PARM_DESC(irq_mode, "0: ayto, 1: legacy, 2: msi (default: 0)");
+
 #define QCA988X_2_0_DEVICE_ID	(0x003c)
 
 static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
@@ -2387,27 +2398,37 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 static int ath10k_pci_init_irq(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X,
+				       ar_pci->features);
 	int ret;
 
 	ath10k_pci_init_irq_tasklets(ar);
 
-	if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features))
-		goto msi;
+	if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO &&
+	    !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
+		ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode);
 
 	/* Try MSI-X */
-	ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
-	ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
-	if (ret == 0)
-		return 0;
-	if (ret > 0)
-		pci_disable_msi(ar_pci->pdev);
+	if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
+		ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
+		ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
+		if (ret == 0)
+			return 0;
+		if (ret > 0)
+			pci_disable_msi(ar_pci->pdev);
+
+		/* fall-through */
+	}
 
-msi:
 	/* Try MSI */
-	ar_pci->num_msi_intrs = 1;
-	ret = pci_enable_msi(ar_pci->pdev);
-	if (ret == 0)
-		return 0;
+	if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) {
+		ar_pci->num_msi_intrs = 1;
+		ret = pci_enable_msi(ar_pci->pdev);
+		if (ret == 0)
+			return 0;
+
+		/* fall-through */
+	}
 
 	/* Try legacy irq
 	 *
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Tue Nov 26 08:57:38 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 26 Nov 2013 14:57:38 +0100
Subject: [PATCH v2 1/3] ath10k: use nss provided by mac80211
In-Reply-To: <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385474260-22385-2-git-send-email-michal.kazior@tieto.com>

Calculating STA NSS just from the mcs rateset is
not the greatest idea.

This should prevent connectivity issues if
mac80211 is ever to set rx_nss to something other
rather than base on max mcs map. As an example
operation mode change notification in assoc
request may change rx_nss initial values in the
future.

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

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b70a3b2..15eda44 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -925,7 +925,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
 	else
 		arg->peer_listen_intval = ar->hw->conf.listen_interval;
 
-	arg->peer_num_spatial_streams = 1;
+	arg->peer_num_spatial_streams = max_t(u32, 1, sta->rx_nss);
 
 	/*
 	 * The assoc capabilities are available only in managed mode.
@@ -1075,7 +1075,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 			arg->peer_ht_rates.rates[n++] = i;
 
 	arg->peer_ht_rates.num_rates = n;
-	arg->peer_num_spatial_streams = max((n+7) / 8, 1);
 
 	ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
 		   arg->addr,
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Tue Nov 26 08:57:40 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 26 Nov 2013 14:57:40 +0100
Subject: [PATCH v2 3/3] ath10k: fix Tx status clearing
In-Reply-To: <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385474260-22385-4-git-send-email-michal.kazior@tieto.com>

Too much of tx info was being cleared. This caused
issues in some setups with tx frame status
reporting.

This should fix some cases of stations not being
able to associate to ath10k AP.

Reported-By: Matti Laakso <malaakso at elisanet.fi>
Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/txrx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index d476b2c..2282980 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -75,7 +75,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 	ath10k_report_offchan_tx(htt->ar, msdu);
 
 	info = IEEE80211_SKB_CB(msdu);
-	memset(info, 0, sizeof(*info));
+	memset(&info->status, 0, sizeof(info->status));
 
 	if (tx_done->discard) {
 		ieee80211_free_txskb(htt->ar->hw, msdu);
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Tue Nov 26 08:57:37 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 26 Nov 2013 14:57:37 +0100
Subject: [PATCH v2 0/3] ath10k: fixes 2013-11-22
In-Reply-To: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>

Hi,

This has some fixes I've stacked in my local repo.
There are no dependencies between them.

v2:
 * refined commit messages

Michal Kazior (3):
  ath10k: use nss provided by mac80211
  ath10k: implement sta_rc_update()
  ath10k: fix Tx status clearing

 drivers/net/wireless/ath/ath10k/mac.c  | 88 +++++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/txrx.c |  2 +-
 drivers/net/wireless/ath/ath10k/wmi.h  |  6 +++
 3 files changed, 93 insertions(+), 3 deletions(-)

-- 
1.8.4.rc3



From michal.kazior at tieto.com  Tue Nov 26 08:57:39 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 26 Nov 2013 14:57:39 +0100
Subject: [PATCH v2 2/3] ath10k: implement sta_rc_update()
In-Reply-To: <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1385474260-22385-3-git-send-email-michal.kazior@tieto.com>

This should fix possible connectivity issues upon
changes of channel width, number of streams or
SMPS on connected stations.

An example trigger would be an action frame with
operation mode change notification.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 85 +++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h |  6 +++
 2 files changed, 91 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 15eda44..65cb63d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3269,6 +3269,90 @@ exit:
 	return ret;
 }
 
+static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_sta *sta,
+				 u32 changed)
+{
+	struct ath10k *ar = hw->priv;
+	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+	u32 chwidth, smps;
+	int ret;
+
+	if (changed & IEEE80211_RC_BW_CHANGED) {
+		switch (sta->bandwidth) {
+		default:
+			ath10k_warn("unsupported STA BW: %d\n", sta->bandwidth);
+		case IEEE80211_STA_RX_BW_20:
+			chwidth = WMI_PEER_CHWIDTH_20MHZ;
+			break;
+		case IEEE80211_STA_RX_BW_40:
+			chwidth = WMI_PEER_CHWIDTH_40MHZ;
+			break;
+		case IEEE80211_STA_RX_BW_80:
+			chwidth = WMI_PEER_CHWIDTH_80MHZ;
+			break;
+		}
+
+		ath10k_dbg(ATH10K_DBG_MAC,
+			   "mac update sta %pM bandwidth (peer chwidth %d) to %d\n",
+			   sta->addr, chwidth, sta->bandwidth);
+
+		ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+						WMI_PEER_CHAN_WIDTH, chwidth);
+		if (ret)
+			ath10k_warn("failed to update STA %pM bandwidth (peer chwidth %d) to %d: %d\n",
+				    sta->addr, chwidth, sta->bandwidth, ret);
+	}
+
+	if (changed & IEEE80211_RC_NSS_CHANGED) {
+		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss to %d\n",
+			   sta->addr, sta->rx_nss);
+
+		ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+						WMI_PEER_NSS, sta->rx_nss);
+		if (ret)
+			ath10k_warn("failed to update STA %pM nss to %d: %d\n",
+				    sta->addr, sta->rx_nss, ret);
+	}
+
+	if (changed & IEEE80211_RC_SMPS_CHANGED) {
+		smps = WMI_PEER_SMPS_PS_NONE;
+
+		switch (sta->smps_mode) {
+		case IEEE80211_SMPS_NUM_MODES:
+			ath10k_warn("invalid smps mode: %d\n", sta->smps_mode);
+		case IEEE80211_SMPS_AUTOMATIC:
+		case IEEE80211_SMPS_OFF:
+			smps = WMI_PEER_SMPS_PS_NONE;
+			break;
+		case IEEE80211_SMPS_STATIC:
+			smps = WMI_PEER_SMPS_STATIC;
+			break;
+		case IEEE80211_SMPS_DYNAMIC:
+			smps = WMI_PEER_SMPS_DYNAMIC;
+			break;
+		}
+
+		ath10k_dbg(ATH10K_DBG_MAC,
+			   "mac update sta %pM smps (peer smps %d) to %d\n",
+			   sta->addr, smps, sta->smps_mode);
+
+		ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+						WMI_PEER_SMPS_STATE, smps);
+		if (ret)
+			ath10k_warn("failed to update STA %pM smps (peer smps %d) to %d: %d\n",
+				    sta->addr, smps, sta->smps_mode, ret);
+	}
+
+	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+		/* FIXME: Not implemented. Not really sure if it's possible to
+		 * influence HW rate control so much. */
+		ath10k_dbg(ATH10K_DBG_MAC,
+			   "mac sta rc update - supp rates changed - not implemented\n");
+	}
+}
+
 static const struct ieee80211_ops ath10k_ops = {
 	.tx				= ath10k_tx,
 	.start				= ath10k_start,
@@ -3291,6 +3375,7 @@ static const struct ieee80211_ops ath10k_ops = {
 	.tx_last_beacon			= ath10k_tx_last_beacon,
 	.restart_complete		= ath10k_restart_complete,
 	.get_survey			= ath10k_get_survey,
+	.sta_rc_update			= ath10k_sta_rc_update,
 #ifdef CONFIG_PM
 	.suspend			= ath10k_suspend,
 	.resume				= ath10k_resume,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 0087d69..e8c4bb7 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -3847,6 +3847,12 @@ enum wmi_peer_smps_state {
 	WMI_PEER_SMPS_DYNAMIC = 0x2
 };
 
+enum wmi_peer_chwidth {
+	WMI_PEER_CHWIDTH_20MHZ = 0,
+	WMI_PEER_CHWIDTH_40MHZ = 1,
+	WMI_PEER_CHWIDTH_80MHZ = 2,
+};
+
 enum wmi_peer_param {
 	WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */
 	WMI_PEER_AMPDU      = 0x2,
-- 
1.8.4.rc3



From michal.kazior at tieto.com  Wed Nov 27 05:25:45 2013
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 27 Nov 2013 11:25:45 +0100
Subject: [PATCH v2 1/3] ath10k: use nss provided by mac80211
In-Reply-To: <1385474260-22385-2-git-send-email-michal.kazior@tieto.com>
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-2-git-send-email-michal.kazior@tieto.com>
Message-ID: <CA+BoTQmtkBGpktbLRfmiLuLDKP9TnUeWu4OMeGUsVcq7m05u4Q@mail.gmail.com>

On 26 November 2013 14:57, Michal Kazior <michal.kazior at tieto.com> wrote:
> Calculating STA NSS just from the mcs rateset is
> not the greatest idea.
>
> This should prevent connectivity issues if
> mac80211 is ever to set rx_nss to something other
> rather than base on max mcs map. As an example
> operation mode change notification in assoc
> request may change rx_nss initial values in the
> future.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
> ---

Drop this single patch, please.

I just noticed rx_nss doesn't seem to have correct value when associating..


Micha?


From kvalo at qca.qualcomm.com  Wed Nov 27 09:48:17 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 27 Nov 2013 16:48:17 +0200
Subject: [PATCH v2 0/8] ath10k: pci fixes 2013-11-22
In-Reply-To: <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 25 Nov 2013 14:06:19 +0100")
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87txexgatq.fsf@kamboji.qca.qualcomm.com>

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

> Hi,
>
> ath10k didn't play well with other devices on a
> shared irq line. This patchset fixes support for
> shared legacy interrupts. 
>
> Some rework was necessary because ath10k was using
> disable_irq and CE irq masking (which is not
> sufficient for shared interrupts).
>
> Since main irq handlers are now registered after
> boot, BMI is now polling for CE updates. I haven't
> observed any differences in boot speed.
>
> Also this plugs a leak I spotted during rework and
> adds an option for testing different irq modes.
>
> v2:
>  * simplify ath10k_pci_irq_pending()
>  * combine memory leak fix patch with a
>    functionality decoupling (it's very closely
>    related)
>  * fix 'irq: nobody cared'
>  * change MSI/MSI-X disabling parameters
>  * some minor fixes & code shuffling to avoid
>    forward declarations
>
>
> Michal Kazior (8):
>   ath10k: don't consume other's shared interrupts
>   ath10k: split up pci irq code
>   ath10k: don't use interrupts for BMI
>   ath10k: decouple ath10k_pci_start_ce()
>   ath10k: defer irq registration until hif start()
>   ath10k: extract functions for legacy irq handling
>   ath10k: re-add support for early fw indication
>   ath10k: allow explicit MSI/MSI-X disabling

Thanks, all eight applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 27 09:47:49 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 27 Nov 2013 16:47:49 +0200
Subject: [PATCH v2 8/8] ath10k: allow explicit MSI/MSI-X disabling
In-Reply-To: <1385384787-12470-9-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 25 Nov 2013 14:06:27 +0100")
References: <1385125518-13461-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-1-git-send-email-michal.kazior@tieto.com>
 <1385384787-12470-9-git-send-email-michal.kazior@tieto.com>
Message-ID: <87y549gaui.fsf@kamboji.qca.qualcomm.com>

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

> This can be useful for testing and debugging.
>
> This introduces new ath10k_pci module parameter
> `irq_mode`. By default it is 0, meaning automatic
> irq mode (MSI-X as long as both target HW and host
> platform supports it). The parameter works on a
> best effort basis.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

[...]

> +MODULE_PARM_DESC(irq_mode, "0: ayto, 1: legacy, 2: msi (default: 0)");

I fixed this typo ("ayto").

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 27 09:55:32 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 27 Nov 2013 16:55:32 +0200
Subject: [PATCH v2 1/3] ath10k: use nss provided by mac80211
In-Reply-To: <CA+BoTQmtkBGpktbLRfmiLuLDKP9TnUeWu4OMeGUsVcq7m05u4Q@mail.gmail.com>
 (Michal Kazior's message of "Wed, 27 Nov 2013 11:25:45 +0100")
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-2-git-send-email-michal.kazior@tieto.com>
 <CA+BoTQmtkBGpktbLRfmiLuLDKP9TnUeWu4OMeGUsVcq7m05u4Q@mail.gmail.com>
Message-ID: <87ppplgahm.fsf@kamboji.qca.qualcomm.com>

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

> On 26 November 2013 14:57, Michal Kazior <michal.kazior at tieto.com> wrote:
>> Calculating STA NSS just from the mcs rateset is
>> not the greatest idea.
>>
>> This should prevent connectivity issues if
>> mac80211 is ever to set rx_nss to something other
>> rather than base on max mcs map. As an example
>> operation mode change notification in assoc
>> request may change rx_nss initial values in the
>> future.
>>
>> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
>> ---
>
> Drop this single patch, please.
>
> I just noticed rx_nss doesn't seem to have correct value when associating..

Ok, I'm dropping this.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 27 10:03:41 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 27 Nov 2013 17:03:41 +0200
Subject: [PATCH v2 2/3] ath10k: implement sta_rc_update()
In-Reply-To: <1385474260-22385-3-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Tue, 26 Nov 2013 14:57:39 +0100")
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-3-git-send-email-michal.kazior@tieto.com>
Message-ID: <87li09ga42.fsf@kamboji.qca.qualcomm.com>

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

> This should fix possible connectivity issues upon
> changes of channel width, number of streams or
> SMPS on connected stations.
>
> An example trigger would be an action frame with
> operation mode change notification.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Sorry, somehow missed these on my previous review:

> +	if (changed & IEEE80211_RC_BW_CHANGED) {
> +		switch (sta->bandwidth) {
> +		default:
> +			ath10k_warn("unsupported STA BW: %d\n", sta->bandwidth);
> +		case IEEE80211_STA_RX_BW_20:
> +			chwidth = WMI_PEER_CHWIDTH_20MHZ;
> +			break;
> +		case IEEE80211_STA_RX_BW_40:
> +			chwidth = WMI_PEER_CHWIDTH_40MHZ;
> +			break;
> +		case IEEE80211_STA_RX_BW_80:
> +			chwidth = WMI_PEER_CHWIDTH_80MHZ;
> +			break;
> +		}

I assume that the idea here is to use WMI_PEER_CHWIDTH_20MHZ for the
default case. Actually I would prefer to avoid using default case
altogether, that way the compiler will warn if there's an enum value we
don't check. So for example you could add "case IEEE80211_STA_RX_BW_160"
which prints a warning and uses 20 MHz.

> +	if (changed & IEEE80211_RC_SMPS_CHANGED) {
> +		smps = WMI_PEER_SMPS_PS_NONE;
> +
> +		switch (sta->smps_mode) {
> +		case IEEE80211_SMPS_NUM_MODES:
> +			ath10k_warn("invalid smps mode: %d\n", sta->smps_mode);
> +		case IEEE80211_SMPS_AUTOMATIC:
> +		case IEEE80211_SMPS_OFF:
> +			smps = WMI_PEER_SMPS_PS_NONE;
> +			break;
> +		case IEEE80211_SMPS_STATIC:
> +			smps = WMI_PEER_SMPS_STATIC;
> +			break;
> +		case IEEE80211_SMPS_DYNAMIC:
> +			smps = WMI_PEER_SMPS_DYNAMIC;
> +			break;
> +		}

This is better, but I think it would be clearer to have
IEEE80211_SMPS_NUM_MODES last and not "fall through" the cases.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Wed Nov 27 10:04:22 2013
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 27 Nov 2013 17:04:22 +0200
Subject: [PATCH v2 0/3] ath10k: fixes 2013-11-22
In-Reply-To: <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Tue, 26 Nov 2013 14:57:37 +0100")
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87haaxga2x.fsf@kamboji.qca.qualcomm.com>

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

> Hi,
>
> This has some fixes I've stacked in my local repo.
> There are no dependencies between them.
>
> v2:
>  * refined commit messages
>
> Michal Kazior (3):
>   ath10k: use nss provided by mac80211

Dropped by your request.

>   ath10k: implement sta_rc_update()

I had comments for this.

>   ath10k: fix Tx status clearing

This is applied.

-- 
Kalle Valo


From bartosz.markowski at tieto.com  Fri Nov 29 10:09:23 2013
From: bartosz.markowski at tieto.com (Bartosz Markowski)
Date: Fri, 29 Nov 2013 16:09:23 +0100
Subject: [PATCH] ath10k: fix multi BSSID with WPA on FW 10.1
Message-ID: <1385737763-10481-1-git-send-email-bartosz.markowski@tieto.com>

From: Michal Kazior <michal.kazior at tieto.com>

FW 10.1 seems to require the default key index to
be updated to point to group key after it is
installed. Otherwise Txed frames are corrupted.

Tested-by: Tomasz Skapski <tomasz.skapski at tieto.com>
Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c |   40 +++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b70a3b2..20821e0 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2717,6 +2717,44 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw,
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
+				        struct ath10k_vif *arvif,
+				        enum set_key_cmd cmd,
+				        struct ieee80211_key_conf *key)
+{
+	u32 vdev_param = arvif->ar->wmi.vdev_param->def_keyid;
+	int ret;
+
+	/* 10.1 firmware branch requires default key index to be set to group
+	 * key index after installing it. Otherwise FW/HW Txes corrupted
+	 * frames with multi-vif APs. This is not required for main firmware
+	 * branch (e.g. 636).
+	 *
+	 * FIXME: This has been tested only in AP. It remains unknown if this
+	 * is required for multi-vif STA interfaces on 10.1 */
+
+	if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+		return;
+
+	if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
+		return;
+
+	if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
+		return;
+
+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+		return;
+
+	if (cmd != SET_KEY)
+		return;
+
+	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+					key->keyidx);
+	if (ret)
+		ath10k_warn("failed to set group key as default key: %d\n",
+			    ret);
+}
+
 static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			  struct ieee80211_vif *vif, struct ieee80211_sta *sta,
 			  struct ieee80211_key_conf *key)
@@ -2778,6 +2816,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		goto exit;
 	}
 
+	ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key);
+
 	spin_lock_bh(&ar->data_lock);
 	peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr);
 	if (peer && cmd == SET_KEY)
-- 
1.7.10



From johannes at sipsolutions.net  Fri Nov 29 10:37:14 2013
From: johannes at sipsolutions.net (Johannes Berg)
Date: Fri, 29 Nov 2013 16:37:14 +0100
Subject: [PATCH v2 1/3] ath10k: use nss provided by mac80211
In-Reply-To: <CA+BoTQmtkBGpktbLRfmiLuLDKP9TnUeWu4OMeGUsVcq7m05u4Q@mail.gmail.com>
 (sfid-20131127_112551_029392_CB0E2653)
References: <1385126819-15311-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-1-git-send-email-michal.kazior@tieto.com>
 <1385474260-22385-2-git-send-email-michal.kazior@tieto.com>
 <CA+BoTQmtkBGpktbLRfmiLuLDKP9TnUeWu4OMeGUsVcq7m05u4Q@mail.gmail.com>
 (sfid-20131127_112551_029392_CB0E2653)
Message-ID: <1385739434.8656.0.camel@jlt4.sipsolutions.net>

On Wed, 2013-11-27 at 11:25 +0100, Michal Kazior wrote:
> On 26 November 2013 14:57, Michal Kazior <michal.kazior at tieto.com> wrote:
> > Calculating STA NSS just from the mcs rateset is
> > not the greatest idea.
> >
> > This should prevent connectivity issues if
> > mac80211 is ever to set rx_nss to something other
> > rather than base on max mcs map. As an example
> > operation mode change notification in assoc
> > request may change rx_nss initial values in the
> > future.
> >
> > Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
> > ---
> 
> Drop this single patch, please.
> 
> I just noticed rx_nss doesn't seem to have correct value when associating..

FWIW, there are pending changes to make the opmode data come from
hostapd to mac80211 so that this would be set correctly when the station
is associating.

Or where did you find it wasn't set correctly?

johannes



