Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH] cfg80211: VLAN offload support for set_key and set_sta_vlan
From: Jouni Malinen @ 2019-08-20 20:50 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Gurumoorthi Gnanasambandhan
In-Reply-To: <3a8edc6691a03ed3c253d95811d5fd6cae453a03.camel@sipsolutions.net>

On Mon, Aug 19, 2019 at 12:16:03PM +0200, Johannes Berg wrote:
> On Thu, 2019-08-15 at 16:38 +0300, Jouni Malinen wrote:
> > From: Gurumoorthi Gnanasambandhan <gguru@codeaurora.org>
> > 
> > This provides an alternative mechanism for AP VLAN support where a
> > single netdev is used with VLAN tagged frames instead of separate
> > netdevs for each VLAN without tagged frames from the WLAN driver.
> > 
> > By setting NL80211_EXT_FEATURE_VLAN_OFFLOAD flag the driver indicates
> > support for a single netdev with VLAN tagged frames. Separate
> > VLAN-specific netdevs are added using vcongig similar to Ethernet.
> > NL80211_CMD_NEW_KEY and NL80211_CMD_SET_STATION will optionally specify
> > vlan_id using NL80211_ATTR_VLAN_ID.
> 
> Without really looking at the specifics, it might be relatively simple
> to support this in mac80211?

Yes, that is something that I was thinking about when going through
this.. I don't remember why exactly mac80211 ended up with its current
design for per-AP_VLAN netdevs without tags, but it could indeed be
quite convenient to have this alternative approach available. I guess
both of them have some benefits, so this would likely be left with two
different mechanisms left to maintain, but the needed implementation in
mac80211 for this would seem to be pretty minimal (also without looking
at the exact details..).

-- 
Jouni Malinen                                            PGP id EFC895FA

^ permalink raw reply

* [PATCH 1/1] [PATCH] Mt76 enabling data pkt transmission.
From: Balakrishna Bandi @ 2019-08-20 21:11 UTC (permalink / raw)
  To: lorenzo.bianconi83; +Cc: linux-wireless, Balakrishna Bandi

Data Packet transmission was disabled during scanning in mt76 driver.

Fix to be, enabling data packet transmission during scanning.

Note:
Mac80211 will handle channel switching. During scanning, it handles
stopping the data transmission on off channel and enabling data
transmission on operating channel also. It does not require to stop data
transmission in mt76 driver during scanning. Verified with other driver
ath9k and rt2x00 driver, data transmission was not stopped during
scanning

Signed-off-by: Balakrishna Bandi <b.balakrishna@globaledgesoft.com>
---
 drivers/net/wireless/mediatek/mt76/tx.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 5397827..376720d 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -438,8 +438,7 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
 		if (probe)
 			break;
 
-		if (test_bit(MT76_OFFCHANNEL, &dev->state) ||
-		    test_bit(MT76_RESET, &dev->state))
+		if (test_bit(MT76_RESET, &dev->state))
 			return -EBUSY;
 
 		skb = mt76_txq_dequeue(dev, mtxq, false);
-- 
1.9.1

Disclaimer:- The information contained in this electronic message and any attachments to this message are intended for the exclusive use of the addressee(s) and may contain proprietary, confidential or privileged information. If you are not the intended recipient, you should not disseminate, distribute or copy this e-mail. Please notify the sender immediately and destroy all copies of this message and any attachments. The views expressed in this E-mail message (including the enclosure/(s) or attachment/(s) if any) are those of the individual sender, except where the sender expressly, and with authority, states them to be the views of GlobalEdge. Before opening any mail and attachments please check them for viruses .GlobalEdge does not accept any liability for virus infected mails.


^ permalink raw reply related

* Re: [RFC 0/1] Allow MAC change on up interface
From: Dan Williams @ 2019-08-20 21:18 UTC (permalink / raw)
  To: Denis Kenzior, Johannes Berg, James Prestwood
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <3313f0a7-2b38-9941-46bf-4c1a3e06a267@gmail.com>

On Tue, 2019-08-20 at 15:37 -0500, Denis Kenzior wrote:
> Hi Johannes,
> 
> On 8/20/19 3:15 PM, Johannes Berg wrote:
> > On Tue, 2019-08-20 at 14:58 -0500, Denis Kenzior wrote:
> > > But what actual complexity are we talking about here? If the
> > > kernel can
> > > do this while the CONNECT is pending, why not?  It makes things
> > > simpler
> > > and faster for userspace.  I don't see the downside unless you
> > > can
> > > somehow objectively explain 'complexity'.
> > 
> > It's just extra code that we have to worry about. Right now you
> > want it
> > for CMD_CONNECT and CMD_AUTH. Somebody will come up with a reason
> > to do
> > it in CMD_ASSOC next, perhaps, who knows. Somebody else will say
> > "oh,
> > this is how it's done, so let's add it to CMD_JOIN_IBSS", because
> > of
> > course that's what they care about. OCB? Mesh? AP mode for
> > tethering?
> > Etc.
> 
> I don't buy the extra code argument.  If you want to do something
> useful 
> you need to write 'extra code'.

Code will be written, but I'd rather it be written once rather than 3+
times for STA/AP/Mesh/etc.

> The rest, I'm not sure why you are worried about them now?  For
> station 
> there's a very clear & present use case.  If such a clear and
> present 
> use case is presented for AP or Mesh, then deal with it then.

Why would you not want to pass a random MAC for AP or Mesh modes? The
same reasons for MAC randomization apply for all those too, I'd think.

> > I don't see how this will not keep proliferating, and each new
> > thing
> > will come with its own dozen lines of code, a new feature flag,
> > etc.
> 
> Such is life? :)

Not really. It's the job of maintainers to balance all these things, to
step back and think of the bigger picture and the future rather than
just solving one particular use-case today.

Your tone leaves the impression you want a particular solution pushed
through without the normal planning/architecture discussions that 
accompany API changes. And that's not how the process typically works.

Dan

> > Relaxing and defining once and for all in which situations while
> > the
> > interface is up you can actually allow changing the address, and
> > then
> > having userspace do it that way is IMHO a better way to design the
> > system, since it forgoes entirely all those questions of when and
> > how
> > and which new use cases will come up etc.
> > 
> 
> That would be great in theory, but practically never works at least
> in 
> my experience.  So maybe keep and open mind?  There is a clear need
> to 
> make this path as fast as possible for STA.  There is no such need
> (yet) 
> for the other cases you mentioned.

> > > This was an RFC.  There isn't much point for us to cross all the
> > > 't's
> > > and dot all the 'i's if you hate the idea in the first place.
> > 
> > Sure, but I cannot distinguish between "we only want it on
> > CMD_CONNECT"
> > and "we'll extend this once we agree" unless you actually say so.
> > It'd
> > help to communicate which t's and i's you didn't cross or dot.
> 
> Okay, I'll admit the RFC description could have been better.  But in
> the 
> end you're human last I checked (at least I recall meeting you
> several 
> times? ;)  How about a simple "Why do you think you need this?"
> first?
> 
> Regards,
> -Denis


^ permalink raw reply

* [PATCH 1/1] nl80211: AP deauthentication flooding.
From: Balakrishna Bandi @ 2019-08-20 21:33 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Balakrishna Bandi

AP sends deauth per each data frame to STA which is not associated to
AP. Non associated STA keeps on sending data frame and leads to deauth
flooding.

Fix to be sending at-most single deauth per second if AP receive data frame from
non-associated STA.

Signed-off-by: Balakrishna Bandi <b.balakrishna@globaledgesoft.com>
---
 net/wireless/core.c    | 67 +++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/core.h    | 17 ++++++++++++
 net/wireless/nl80211.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 152 insertions(+), 5 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index a599469..a29b02a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -360,6 +360,71 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
 	rtnl_unlock();
 }
 
+/**
+ * This timer will check for expired node and it will delete that node.
+ * Timer will run for every 10 seconds till list is empty.
+ **/
+void cfg80211_non_assoc_sta_timer_wk(struct work_struct *work)
+{
+	struct delayed_work *delayed_work = to_delayed_work(work);
+	struct cfg80211_non_assoc_stas_info *uk_stas_info;
+	struct cfg80211_non_assoc_single_sta_info *sta, *tsta;
+
+	uk_stas_info = container_of(delayed_work,
+			struct cfg80211_non_assoc_stas_info, sta_update_timer);
+
+	if (list_empty(&uk_stas_info->non_assoc_sta_list))
+		return;
+
+	spin_lock(&uk_stas_info->sta_lock);
+	list_for_each_entry_safe(sta, tsta,
+	 &uk_stas_info->non_assoc_sta_list, list) {
+	/* Clearing the node if we didn't receive any packet within 4 seconds */
+	    if (time_before(sta->last_rx_pkt +
+	     (CFG80211_NON_ASSOC_MIN_CACHE_UPDATE * HZ), jiffies)) {
+	        list_del(&sta->list);
+	        kfree(sta);
+	    }
+	}
+	spin_unlock(&uk_stas_info->sta_lock);
+
+	schedule_delayed_work(&uk_stas_info->sta_update_timer,
+	            CFG80211_NON_ASSOC_FILTER_TIMER_INT * HZ);
+}
+
+static void cfg80211_non_assoc_sta_info_dealloc(
+	                struct cfg80211_registered_device *rdev)
+{
+	struct cfg80211_non_assoc_single_sta_info *sta, *tsta;
+	struct cfg80211_non_assoc_stas_info *uk_stas_info =
+	                    rdev->non_assoc_stas_info;
+
+	cancel_delayed_work_sync(&uk_stas_info->sta_update_timer);
+	spin_lock(&uk_stas_info->sta_lock);
+	list_for_each_entry_safe(sta, tsta,
+	 &uk_stas_info->non_assoc_sta_list, list) {
+	    list_del(&sta->list);
+	    kfree(sta);
+	}
+	spin_unlock(&uk_stas_info->sta_lock);
+
+	kfree(rdev->non_assoc_stas_info);
+}
+
+static void cfg80211_non_assoc_sta_info_alloc(
+	                struct cfg80211_registered_device *rdev)
+{
+	rdev->non_assoc_stas_info = kzalloc(
+	    sizeof(struct cfg80211_non_assoc_stas_info), GFP_KERNEL);
+	if (!rdev->non_assoc_stas_info)
+		return;
+
+	INIT_LIST_HEAD(&rdev->non_assoc_stas_info->non_assoc_sta_list);
+	spin_lock_init(&rdev->non_assoc_stas_info->sta_lock);
+	INIT_DELAYED_WORK(&rdev->non_assoc_stas_info->sta_update_timer,
+	                cfg80211_non_assoc_sta_timer_wk);
+}
+
 static void cfg80211_propagate_radar_detect_wk(struct work_struct *work)
 {
 	struct cfg80211_registered_device *rdev;
@@ -521,6 +586,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
 	INIT_WORK(&rdev->event_work, cfg80211_event_work);
 
 	init_waitqueue_head(&rdev->dev_wait);
+	cfg80211_non_assoc_sta_info_alloc(rdev);
 
 	/*
 	 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
@@ -1024,6 +1090,7 @@ void wiphy_unregister(struct wiphy *wiphy)
 	flush_work(&rdev->destroy_work);
 	flush_work(&rdev->sched_scan_stop_wk);
 	flush_work(&rdev->mlme_unreg_wk);
+	cfg80211_non_assoc_sta_info_dealloc(rdev);
 	flush_work(&rdev->propagate_radar_detect_wk);
 	flush_work(&rdev->propagate_cac_done_wk);
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 77556c5..7bfbbec 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -21,6 +21,22 @@
 
 #define WIPHY_IDX_INVALID	-1
 
+/* Running  non-association filter timer for every 10 seconds */
+#define CFG80211_NON_ASSOC_FILTER_TIMER_INT    10
+#define CFG80211_NON_ASSOC_MIN_CACHE_UPDATE    4
+struct cfg80211_non_assoc_stas_info {
+	struct list_head non_assoc_sta_list;
+	spinlock_t sta_lock;
+	struct delayed_work sta_update_timer;
+};
+
+struct cfg80211_non_assoc_single_sta_info {
+	u8 address[ETH_ALEN];
+	u16 count;
+	unsigned long last_rx_pkt;
+	struct list_head list;
+};
+
 struct cfg80211_registered_device {
 	const struct cfg80211_ops *ops;
 	struct list_head list;
@@ -103,6 +119,7 @@ struct cfg80211_registered_device {
 	struct cfg80211_chan_def cac_done_chandef;
 	struct work_struct propagate_cac_done_wk;
 
+	struct cfg80211_non_assoc_stas_info *non_assoc_stas_info;
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
 	struct wiphy wiphy __aligned(NETDEV_ALIGN);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 92e0648..10ee3cf 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -15686,11 +15686,31 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
 	return true;
 }
 
+struct cfg80211_non_assoc_single_sta_info * cfg80211_find_non_assoc_sta_entry(
+	struct cfg80211_non_assoc_stas_info *uk_stas_info, const u8 *addr)
+{
+	struct cfg80211_non_assoc_single_sta_info *sta, *find_sta = NULL;
+
+	spin_lock(&uk_stas_info->sta_lock);
+	list_for_each_entry(sta, &uk_stas_info->non_assoc_sta_list, list) {
+	    if (ether_addr_equal(addr, sta->address)) {
+	        find_sta = sta;
+	        break;
+	    }
+	}
+	spin_unlock(&uk_stas_info->sta_lock);
+
+	return find_sta;
+}
+
 bool cfg80211_rx_spurious_frame(struct net_device *dev,
 				const u8 *addr, gfp_t gfp)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	bool ret;
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	bool ret, run_timer = false, deauth = true;
+	struct cfg80211_non_assoc_single_sta_info *sta;
 
 	trace_cfg80211_rx_spurious_frame(dev, addr);
 
@@ -15699,10 +15719,53 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev,
 		trace_cfg80211_return_bool(false);
 		return false;
 	}
-	ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
-					 addr, gfp);
-	trace_cfg80211_return_bool(ret);
-	return ret;
+
+	if (!rdev->non_assoc_stas_info)
+	    return true;
+
+	/* If list is empty, we should trigger the timer to clear the node */
+	if (list_empty(&rdev->non_assoc_stas_info->non_assoc_sta_list))
+	    run_timer = true;
+
+
+	/* If we didn't find the station, creating new node. Else, updating the time */
+	sta = cfg80211_find_non_assoc_sta_entry(
+	                rdev->non_assoc_stas_info, addr);
+	if (sta) {
+	/* Checking pkt is received within second. If we didn't update, sending deauth packet */
+	    if (time_after(sta->last_rx_pkt + HZ, jiffies))
+	        deauth = false;
+	    else
+	        sta->last_rx_pkt = jiffies;
+	} else {
+	    sta = kzalloc(sizeof
+	     (struct cfg80211_non_assoc_single_sta_info), GFP_ATOMIC);
+	    if (sta == NULL)
+	        return true;
+
+	    memcpy(sta->address, addr, ETH_ALEN);
+	    spin_lock(&rdev->non_assoc_stas_info->sta_lock);
+	    list_add(&sta->list,
+	        &rdev->non_assoc_stas_info->non_assoc_sta_list);
+	    spin_unlock(&rdev->non_assoc_stas_info->sta_lock);
+	    sta->last_rx_pkt = jiffies;
+	}
+
+	sta->count++;
+
+	if (run_timer)
+	    schedule_delayed_work(
+	        &rdev->non_assoc_stas_info->sta_update_timer,
+	        CFG80211_NON_ASSOC_FILTER_TIMER_INT * HZ);
+
+	if (deauth) {
+	    ret = __nl80211_unexpected_frame(dev,
+	            NL80211_CMD_UNEXPECTED_FRAME, addr, gfp);
+	    trace_cfg80211_return_bool(ret);
+	    return ret;
+	}
+
+	return true;
 }
 EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
 
-- 
1.9.1

Disclaimer:- The information contained in this electronic message and any attachments to this message are intended for the exclusive use of the addressee(s) and may contain proprietary, confidential or privileged information. If you are not the intended recipient, you should not disseminate, distribute or copy this e-mail. Please notify the sender immediately and destroy all copies of this message and any attachments. The views expressed in this E-mail message (including the enclosure/(s) or attachment/(s) if any) are those of the individual sender, except where the sender expressly, and with authority, states them to be the views of GlobalEdge. Before opening any mail and attachments please check them for viruses .GlobalEdge does not accept any liability for virus infected mails.


^ permalink raw reply related

* ACS for ath10k?
From: Robert White @ 2019-08-20 21:37 UTC (permalink / raw)
  To: linux-wireless

For a brief shining moment several months ago the ath10k board I kitted 
up for my access point... worked. I wish I remembered the details. 
Anyway, now days hostapd ACS fails with:

Configuration file: hostapd.conf.experimental
wlan0: interface state UNINITIALIZED->COUNTRY_UPDATE
ACS: Automatic channel selection started, this may take a bit
wlan0: interface state COUNTRY_UPDATE->ACS
wlan0: ACS-STARTED
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Channel 52 has insufficient survey data
...
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Survey is missing noise floor
ACS: Channel 144 has insufficient survey data
ACS: Surveys have insufficient data
ACS: All study options have failed
Interface initialization failed
wlan0: interface state ACS->DISABLED
wlan0: AP-DISABLED
ACS: Possibly channel configuration is invalid, please report this along 
with your config file.
ACS: Failed to start
wlan0: AP-DISABLED
hostapd_free_hapd_data: Interface wlan0 wasn't started
nl80211: deinit ifname=wlan0 disabled_11b_rates=0
wlan0: interface state DISABLED->DISABLED
wlan0: interface state DISABLED->DISABLED
wlan0: AP-DISABLED
wlan0: CTRL-EVENT-TERMINATING
hostapd_free_hapd_data: Interface wlan0 wasn't started

In dmesg I get about 200 (if I include the suppressed redundant 
messages) copies of
ath10k_pci 0000:03:00.0: failed to parse chan info event: -71

preceeded by:
[  389.383439] ath10k_pci 0000:03:00.0: unsupported HTC service id: 1536



Relevant info:
[   15.279360] ath10k_pci 0000:03:00.0: limiting irq mode to: 2
[   15.279446] ath10k_pci 0000:03:00.0: pci irq msi oper_irq_mode 2 
irq_mode 2 reset_mode 0
[   15.834892] ath10k_pci 0000:03:00.0: qca988x hw2.0 target 0x4100016c 
chip_id 0x043202ff sub 0000:0000
[   15.834900] ath10k_pci 0000:03:00.0: kconfig debug 0 debugfs 1 
tracing 0 dfs 1 testmode 0
[   15.835488] ath10k_pci 0000:03:00.0: firmware ver 10.2.4-1.0-00045 
api 5 features no-p2p,raw-mode,mfp,allows-mesh-bcast crc32 ccbd5104
[   15.913439] ath10k_pci 0000:03:00.0: board_file api 1 bmi_id N/A 
crc32 bebc7c08
[   17.022617] ath10k_pci 0000:03:00.0: unsupported HTC service id: 1536
[   17.043897] ath10k_pci 0000:03:00.0: htt-ver 2.1 wmi-op 5 htt-op 2 
cal otp max-sta 128 raw 0 hwcrypto 1
[   17.100699] ath: EEPROM regdomain: 0x6a
[   17.100701] ath: EEPROM indicates we should expect a direct regpair map
[   17.100703] ath: Country alpha2 being used: 00
[   17.100704] ath: Regpair used: 0x6a


Note that if I manually select a channel the AP runs fine, so everythign 
else seemes to be good except the parse error or firmware issue.


lspci output:

03:00.0 Network controller: Qualcomm Atheros QCA986x/988x 802.11ac 
Wireless Network Adapter

Am I just SOL?
Is there a way to check/dump the channel info event that cannot be parsed?


--Rob.

^ permalink raw reply

* Re: [RFC 0/1] Allow MAC change on up interface
From: Denis Kenzior @ 2019-08-20 21:52 UTC (permalink / raw)
  To: Dan Williams, Johannes Berg, James Prestwood
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <3beb3208443d39201272e822d26c1389aa4940db.camel@redhat.com>

Hi Dan,

On 8/20/19 4:18 PM, Dan Williams wrote:

<snip>

> 
> Code will be written, but I'd rather it be written once rather than 3+
> times for STA/AP/Mesh/etc.
> 

I'm not sure you can state that definitively just yet?  So the real 
question is whether saving the extra round-trip to the kernel is worth 
the in-kernel complexity.  Given that interleaved system calls are 
_always_ a problem, I argue that it is worth it for at least the Station 
case (and it will keep connection times even faster to boot).  Isn't 
minimizing the latency of connections the end goal here?  I get that 
there are trade offs and people have other opinions on what a good trade 
off is.

But don't misunderstand, either solution is better than what we have 
today.  My argument is: "why close the door on a particular solution 
until the costs are known?"

>> The rest, I'm not sure why you are worried about them now?  For
>> station
>> there's a very clear & present use case.  If such a clear and
>> present
>> use case is presented for AP or Mesh, then deal with it then.
> 
> Why would you not want to pass a random MAC for AP or Mesh modes? The
> same reasons for MAC randomization apply for all those too, I'd think.

Umm, I was not arguing against doing that at all?  All I said was that 
no such use case was yet presented.  For AP it isn't typically needed to 
rapidly switch between MAC addresses while keeping the device UP.  If 
you think there's such a need, I'm happy to learn something new? Same 
goes for Mesh really?

> 
>>> I don't see how this will not keep proliferating, and each new
>>> thing
>>> will come with its own dozen lines of code, a new feature flag,
>>> etc.
>>
>> Such is life? :)
> 
> Not really. It's the job of maintainers to balance all these things, to
> step back and think of the bigger picture and the future rather than
> just solving one particular use-case today.
>  > Your tone leaves the impression you want a particular solution pushed
> through without the normal planning/architecture discussions that
> accompany API changes. And that's not how the process typically works.
> 

So who's attacking who now?  We're trying to solve a long standing issue 
that nobody has bothered to fix for years in a clean way.  Something 
that one of your projects would benefit from, btw.

I have a technical opinion about how it should look like.  Johannes 
might have a different opinion.  In the end it is up to him and I can go 
pound sand.  So yes, I know how the process works ;)

Regards,
-Denis

^ permalink raw reply

* [PATCH 1/1] rt2x00: Queue flush fix
From: Balakrishna Bandi @ 2019-08-20 22:13 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, Balakrishna Bandi

Added rt2x00 queue flush fix and beacon frames checks.

Signed-off-by: Balakrishna Bandi <b.balakrishna@globaledgesoft.com>
---
 drivers/net/wireless/ralink/rt2x00/rt2800mmio.c  |  2 +-
 drivers/net/wireless/ralink/rt2x00/rt2x00dev.c   |  7 ++--
 drivers/net/wireless/ralink/rt2x00/rt2x00mac.c   | 22 ++++++++++--
 drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 44 +++++++++++++++++++-----
 4 files changed, 61 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
index 110bb39..9964371 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -566,7 +566,7 @@ void rt2800mmio_queue_init(struct data_queue *queue)
 
 	switch (queue->qid) {
 	case QID_RX:
-		queue->limit = 128;
+		queue->limit = 512;
 		queue->data_size = AGGREGATION_SIZE;
 		queue->desc_size = RXD_DESC_SIZE;
 		queue->winfo_size = rxwi_size;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index 35414f9..085a41e 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -128,7 +128,8 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 
 	if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) {
 		mutex_lock(&intf->beacon_skb_mutex);
-		rt2x00queue_update_beacon(rt2x00dev, vif);
+		if (intf->enable_beacon)
+			rt2x00queue_update_beacon(rt2x00dev, vif);
 		mutex_unlock(&intf->beacon_skb_mutex);
 	}
 }
@@ -191,6 +192,7 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
 					struct ieee80211_vif *vif)
 {
 	struct rt2x00_dev *rt2x00dev = data;
+	struct rt2x00_intf *intf = vif_to_intf(vif);
 
 	if (vif->type != NL80211_IFTYPE_AP &&
 	    vif->type != NL80211_IFTYPE_ADHOC &&
@@ -204,7 +206,8 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
 	 * never be called for USB devices.
 	 */
 	WARN_ON(rt2x00_is_usb(rt2x00dev));
-	rt2x00queue_update_beacon(rt2x00dev, vif);
+	if (intf->enable_beacon)
+		rt2x00queue_update_beacon(rt2x00dev, vif);
 }
 
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
index beb20c5..5c424da 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -103,6 +103,25 @@ void rt2x00mac_tx(struct ieee80211_hw *hw,
 	 */
 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		goto exit_free_skb;
+	/* Dirty hack for queue overrun protection,
+	 * if AC_VO/AC_VI/AC_BE is full, use next queue.
+	 * if AC_BK is full use previous queue.
+	 */
+	if (qid < 4) {
+		queue = rt2x00queue_get_tx_queue(rt2x00dev,qid);
+		if (unlikely(rt2x00queue_full(queue))) {
+			switch(qid) {
+				case 0: /* QID_AC_VO */
+				case 1: /* QID_AC_VI */
+				case 2: /* QID_AC_BE */
+					qid++;
+					break;
+				case 3: /* QID_AC_BK */
+					qid--;
+					break;
+			}
+		}
+	}
 
 	/*
 	 * Use the ATIM queue if appropriate and present.
@@ -602,8 +621,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 			 * Upload beacon to the H/W. This is only required on
 			 * USB devices. PCI devices fetch beacons periodically.
 			 */
-			if (rt2x00_is_usb(rt2x00dev))
-				rt2x00queue_update_beacon(rt2x00dev, vif);
+			rt2x00queue_update_beacon(rt2x00dev, vif);
 
 			if (rt2x00dev->intf_beaconing == 1) {
 				/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
index 3b6100e..4254811 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -986,25 +986,37 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
 
 void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
 {
+	unsigned int i;
+	bool started;
 	bool tx_queue =
 		(queue->qid == QID_AC_VO) ||
 		(queue->qid == QID_AC_VI) ||
 		(queue->qid == QID_AC_BE) ||
 		(queue->qid == QID_AC_BK);
+	mutex_lock(&queue->status_lock);
+	/* If the queue has been started, we must stop it temporarily
+	 * to prevent any new frames to be queued on the device. If
+	 * we are not dropping the pending frames, the queue must
+	 * only be stopped in the software and not the hardware,
+	 * otherwise the queue will never become empty on its own.
+	 */
+	started = test_bit(QUEUE_STARTED, &queue->flags);
+	if (started) {
+		// pause the queue.
+		rt2x00queue_pause_queue(queue);
 
+		/* If we are not supposed to drop any pending
+		 * frames, this means we must force a start (=kick)
+		 * to the queue to make sure the hardware will
+		 * start transmitting.
+		 */
+		if (!drop && tx_queue)
+			queue->rt2x00dev->ops->lib->kick_queue(queue);
+	}
 	if (rt2x00queue_empty(queue))
 		return;
 
 	/*
-	 * If we are not supposed to drop any pending
-	 * frames, this means we must force a start (=kick)
-	 * to the queue to make sure the hardware will
-	 * start transmitting.
-	 */
-	if (!drop && tx_queue)
-		queue->rt2x00dev->ops->lib->kick_queue(queue);
-
-	/*
 	 * Check if driver supports flushing, if that is the case we can
 	 * defer the flushing to the driver. Otherwise we must use the
 	 * alternative which just waits for the queue to become empty.
@@ -1013,11 +1025,25 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
 		queue->rt2x00dev->ops->lib->flush_queue(queue, drop);
 
 	/*
+	 * When we don't want to drop any frames, or when
+	 * the driver doesn't fully flush the queue correcly,
+	 * we must wait for the queue to become empty.
+	 */
+	for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
+		msleep(10);
+
+	/*
 	 * The queue flush has failed...
 	 */
 	if (unlikely(!rt2x00queue_empty(queue)))
 		rt2x00_warn(queue->rt2x00dev, "Queue %d failed to flush\n",
 			    queue->qid);
+	/*
+	 * Restore the queue to the previous status.
+	 */
+	if (started)
+		rt2x00queue_unpause_queue(queue);
+	mutex_unlock(&queue->status_lock);
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_flush_queue);
 
-- 
1.9.1

Disclaimer:- The information contained in this electronic message and any attachments to this message are intended for the exclusive use of the addressee(s) and may contain proprietary, confidential or privileged information. If you are not the intended recipient, you should not disseminate, distribute or copy this e-mail. Please notify the sender immediately and destroy all copies of this message and any attachments. The views expressed in this E-mail message (including the enclosure/(s) or attachment/(s) if any) are those of the individual sender, except where the sender expressly, and with authority, states them to be the views of GlobalEdge. Before opening any mail and attachments please check them for viruses .GlobalEdge does not accept any liability for virus infected mails.


^ permalink raw reply related

* Re: PROBLEM: 5.3.0-rc* causes iwlwifi failure
From: Stuart Little @ 2019-08-20 23:37 UTC (permalink / raw)
  To: Luciano Coelho
  Cc: Serge Belyshev, Johannes Berg, Emmanuel Grumbach, kernel list,
	Intel Linux Wireless, linux-wireless, Haim Dreyfuss
In-Reply-To: <1b1e573e6502c97851838a3b27ac0b272198926c.camel@intel.com>

On Tue, Aug 20, 2019 at 01:45:37PM +0300, Luciano Coelho wrote:
> I'll have to look into all NIC/FW-version combinations that we have and
> update the iwl_mvm_sar_geo_support() function accordingly, which is,
> BTW, the easier place for you to change if you want to workaround the
> issue.

Thanks!

I didn't quite know how to interpret this suggestion (i.e. what the change should be), so I was poking around in there out of curiosity. One simple-minded thing that worked was to just pretend that that function always returns false:

--- cut here ---

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 5de54d1559dd..8c0160e5588f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -925,7 +925,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
                .data = { data },
        };
 
-       if (!iwl_mvm_sar_geo_support(mvm))
+       /*if (!iwl_mvm_sar_geo_support(mvm))*/
                return -EOPNOTSUPP;
 
        ret = iwl_mvm_send_cmd(mvm, &cmd);
@@ -953,7 +953,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
        int ret, i, j;
        u16 cmd_wide_id =  WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT);
 
-       if (!iwl_mvm_sar_geo_support(mvm))
+       /*if (!iwl_mvm_sar_geo_support(mvm))*/
                return 0;
 
        ret = iwl_mvm_sar_get_wgds_table(mvm);

--- cut here ---

^ permalink raw reply related

* [PATCH v2] mt76: fix some checkpatch warnings
From: Ryder Lee @ 2019-08-21  3:11 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi
  Cc: Roy Luo, YF Luo, Yiwei Chung, Sean Wang, linux-wireless,
	linux-mediatek, linux-kernel, Ryder Lee

This fixes the following checkpatch warnings:
CHECK: Alignment should match open parenthesis
CHECK: No space is necessary after a cast

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
Changes since v2: remove false positive checkpatch warnings.
Changes since v1: none.
---
 drivers/net/wireless/mediatek/mt76/agg-rx.c   | 23 +++++++-------
 drivers/net/wireless/mediatek/mt76/dma.c      |  2 +-
 drivers/net/wireless/mediatek/mt76/mac80211.c | 30 +++++++++---------
 drivers/net/wireless/mediatek/mt76/mt76.h     |  2 +-
 .../net/wireless/mediatek/mt76/mt7615/mac.c   |  3 +-
 drivers/net/wireless/mediatek/mt76/trace.h    |  9 +++---
 drivers/net/wireless/mediatek/mt76/tx.c       | 18 +++++------
 drivers/net/wireless/mediatek/mt76/usb.c      | 31 ++++++++++---------
 .../net/wireless/mediatek/mt76/usb_trace.h    | 11 ++++---
 drivers/net/wireless/mediatek/mt76/util.h     |  4 +--
 10 files changed, 70 insertions(+), 63 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c
index 2ba157f73bf1..8f3d36a15e17 100644
--- a/drivers/net/wireless/mediatek/mt76/agg-rx.c
+++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c
@@ -23,8 +23,9 @@ mt76_aggr_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames, int idx)
 }
 
 static void
-mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, struct sk_buff_head *frames,
-			 u16 head)
+mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid,
+			    struct sk_buff_head *frames,
+			    u16 head)
 {
 	int idx;
 
@@ -63,15 +64,14 @@ mt76_rx_aggr_check_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames)
 	for (idx = (tid->head + 1) % tid->size;
 	     idx != start && nframes;
 	     idx = (idx + 1) % tid->size) {
-
 		skb = tid->reorder_buf[idx];
 		if (!skb)
 			continue;
 
 		nframes--;
-		status = (struct mt76_rx_status *) skb->cb;
-		if (!time_after(jiffies, status->reorder_time +
-					 REORDER_TIMEOUT))
+		status = (struct mt76_rx_status *)skb->cb;
+		if (!time_after(jiffies,
+				status->reorder_time + REORDER_TIMEOUT))
 			continue;
 
 		mt76_rx_aggr_release_frames(tid, frames, status->seqno);
@@ -111,8 +111,8 @@ mt76_rx_aggr_reorder_work(struct work_struct *work)
 static void
 mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
 {
-	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
-	struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data;
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+	struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
 	struct mt76_wcid *wcid = status->wcid;
 	struct mt76_rx_tid *tid;
 	u16 seqno;
@@ -137,8 +137,8 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
 
 void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
 {
-	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct mt76_wcid *wcid = status->wcid;
 	struct ieee80211_sta *sta;
 	struct mt76_rx_tid *tid;
@@ -222,7 +222,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
 	tid->nframes++;
 	mt76_rx_aggr_release_head(tid, frames);
 
-	ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, REORDER_TIMEOUT);
+	ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work,
+				     REORDER_TIMEOUT);
 
 out:
 	spin_unlock_bh(&tid->lock);
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index dbfd15e861e9..46f5223b4d89 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -493,7 +493,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
 		skb_reserve(skb, q->buf_offset);
 
 		if (q == &dev->q_rx[MT_RXQ_MCU]) {
-			u32 *rxfce = (u32 *) skb->cb;
+			u32 *rxfce = (u32 *)skb->cb;
 			*rxfce = info;
 		}
 
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 581415425cd6..d1075e13ecf7 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -491,7 +491,7 @@ struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	struct mt76_rx_status mstat;
 
-	mstat = *((struct mt76_rx_status *) skb->cb);
+	mstat = *((struct mt76_rx_status *)skb->cb);
 	memset(status, 0, sizeof(*status));
 
 	status->flag = mstat.flag;
@@ -506,8 +506,10 @@ struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
 	status->chains = mstat.chains;
 
 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
-	BUILD_BUG_ON(sizeof(status->chain_signal) != sizeof(mstat.chain_signal));
-	memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal));
+	BUILD_BUG_ON(sizeof(status->chain_signal) !=
+		     sizeof(mstat.chain_signal));
+	memcpy(status->chain_signal, mstat.chain_signal,
+	       sizeof(mstat.chain_signal));
 
 	return wcid_to_sta(mstat.wcid);
 }
@@ -516,7 +518,7 @@ EXPORT_SYMBOL(mt76_rx_convert);
 static int
 mt76_check_ccmp_pn(struct sk_buff *skb)
 {
-	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
 	struct mt76_wcid *wcid = status->wcid;
 	struct ieee80211_hdr *hdr;
 	int ret;
@@ -532,7 +534,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
 		 * Validate the first fragment both here and in mac80211
 		 * All further fragments will be validated by mac80211 only.
 		 */
-		hdr = (struct ieee80211_hdr *) skb->data;
+		hdr = (struct ieee80211_hdr *)skb->data;
 		if (ieee80211_is_frag(hdr) &&
 		    !ieee80211_is_first_frag(hdr->frame_control))
 			return 0;
@@ -555,8 +557,8 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
 static void
 mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
 {
-	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_sta *sta;
 	struct mt76_wcid *wcid = status->wcid;
 	bool ps;
@@ -565,13 +567,13 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
 		sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL);
 		if (sta)
-			wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv;
+			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
 	}
 
 	if (!wcid || !wcid->sta)
 		return;
 
-	sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv);
+	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
 
 	if (status->signal <= 0)
 		ewma_signal_add(&wcid->rssi, -status->signal);
@@ -587,8 +589,8 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
 	}
 
 	if (ieee80211_has_morefrags(hdr->frame_control) ||
-		!(ieee80211_is_mgmt(hdr->frame_control) ||
-		  ieee80211_is_data(hdr->frame_control)))
+	    !(ieee80211_is_mgmt(hdr->frame_control) ||
+	    ieee80211_is_data(hdr->frame_control)))
 		return;
 
 	ps = ieee80211_has_pm(hdr->frame_control);
@@ -617,7 +619,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
 		if (!sta->txq[i])
 			continue;
 
-		mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv;
+		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
 		if (!skb_queue_empty(&mtxq->retry_q))
 			ieee80211_schedule_txq(dev->hw, sta->txq[i]);
 	}
@@ -739,7 +741,7 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		dev->drv->sta_assoc(dev, vif, sta);
 
 	if (old_state == IEEE80211_STA_NONE &&
-		 new_state == IEEE80211_STA_NOTEXIST)
+	    new_state == IEEE80211_STA_NOTEXIST)
 		mt76_sta_remove(dev, vif, sta);
 
 	return 0;
@@ -779,7 +781,7 @@ static void
 __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
 {
 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
-	    ieee80211_csa_finish(vif);
+		ieee80211_csa_finish(vif);
 }
 
 void mt76_csa_finish(struct mt76_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 95ba6e98afa2..1131fcff358b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -671,7 +671,7 @@ static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb)
 {
 	BUILD_BUG_ON(sizeof(struct mt76_tx_cb) >
 		     sizeof(IEEE80211_SKB_CB(skb)->status.status_driver_data));
-	return ((void *) IEEE80211_SKB_CB(skb)->status.status_driver_data);
+	return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data);
 }
 
 static inline void mt76_insert_hdr_pad(struct sk_buff *skb)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 0554aa2dbe2f..af92150907b5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -336,7 +336,8 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
 	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
 
 	if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) {
-		q_idx = skb_get_queue_mapping(skb) + wmm_idx * MT7615_MAX_WMM_SETS;
+		q_idx = wmm_idx * MT7615_MAX_WMM_SETS +
+			skb_get_queue_mapping(skb);
 		p_fmt = MT_TX_TYPE_CT;
 	} else if (ieee80211_is_beacon(fc)) {
 		q_idx = MT_LMAC_BCN0;
diff --git a/drivers/net/wireless/mediatek/mt76/trace.h b/drivers/net/wireless/mediatek/mt76/trace.h
index e432f9e845df..0b3e635da868 100644
--- a/drivers/net/wireless/mediatek/mt76/trace.h
+++ b/drivers/net/wireless/mediatek/mt76/trace.h
@@ -13,10 +13,11 @@
 #define TRACE_SYSTEM mt76
 
 #define MAXNAME		32
-#define DEV_ENTRY   __array(char, wiphy_name, 32)
-#define DEV_ASSIGN  strlcpy(__entry->wiphy_name, wiphy_name(dev->hw->wiphy), MAXNAME)
-#define DEV_PR_FMT  "%s"
-#define DEV_PR_ARG  __entry->wiphy_name
+#define DEV_ENTRY	__array(char, wiphy_name, 32)
+#define DEV_ASSIGN	strlcpy(__entry->wiphy_name,	\
+				wiphy_name(dev->hw->wiphy), MAXNAME)
+#define DEV_PR_FMT	"%s"
+#define DEV_PR_ARG	__entry->wiphy_name
 
 #define REG_ENTRY	__field(u32, reg) __field(u32, val)
 #define REG_ASSIGN	__entry->reg = reg; __entry->val = val
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 969fedfa3c62..fb86ad956478 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -86,7 +86,7 @@ mt76_txq_get_qid(struct ieee80211_txq *txq)
 static void
 mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
 	if (!ieee80211_is_data_qos(hdr->frame_control) ||
 	    !ieee80211_is_data_present(hdr->frame_control))
@@ -206,8 +206,8 @@ mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid,
 		if (cb->pktid == pktid)
 			return skb;
 
-		if (pktid >= 0 &&
-		    !time_after(jiffies, cb->jiffies + MT_TX_STATUS_SKB_TIMEOUT))
+		if (pktid >= 0 && !time_after(jiffies, cb->jiffies +
+					      MT_TX_STATUS_SKB_TIMEOUT))
 			continue;
 
 		__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED |
@@ -249,7 +249,7 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
 	struct mt76_wcid *wcid, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct mt76_queue *q;
 	int qid = skb_get_queue_mapping(skb);
 
@@ -269,7 +269,7 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
 
 		tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
 		txq = sta->txq[tid];
-		mtxq = (struct mt76_txq *) txq->drv_priv;
+		mtxq = (struct mt76_txq *)txq->drv_priv;
 
 		if (mtxq->aggr)
 			mt76_check_agg_ssn(mtxq, skb);
@@ -317,7 +317,7 @@ static void
 mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
 		  struct sk_buff *skb, bool last)
 {
-	struct mt76_wcid *wcid = (struct mt76_wcid *) sta->drv_priv;
+	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
 	info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
@@ -343,7 +343,7 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
 	spin_lock_bh(&hwq->lock);
 	for (i = 0; tids && nframes; i++, tids >>= 1) {
 		struct ieee80211_txq *txq = sta->txq[i];
-		struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv;
+		struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv;
 		struct sk_buff *skb;
 
 		if (!(tids & 1))
@@ -599,7 +599,7 @@ void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq)
 	if (!txq)
 		return;
 
-	mtxq = (struct mt76_txq *) txq->drv_priv;
+	mtxq = (struct mt76_txq *)txq->drv_priv;
 
 	while ((skb = skb_dequeue(&mtxq->retry_q)) != NULL)
 		ieee80211_free_txskb(dev->hw, skb);
@@ -608,7 +608,7 @@ EXPORT_SYMBOL_GPL(mt76_txq_remove);
 
 void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
 {
-	struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv;
+	struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv;
 
 	skb_queue_head_init(&mtxq->retry_q);
 
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index cba19a551224..20c6fe510e9d 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -154,7 +154,7 @@ static void mt76u_copy(struct mt76_dev *dev, u32 offset,
 
 	mutex_lock(&usb->usb_ctrl_mtx);
 	for (i = 0; i < DIV_ROUND_UP(len, 4); i++) {
-		put_unaligned(val[i], (u32 *) usb->data);
+		put_unaligned(val[i], (u32 *)usb->data);
 		ret = __mt76u_vendor_request(dev, MT_VEND_MULTI_WRITE,
 					     USB_DIR_OUT | USB_TYPE_VENDOR,
 					     0, offset + i * 4, usb->data,
@@ -309,14 +309,13 @@ mt76u_refill_rx(struct mt76_dev *dev, struct urb *urb, int nsgs, gfp_t gfp)
 {
 	struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
 
-	if (dev->usb.sg_en) {
+	if (dev->usb.sg_en)
 		return mt76u_fill_rx_sg(dev, q, urb, nsgs, gfp);
-	} else {
-		urb->transfer_buffer_length = q->buf_size;
-		urb->transfer_buffer = page_frag_alloc(&q->rx_page,
-						       q->buf_size, gfp);
-		return urb->transfer_buffer ? 0 : -ENOMEM;
-	}
+
+	urb->transfer_buffer_length = q->buf_size;
+	urb->transfer_buffer = page_frag_alloc(&q->rx_page, q->buf_size, gfp);
+
+	return urb->transfer_buffer ? 0 : -ENOMEM;
 }
 
 static int
@@ -752,13 +751,14 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb,
 	if (!dev->usb.sg_en) {
 		urb->transfer_buffer = skb->data;
 		return 0;
-	} else {
-		sg_init_table(urb->sg, MT_TX_SG_MAX_SIZE);
-		urb->num_sgs = skb_to_sgvec(skb, urb->sg, 0, skb->len);
-		if (urb->num_sgs == 0)
-			return -ENOMEM;
-		return urb->num_sgs;
 	}
+
+	sg_init_table(urb->sg, MT_TX_SG_MAX_SIZE);
+	urb->num_sgs = skb_to_sgvec(skb, urb->sg, 0, skb->len);
+	if (!urb->num_sgs)
+		return -ENOMEM;
+
+	return urb->num_sgs;
 }
 
 static int
@@ -874,7 +874,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
 	struct mt76_queue *q;
 	int i, j, ret;
 
-	ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), HZ/5);
+	ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev),
+				 HZ / 5);
 	if (!ret) {
 		dev_err(dev->dev, "timed out waiting for pending tx\n");
 
diff --git a/drivers/net/wireless/mediatek/mt76/usb_trace.h b/drivers/net/wireless/mediatek/mt76/usb_trace.h
index f37bd9feacf0..f5ab3215af80 100644
--- a/drivers/net/wireless/mediatek/mt76/usb_trace.h
+++ b/drivers/net/wireless/mediatek/mt76/usb_trace.h
@@ -13,10 +13,11 @@
 #define TRACE_SYSTEM mt76_usb
 
 #define MAXNAME		32
-#define DEV_ENTRY   __array(char, wiphy_name, 32)
-#define DEV_ASSIGN  strlcpy(__entry->wiphy_name, wiphy_name(dev->hw->wiphy), MAXNAME)
-#define DEV_PR_FMT  "%s "
-#define DEV_PR_ARG  __entry->wiphy_name
+#define DEV_ENTRY	__array(char, wiphy_name, 32)
+#define DEV_ASSIGN	strlcpy(__entry->wiphy_name,	\
+				wiphy_name(dev->hw->wiphy), MAXNAME)
+#define DEV_PR_FMT	"%s "
+#define DEV_PR_ARG	__entry->wiphy_name
 
 #define REG_ENTRY	__field(u32, reg) __field(u32, val)
 #define REG_ASSIGN	__entry->reg = reg; __entry->val = val
@@ -54,7 +55,7 @@ DECLARE_EVENT_CLASS(urb_transfer,
 	TP_PROTO(struct mt76_dev *dev, struct urb *u),
 	TP_ARGS(dev, u),
 	TP_STRUCT__entry(
-		DEV_ENTRY __field(unsigned, pipe) __field(u32, len)
+		DEV_ENTRY __field(unsigned int, pipe) __field(u32, len)
 	),
 	TP_fast_assign(
 		DEV_ASSIGN;
diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
index 9f8d59269a9e..fe3479c8e561 100644
--- a/drivers/net/wireless/mediatek/mt76/util.h
+++ b/drivers/net/wireless/mediatek/mt76/util.h
@@ -12,7 +12,7 @@
 #include <linux/bitfield.h>
 
 #define MT76_INCR(_var, _size) \
-	_var = (((_var) + 1) % _size)
+	(_var = (((_var) + 1) % (_size)))
 
 int mt76_wcid_alloc(unsigned long *mask, int size);
 
@@ -25,7 +25,7 @@ mt76_wcid_free(unsigned long *mask, int idx)
 static inline void
 mt76_skb_set_moredata(struct sk_buff *skb, bool enable)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
 	if (enable)
 		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-- 
2.18.0


^ permalink raw reply related

* Re: [PATCH 31/49] ath11k: add mac.c
From: Vasanthakumar Thiagarajan @ 2019-08-21  5:02 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen
  Cc: Kalle Valo, linux-wireless, ath11k, devicetree,
	linux-wireless-owner
In-Reply-To: <8736hvu6e6.fsf@toke.dk>

On 2019-08-20 22:21, Toke Høiland-Jørgensen wrote:
> [... snip ... ]
> 
>> +static const struct ieee80211_ops ath11k_ops = {
>> +	.tx				= ath11k_mac_op_tx,
> 
> No wake_tx_queue? :(

Yes, packet queueing is handled in firmware. This makes sense especially 
when we enable 802.11 encap
offload support where most of the data path processing in mac80211 will 
be skipped and packet is given
to driver/firmware in 802.3 format itself. Then firmware would take care 
of all the classification,
queueing and encapsulation operations.

Vasanth

^ permalink raw reply

* Re: PROBLEM: 5.3.0-rc* causes iwlwifi failure
From: Luciano Coelho @ 2019-08-21  5:04 UTC (permalink / raw)
  To: Stuart Little
  Cc: Serge Belyshev, Johannes Berg, Emmanuel Grumbach, kernel list,
	Intel Linux Wireless, linux-wireless, Haim Dreyfuss
In-Reply-To: <20190820233734.GA1406@chirva-slack.chirva-slack>

On Tue, 2019-08-20 at 19:37 -0400, Stuart Little wrote:
> On Tue, Aug 20, 2019 at 01:45:37PM +0300, Luciano Coelho wrote:
> > I'll have to look into all NIC/FW-version combinations that we have
> > and
> > update the iwl_mvm_sar_geo_support() function accordingly, which
> > is,
> > BTW, the easier place for you to change if you want to workaround
> > the
> > issue.
> 
> Thanks!
> 
> I didn't quite know how to interpret this suggestion (i.e. what the
> change should be), so I was poking around in there out of curiosity.
> One simple-minded thing that worked was to just pretend that that
> function always returns false:
> 
> --- cut here ---
> 
> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
> b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
> index 5de54d1559dd..8c0160e5588f 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
> @@ -925,7 +925,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm
> *mvm)
>                 .data = { data },
>         };
>  
> -       if (!iwl_mvm_sar_geo_support(mvm))
> +       /*if (!iwl_mvm_sar_geo_support(mvm))*/
>                 return -EOPNOTSUPP;
>  
>         ret = iwl_mvm_send_cmd(mvm, &cmd);
> @@ -953,7 +953,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm
> *mvm)
>         int ret, i, j;
>         u16 cmd_wide_id =  WIDE_ID(PHY_OPS_GROUP,
> GEO_TX_POWER_LIMIT);
>  
> -       if (!iwl_mvm_sar_geo_support(mvm))
> +       /*if (!iwl_mvm_sar_geo_support(mvm))*/
>                 return 0;
>  
>         ret = iwl_mvm_sar_get_wgds_table(mvm);
> 
> --- cut here ---

Yeah, I meant more or less to return false for your NIC.  You could
have just forced that function return false.

--
Cheers,
Luca.


^ permalink raw reply

* Re: iwlwifi 9000 issue with FW v46
From: Luca Coelho @ 2019-08-21  5:29 UTC (permalink / raw)
  To: Alexander Beregalov, linux-wireless
In-Reply-To: <CAA1sL1SoUWqQ7TRFnsPthHpPRhYjF6cnSh0tTY4nwO2O=FAGUQ@mail.gmail.com>

Hi Alex,

On Thu, 2019-08-01 at 16:30 -0400, Alexander Beregalov wrote:
> Hello,
> After some update WiFi stopped working, there is an error with FW 9000 ver46
> /lib/firmware/iwlwifi-9000-pu-b0-jf-b0-46.ucode
> 
> iwlwifi 0000:00:14.3: loaded firmware version 46.a41adfe7.0 op_mode iwlmvm
> iwlwifi 0000:00:14.3: Detected Intel(R) Dual Band Wireless AC 9560, REV=0x318
> iwlwifi 0000:00:14.3: Applying debug destination EXTERNAL_DRAM
> iwlwifi 0000:00:14.3: FW already configured (0) - re-configuring
> iwlwifi 0000:00:14.3: Microcode SW error detected. Restarting 0x0.
> iwlwifi 0000:00:14.3: Start IWL Error Log Dump:
> iwlwifi 0000:00:14.3: Status: 0x00000100, count: 6
> iwlwifi 0000:00:14.3: Loaded firmware version: 46.a41adfe7.0
> ieee80211 phy0: Hardware restart was requested
> iwlwifi 0000:00:14.3: iwlwifi transaction failed, dumping registers
> iwlwifi 0000:00:14.3: iwlwifi device config registers:
> iwlwifi 0000:00:14.3: 00000000: 9df08086 00100406 02800030 00800010
> a121c004 00000000 00000000 00000000
> iwlwifi 0000:00:14.3: 00000020: 00000000 00000000 00000000 42348086
> 00000000 000000c8 00000000 000001ff
> iwlwifi 0000:00:14.3: iwlwifi device memory mapped registers:
> iwlwifi 0000:00:14.3: 00000000: 00c89008 00000040 00000000 00000000
> 00000000 00000000 00000000 00000000
> iwlwifi 0000:00:14.3: 00000020: 00000000 0c040005 00000312 d55555d5
> d55555d5 d55555d5 80008040 041f0040
> iwlwifi 0000:00:14.3: FW error in SYNC CMD GEO_TX_POWER_LIMIT
> 
> FW is provided by
> iwl7260-firmware-25.30.13.0-99.fc30.noarch
> 
> Kernel is 5.1.16-300.fc30.x86_64
> Full dmesg is attached
> 
> ver43 does work
> 
> iwlwifi 0000:00:14.3: Direct firmware load for
> iwlwifi-9000-pu-b0-jf-b0-46.ucode failed with error -2
> iwlwifi 0000:00:14.3: Direct firmware load for
> iwlwifi-9000-pu-b0-jf-b0-45.ucode failed with error -2
> iwlwifi 0000:00:14.3: Direct firmware load for
> iwlwifi-9000-pu-b0-jf-b0-44.ucode failed with error -2
> iwlwifi 0000:00:14.3: loaded firmware version 43.95eb4e97.0 op_mode iwlmvm
> iwlwifi 0000:00:14.3: Detected Intel(R) Dual Band Wireless AC 9560, REV=0x318
> iwlwifi 0000:00:14.3: base HW address: a8:6d:aa:5e:59:ed
> ieee80211 phy0: Selected rate control algorithm 'iwl-mvm-rs'
> thermal thermal_zone8: failed to read out thermal zone (-61)
> iwlwifi 0000:00:14.3 wlo1: renamed from wlan0
> wlo1: authenticate with 70:b3:17:4a:cc:ce
> wlo1: send auth to 70:b3:17:4a:cc:ce (try 1/3)
> wlo1: authenticated
> 
> I also tried iwlwifi-9000-pu-b0-jf-b0-46.ucode from git
> (git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git)
> with the same result, however images are different:
> FC30: size 1460788, md5 43103f10a8f8657db3f5791f5d0e82aa
> git: size 1467952, md5 b0158bcaded550a01f9c446bb7940a9e

This problem was solved with the following patch:

https://patchwork.kernel.org/patch/11021735/

I have sent it to stable v5.2 and Greg queued it for the next stable
release.  Not that v5.1 has reached EOL, so it will probably never get
the fix.

--
Cheers,
Luca.


^ permalink raw reply

* RE: [PATCH 2/7] ath10k: change max RX bundle size from 8 to 32 for sdio
From: Wen Gong @ 2019-08-21  6:01 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, Wen Gong,
	ath10k@lists.infradead.org
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <87ef1gt49d.fsf@toke.dk>

> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Toke
> Høiland-Jørgensen
> Sent: Tuesday, August 20, 2019 8:23 PM
> To: Wen Gong <wgong@codeaurora.org>; ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
> 32 for sdio
> 
> Wen Gong <wgong@codeaurora.org> writes:
> 
> > The max bundle size support by firmware is 32, change it from 8 to 32
> > will help performance. This results in significant performance
> > improvement on RX path.
> 
> What happens when the hardware doesn't have enough data to fill a
> bundle? Does it send a smaller one, or does it wait until it can fill
> it?
> 

The bundle is filled by firmware. 
It will not wait until it can fill it.
For example, if you do ping per second, it will have only 1 ping packet
In the bundle.

> -Toke
> 
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply

* pull-request: wireless-drivers 2019-08-21
From: Kalle Valo @ 2019-08-21  6:07 UTC (permalink / raw)
  To: David Miller; +Cc: linux-wireless, netdev, linux-kernel, Johannes Berg

Hi Dave,

here's a pull request to net for 5.3, more info below. I will be offline
the next week, but Johannes should be able to help if there are any
issues.

Kalle


The following changes since commit d1abaeb3be7b5fa6d7a1fbbd2e14e3310005c4c1:

  Linux 5.3-rc5 (2019-08-18 14:31:08 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git tags/wireless-drivers-for-davem-2019-08-21

for you to fetch changes up to 5a8c31aa63578cb0ff390a57537f1cb4b312a1ed:

  iwlwifi: pcie: fix recognition of QuZ devices (2019-08-20 17:00:42 +0300)

----------------------------------------------------------------
wireless-drivers fixes for 5.3

Third set of fixes for 5.3, and most likely the last one. The rt2x00
regression has been reported multiple times, others are of lower
priority.

mt76

* fix hang on resume on certain machines

rt2x00

* fix AP mode regression related to encryption

iwlwifi

* avoid unnecessary error messages due to multicast frames when not
  associated

* fix configuration for ax201 devices

* fix recognition of QuZ devices

----------------------------------------------------------------
Emmanuel Grumbach (1):
      iwlwifi: pcie: fix the byte count table format for 22560 devices

Ilan Peer (1):
      iwlwifi: mvm: Allow multicast data frames only when associated

Luca Coelho (2):
      iwlwifi: pcie: don't switch FW to qnj when ax201 is detected
      iwlwifi: pcie: fix recognition of QuZ devices

Stanislaw Gruszka (2):
      mt76: mt76x0u: do not reset radio on resume
      rt2x00: clear IV's on start to fix AP mode regression

 drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 33 ++++++++++++++++++++---
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +++++++
 drivers/net/wireless/intel/iwlwifi/pcie/drv.c     | 17 ++++++++++++
 drivers/net/wireless/intel/iwlwifi/pcie/trans.c   |  1 +
 drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 20 +++++++++-----
 drivers/net/wireless/mediatek/mt76/mt76x0/usb.c   |  8 +++---
 drivers/net/wireless/ralink/rt2x00/rt2800lib.c    |  9 +++++++
 drivers/net/wireless/ralink/rt2x00/rt2x00.h       |  1 +
 drivers/net/wireless/ralink/rt2x00/rt2x00dev.c    | 13 +++++----
 9 files changed, 93 insertions(+), 19 deletions(-)

^ permalink raw reply

* Re: [PATCH 31/49] ath11k: add mac.c
From: Sven Eckelmann @ 2019-08-21  6:16 UTC (permalink / raw)
  To: ath11k; +Cc: Kalle Valo, linux-wireless, devicetree
In-Reply-To: <1566316095-27507-32-git-send-email-kvalo@codeaurora.org>

[-- Attachment #1: Type: text/plain, Size: 773 bytes --]

On Tuesday, 20 August 2019 17:47:57 CEST Kalle Valo wrote:
> +static void ath11k_peer_assoc_h_rates(struct ath11k *ar,
> +                                     struct ieee80211_vif *vif,
> +                                     struct ieee80211_sta *sta,
> +                                     struct peer_assoc_params *arg)
> +{
> +       struct ath11k_vif *arvif = (void *)vif->drv_priv;
> +       struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
> +       struct cfg80211_chan_def def;
> +       const struct ieee80211_supported_band *sband;
> +       const struct ieee80211_rate *rates;
> +       enum nl80211_band band;
> +       u32 ratemask;
> +       u8 rate;

rate has to be u32 [1].

Kind regards,
	Sven

[1] https://patchwork.kernel.org/patch/11089507/

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* RE: [PATCH 4/7] ath10k: disable TX complete indication of htt for sdio
From: Wen Gong @ 2019-08-21  6:20 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, Wen Gong,
	ath10k@lists.infradead.org
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <87blwkt480.fsf@toke.dk>

> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Toke
> Høiland-Jørgensen
> Sent: Tuesday, August 20, 2019 8:24 PM
> To: Wen Gong <wgong@codeaurora.org>; ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: [EXT] Re: [PATCH 4/7] ath10k: disable TX complete indication of htt
> for sdio
> 
> Wen Gong <wgong@codeaurora.org> writes:
> 
> > Tx complete message from firmware cost bus bandwidth of sdio, and bus
> > bandwidth is the bollteneck of throughput, it will effect the bandwidth
> > occupancy of data packet of TX and RX.
> >
> > This patch disable TX complete indication from firmware for htt data
> > packet, it results in significant performance improvement on TX path.
> 
> Wait, how does that work? Am I understanding it correctly that this
> replaces a per-packet TX completion with a periodic one sent out of
> band?
When this patch applied, firmware will not indicate tx complete for tx
Data, it only indicate HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
This htt msg will tell how many data tx complete without status(status maybe success/fail).
> 
> And could you explain what the credits thing is for, please? :)
For high latency bus chip, all the tx data's content(include ip/udp/tcp header
and payload) will be transfer to firmware's memory via bus.
And firmware has limited memory for tx data, the tx data's content must
Saved in firmware memory before it tx complete, if ath10k transfer tx
data more than the limit, firmware will occur error. The credit is used
to avoid ath10k exceed the limit.
> 
> -Toke
> 
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply

* [PATCH] ath10k: add reorder and change PN check logic for mac80211
From: Wen Gong @ 2019-08-21  6:23 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless

For sdio chip, if the rssi is not good, then it have some retry,
firmware will indicate the msdu list of a ppdu with a hole, it
means it lost the hole msdu, after the msdu retry from AP, the
hole msdu will indicate from firmware later. The hole msdu's PN
check will fail and the hole msdu will be dropped.

PN check fail example:
Sequence number PN number  PN check status
     3814         6101         success
     3815         6102         success
     3816         6103         success
     3818         6105         success
     3819         6106         success
     3820         6107         success
     3817         6104         fail

The correct logic is reorder the msdu list and then do PN check.
ieee80211_rx_reorder_ampdu of mac80211 will do the reorer logic
and then do PN check in ieee80211_rx_h_decrypt of mac80211.

example after reorder:
Sequence number PN number  PN check status
     3814         6101         success
     3815         6102         success
     3816         6103         success
     3817         6104         success
     3818         6105         success
     3819         6106         success
     3820         6107         success

Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00017-QCARMSWP-1.

Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 91 +++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 83a7fb6..53f1095 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2151,6 +2151,10 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 	struct ath10k_peer *peer;
 	struct htt_rx_indication_mpdu_range *mpdu_ranges;
 	struct fw_rx_desc_hl *fw_desc;
+	enum htt_txrx_sec_cast_type sec_index;
+	enum htt_security_types sec_type;
+	union htt_rx_pn_t new_pn = {0};
+	struct htt_hl_rx_desc *rx_desc;
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_rx_status *rx_status;
 	u16 peer_id;
@@ -2158,9 +2162,11 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 	int num_mpdu_ranges;
 	size_t tot_hdr_len;
 	struct ieee80211_channel *ch;
-	bool pn_invalid;
+	bool pn_invalid, qos, first_msdu;
+	u32 tid, rx_desc_info;
 
 	peer_id = __le16_to_cpu(rx->hdr.peer_id);
+	tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
 
 	spin_lock_bh(&ar->data_lock);
 	peer = ath10k_peer_find_by_id(ar, peer_id);
@@ -2168,6 +2174,9 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 	if (!peer && peer_id != HTT_INVALID_PEERID)
 		ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id);
 
+	if (!peer)
+		return true;
+
 	num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
 			     HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
 	mpdu_ranges = htt_rx_ind_get_mpdu_ranges_hl(rx);
@@ -2192,10 +2201,24 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 		goto err;
 	}
 
-	if (check_pn_type == HTT_RX_PN_CHECK) {
+	rx_desc = (struct htt_hl_rx_desc *)&rx->mpdu_ranges[num_mpdu_ranges];
+	rx_desc_info = __le32_to_cpu(rx_desc->info);
+
+	if (MS(rx_desc_info, HTT_RX_DESC_HL_INFO_MCAST_BCAST))
+		sec_index = HTT_TXRX_SEC_MCAST;
+	else
+		sec_index = HTT_TXRX_SEC_UCAST;
+
+	sec_type = peer->rx_pn[sec_index].sec_type;
+	first_msdu = rx->fw_desc.flags & FW_RX_DESC_FLAGS_FIRST_MSDU;
+
+	ath10k_htt_rx_mpdu_desc_pn_hl(rx_desc, &new_pn, peer->rx_pn[sec_index].pn_len);
+
+	if (check_pn_type == HTT_RX_PN_CHECK && tid >= IEEE80211_NUM_TIDS) {
 		spin_lock_bh(&ar->data_lock);
 		pn_invalid = ath10k_htt_rx_pn_check_replay_hl(ar, peer, rx);
 		spin_unlock_bh(&ar->data_lock);
+
 		if (pn_invalid)
 			goto err;
 	}
@@ -2211,6 +2234,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 	skb_pull(skb, tot_hdr_len);
 
 	hdr = (struct ieee80211_hdr *)skb->data;
+	qos = ieee80211_is_data_qos(hdr->frame_control);
 	rx_status = IEEE80211_SKB_RXCB(skb);
 	rx_status->chains |= BIT(0);
 	if (rx->ppdu.combined_rssi == 0) {
@@ -2254,6 +2278,55 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 		rx_status->flag |= RX_FLAG_DECRYPTED |
 				   RX_FLAG_IV_STRIPPED |
 				   RX_FLAG_MMIC_STRIPPED;
+
+		if (tid < IEEE80211_NUM_TIDS &&
+		    first_msdu &&
+		    check_pn_type == HTT_RX_PN_CHECK &&
+		   (sec_type == HTT_SECURITY_AES_CCMP ||
+		    sec_type == HTT_SECURITY_TKIP ||
+		    sec_type == HTT_SECURITY_TKIP_NOMIC)) {
+			u8 offset, *ivp, i;
+			s8 keyidx = 0;
+			__le64 pn48 = cpu_to_le64(new_pn.pn48);
+
+			hdr = (struct ieee80211_hdr *)skb->data;
+			offset = ieee80211_hdrlen(hdr->frame_control);
+			hdr->frame_control |= __cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+			rx_status->flag &= ~RX_FLAG_IV_STRIPPED;
+
+			memmove(skb->data - IEEE80211_CCMP_HDR_LEN,
+				skb->data, offset);
+			skb_push(skb, IEEE80211_CCMP_HDR_LEN);
+			ivp = skb->data + offset;
+			memset(skb->data + offset, 0, IEEE80211_CCMP_HDR_LEN);
+			/* Ext IV */
+			ivp[IEEE80211_WEP_IV_LEN - 1] |= ATH10K_IEEE80211_EXTIV;
+
+			for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
+				if (peer->keys[i] &&
+				    peer->keys[i]->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+					keyidx = peer->keys[i]->keyidx;
+			}
+
+			/* Key ID */
+			ivp[IEEE80211_WEP_IV_LEN - 1] |= keyidx << 6;
+
+			if (sec_type == HTT_SECURITY_AES_CCMP) {
+				rx_status->flag |= RX_FLAG_MIC_STRIPPED;
+				/* pn 0, pn 1 */
+				memcpy(skb->data + offset, &pn48, 2);
+				/* pn 1, pn 3 , pn 34 , pn 5 */
+				memcpy(skb->data + offset + 4, ((u8 *)&pn48) + 2, 4);
+			} else {
+				rx_status->flag |= RX_FLAG_ICV_STRIPPED;
+				/* TSC 0 */
+				memcpy(skb->data + offset + 2, &pn48, 1);
+				/* TSC 1 */
+				memcpy(skb->data + offset, ((u8 *)&pn48) + 1, 1);
+				/* TSC 2 , TSC 3 , TSC 4 , TSC 5*/
+				memcpy(skb->data + offset + 4, ((u8 *)&pn48) + 2, 4);
+			}
+		}
 	}
 
 	if (tkip_mic_type == HTT_RX_TKIP_MIC)
@@ -2263,6 +2336,20 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 	if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
 		rx_status->flag |= RX_FLAG_MMIC_ERROR;
 
+	if (!qos && tid < IEEE80211_NUM_TIDS) {
+		u8 offset;
+		__le16 qos_ctrl = 0;
+
+		hdr = (struct ieee80211_hdr *)skb->data;
+		offset = ieee80211_hdrlen(hdr->frame_control);
+
+		hdr->frame_control |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+		memmove(skb->data - IEEE80211_QOS_CTL_LEN, skb->data, offset);
+		skb_push(skb, IEEE80211_QOS_CTL_LEN);
+		qos_ctrl = cpu_to_le16(tid);
+		memcpy(skb->data + offset, &qos_ctrl, IEEE80211_QOS_CTL_LEN);
+	}
+
 	ieee80211_rx_ni(ar->hw, skb);
 
 	/* We have delivered the skb to the upper layers (mac80211) so we
-- 
1.9.1


^ permalink raw reply related

* Re: PROBLEM: 5.3.0-rc* causes iwlwifi failure
From: Sedat Dilek @ 2019-08-21  6:49 UTC (permalink / raw)
  To: Luciano Coelho
  Cc: Stuart Little, Serge Belyshev, Johannes Berg, Emmanuel Grumbach,
	kernel list, Intel Linux Wireless, linux-wireless, Haim Dreyfuss
In-Reply-To: <1b1e573e6502c97851838a3b27ac0b272198926c.camel@intel.com>

On Tue, Aug 20, 2019 at 12:45 PM Luciano Coelho
<luciano.coelho@intel.com> wrote:
>
> On Sat, 2019-08-17 at 17:44 -0400, Stuart Little wrote:
> > After some private coaching from Serge Belyshev on git-revert I can
> > confirm that reverting that commit atop the current tree resolves the
> > issue (the wifi card scans for and finds networks just fine, no dmesg
> > errors reported, etc.).
>
> Sorry for the delay in responding, I had to go and dig in our FW
> sources to see what was going on.
>
> Unfortunately when this feature was implemented in the FW, we forgot to
> add the usual flag (capabilities TLV) that we add to let the driver
> know whether the command is supported or not.  So we need to match on
> the FW version instead, but apparently that doesn't work for all
> different NICs.
>
> I'll have to look into all NIC/FW-version combinations that we have and
> update the iwl_mvm_sar_geo_support() function accordingly, which is,
> BTW, the easier place for you to change if you want to workaround the
> issue.

For the records (here: Linux v5.2.y)

"iwlwifi: Add support for SAR South Korea limitation"
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/commit/?h=linux-5.2.y&id=2b9d99b399d5e4cd516973a4c56035fb0e2ee744

- Sedat -

^ permalink raw reply

* Re: [PATCH 1/1] nl80211: AP deauthentication flooding.
From: Johannes Berg @ 2019-08-21  7:11 UTC (permalink / raw)
  To: Balakrishna Bandi; +Cc: linux-wireless
In-Reply-To: <1566336839-11508-1-git-send-email-b.balakrishna@globaledgesoft.com>

On Wed, 2019-08-21 at 03:03 +0530, Balakrishna Bandi wrote:
> AP sends deauth per each data frame to STA which is not associated to
> AP. Non associated STA keeps on sending data frame and leads to deauth
> flooding.

Yeah. I've sort of vaguely known about this issue, but never got around
to it. Thanks.

> Fix to be sending at-most single deauth per second if AP receive data frame from
> non-associated STA.

Can you please add to the commit message why this should be done in the
kernel? I have a feeling that perhaps pushing out all those nl80211
events might also overwhelm hostapd etc. but it'd be good to state this
here.

> +/**
> + * This timer will check for expired node and it will delete that node.
> + * Timer will run for every 10 seconds till list is empty.
> + **/

This isn't kernel-doc so the ** should just be *.

> +void cfg80211_non_assoc_sta_timer_wk(struct work_struct *work)
> +{
> +	struct delayed_work *delayed_work = to_delayed_work(work);
> +	struct cfg80211_non_assoc_stas_info *uk_stas_info;

What should "uk" mean here? Doesn't seem very obvious to me?

> +	struct cfg80211_non_assoc_single_sta_info *sta, *tsta;
> +
> +	uk_stas_info = container_of(delayed_work,
> +			struct cfg80211_non_assoc_stas_info, sta_update_timer);
> +
> +	if (list_empty(&uk_stas_info->non_assoc_sta_list))
> +		return;
> +
> +	spin_lock(&uk_stas_info->sta_lock);

This quite likely needs to be spin_lock_bh() since you're in a worker
(process context) here, but the RX path may be in a tasklet.

> +	list_for_each_entry_safe(sta, tsta,
> +	 &uk_stas_info->non_assoc_sta_list, list) {
> +	/* Clearing the node if we didn't receive any packet within 4 seconds */
> +	    if (time_before(sta->last_rx_pkt +
> +	     (CFG80211_NON_ASSOC_MIN_CACHE_UPDATE * HZ), jiffies)) {
> +	        list_del(&sta->list);
> +	        kfree(sta);
> +	    }
> +	}

You have a lot of coding style issues in this patch, please run
checkpatch and address those.

> +static void cfg80211_non_assoc_sta_info_alloc(
> +	                struct cfg80211_registered_device *rdev)
> +{
> +	rdev->non_assoc_stas_info = kzalloc(
> +	    sizeof(struct cfg80211_non_assoc_stas_info), GFP_KERNEL);
> +	if (!rdev->non_assoc_stas_info)
> +		return;


I think you should just embed the struct instead of allocating it.

> +	struct cfg80211_non_assoc_stas_info *non_assoc_stas_info;

Here I mean, just make that the struct itself rather than a pointer,
there's no value in the extra allocation since it's always done anyway.

> +struct cfg80211_non_assoc_single_sta_info {
> +       u8 address[ETH_ALEN];
> +       u16 count;
> +       unsigned long last_rx_pkt;
> +       struct list_head list;
> +};

I don't think you need the count?

> +struct cfg80211_non_assoc_single_sta_info * cfg80211_find_non_assoc_sta_entry(
> +	struct cfg80211_non_assoc_stas_info *uk_stas_info, const u8 *addr)
> +{
> +	struct cfg80211_non_assoc_single_sta_info *sta, *find_sta = NULL;
> +
> +	spin_lock(&uk_stas_info->sta_lock);
> +	list_for_each_entry(sta, &uk_stas_info->non_assoc_sta_list, list) {
> +	    if (ether_addr_equal(addr, sta->address)) {

We really should use a hashtable here, this linear list walk is going to
be an attack vector itself. I'd say rhashtable is a good idea.

> +	/* If we didn't find the station, creating new node. Else, updating the time */

Also, we need to limit the # of entries in this list (which should be a
hashtable).

The interesting question is what we should do if we overflow our
hashtable limit (i.e. the max # of stations we're willing to have
there).

Arguably, this constitutes an attack scenario, and in that case we
should just start dropping things completely, i.e. not respond with
deauth even if we *don't* have an entry in the hashtable.


Btw, we have similar patterns elsewhere (e.g. RX of data frames in IBSS
where we'd like to send probe requests, not deauth), so we should
probably expose the struct, init functionality and some helpers in
cfg80211.h so we can use it elsewhere in a general fashion.


> +	if (sta) {
> +	/* Checking pkt is received within second. If we didn't update, sending deauth packet */
> +	    if (time_after(sta->last_rx_pkt + HZ, jiffies))
> +	        deauth = false;
> +	    else
> +	        sta->last_rx_pkt = jiffies;

Not sure I understand this - wouldn't we just always suppress the event
to userspace (btw, we don't actually send the deauth, so you should
adjust the comments here, we send the event to userspace) if we have an
entry, and expire the entry after ~1s? Why keep the entries alive for
longer than that?

Or maybe not - you keep the entries alive, but send the event up even if
the entry is alive, but didn't actually cause an event in the past
second, I guess?

Maybe that one second should also be a bit less? Yeah, we don't want to
flood, but keeping the station waiting for a second if it got
desynchronized feels a bit long?

> +	} else {
> +	    sta = kzalloc(sizeof
> +	     (struct cfg80211_non_assoc_single_sta_info), GFP_ATOMIC);
> +	    if (sta == NULL)
> +	        return true;

Also, you should put all those return paths go through a common place
and still call the tracing, not just in the case where we actually send
the event.

> +	    memcpy(sta->address, addr, ETH_ALEN);
> +	    spin_lock(&rdev->non_assoc_stas_info->sta_lock);
> +	    list_add(&sta->list,
> +	        &rdev->non_assoc_stas_info->non_assoc_sta_list);
> +	    spin_unlock(&rdev->non_assoc_stas_info->sta_lock);
> +	    sta->last_rx_pkt = jiffies;
> +	}
> +
> +	sta->count++;
> +
> +	if (run_timer)
> +	    schedule_delayed_work(
> +	        &rdev->non_assoc_stas_info->sta_update_timer,
> +	        CFG80211_NON_ASSOC_FILTER_TIMER_INT * HZ);

You don't really need the "run_timer" variable, you can just trigger the
timer at the beginning? In the unlikely event that you have an
allocation failure here, you'd run the time once too much, but that
seems acceptable to me, the allocation is very unlikely to fail.

johannes


^ permalink raw reply

* [PATCH] ath10k: add fw coredump for sdio when firmware assert
From: Wen Gong @ 2019-08-21  7:19 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless

When firmware assert, it need coredump to analyze, this patch will
collect the register and memory info for sdio chip.

The coredump configuration is different between PCIE and SDIO for
the same reversion, so this patch add bus type to distinguish PCIE
and SDIO chip for coredump.

Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.

Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/bmi.c       |   1 +
 drivers/net/wireless/ath/ath10k/core.c      |   7 +-
 drivers/net/wireless/ath/ath10k/core.h      |   4 +-
 drivers/net/wireless/ath/ath10k/coredump.c  | 338 +++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/coredump.h  |   1 +
 drivers/net/wireless/ath/ath10k/hw.h        |   1 +
 drivers/net/wireless/ath/ath10k/sdio.c      | 335 ++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/targaddrs.h |  10 +
 8 files changed, 692 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c
index 95dc4be..990fa4d 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -197,6 +197,7 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
 
 	return 0;
 }
+EXPORT_SYMBOL(ath10k_bmi_read_memory);
 
 int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
 {
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index dc45d16..0ea4c36 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -33,7 +33,6 @@
 static bool skip_otp;
 static bool rawmode;
 static bool fw_diag_log;
-
 unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) |
 				     BIT(ATH10K_FW_CRASH_DUMP_CE_DATA);
 
@@ -708,6 +707,10 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
 	ath10k_bmi_read32(ar, hi_option_flag, &param);
 	param |= HI_OPTION_DISABLE_DBGLOG;
 	ath10k_bmi_write32(ar, hi_option_flag, param);
+
+	ath10k_bmi_read32(ar, hi_option_flag2, &param);
+	param |= HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST;
+	ath10k_bmi_write32(ar, hi_option_flag2, param);
 }
 
 static int ath10k_init_configure_target(struct ath10k *ar)
@@ -1953,6 +1956,8 @@ static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name,
 		scnprintf(fw_name, fw_name_len, "%s-%d.bin",
 			  ATH10K_FW_FILE_BASE, fw_api);
 		break;
+	default:
+		break;
 	}
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4d7db07..1b52a3c 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -97,7 +97,9 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
 		return "usb";
 	case ATH10K_BUS_SNOC:
 		return "snoc";
-	}
+	default:
+		return "unknown";
+}
 
 	return "unknown";
 }
diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c
index b6d2932..b287509 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.c
+++ b/drivers/net/wireless/ath/ath10k/coredump.c
@@ -270,6 +270,277 @@
 	{0x80010, 0x80020},
 };
 
+static const struct ath10k_mem_section qca6174_hw30_sdio_register_sections[] = {
+	{0x800, 0x810},
+	{0x820, 0x82C},
+	{0x830, 0x8F4},
+	{0x90C, 0x91C},
+	{0xA14, 0xA18},
+	{0xA84, 0xA94},
+	{0xAA8, 0xAD4},
+	{0xADC, 0xB40},
+	{0x1000, 0x10A4},
+	{0x10BC, 0x111C},
+	{0x1134, 0x1138},
+	{0x1144, 0x114C},
+	{0x1150, 0x115C},
+	{0x1160, 0x1178},
+	{0x1240, 0x1260},
+	{0x2000, 0x207C},
+	{0x3000, 0x3014},
+	{0x4000, 0x4014},
+	{0x5000, 0x5124},
+	{0x6000, 0x6040},
+	{0x6080, 0x60CC},
+	{0x6100, 0x611C},
+	{0x6140, 0x61D8},
+	{0x6200, 0x6238},
+	{0x6240, 0x628C},
+	{0x62C0, 0x62EC},
+	{0x6380, 0x63E8},
+	{0x6400, 0x6440},
+	{0x6480, 0x64CC},
+	{0x6500, 0x651C},
+	{0x6540, 0x6580},
+	{0x6600, 0x6638},
+	{0x6640, 0x668C},
+	{0x66C0, 0x66EC},
+	{0x6780, 0x67E8},
+	{0x7080, 0x708C},
+	{0x70C0, 0x70C8},
+	{0x7400, 0x741C},
+	{0x7440, 0x7454},
+	{0x7800, 0x7818},
+	{0x8010, 0x8060},
+	{0x8080, 0x8084},
+	{0x80A0, 0x80A4},
+	{0x80C0, 0x80C4},
+	{0x80E0, 0x80ec},
+	{0x8110, 0x8128},
+	{0x9000, 0x9004},
+	{0xF000, 0xF0E0},
+	{0xF140, 0xF190},
+	{0xF250, 0xF25C},
+	{0xF260, 0xF268},
+	{0xF26C, 0xF2A8},
+	{0x10008, 0x1000C},
+	{0x10014, 0x10018},
+	{0x1001C, 0x10020},
+	{0x10024, 0x10028},
+	{0x10030, 0x10034},
+	{0x10040, 0x10054},
+	{0x10058, 0x1007C},
+	{0x10080, 0x100C4},
+	{0x100C8, 0x10114},
+	{0x1012C, 0x10130},
+	{0x10138, 0x10144},
+	{0x10200, 0x10220},
+	{0x10230, 0x10250},
+	{0x10260, 0x10280},
+	{0x10290, 0x102B0},
+	{0x102C0, 0x102DC},
+	{0x102E0, 0x102F4},
+	{0x102FC, 0x1037C},
+	{0x10380, 0x10390},
+	{0x10800, 0x10828},
+	{0x10840, 0x10844},
+	{0x10880, 0x10884},
+	{0x108C0, 0x108E8},
+	{0x10900, 0x10928},
+	{0x10940, 0x10944},
+	{0x10980, 0x10984},
+	{0x109C0, 0x109E8},
+	{0x10A00, 0x10A28},
+	{0x10A40, 0x10A50},
+	{0x11000, 0x11028},
+	{0x11030, 0x11034},
+	{0x11038, 0x11068},
+	{0x11070, 0x11074},
+	{0x11078, 0x110A8},
+	{0x110B0, 0x110B4},
+	{0x110B8, 0x110E8},
+	{0x110F0, 0x110F4},
+	{0x110F8, 0x11128},
+	{0x11138, 0x11144},
+	{0x11178, 0x11180},
+	{0x111B8, 0x111C0},
+	{0x111F8, 0x11200},
+	{0x11238, 0x1123C},
+	{0x11270, 0x11274},
+	{0x11278, 0x1127C},
+	{0x112B0, 0x112B4},
+	{0x112B8, 0x112BC},
+	{0x112F0, 0x112F4},
+	{0x112F8, 0x112FC},
+	{0x11338, 0x1133C},
+	{0x11378, 0x1137C},
+	{0x113B8, 0x113BC},
+	{0x113F8, 0x113FC},
+	{0x11438, 0x11440},
+	{0x11478, 0x11480},
+	{0x114B8, 0x114BC},
+	{0x114F8, 0x114FC},
+	{0x11538, 0x1153C},
+	{0x11578, 0x1157C},
+	{0x115B8, 0x115BC},
+	{0x115F8, 0x115FC},
+	{0x11638, 0x1163C},
+	{0x11678, 0x1167C},
+	{0x116B8, 0x116BC},
+	{0x116F8, 0x116FC},
+	{0x11738, 0x1173C},
+	{0x11778, 0x1177C},
+	{0x117B8, 0x117BC},
+	{0x117F8, 0x117FC},
+	{0x17000, 0x1701C},
+	{0x17020, 0x170AC},
+	{0x18000, 0x18050},
+	{0x18054, 0x18074},
+	{0x18080, 0x180D4},
+	{0x180DC, 0x18104},
+	{0x18108, 0x1813C},
+	{0x18144, 0x18148},
+	{0x18168, 0x18174},
+	{0x18178, 0x18180},
+	{0x181C8, 0x181E0},
+	{0x181E4, 0x181E8},
+	{0x181EC, 0x1820C},
+	{0x1825C, 0x18280},
+	{0x18284, 0x18290},
+	{0x18294, 0x182A0},
+	{0x18300, 0x18304},
+	{0x18314, 0x18320},
+	{0x18328, 0x18350},
+	{0x1835C, 0x1836C},
+	{0x18370, 0x18390},
+	{0x18398, 0x183AC},
+	{0x183BC, 0x183D8},
+	{0x183DC, 0x183F4},
+	{0x18400, 0x186F4},
+	{0x186F8, 0x1871C},
+	{0x18720, 0x18790},
+	{0x19800, 0x19830},
+	{0x19834, 0x19840},
+	{0x19880, 0x1989C},
+	{0x198A4, 0x198B0},
+	{0x198BC, 0x19900},
+	{0x19C00, 0x19C88},
+	{0x19D00, 0x19D20},
+	{0x19E00, 0x19E7C},
+	{0x19E80, 0x19E94},
+	{0x19E98, 0x19EAC},
+	{0x19EB0, 0x19EBC},
+	{0x19F70, 0x19F74},
+	{0x19F80, 0x19F8C},
+	{0x19FA0, 0x19FB4},
+	{0x19FC0, 0x19FD8},
+	{0x1A000, 0x1A200},
+	{0x1A204, 0x1A210},
+	{0x1A228, 0x1A22C},
+	{0x1A230, 0x1A248},
+	{0x1A250, 0x1A270},
+	{0x1A280, 0x1A290},
+	{0x1A2A0, 0x1A2A4},
+	{0x1A2C0, 0x1A2EC},
+	{0x1A300, 0x1A3BC},
+	{0x1A3F0, 0x1A3F4},
+	{0x1A3F8, 0x1A434},
+	{0x1A438, 0x1A444},
+	{0x1A448, 0x1A468},
+	{0x1A580, 0x1A58C},
+	{0x1A644, 0x1A654},
+	{0x1A670, 0x1A698},
+	{0x1A6AC, 0x1A6B0},
+	{0x1A6D0, 0x1A6D4},
+	{0x1A6EC, 0x1A70C},
+	{0x1A710, 0x1A738},
+	{0x1A7C0, 0x1A7D0},
+	{0x1A7D4, 0x1A7D8},
+	{0x1A7DC, 0x1A7E4},
+	{0x1A7F0, 0x1A7F8},
+	{0x1A888, 0x1A89C},
+	{0x1A8A8, 0x1A8AC},
+	{0x1A8C0, 0x1A8DC},
+	{0x1A8F0, 0x1A8FC},
+	{0x1AE04, 0x1AE08},
+	{0x1AE18, 0x1AE24},
+	{0x1AF80, 0x1AF8C},
+	{0x1AFA0, 0x1AFB4},
+	{0x1B000, 0x1B200},
+	{0x1B284, 0x1B288},
+	{0x1B2D0, 0x1B2D8},
+	{0x1B2DC, 0x1B2EC},
+	{0x1B300, 0x1B340},
+	{0x1B374, 0x1B378},
+	{0x1B380, 0x1B384},
+	{0x1B388, 0x1B38C},
+	{0x1B404, 0x1B408},
+	{0x1B420, 0x1B428},
+	{0x1B440, 0x1B444},
+	{0x1B448, 0x1B44C},
+	{0x1B450, 0x1B458},
+	{0x1B45C, 0x1B468},
+	{0x1B584, 0x1B58C},
+	{0x1B68C, 0x1B690},
+	{0x1B6AC, 0x1B6B0},
+	{0x1B7F0, 0x1B7F8},
+	{0x1C800, 0x1CC00},
+	{0x1CE00, 0x1CE04},
+	{0x1CF80, 0x1CF84},
+	{0x1D200, 0x1D800},
+	{0x1E000, 0x20014},
+	{0x20100, 0x20124},
+	{0x21400, 0x217A8},
+	{0x21800, 0x21BA8},
+	{0x21C00, 0x21FA8},
+	{0x22000, 0x223A8},
+	{0x22400, 0x227A8},
+	{0x22800, 0x22BA8},
+	{0x22C00, 0x22FA8},
+	{0x23000, 0x233A8},
+	{0x24000, 0x24034},
+
+	/* EFUSE0,1,2 is disabled here
+	 * because it's state may be reset
+	 *
+	 * {0x24800, 0x24804},
+	 * {0x25000, 0x25004},
+	 * {0x25800, 0x25804},
+	 */
+
+	{0x26000, 0x26064},
+	{0x27000, 0x27024},
+	{0x34000, 0x3400C},
+	{0x34400, 0x3445C},
+	{0x34800, 0x3485C},
+	{0x34C00, 0x34C5C},
+	{0x35000, 0x3505C},
+	{0x35400, 0x3545C},
+	{0x35800, 0x3585C},
+	{0x35C00, 0x35C5C},
+	{0x36000, 0x3605C},
+	{0x38000, 0x38064},
+	{0x38070, 0x380E0},
+	{0x3A000, 0x3A074},
+
+	/* DBI windows is skipped here, it can be only accessed when pcie
+	 * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 &&
+	 * PCIE_CTRL_APP_LTSSM_ENALBE=0.
+	 * {0x3C000 , 0x3C004},
+	 */
+
+	{0x40000, 0x400A4},
+
+	/* SI register is skiped here.
+	 * Because it will cause bus hang
+	 *
+	 * {0x50000, 0x50018},
+	 */
+
+	{0x80000, 0x8000C},
+	{0x80010, 0x80020},
+};
+
 static const struct ath10k_mem_section qca6174_hw30_register_sections[] = {
 	{0x800, 0x810},
 	{0x820, 0x82C},
@@ -602,6 +873,59 @@
 	},
 };
 
+static const struct ath10k_mem_region qca6174_hw30_sdio_mem_regions[] = {
+	{
+		.type = ATH10K_MEM_REGION_TYPE_DRAM,
+		.start = 0x400000,
+		.len = 0xa8000,
+		.name = "DRAM",
+		.section_table = {
+		.sections = NULL,
+		.size = 0,
+		},
+	},
+	{
+		.type = ATH10K_MEM_REGION_TYPE_AXI,
+		.start = 0xa0000,
+		.len = 0x18000,
+		.name = "AXI",
+		.section_table = {
+			.sections = NULL,
+			.size = 0,
+		},
+	},
+	{
+		.type = ATH10K_MEM_REGION_TYPE_IRAM1,
+		.start = 0x00980000,
+		.len = 0x00080000,
+		.name = "IRAM1",
+		.section_table = {
+		.sections = NULL,
+		.size = 0,
+		},
+	},
+	{
+		.type = ATH10K_MEM_REGION_TYPE_IRAM2,
+		.start = 0x00a00000,
+		.len = 0x00040000,
+		.name = "IRAM2",
+		.section_table = {
+		.sections = NULL,
+		.size = 0,
+		},
+	},
+	{
+		.type = ATH10K_MEM_REGION_TYPE_REG,
+		.start = 0x800,
+		.len = 0x80020 - 0x800,
+		.name = "REG_TOTAL",
+		.section_table = {
+			.sections = qca6174_hw30_sdio_register_sections,
+			.size = ARRAY_SIZE(qca6174_hw30_sdio_register_sections),
+		},
+	},
+};
+
 static const struct ath10k_mem_region qca6174_hw30_mem_regions[] = {
 	{
 		.type = ATH10K_MEM_REGION_TYPE_DRAM,
@@ -995,12 +1319,22 @@
 	{
 		.hw_id = QCA6174_HW_3_2_VERSION,
 		.hw_rev = ATH10K_HW_QCA6174,
+		.bus = ATH10K_BUS_PCI,
 		.region_table = {
 			.regions = qca6174_hw30_mem_regions,
 			.size = ARRAY_SIZE(qca6174_hw30_mem_regions),
 		},
 	},
 	{
+		.hw_id = QCA6174_HW_3_2_VERSION,
+		.hw_rev = ATH10K_HW_QCA6174,
+		.bus = ATH10K_BUS_SDIO,
+		.region_table = {
+			.regions = qca6174_hw30_sdio_mem_regions,
+			.size = ARRAY_SIZE(qca6174_hw30_sdio_mem_regions),
+		},
+	},
+	{
 		.hw_id = QCA9377_HW_1_1_DEV_VERSION,
 		.hw_rev = ATH10K_HW_QCA9377,
 		.region_table = {
@@ -1090,7 +1424,9 @@ const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k
 
 	for (i = 0; i < ARRAY_SIZE(hw_mem_layouts); i++) {
 		if (ar->target_version == hw_mem_layouts[i].hw_id &&
-		    ar->hw_rev == hw_mem_layouts[i].hw_rev)
+		    ar->hw_rev == hw_mem_layouts[i].hw_rev &&
+		    (hw_mem_layouts[i].bus == ATH10K_BUS_UNDEF ||
+		     hw_mem_layouts[i].bus == ar->hif.bus))
 			return &hw_mem_layouts[i];
 	}
 
diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h
index 09de419..b191746 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.h
+++ b/drivers/net/wireless/ath/ath10k/coredump.h
@@ -155,6 +155,7 @@ struct ath10k_mem_region {
 struct ath10k_hw_mem_layout {
 	u32 hw_id;
 	u32 hw_rev;
+	enum ath10k_bus bus;
 
 	struct {
 		const struct ath10k_mem_region *regions;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 2ae57c1..d2cfd29 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -11,6 +11,7 @@
 #include "targaddrs.h"
 
 enum ath10k_bus {
+	ATH10K_BUS_UNDEF,
 	ATH10K_BUS_PCI,
 	ATH10K_BUS_AHB,
 	ATH10K_BUS_SDIO,
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 8ed4fbd..cb75463 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -23,6 +23,9 @@
 #include "targaddrs.h"
 #include "trace.h"
 #include "sdio.h"
+#include "coredump.h"
+
+void ath10k_sdio_fw_crashed_dump(struct ath10k *ar);
 
 /* inlined helper functions */
 
@@ -860,8 +863,7 @@ static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k *ar)
 out:
 	mutex_unlock(&irq_data->mtx);
 	if (cpu_int_status & MBOX_CPU_STATUS_ENABLE_ASSERT_MASK) {
-		ath10k_err(ar, "firmware crashed!\n");
-		queue_work(ar->workqueue, &ar->restart_work);
+		ath10k_sdio_fw_crashed_dump(ar);
 	}
 	return ret;
 }
@@ -1967,6 +1969,335 @@ static SIMPLE_DEV_PM_OPS(ath10k_sdio_pm_ops, ath10k_sdio_pm_suspend,
 
 #endif /* CONFIG_PM_SLEEP */
 
+static int ath10k_sdio_read_host_interest_value(struct ath10k *ar,
+						u32 item_offset,
+						u32 *val)
+{
+	u32 addr;
+	int ret;
+
+	addr = host_interest_item_address(item_offset);
+
+	ret = ath10k_sdio_hif_diag_read32(ar, addr, val);
+
+	if (ret)
+		ath10k_warn(ar, "unable to read host interest offset %d value\n",
+			    item_offset);
+
+	return ret;
+}
+
+static int ath10k_sdio_read_mem(struct ath10k *ar, u32 address, void *buf,
+				u32 buf_len)
+{
+	u32 val;
+	int i, ret;
+
+	for (i = 0; i < buf_len; i += 4) {
+		ret = ath10k_sdio_hif_diag_read32(ar, address + i, &val);
+		if (ret) {
+			ath10k_warn(ar, "unable to read mem %d value\n", address + i);
+			break;
+		}
+		memcpy(buf + i, &val, 4);
+	}
+
+	return ret;
+}
+
+void ath10k_sdio_check_fw_reg(struct ath10k *ar, u32 *fast_dump)
+{
+	int ret = 0;
+	u32 param;
+
+	ret = ath10k_sdio_read_host_interest_value(ar, HI_ITEM(hi_option_flag2), &param);
+
+	*fast_dump = ((param & HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW)
+			     == HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW);
+
+	ath10k_err(ar, "check fw reg : %x\n", param);
+}
+
+static void ath10k_sdio_dump_registers(struct ath10k *ar,
+				       struct ath10k_fw_crash_data *crash_data,
+				       u32 fast_dump)
+{
+	u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
+	int i, ret;
+	u32 reg_dump_area;
+
+	ret = ath10k_sdio_read_host_interest_value(ar, HI_ITEM(hi_failure_state),
+						   &reg_dump_area);
+	if (ret) {
+		ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
+		return;
+	}
+
+	if (fast_dump)
+		ret = ath10k_bmi_read_memory(ar, reg_dump_area, reg_dump_values,
+					     sizeof(reg_dump_values));
+	else
+		ret = ath10k_sdio_read_mem(ar, reg_dump_area, reg_dump_values,
+					   sizeof(reg_dump_values));
+
+	if (ret) {
+		ath10k_err(ar, "failed to read firmware dump value: %d\n", ret);
+		return;
+	}
+
+	ath10k_err(ar, "firmware register dump:\n");
+	for (i = 0; i < ARRAY_SIZE(reg_dump_values); i += 4)
+		ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
+			   i,
+			   reg_dump_values[i],
+			   reg_dump_values[i + 1],
+			   reg_dump_values[i + 2],
+			   reg_dump_values[i + 3]);
+
+	if (!crash_data)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(reg_dump_values); i++)
+		crash_data->registers[i] = __cpu_to_le32(reg_dump_values[i]);
+}
+
+static int ath10k_sdio_dump_memory_section(struct ath10k *ar,
+					   const struct ath10k_mem_region *mem_region,
+					   u8 *buf, size_t buf_len)
+{
+	const struct ath10k_mem_section *cur_section, *next_section;
+	unsigned int count, section_size, skip_size;
+	int ret, i, j;
+
+	if (!mem_region || !buf)
+		return 0;
+
+	cur_section = &mem_region->section_table.sections[0];
+
+	if (mem_region->start > cur_section->start) {
+		ath10k_warn(ar, "incorrect memdump region 0x%x with section start address 0x%x.\n",
+			    mem_region->start, cur_section->start);
+		return 0;
+	}
+
+	skip_size = cur_section->start - mem_region->start;
+
+	/* fill the gap between the first register section and register
+	 * start address
+	 */
+	for (i = 0; i < skip_size; i++) {
+		*buf = ATH10K_MAGIC_NOT_COPIED;
+		buf++;
+	}
+
+	count = 0;
+
+	for (i = 0; cur_section; i++) {
+		section_size = cur_section->end - cur_section->start;
+
+		if (section_size <= 0) {
+			ath10k_warn(ar, "incorrect ramdump format with start address 0x%x and stop address 0x%x\n",
+				    cur_section->start,
+				    cur_section->end);
+			break;
+		}
+
+		if ((i + 1) == mem_region->section_table.size) {
+			/* last section */
+			next_section = NULL;
+			skip_size = 0;
+		} else {
+			next_section = cur_section + 1;
+
+			if (cur_section->end > next_section->start) {
+				ath10k_warn(ar, "next ramdump section 0x%x is smaller than current end address 0x%x\n",
+					    next_section->start,
+					    cur_section->end);
+				break;
+			}
+
+			skip_size = next_section->start - cur_section->end;
+		}
+
+		if (buf_len < (skip_size + section_size)) {
+			ath10k_warn(ar, "ramdump buffer is too small: %zu\n", buf_len);
+			break;
+		}
+
+		buf_len -= skip_size + section_size;
+
+		/* read section to dest memory */
+		ret = ath10k_sdio_read_mem(ar, cur_section->start,
+					   buf, section_size);
+		if (ret) {
+			ath10k_warn(ar, "failed to read ramdump from section 0x%x: %d\n",
+				    cur_section->start, ret);
+			break;
+		}
+
+		buf += section_size;
+		count += section_size;
+
+		/* fill in the gap between this section and the next */
+		for (j = 0; j < skip_size; j++) {
+			*buf = ATH10K_MAGIC_NOT_COPIED;
+			buf++;
+		}
+
+		count += skip_size;
+
+		if (!next_section)
+			/* this was the last section */
+			break;
+
+		cur_section = next_section;
+	}
+
+	return count;
+}
+
+/* if an error happened returns < 0, otherwise the length */
+static int ath10k_sdio_dump_memory_generic(struct ath10k *ar,
+					   const struct ath10k_mem_region *current_region,
+					   u8 *buf,
+					   u32 fast_dump)
+{
+	int ret;
+
+	if (current_region->section_table.size > 0)
+		/* Copy each section individually. */
+		return ath10k_sdio_dump_memory_section(ar,
+						      current_region,
+						      buf,
+						      current_region->len);
+
+	/* No individiual memory sections defined so we can
+	 * copy the entire memory region.
+	 */
+	if (fast_dump)
+		ret = ath10k_bmi_read_memory(ar,
+					     current_region->start,
+					     buf,
+					     current_region->len);
+	else
+		ret = ath10k_sdio_read_mem(ar,
+					   current_region->start,
+					   buf,
+					   current_region->len);
+
+	if (ret) {
+		ath10k_warn(ar, "failed to copy ramdump region %s: %d\n",
+			    current_region->name, ret);
+		return ret;
+	}
+
+	return current_region->len;
+}
+
+static void ath10k_sdio_dump_memory(struct ath10k *ar,
+				    struct ath10k_fw_crash_data *crash_data,
+				    u32 fast_dump)
+{
+	const struct ath10k_hw_mem_layout *mem_layout;
+	const struct ath10k_mem_region *current_region;
+	struct ath10k_dump_ram_data_hdr *hdr;
+	u32 count;
+	size_t buf_len;
+	int ret, i;
+	u8 *buf;
+
+	if (!crash_data)
+		return;
+
+	mem_layout = ath10k_coredump_get_mem_layout(ar);
+	if (!mem_layout)
+		return;
+
+	current_region = &mem_layout->region_table.regions[0];
+
+	buf = crash_data->ramdump_buf;
+	buf_len = crash_data->ramdump_buf_len;
+
+	memset(buf, 0, buf_len);
+
+	for (i = 0; i < mem_layout->region_table.size; i++) {
+		count = 0;
+
+		if (current_region->len > buf_len) {
+			ath10k_warn(ar, "memory region %s size %d is larger that remaining ramdump buffer size %zu\n",
+				    current_region->name,
+				    current_region->len,
+				    buf_len);
+			break;
+		}
+
+		/* Reserve space for the header. */
+		hdr = (void *)buf;
+		buf += sizeof(*hdr);
+		buf_len -= sizeof(*hdr);
+
+		ret = ath10k_sdio_dump_memory_generic(ar, current_region, buf, fast_dump);
+
+		ath10k_err(ar, "dump mem, name:%s, type:%d, start:0x%x, len:0x%x, size:%d, ret:0x%x\n",
+			   current_region->name,
+			   current_region->type,
+			   current_region->start,
+			   current_region->len,
+			   current_region->section_table.size,
+			   ret);
+
+		if (ret >= 0)
+			count = ret;
+
+		hdr->region_type = cpu_to_le32(current_region->type);
+		hdr->start = cpu_to_le32(current_region->start);
+		hdr->length = cpu_to_le32(count);
+
+		if (count == 0)
+			/* Note: the header remains, just with zero length. */
+			break;
+
+		buf += count;
+		buf_len -= count;
+
+		current_region++;
+	}
+}
+
+void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
+{
+	struct ath10k_fw_crash_data *crash_data;
+	char guid[UUID_STRING_LEN + 1];
+	u32 fast_dump = 0;
+
+	ath10k_err(ar, "begin fw dump\n", guid);
+
+	ath10k_sdio_check_fw_reg(ar, &fast_dump);
+
+	if (fast_dump)
+		ar->bmi.done_sent = false;
+
+	ar->stats.fw_crash_counter++;
+
+	ath10k_sdio_hif_disable_intrs(ar);
+
+	crash_data = ath10k_coredump_new(ar);
+
+	if (crash_data)
+		scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);
+	else
+		scnprintf(guid, sizeof(guid), "n/a");
+
+	ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);
+	ath10k_print_driver_info(ar);
+	ath10k_sdio_dump_registers(ar, crash_data, fast_dump);
+	ath10k_sdio_dump_memory(ar, crash_data, fast_dump);
+
+	ath10k_sdio_hif_enable_intrs(ar);
+
+	queue_work(ar->workqueue, &ar->restart_work);
+}
+
 static int ath10k_sdio_probe(struct sdio_func *func,
 			     const struct sdio_device_id *id)
 {
diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h
index dff6c8a..c65045a 100644
--- a/drivers/net/wireless/ath/ath10k/targaddrs.h
+++ b/drivers/net/wireless/ath/ath10k/targaddrs.h
@@ -334,6 +334,16 @@ struct host_interest {
 #define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17)
 
 /*
+ * If both SDIO_CRASH_DUMP_ENHANCEMENT_HOST and SDIO_CRASH_DUMP_ENHANCEMENT_FW
+ * flags are set, then crashdump upload will be done using the BMI host/target
+ * communication channel.
+ */
+/* HOST to support using BMI dump FW memory when hit assert */
+#define HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST 0x400
+/* FW to support using BMI dump FW memory when hit assert */
+#define HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW   0x800
+
+/*
  * CONSOLE FLAGS
  *
  * Bit Range  Meaning
-- 
1.9.1


^ permalink raw reply related

* Re: [RFC 0/1] Allow MAC change on up interface
From: Johannes Berg @ 2019-08-21  7:21 UTC (permalink / raw)
  To: Denis Kenzior, Dan Williams, James Prestwood
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <86a8b422-87e3-5ab7-40fe-604969ec8ec1@gmail.com>

On Tue, 2019-08-20 at 16:52 -0500, Denis Kenzior wrote:

> I'm not sure you can state that definitively just yet?  

That's not an argument, you also cannot state definitively that it will
not happen. But yes, I'd think it _is_ in fact likely to happen at some
point for something new, maybe it won't be IBSS but NAN, or something
new that we can't even consider yet. Why close the door on it?

> So the real 
> question is whether saving the extra round-trip to the kernel is worth 
> the in-kernel complexity.

Sort of.

>   Given that interleaved system calls are _always_ a problem

They're not interleaved, they're just serial. And seriously, if syscalls
were such a big problem, we wouldn't be using them, we'd have found a
better solution.

(and FWIW, I don't feel you're really arguing in good faith here. You're
just throwing out statements like that and dismissing all other
arguments with no good explanation.)

> , I argue that it is worth it for at least the Station 
> case (and it will keep connection times even faster to boot).  Isn't 
> minimizing the latency of connections the end goal here?  I get that 
> there are trade offs and people have other opinions on what a good trade 
> off is.

That's ridiculous. If I extrapolate that statement the logical
consequence is that you should put iwd into a kernel module. You're not
doing that, last I checked? So minimizing the latency of connections is
quite clearly not the only goal here.

I understand that you're interested in minimizing the latency of
connections. I can even agree that it's a worthwhile goal. But it cannot
be the only goal.

> But don't misunderstand, either solution is better than what we have 
> today.  My argument is: "why close the door on a particular solution 
> until the costs are known?"

That's not actually what you said.

> > Not really. It's the job of maintainers to balance all these things, to
> > step back and think of the bigger picture and the future rather than
> > just solving one particular use-case today.
> >  > Your tone leaves the impression you want a particular solution pushed
> > through without the normal planning/architecture discussions that
> > accompany API changes. And that's not how the process typically works.
> > 
> 
> So who's attacking who now?  We're trying to solve a long standing issue 
> that nobody has bothered to fix for years in a clean way.  Something 
> that one of your projects would benefit from, btw.

Seriously Denis, stop it.

johannes


^ permalink raw reply

* Re: [PATCH] cfg80211: VLAN offload support for set_key and set_sta_vlan
From: Johannes Berg @ 2019-08-21  7:28 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless, Gurumoorthi Gnanasambandhan
In-Reply-To: <20190815133825.8131-1-jouni@codeaurora.org>

On Thu, 2019-08-15 at 16:38 +0300, Jouni Malinen wrote:

> +/**
> + * DOC: VLAN offload support for setting group keys and binding STAs to VLANs
> + *
> + * By setting @NL80211_EXT_FEATURE_VLAN_OFFLOAD flag drivers can indicate they
> + * support offloading VLAN functionality in a manner where the driver exposes a
> + * single netdev that used VLAN tagged frames and separate VLAN-specific netdevs
> + * can then be added using vconfig similarly to the Ethernet case.

I don't think we should be referring to vconfig these days? It's pretty
much a deprecated userspace tool, the kernel would like to think that
all of this is done over netlink with iproute2 now :-)

But even then, it should probably just reference the kernel mechanisms
(creating a VLAN netdev) than the userspace implementation thereof
(vconfig or iproute2).

Something that's not quite clear to me - I think we support some frames
on the AP interface even when VLANs are in use. Would the tagged AP/VLAN
interface actually support untagged frames, and then in what way? I
think it'd be good to specify that here.


> + * %NL80211_CMD_NEW_KEY and %NL80211_CMD_SET_STATION will optionally specify
> + * vlan_id using NL80211_ATTR_VLAN_ID.

Guess that should be %NL80211_ATTR_VLAN_ID too.

> +	[NL80211_ATTR_VLAN_ID] = { .type = NLA_U16 },

That should probably have a range, VLAN IDs can only be 1-4094 since
there's only a 12-bit field and all-0/all-1 are reserved.

Saves us from having to check it in the drivers later on, since they'd
otherwise generate invalid (or confusing) frames if there's no check.
 
>  /* policy for the key attributes */
> @@ -3865,6 +3866,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
>  	if (info->attrs[NL80211_ATTR_MAC])
>  		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
>  
> +	if (info->attrs[NL80211_ATTR_VLAN_ID])
> +		key.p.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);

Seems like there probably should be some kind of check on what type of
key can set a VLAN ID?

>  	if (key.type == -1) {
>  		if (mac_addr)
>  			key.type = NL80211_KEYTYPE_PAIRWISE;
> @@ -5647,6 +5651,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
>  	if (info->attrs[NL80211_ATTR_STA_AID])
>  		params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
>  
> +	if (info->attrs[NL80211_ATTR_VLAN_ID])
> +		params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]);

How about nl80211_new_station()? Also, should it really be allowed to
change this at will? I'm not sure we allow changing the VLAN netdev (if
used) at will?

johannes


^ permalink raw reply

* Re: [PATCH] cfg80211: VLAN offload support for set_key and set_sta_vlan
From: Johannes Berg @ 2019-08-21  7:33 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless, Gurumoorthi Gnanasambandhan
In-Reply-To: <20190820205046.GA9860@jouni.qca.qualcomm.com>

On Tue, 2019-08-20 at 23:50 +0300, Jouni Malinen wrote:

> > Without really looking at the specifics, it might be relatively simple
> > to support this in mac80211?
> 
> Yes, that is something that I was thinking about when going through
> this.. I don't remember why exactly mac80211 ended up with its current
> design for per-AP_VLAN netdevs without tags, but it could indeed be
> quite convenient to have this alternative approach available. 

Even just for testing it :-)

> I guess
> both of them have some benefits, so this would likely be left with two
> different mechanisms left to maintain, 

Yes, unless we find a way to attach nl80211 to 802.1q interfaces so we
can pretend to do the netdevs ... not really worth it.

We could encapsulate the backward compatibility on top of this feature,
theoretically, by always asking the drivers to use this feature and then
implementing the AP_VLAN interfaces in cfg80211 entirely, but again,
probably not worth it since it's only mac80211, not a bunch of drivers.

> but the needed implementation in
> mac80211 for this would seem to be pretty minimal (also without looking
> at the exact details..).

Yeah, on RX the station lookup would just have to find the VLAN ID and
use __vlan_hwaccel_put_tag(); on TX ... not sure, probably
skb_vlan_tag_present()?

johannes


^ permalink raw reply

* Re: Unaligned Memory Access on mesh_*.c files
From: Johannes Berg @ 2019-08-21  7:39 UTC (permalink / raw)
  To: Guo Wei Lim; +Cc: linux-wireless
In-Reply-To: <CAJSNYx3Paw7RXpHFbC55zNptT+1AGeYPx08m0=XSr6sSGtC33g@mail.gmail.com>

On Sat, 2019-08-10 at 10:28 +0000, Guo Wei Lim wrote:
> Hi Johannes,
> 
> Correct me if I am wrong.
> The problem is largely in net/mac80211/mesh_hwmp.c
> The macros
> #define PREQ_IE_ORIG_ADDR(x) (x + 7)
> #define PREP_IE_TARGET_ADDR(x) (x + 3)
> 
> Almost guarantees the addresses will be odd when it hit the following

Oh, yeah, good point.

> if (ether_addr_equal(orig_addr, sdata->vif.addr)) {
> 
> Results in unaligned memory access

Right.

> I have tested that replacing ether_addr_equal with
> ether_addr_equal_unaligned fixes the issue but this happens in many
> places as well as other functions like is_multicast_ether_addr(),
> is_broadcast_ether_addr() so it isn't the correct fix.

Unfortunately, I think it _is_ in fact the correct (and only possible)
fix, I can't think of anything other than making the code properly
handle unaligned addresses, as they do seem to happen here.

johannes


^ permalink raw reply

* Re: [PATCHv6 2/9] nl80211: Add new netlink attribute for TID speicific retry count
From: Johannes Berg @ 2019-08-21  7:41 UTC (permalink / raw)
  To: Tamizh chelvam; +Cc: ath10k, linux-wireless
In-Reply-To: <66f9219ed5bd03f96f23947c2bb6f990@codeaurora.org>

On Sat, 2019-08-10 at 17:36 +0530, Tamizh chelvam wrote:
> 
> > > +	[NL80211_TID_ATTR_CONFIG_RETRY] = { .type = NLA_FLAG },
> > > +	[NL80211_TID_ATTR_CONFIG_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 0),
> > > +	[NL80211_TID_ATTR_CONFIG_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 0),
> > 
> > min of 0 doesn't make sense, maybe you meant 1? otherwise just don't 
> > set
> > anything here.
> > 
> The min value changed to 0 from 1 as per the previous discussions, since 
> this is a retry count and not a tx count.
> Or Shall I remove this min value to avoid the confusion ?

Yeah, I think then you should just remove the min value. Perhaps a max
value is needed, but I don't know.

> > > +			tid_conf->retry_short = -1;
> > > +
> > 
> > I guess you should document that -1 means no changes? Not sure how the
> > IEEE80211_TID_CONF_RETRY comes in, you're always setting it, so that's
> > useless - better remove that and document that -1 means no changes?
> > 
> The value -1 is to notify the driver to use default value by removing 
> peer specific retry count.

Oh. So I think that's slightly different, please document that.

johannes


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox