Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v3 3/3] mac80211: mesh: fixed HT ies in beacon template
From: Masashi Honma @ 2016-07-26  3:41 UTC (permalink / raw)
  To: Yaniv Machani, linux-kernel
  Cc: Meirav Kama, Johannes Berg, David S. Miller, linux-wireless,
	netdev
In-Reply-To: <40a34537-486e-a466-5a7e-e253f19d81c3@gmail.com>

On 2016年07月22日 14:26, Masashi Honma wrote:
 > On 2016年07月14日 05:07, Yaniv Machani wrote:
 >> +
 >> +    /* if channel width is 20MHz - configure HT capab accordingly*/
 >> +    if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20) {
 >> +        cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 >> +        cap &= ~IEEE80211_HT_CAP_DSSSCCK40;
 >> +    }
 >
 > I have tested this part of your patch and this works for me.
 >
 > Previouly, "Supported Channel Width Set bit" in HT Capabilities element
 > was 1 even though disable_ht40=1 existed in wpa_supplicant.conf.
 > After appllication of patch, the bit was 0.
 >
 >

# I retransmit this because of mail delivery errors.

I forgot to mention I have used this patch to test.
http://lists.infradead.org/pipermail/hostap/2016-July/036029.html

^ permalink raw reply

* Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
From: Alan Curry @ 2016-07-26  4:32 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: linux-wireless, netdev, linux-kernel, Al Viro, alexmcwhirter
In-Reply-To: <1659922.nTqITfJpFk@debian64>

Christian Lamparter wrote:
> 
> As for carl9170: I'm not sure what the driver or firmware can do about
> this at this time. You can try to disable the hardware crypto by setting
> nohwcrypt via the module option. However, this might not do anything at all.

The nohwcrypt parameter didn't make any difference.

> > 
> > lsusb identifies my network device as:
> > 
> > Bus 005 Device 004: ID 0cf3:1002 Atheros Communications, Inc. TP-Link TL-WN821N v2 802.11n [Atheros AR9170]
> > 
> > I have version 1.9.9 of carl9170-1.fw in /lib/firmware
> Just one additional question: Is the TL-WN821N connected to a USB3 port?

It never has been before. I tried it today and it made no difference.

-- 
Alan Curry

^ permalink raw reply

* Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
From: Alan Curry @ 2016-07-26  4:57 UTC (permalink / raw)
  To: Al Viro
  Cc: Christian Lamparter, Alan Curry, linux-wireless, netdev,
	linux-kernel, alexmcwhirter
In-Reply-To: <20160724190237.GP2356@ZenIV.linux.org.uk>

Al Viro wrote:
> On Sun, Jul 24, 2016 at 07:45:13PM +0200, Christian Lamparter wrote:
> 
> > > The symptom is that downloaded files (http, ftp, and probably other
> > > protocols) have small corrupted segments (about 1-2 kilobytes long) in
> > > random locations. Only downloads that sustain a high speed for at least a
> > > few seconds are corrupted. Anything small enough to be received in less
> > > than about 5 seconds is not affected.
> 
> Can that sucker be reproduced with netcat?  That would eliminate all issues
> with multi-iovec recvmsg(2), narrowing the things down quite bit.

netcat seems to be immune. Comparing strace results, I didn't see any
recvmsg() calls in the other programs that have had the problem, but there
is an interesting difference: netcat calls select() to wait for the socket
to be ready for reading, where my other test programs just call read() and
let it block until ready.

So I wrote a small test program to isolate that difference. It downloads
a file using only read() and write() and a hardcoded HTTP request. It has
a select mode (main loop alternates read() and select() on the TCP socket)
and a noselect mode (main loop just read()s the TCP socket).

The program is included at the bottom of this message.

I ran it several times in both modes and got corruption if and only if the
noselect mode was used.

> 
> Another thing (and if that works, it's *NOT* a proper fix - it would be
> papering over the problem, but at least it would show where to look for
> it) - try (on top of mainline) the following delta:
> 
> diff --git a/net/core/datagram.c b/net/core/datagram.c

Will try that patch soon. Meanwhile, here's my test:

/* Demonstration program "dlbug".
   Usage: dlbug select > outfile
          or
          dlbug noselect > outfile
   outfile will contain the full HTTP response. Edit out the HTTP headers
   and what's left should be a valid gzip if the download worked. */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>

int main(int argc, char **argv)
{
  const char *request =
    "GET /debian/dists/stable/main/Contents-amd64.gz HTTP/1.0\r\n"
    "Host: ftp.us.debian.org\r\n"
    "\r\n";
  ssize_t request_len = strlen(request), w, r, copied;
  struct addrinfo hints, *host;
  int sock, err, doselect;
  char buf[10240];

  if(argc!=2 || (!strcmp(argv[1], "select") && !strcmp(argv[1], "noselect"))) {
    fprintf(stderr, "Usage: %s {select|noselect}\n", argv[0]);
    return 1;
  }

  doselect = !strcmp(argv[1], "select");

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;

  err = getaddrinfo("ftp.us.debian.org", 0, &hints, &host);
  if(err) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
    return 1;
  }

  sock = socket(host->ai_family, host->ai_socktype, host->ai_protocol);
  if(sock < 0) {
    perror("socket");
    return 1;
  }

  ((struct sockaddr_in *)host->ai_addr)->sin_port = htons(80);

  if(connect(sock, host->ai_addr, host->ai_addrlen) < 0) {
    perror("connect");
    return 1;
  }

  while(request_len) {
    w = write(sock, request, request_len);
    if(w < 0) {
      perror("write to socket");
      return 1;
    }
    request += w;
    request_len -= w;
  }

  while((r = read(sock, buf, sizeof buf))) {
    if(r < 0) {
      perror("read from socket");
      return 1;
    }

    copied = 0;
    while(copied < r) {
      w = write(1, buf+copied, r-copied);
      if(w < 0) {
        perror("write to stdout");
        return 1;
      }
      copied += w;
    }

    if(doselect) {
      fd_set rfds;
      FD_ZERO(&rfds);
      FD_SET(sock, &rfds);
      select(sock+1, &rfds, 0, 0, 0);
    }
  }

  return 0;
}

-- 
Alan Curry

^ permalink raw reply

* Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
From: alexmcwhirter @ 2016-07-26  4:38 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Alan Curry, linux-wireless, netdev, linux-kernel, Al Viro
In-Reply-To: <1659922.nTqITfJpFk@debian64>

> Thanks for the detailed bug-report. I looked around the web to see if 
> it
> was already reported or not. If found that this issue was reported 
> before:
> [0], [1] and [2] by the same person (CC'ed). One difference is that the
> reporter had this issue with rsync on multiple SPARC systems. I ran a
> git grep on a 4.7.0-rc7+ (wt-2016-07-21-15-g97bd3b0). But it didn't 
> find
> any patches directly referencing the commit. I'm not sure if this issue
> has been fixed by now or not. I would greatly appreciate any comment
> about this from the "people of netdev" (Al Viro? Alex Mcwhirter?).

I can confirm the issue i was having with this commit still exists on 
sparc with the latest mainline kernel.

^ permalink raw reply

* Re: staging: wilc1000: Reduce scope for a few variables in mac_ioctl()
From: SF Markus Elfring @ 2016-07-26  6:25 UTC (permalink / raw)
  To: Lino Sanfilippo
  Cc: LKML, kernel-janitors, linux-wireless, devel, Greg Kroah-Hartman,
	Steve Caldwell
In-Reply-To: <1c4cac35-dded-ea88-45aa-3f8ac098289d@gmx.de>

>> -			if (strncasecmp(buff, "RSSI", length) == 0) {
>> +			if (strncasecmp(buff, "RSSI", 0) == 0) {
>> +				s8 rssi;
>> +
> 
> Um, please think a second about if it makes any sense at all to compare 
> zero chars of two strings.

Under which circumstances should the variable "length" contain an other
value than zero?

How can this open issue be fixed better?

Regards,
Markus

^ permalink raw reply

* [PATCH] ath9k: fix client mode beacon configuration
From: Felix Fietkau @ 2016-07-26  6:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, benjamin.berg

For pure station mode, iter_data.primary_beacon_vif was used and passed
to ath_beacon_config, but not set to the station vif.
This was causing the following warning:

[  100.310919] ------------[ cut here ]------------
[  100.315683] WARNING: CPU: 0 PID: 7 at compat-wireless-2016-06-20/drivers/net/wireless/ath/ath9k/beacon.c:642 ath9k_calculate_summary_state+0x250/0x60c [ath9k]()
[  100.402028] CPU: 0 PID: 7 Comm: kworker/u2:1 Tainted: G        W       4.4.15 #5
[  100.409676] Workqueue: phy0 ieee80211_ibss_leave [mac80211]
[  100.415351] Stack : 8736e98c 870b4b20 87a25b54 800a6800 8782a080 80400d63 8039b96c 00000007
[  100.415351]    803c5edc 87875914 80400000 800a47cc 87a25b54 800a6800 803a0fd8 80400000
[  100.415351]    00000003 87875914 80400000 80094ae0 87a25b54 8787594c 00000000 801ef308
[  100.415351]    803ffe70 801ef300 87193d58 87b3a400 87b3ad00 70687930 00000000 00000000
[  100.415351]    00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[  100.415351]    ...
[  100.451703] Call Trace:
[  100.454235] [<800a6800>] vprintk_default+0x24/0x30
[  100.459110] [<800a47cc>] printk+0x2c/0x38
[  100.463190] [<800a6800>] vprintk_default+0x24/0x30
[  100.468072] [<80094ae0>] print_worker_info+0x148/0x174
[  100.473378] [<801ef308>] serial8250_console_putchar+0x0/0x44
[  100.479122] [<801ef300>] wait_for_xmitr+0xc4/0xcc
[  100.484014] [<87193d58>] ieee80211_ibss_leave+0xb90/0x1900 [mac80211]
[  100.490590] [<80081604>] warn_slowpath_common+0xa0/0xd0
[  100.495922] [<801a359c>] dump_stack+0x14/0x28
[  100.500350] [<80071a00>] show_stack+0x50/0x84
[  100.504784] [<80081604>] warn_slowpath_common+0xa0/0xd0
[  100.510106] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k]
[  100.517105] [<800816b8>] warn_slowpath_null+0x18/0x24
[  100.522256] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k]
[  100.529273] [<87025418>] ath9k_set_txpower+0x148/0x498 [ath9k]
[  100.535302] [<871d2c64>] cleanup_module+0xa74/0xd4c [mac80211]
[  100.541237] [<801ef308>] serial8250_console_putchar+0x0/0x44
[  100.547042] [<800a5d18>] wake_up_klogd+0x54/0x68
[  100.551730] [<800a6650>] vprintk_emit+0x404/0x43c
[  100.556623] [<871b9db8>] ieee80211_sta_rx_notify+0x258/0x32c [mac80211]
[  100.563475] [<871ba6a4>] ieee80211_sta_rx_queued_mgmt+0x63c/0x734 [mac80211]
[  100.570693] [<871aa49c>] ieee80211_tx_prepare_skb+0x210/0x230 [mac80211]
[  100.577609] [<800af5d4>] mod_timer+0x15c/0x190
[  100.582220] [<871ba8b8>] ieee80211_sta_work+0xfc/0xe1c [mac80211]
[  100.588539] [<871940b4>] ieee80211_ibss_leave+0xeec/0x1900 [mac80211]
[  100.595122] [<8009ec84>] dequeue_task_fair+0x44/0x130
[  100.600281] [<80092a34>] process_one_work+0x1f8/0x334
[  100.605454] [<80093830>] worker_thread+0x2b4/0x408
[  100.610317] [<8009357c>] worker_thread+0x0/0x408
[  100.615019] [<8009357c>] worker_thread+0x0/0x408
[  100.619705] [<80097b68>] kthread+0xdc/0xe8
[  100.623886] [<80097a8c>] kthread+0x0/0xe8
[  100.627961] [<80060878>] ret_from_kernel_thread+0x14/0x1c
[  100.633448]
[  100.634956] ---[ end trace aafbe57e9ae6862f ]---

Fixes: cfda2d8e2314 ("ath9k: Fix beacon configuration for addition/removal of interfaces")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/ath/ath9k/main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 6b68584..439eb06 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1154,6 +1154,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
 		bool changed = (iter_data.primary_sta != ctx->primary_sta);
 
 		if (iter_data.primary_sta) {
+			iter_data.primary_beacon_vif = iter_data.primary_sta;
 			iter_data.beacons = true;
 			ath9k_set_assoc_state(sc, iter_data.primary_sta,
 					      changed);
-- 
2.8.4


^ permalink raw reply related

* RE: [v3] UCC_GETH/UCC_FAST: Use IS_ERR_VALUE_U32 API to avoid IS_ERR_VALUE abuses.
From: David Laight @ 2016-07-26  9:04 UTC (permalink / raw)
  To: 'Arvind Yadav', zajec5@gmail.com, leoli@freescale.com
  Cc: qiang.zhao@freescale.com, scottwood@freescale.com,
	viresh.kumar@linaro.org, akpm@linux-foundation.org,
	linux-wireless@vger.kernel.org, netdev@vger.kernel.org,
	linuxppc-dev@lists.ozlabs.org, linux@roeck-us.net, arnd@arndb.de
In-Reply-To: <1469297151-9763-1-git-send-email-arvind.yadav.cs@gmail.com>

From: Arvind Yadav
> Sent: 23 July 2016 19:06
> IS_ERR_VALUE() assumes that its parameter is an unsigned long.
> It can not be used to check if an 'unsigned int' reflects an error.
> As they pass an 'unsigned int' into a function that takes an
> 'unsigned long' argument. This happens to work because the type
> is sign-extended on 64-bit architectures before it gets converted
> into an unsigned type.
> 
> However, anything that passes an 'unsigned short' or 'unsigned int'
> argument into IS_ERR_VALUE() is guaranteed to be broken, as are
> 8-bit integers and types that are wider than 'unsigned long'.
> 
> It would be nice to any users that are not passing 'unsigned int'
> arguments.

Isn't that a load of bollocks???
It is certainly very over-wordy.

IS_ERR_VALUE(x) is ((x) >= (unsigned long)-4096)

Assuming sizeof (short) == 2 && sizeof (int) == 4 && sizeof (long) == 8.

'signed char' and 'signed short' are first sign extended to 'signed int'.
'unsigned char' and 'unsigned short' are first zero extended to 'signed int'.
'signed int' is sign extended to 'signed long'.
'signed long' is converted to 'unsigned long' treating the bit-pattern as 'unsigned long'.
'unsigned int' is zero extended to 'unsigned long'.

It is probably enough to say that on 64bit systems IS_ERR_VALUE() of unsigned int
is always false because the 32bit value is zero extended to 64 bits.

A possible 'fix' would be to define IS_ERR_VALUE() as:
#define IS_ERR_VALUE(x) unlikely(sizeof (x) > sizeof (int) ? (x) > (unsigned long)-MAX_ERRNO : (x) > (unsigned int)-MAX_ERRNO)

However correct analysis of every case might show up real errors.
So a compilation warning/error might be more appropriate.

	David


^ permalink raw reply

* [PATCH v4 1/2] mwifiex: add manufacturing mode support
From: Amitkumar Karwar @ 2016-07-26  9:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: Cathy Luo, Nishant Sarmukadam, Amitkumar Karwar

By default normal mode is chosen when driver is loaded. This
patch adds a provision to choose manufacturing mode via module
parameters.

Below command loads driver in manufacturing mode
insmod mwifiex.ko mfg_mode=1.

Tested-by: chunfan chen <jeffc@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v4: Removed mfg_firmware module parameter and hardcoded the firmware name
    in driver(Kalle Valo).
---
 drivers/net/wireless/marvell/mwifiex/cmdevt.c |  8 ++++++++
 drivers/net/wireless/marvell/mwifiex/init.c   | 22 +++++++++++++++-------
 drivers/net/wireless/marvell/mwifiex/main.c   | 25 +++++++++++++++++++++----
 drivers/net/wireless/marvell/mwifiex/main.h   |  2 ++
 drivers/net/wireless/marvell/mwifiex/pcie.c   |  2 +-
 drivers/net/wireless/marvell/mwifiex/sdio.c   |  2 +-
 drivers/net/wireless/marvell/mwifiex/usb.c    |  2 +-
 7 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index d433aa0..636cfa0 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -595,6 +595,14 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
 			return -1;
 		}
 	}
+	/* We don't expect commands in manufacturing mode. They are cooked
+	 * in application and ready to download buffer is passed to the driver
+	*/
+	if (adapter->mfg_mode && cmd_no) {
+		dev_dbg(adapter->dev, "Ignoring commands in manufacturing mode\n");
+		return -1;
+	}
+
 
 	/* Get a new command node */
 	cmd_node = mwifiex_get_cmd_node(adapter);
diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 1489c90..82839d9 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -298,6 +298,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
 	memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
 	adapter->arp_filter_size = 0;
 	adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
+	adapter->mfg_mode = mfg_mode;
 	adapter->key_api_major_ver = 0;
 	adapter->key_api_minor_ver = 0;
 	eth_broadcast_addr(adapter->perm_addr);
@@ -553,15 +554,22 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
 				return -1;
 		}
 	}
+	if (adapter->mfg_mode) {
+		adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+		ret = -EINPROGRESS;
+	} else {
+		for (i = 0; i < adapter->priv_num; i++) {
+			if (adapter->priv[i]) {
+				ret = mwifiex_sta_init_cmd(adapter->priv[i],
+							   first_sta, true);
+				if (ret == -1)
+					return -1;
+
+				first_sta = false;
+			}
+
 
-	for (i = 0; i < adapter->priv_num; i++) {
-		if (adapter->priv[i]) {
-			ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta,
-						   true);
-			if (ret == -1)
-				return -1;
 
-			first_sta = false;
 		}
 	}
 
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index db4925d..7fbf74b 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -23,6 +23,7 @@
 #include "11n.h"
 
 #define VERSION	"1.0"
+#define MFG_FIRMWARE	"mwifiex_mfg.bin"
 
 static unsigned int debug_mask = MWIFIEX_DEFAULT_DEBUG_MASK;
 module_param(debug_mask, uint, 0);
@@ -36,6 +37,9 @@ static unsigned short driver_mode;
 module_param(driver_mode, ushort, 0);
 MODULE_PARM_DESC(driver_mode,
 		 "station=0x1(default), ap-sta=0x3, station-p2p=0x5, ap-sta-p2p=0x7");
+bool mfg_mode;
+module_param(mfg_mode, bool, 0);
+MODULE_PARM_DESC(mfg_mode, "0:disable 1:enable (bool)");
 
 /*
  * This function registers the device and performs all the necessary
@@ -559,10 +563,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 		goto done;
 	}
 	/* Wait for mwifiex_init to complete */
-	wait_event_interruptible(adapter->init_wait_q,
-				 adapter->init_wait_q_woken);
-	if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
-		goto err_init_fw;
+	if (!adapter->mfg_mode) {
+		wait_event_interruptible(adapter->init_wait_q,
+					 adapter->init_wait_q_woken);
+		if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
+			goto err_init_fw;
+	}
 
 	priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
 	if (mwifiex_register_cfg80211(adapter)) {
@@ -666,6 +672,17 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
 {
 	int ret;
 
+	/* Override default firmware with manufacturing one if
+	 * manufacturing mode is enabled
+	 */
+	if (mfg_mode) {
+		if (strlcpy(adapter->fw_name, MFG_FIRMWARE,
+			    sizeof(adapter->fw_name)) >=
+			    sizeof(adapter->fw_name)) {
+			pr_err("%s: fw_name too long!\n", __func__);
+			return -1;
+		}
+	}
 	ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
 				      adapter->dev, GFP_KERNEL, adapter,
 				      mwifiex_fw_dpc);
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 5902600..fcc2af35 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -58,6 +58,7 @@
 #include "sdio.h"
 
 extern const char driver_version[];
+extern bool mfg_mode;
 
 struct mwifiex_adapter;
 struct mwifiex_private;
@@ -990,6 +991,7 @@ struct mwifiex_adapter {
 	u32 drv_info_size;
 	bool scan_chan_gap_enabled;
 	struct sk_buff_head rx_data_q;
+	bool mfg_mode;
 	struct mwifiex_chan_stats *chan_stats;
 	u32 num_in_chan_stats;
 	int survey_idx;
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 453ab6a..a6af85d 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -225,7 +225,7 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
 	if (!adapter || !adapter->priv_num)
 		return;
 
-	if (user_rmmod) {
+	if (user_rmmod && !adapter->mfg_mode) {
 #ifdef CONFIG_PM_SLEEP
 		if (adapter->is_suspended)
 			mwifiex_pcie_resume(&pdev->dev);
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index d3e1561..6dba409 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -289,7 +289,7 @@ mwifiex_sdio_remove(struct sdio_func *func)
 
 	mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num);
 
-	if (user_rmmod) {
+	if (user_rmmod && !adapter->mfg_mode) {
 		if (adapter->is_suspended)
 			mwifiex_sdio_resume(adapter->dev);
 
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index 0857575..ba616ec 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -611,7 +611,7 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
 	if (!adapter->priv_num)
 		return;
 
-	if (user_rmmod) {
+	if (user_rmmod && !adapter->mfg_mode) {
 #ifdef CONFIG_PM
 		if (adapter->is_suspended)
 			mwifiex_usb_resume(intf);
-- 
1.9.1


^ permalink raw reply related

* [PATCH v4 2/2] mwifiex: add cfg80211 testmode support
From: Amitkumar Karwar @ 2016-07-26  9:39 UTC (permalink / raw)
  To: linux-wireless
  Cc: Cathy Luo, Nishant Sarmukadam, Xinming Hu, Amitkumar Karwar
In-Reply-To: <1469525960-6643-1-git-send-email-akarwar@marvell.com>

From: Xinming Hu <huxm@marvell.com>

This patch adds cfg80211 testmode support so that userspace tools can
download necessary commands to firmware during manufacturing mode tests.

Signed-off-by: Xinming <huxm@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v4: Used cfg80211 testmode interface instead of wext in 2/2 patch.(Kalle Valo)
v3: Add "select WIRELESS_EXT" in Kconfig to resolve kbuild test robot errors.
    WEXT_PRIV seems to have a dependency with WIRELESS_EXT.
v2: 1) Sequence of these two patches are changed to resolve compilation
    error seen if only 1/2 is applied.
    2) Add "select WEXT_PRIV" in Kconfig to resolve warnings reported by
    kbuild test robot.
---
 drivers/net/wireless/marvell/mwifiex/cfg80211.c | 83 +++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 235fb39..86b31b1 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -3919,6 +3919,88 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
 	return ret;
 }
 
+#ifdef CONFIG_NL80211_TESTMODE
+
+enum mwifiex_tm_attr {
+	__MWIFIEX_TM_ATTR_INVALID	= 0,
+	MWIFIEX_TM_ATTR_CMD		= 1,
+	MWIFIEX_TM_ATTR_DATA		= 2,
+
+	/* keep last */
+	__MWIFIEX_TM_ATTR_AFTER_LAST,
+	MWIFIEX_TM_ATTR_MAX		= __MWIFIEX_TM_ATTR_AFTER_LAST - 1,
+};
+
+static const struct nla_policy mwifiex_tm_policy[MWIFIEX_TM_ATTR_MAX + 1] = {
+	[MWIFIEX_TM_ATTR_CMD]		= { .type = NLA_U32 },
+	[MWIFIEX_TM_ATTR_DATA]		= { .type = NLA_BINARY,
+					    .len = MWIFIEX_SIZE_OF_CMD_BUFFER },
+};
+
+enum mwifiex_tm_cmd {
+	MWIFIEX_TM_CMD_HOSTCMD	= 0,
+};
+
+int mwifiex_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
+		   void *data, int len)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+	struct mwifiex_ds_misc_cmd *hostcmd;
+	struct nlattr *tb[MWIFIEX_TM_ATTR_MAX + 1];
+	struct mwifiex_adapter *adapter;
+	struct sk_buff *skb;
+	int err;
+
+	if (!priv)
+		return -EINVAL;
+	adapter = priv->adapter;
+
+	err = nla_parse(tb, MWIFIEX_TM_ATTR_MAX, data, len,
+			mwifiex_tm_policy);
+	if (err)
+		return err;
+
+	if (!tb[MWIFIEX_TM_ATTR_CMD])
+		return -EINVAL;
+
+	switch (nla_get_u32(tb[MWIFIEX_TM_ATTR_CMD])) {
+	case MWIFIEX_TM_CMD_HOSTCMD:
+		if (!tb[MWIFIEX_TM_ATTR_DATA])
+			return -EINVAL;
+
+		hostcmd = kzalloc(sizeof(*hostcmd), GFP_KERNEL);
+		if (!hostcmd)
+			return -ENOMEM;
+
+		hostcmd->len = nla_len(tb[MWIFIEX_TM_ATTR_DATA]);
+		memcpy(hostcmd->cmd, nla_data(tb[MWIFIEX_TM_ATTR_DATA]),
+		       hostcmd->len);
+
+		if (mwifiex_send_cmd(priv, 0, 0, 0, hostcmd, true)) {
+			dev_err(priv->adapter->dev, "Failed to process hostcmd\n");
+			return -EFAULT;
+		}
+
+		/* process hostcmd response*/
+		skb = cfg80211_testmode_alloc_reply_skb(wiphy, hostcmd->len);
+		if (!skb)
+			return -ENOMEM;
+		err = nla_put(skb, MWIFIEX_TM_ATTR_DATA,
+			      hostcmd->len, hostcmd->cmd);
+		if (err) {
+			kfree_skb(skb);
+			return -EMSGSIZE;
+		}
+
+		err = cfg80211_testmode_reply(skb);
+		kfree(hostcmd);
+		return err;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+#endif
+
 static int
 mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
 				       struct net_device *dev,
@@ -4031,6 +4113,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
 	.tdls_cancel_channel_switch = mwifiex_cfg80211_tdls_cancel_chan_switch,
 	.add_station = mwifiex_cfg80211_add_station,
 	.change_station = mwifiex_cfg80211_change_station,
+	CFG80211_TESTMODE_CMD(mwifiex_tm_cmd)
 	.get_channel = mwifiex_cfg80211_get_channel,
 	.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
 	.channel_switch = mwifiex_cfg80211_channel_switch,
-- 
1.9.1


^ permalink raw reply related

* Re: [v3] UCC_GETH/UCC_FAST: Use IS_ERR_VALUE_U32 API to avoid IS_ERR_VALUE abuses.
From: Arnd Bergmann @ 2016-07-26 11:39 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Arvind Yadav, zajec5, leoli, qiang.zhao, viresh.kumar,
	linux-wireless, netdev, scottwood, akpm, linux
In-Reply-To: <1469297151-9763-1-git-send-email-arvind.yadav.cs@gmail.com>

On Saturday, July 23, 2016 11:35:51 PM CEST Arvind Yadav wrote:
> diff --git a/include/linux/err.h b/include/linux/err.h
> index 1e35588..a42f942 100644
> --- a/include/linux/err.h
> +++ b/include/linux/err.h
> @@ -19,6 +19,7 @@
>  #ifndef __ASSEMBLY__
>  
>  #define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)
> +#define IS_ERR_VALUE_U32(x) unlikely((unsigned int)(x) >= (unsigned int)-MAX_ERRNO)
>  
>  static inline void * __must_check ERR_PTR(long error)
>  {

This doesn't really look like something we want to have as a generic
interface. The IS_ERR_VALUE() API is rather awkward already, and your
use seems specific to the cpu_muram_alloc() function.

How about something like

int cpm_muram_error(unsigned long addr)
{
	if (addr >= (unsigned long)-MAX_ERRNO)
		return addr;
	else
		return 0;
}

and then use that to check the value returned by the allocation
that is still an 'unsigned long', before assigning it to a 'u32'.

	Arnd

^ permalink raw reply

* Re: [PATCH] ath9k: fix client mode beacon configuration
From: Kalle Valo @ 2016-07-26 12:56 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, benjamin.berg
In-Reply-To: <20160726062923.98555-1-nbd@nbd.name>

Felix Fietkau <nbd@nbd.name> writes:

> For pure station mode, iter_data.primary_beacon_vif was used and passed
> to ath_beacon_config, but not set to the station vif.
> This was causing the following warning:
>
> [  100.310919] ------------[ cut here ]------------
> [  100.315683] WARNING: CPU: 0 PID: 7 at compat-wireless-2016-06-20/drivers/net/wireless/ath/ath9k/beacon.c:642 ath9k_calculate_summary_state+0x250/0x60c [ath9k]()
> [  100.402028] CPU: 0 PID: 7 Comm: kworker/u2:1 Tainted: G        W       4.4.15 #5
> [  100.409676] Workqueue: phy0 ieee80211_ibss_leave [mac80211]
> [  100.415351] Stack : 8736e98c 870b4b20 87a25b54 800a6800 8782a080 80400d63 8039b96c 00000007
> [  100.415351]    803c5edc 87875914 80400000 800a47cc 87a25b54 800a6800 803a0fd8 80400000
> [  100.415351]    00000003 87875914 80400000 80094ae0 87a25b54 8787594c 00000000 801ef308
> [  100.415351]    803ffe70 801ef300 87193d58 87b3a400 87b3ad00 70687930 00000000 00000000
> [  100.415351]    00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> [  100.415351]    ...
> [  100.451703] Call Trace:
> [  100.454235] [<800a6800>] vprintk_default+0x24/0x30
> [  100.459110] [<800a47cc>] printk+0x2c/0x38
> [  100.463190] [<800a6800>] vprintk_default+0x24/0x30
> [  100.468072] [<80094ae0>] print_worker_info+0x148/0x174
> [  100.473378] [<801ef308>] serial8250_console_putchar+0x0/0x44
> [  100.479122] [<801ef300>] wait_for_xmitr+0xc4/0xcc
> [  100.484014] [<87193d58>] ieee80211_ibss_leave+0xb90/0x1900 [mac80211]
> [  100.490590] [<80081604>] warn_slowpath_common+0xa0/0xd0
> [  100.495922] [<801a359c>] dump_stack+0x14/0x28
> [  100.500350] [<80071a00>] show_stack+0x50/0x84
> [  100.504784] [<80081604>] warn_slowpath_common+0xa0/0xd0
> [  100.510106] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k]
> [  100.517105] [<800816b8>] warn_slowpath_null+0x18/0x24
> [  100.522256] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k]
> [  100.529273] [<87025418>] ath9k_set_txpower+0x148/0x498 [ath9k]
> [  100.535302] [<871d2c64>] cleanup_module+0xa74/0xd4c [mac80211]
> [  100.541237] [<801ef308>] serial8250_console_putchar+0x0/0x44
> [  100.547042] [<800a5d18>] wake_up_klogd+0x54/0x68
> [  100.551730] [<800a6650>] vprintk_emit+0x404/0x43c
> [  100.556623] [<871b9db8>] ieee80211_sta_rx_notify+0x258/0x32c [mac80211]
> [  100.563475] [<871ba6a4>] ieee80211_sta_rx_queued_mgmt+0x63c/0x734 [mac80211]
> [  100.570693] [<871aa49c>] ieee80211_tx_prepare_skb+0x210/0x230 [mac80211]
> [  100.577609] [<800af5d4>] mod_timer+0x15c/0x190
> [  100.582220] [<871ba8b8>] ieee80211_sta_work+0xfc/0xe1c [mac80211]
> [  100.588539] [<871940b4>] ieee80211_ibss_leave+0xeec/0x1900 [mac80211]
> [  100.595122] [<8009ec84>] dequeue_task_fair+0x44/0x130
> [  100.600281] [<80092a34>] process_one_work+0x1f8/0x334
> [  100.605454] [<80093830>] worker_thread+0x2b4/0x408
> [  100.610317] [<8009357c>] worker_thread+0x0/0x408
> [  100.615019] [<8009357c>] worker_thread+0x0/0x408
> [  100.619705] [<80097b68>] kthread+0xdc/0xe8
> [  100.623886] [<80097a8c>] kthread+0x0/0xe8
> [  100.627961] [<80060878>] ret_from_kernel_thread+0x14/0x1c
> [  100.633448]
> [  100.634956] ---[ end trace aafbe57e9ae6862f ]---
>
> Fixes: cfda2d8e2314 ("ath9k: Fix beacon configuration for addition/removal of interfaces")
> Signed-off-by: Felix Fietkau <nbd@nbd.name>

I'm planning to push this to 4.8.

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCHv5 wl-drv-next 0/2] register-field manipulation macros
From: Kalle Valo @ 2016-07-26 13:00 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20160725154549.6492cac1@jkicinski-Precision-T1700>

Jakub Kicinski <jakub.kicinski@netronome.com> writes:

> On Wed,  6 Jul 2016 17:19:35 +0100, Jakub Kicinski wrote:
>> Hi!
>> 
>> I've added few lines about the compilation problems in 
>> the commit message of patch 1.  I would prefer the mass
>> rename of macros in mt7601u not to be part of this series
>> so patch 2 is left as it was and I'll follow up once this
>> is accepted.
>
> Hi Kalle,
>
> what's the status of this set?  It's marked as 'Deferred' in
> linux-wireless patchwork.

Like I said before, I would prefer to see an ack from someone else like
Andrew Morton or Dave Miller. I don't feel comfortable adding new files
to include/ without some sort of support from others. Or maybe Andrew
could even take these directly to his tree?

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCHv5 wl-drv-next 0/2] register-field manipulation macros
From: Jakub Kicinski @ 2016-07-26 13:13 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <87y44od06j.fsf@kamboji.qca.qualcomm.com>

On Tue, 26 Jul 2016 16:00:04 +0300, Kalle Valo wrote:
> Jakub Kicinski <jakub.kicinski@netronome.com> writes:
> 
> > On Wed,  6 Jul 2016 17:19:35 +0100, Jakub Kicinski wrote:  
> >> Hi!
> >> 
> >> I've added few lines about the compilation problems in 
> >> the commit message of patch 1.  I would prefer the mass
> >> rename of macros in mt7601u not to be part of this series
> >> so patch 2 is left as it was and I'll follow up once this
> >> is accepted.  
> >
> > Hi Kalle,
> >
> > what's the status of this set?  It's marked as 'Deferred' in
> > linux-wireless patchwork.  
> 
> Like I said before, I would prefer to see an ack from someone else like
> Andrew Morton or Dave Miller. I don't feel comfortable adding new files
> to include/ without some sort of support from others. Or maybe Andrew
> could even take these directly to his tree?

OK, once the merge window is over I'll repost and TO: some important
guys.  Hopefully we'll catch someone's attention :)

^ permalink raw reply

* Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
From: Christian Lamparter @ 2016-07-26 13:59 UTC (permalink / raw)
  To: Alan Curry
  Cc: Al Viro, Christian Lamparter, linux-wireless, netdev,
	linux-kernel, alexmcwhirter
In-Reply-To: <201607260457.u6Q4v3pM010082@sdf.org>

On Tuesday, July 26, 2016 4:57:03 AM CEST Alan Curry wrote:
> Al Viro wrote:
> > On Sun, Jul 24, 2016 at 07:45:13PM +0200, Christian Lamparter wrote:
> > 
> > > > The symptom is that downloaded files (http, ftp, and probably other
> > > > protocols) have small corrupted segments (about 1-2 kilobytes long) in
> > > > random locations. Only downloads that sustain a high speed for at least a
> > > > few seconds are corrupted. Anything small enough to be received in less
> > > > than about 5 seconds is not affected.
> > 
> > Can that sucker be reproduced with netcat?  That would eliminate all issues
> > with multi-iovec recvmsg(2), narrowing the things down quite bit.
> 
> netcat seems to be immune. Comparing strace results, I didn't see any
> recvmsg() calls in the other programs that have had the problem, but there
> is an interesting difference: netcat calls select() to wait for the socket
> to be ready for reading, where my other test programs just call read() and
> let it block until ready.
> 
> So I wrote a small test program to isolate that difference. It downloads
> a file using only read() and write() and a hardcoded HTTP request. It has
> a select mode (main loop alternates read() and select() on the TCP socket)
> and a noselect mode (main loop just read()s the TCP socket).
> 
> The program is included at the bottom of this message.
> 
> I ran it several times in both modes and got corruption if and only if the
> noselect mode was used.
> 
> > 
> > Another thing (and if that works, it's *NOT* a proper fix - it would be
> > papering over the problem, but at least it would show where to look for
> > it) - try (on top of mainline) the following delta:
> > 
> > diff --git a/net/core/datagram.c b/net/core/datagram.c
> 
> Will try that patch soon. Meanwhile, here's my test:
> 
> /* Demonstration program "dlbug".
>    Usage: dlbug select > outfile
>           or
>           dlbug noselect > outfile
>    outfile will contain the full HTTP response. Edit out the HTTP headers
>    and what's left should be a valid gzip if the download worked. */
> [...]
Thanks, I gave the program a try with my WNDA3100 and a WN821N v2 devices.
I did not see any corruptions in any of the tests though. Can you tell me
something about your wireless network too? I would like to know what router
and firmware are you using? Also important: what's your wireless configuration?
(WPA?, CCMP or TKIP? HT40, HT20 or Legacy rates? ...)

Probably the quickest and easiest way to get that information is by running
the following commands as root, when you are connected to your wifi network
and post the results:
# iw dev wlan0 link
# iw dev wlan0 scan dump

(You can of course remove your device's MACs, but please do it consistently).

Regards,
Christian

^ permalink raw reply

* [PATCH] mwifiex: add PCIe function level reset support
From: Amitkumar Karwar @ 2016-07-26 14:01 UTC (permalink / raw)
  To: linux-wireless; +Cc: Amitkumar Karwar

This patch implements pre and post FLR handlers to support PCIe FLR
functionality. Software cleanup is performed in pre-FLR whereas
firmware is downloaded and software is re-initialised in
post-FLR handler.

Following command triggers FLR.
echo "1" > /sys/bus/pci/devices/$NUMBER/reset

This feature can be used as a recovery mechanism when firmware gets
hang.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
 drivers/net/wireless/marvell/mwifiex/main.c | 242 ++++++++++++++++++++++++++--
 drivers/net/wireless/marvell/mwifiex/main.h |   3 +
 drivers/net/wireless/marvell/mwifiex/pcie.c | 136 +++++++++++++++-
 drivers/net/wireless/marvell/mwifiex/pcie.h |   1 +
 4 files changed, 365 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 7fbf74b..0181247 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -490,9 +490,11 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
  */
 static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
 {
-	flush_workqueue(adapter->workqueue);
-	destroy_workqueue(adapter->workqueue);
-	adapter->workqueue = NULL;
+	if (adapter->workqueue) {
+		flush_workqueue(adapter->workqueue);
+		destroy_workqueue(adapter->workqueue);
+		adapter->workqueue = NULL;
+	}
 
 	if (adapter->rx_workqueue) {
 		flush_workqueue(adapter->rx_workqueue);
@@ -571,10 +573,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 	}
 
 	priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
-	if (mwifiex_register_cfg80211(adapter)) {
-		mwifiex_dbg(adapter, ERROR,
-			    "cannot register with cfg80211\n");
-		goto err_init_fw;
+
+	if (!adapter->wiphy) {
+		if (mwifiex_register_cfg80211(adapter)) {
+			mwifiex_dbg(adapter, ERROR,
+				    "cannot register with cfg80211\n");
+			goto err_init_fw;
+		}
 	}
 
 	if (mwifiex_init_channel_scan_gap(adapter)) {
@@ -668,7 +673,8 @@ done:
 /*
  * This function initializes the hardware and gets firmware.
  */
-static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter,
+			      bool req_fw_nowait)
 {
 	int ret;
 
@@ -683,12 +689,25 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
 			return -1;
 		}
 	}
-	ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
-				      adapter->dev, GFP_KERNEL, adapter,
-				      mwifiex_fw_dpc);
-	if (ret < 0)
-		mwifiex_dbg(adapter, ERROR,
-			    "request_firmware_nowait error %d\n", ret);
+
+	if (req_fw_nowait) {
+		ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
+					      adapter->dev, GFP_KERNEL, adapter,
+					      mwifiex_fw_dpc);
+		if (ret < 0)
+			mwifiex_dbg(adapter, ERROR,
+				    "request_firmware_nowait error %d\n", ret);
+	} else {
+		ret = request_firmware(&adapter->firmware,
+				       adapter->fw_name,
+				       adapter->dev);
+		if (ret < 0)
+			mwifiex_dbg(adapter, ERROR,
+				    "request_firmware error %d\n", ret);
+		else
+			mwifiex_fw_dpc(adapter->firmware, (void *)adapter);
+	}
+
 	return ret;
 }
 
@@ -1338,6 +1357,199 @@ static void mwifiex_main_work_queue(struct work_struct *work)
 }
 
 /*
+ * This function gets called during PCIe function level reset. Required
+ * code is extracted from mwifiex_remove_card()
+ */
+static int
+mwifiex_shutdown_sw(struct mwifiex_adapter *adapter, struct semaphore *sem)
+{
+	struct mwifiex_private *priv;
+	int i;
+
+	if (down_interruptible(sem))
+		goto exit_sem_err;
+
+	if (!adapter)
+		goto exit_remove;
+
+	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	mwifiex_deauthenticate(priv, NULL);
+
+	/* We can no longer handle interrupts once we start doing the teardown
+	 * below.
+	 */
+	if (adapter->if_ops.disable_int)
+		adapter->if_ops.disable_int(adapter);
+
+	adapter->surprise_removed = true;
+	mwifiex_terminate_workqueue(adapter);
+
+	/* Stop data */
+	for (i = 0; i < adapter->priv_num; i++) {
+		priv = adapter->priv[i];
+		if (priv && priv->netdev) {
+			mwifiex_stop_net_dev_queue(priv->netdev, adapter);
+			if (netif_carrier_ok(priv->netdev))
+				netif_carrier_off(priv->netdev);
+			netif_device_detach(priv->netdev);
+		}
+	}
+
+	mwifiex_dbg(adapter, CMD, "cmd: calling mwifiex_shutdown_drv...\n");
+	adapter->init_wait_q_woken = false;
+
+	if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
+		wait_event_interruptible(adapter->init_wait_q,
+					 adapter->init_wait_q_woken);
+	if (adapter->if_ops.down_dev)
+		adapter->if_ops.down_dev(adapter);
+
+	mwifiex_dbg(adapter, CMD, "cmd: mwifiex_shutdown_drv done\n");
+	if (atomic_read(&adapter->rx_pending) ||
+	    atomic_read(&adapter->tx_pending) ||
+	    atomic_read(&adapter->cmd_pending)) {
+		mwifiex_dbg(adapter, ERROR,
+			    "rx_pending=%d, tx_pending=%d,\t"
+			    "cmd_pending=%d\n",
+			    atomic_read(&adapter->rx_pending),
+			    atomic_read(&adapter->tx_pending),
+			    atomic_read(&adapter->cmd_pending));
+	}
+
+	for (i = 0; i < adapter->priv_num; i++) {
+		priv = adapter->priv[i];
+		if (!priv)
+			continue;
+		rtnl_lock();
+		if (priv->netdev &&
+		    priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED)
+			mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev);
+		rtnl_unlock();
+	}
+
+exit_remove:
+	up(sem);
+exit_sem_err:
+	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+	return 0;
+}
+
+/* This function gets called during PCIe function level reset. Required
+ * code is extracted from mwifiex_add_card()
+ */
+static int
+mwifiex_reinit_sw(struct mwifiex_adapter *adapter, struct semaphore *sem,
+		  struct mwifiex_if_ops *if_ops, u8 iface_type)
+{
+	char fw_name[32];
+	struct pcie_service_card *card = adapter->card;
+
+	if (down_interruptible(sem))
+		goto exit_sem_err;
+
+	mwifiex_init_lock_list(adapter);
+	if (adapter->if_ops.up_dev)
+		adapter->if_ops.up_dev(adapter);
+
+	adapter->iface_type = iface_type;
+	adapter->card_sem = sem;
+
+	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
+	adapter->surprise_removed = false;
+	init_waitqueue_head(&adapter->init_wait_q);
+	adapter->is_suspended = false;
+	adapter->hs_activated = false;
+	init_waitqueue_head(&adapter->hs_activate_wait_q);
+	init_waitqueue_head(&adapter->cmd_wait_q.wait);
+	adapter->cmd_wait_q.status = 0;
+	adapter->scan_wait_q_woken = false;
+
+	if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB)
+		adapter->rx_work_enabled = true;
+
+	adapter->workqueue =
+		alloc_workqueue("MWIFIEX_WORK_QUEUE",
+				WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+	if (!adapter->workqueue)
+		goto err_kmalloc;
+
+	INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
+
+	if (adapter->rx_work_enabled) {
+		adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
+							WQ_HIGHPRI |
+							WQ_MEM_RECLAIM |
+							WQ_UNBOUND, 1);
+		if (!adapter->rx_workqueue)
+			goto err_kmalloc;
+		INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
+	}
+
+	/* Register the device. Fill up the private data structure with
+	 * relevant information from the card. Some code extracted from
+	 * mwifiex_register_dev()
+	 */
+	mwifiex_dbg(adapter, INFO, "%s, mwifiex_init_hw_fw()...\n", __func__);
+	strcpy(fw_name, adapter->fw_name);
+	strcpy(adapter->fw_name, PCIE8997_DEFAULT_WIFIFW_NAME);
+
+	adapter->tx_buf_size = card->pcie.tx_buf_size;
+	adapter->ext_scan = card->pcie.can_ext_scan;
+	if (mwifiex_init_hw_fw(adapter, false)) {
+		strcpy(adapter->fw_name, fw_name);
+		mwifiex_dbg(adapter, ERROR,
+			    "%s: firmware init failed\n", __func__);
+		goto err_init_fw;
+	}
+	strcpy(adapter->fw_name, fw_name);
+	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+	up(sem);
+	return 0;
+
+err_init_fw:
+	mwifiex_dbg(adapter, ERROR, "info: %s: unregister device\n", __func__);
+	if (adapter->if_ops.unregister_dev)
+		adapter->if_ops.unregister_dev(adapter);
+	if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) {
+		mwifiex_dbg(adapter, ERROR,
+			    "info: %s: shutdown mwifiex\n", __func__);
+		adapter->init_wait_q_woken = false;
+
+		if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
+			wait_event_interruptible(adapter->init_wait_q,
+						 adapter->init_wait_q_woken);
+	}
+
+err_kmalloc:
+	mwifiex_terminate_workqueue(adapter);
+	adapter->surprise_removed = true;
+	up(sem);
+exit_sem_err:
+	mwifiex_dbg(adapter, INFO, "%s, error\n", __func__);
+
+	return -1;
+}
+
+/* This function processes pre and post PCIe function level resets.
+ * It performs software cleanup without touching PCIe specific code.
+ * Also, during initialization PCIe stuff is skipped.
+ */
+void mwifiex_do_flr(struct mwifiex_adapter *adapter, bool prepare)
+{
+	struct mwifiex_if_ops if_ops;
+
+	if (!prepare) {
+		mwifiex_reinit_sw(adapter, adapter->card_sem, &if_ops,
+				  adapter->iface_type);
+	} else {
+		memcpy(&if_ops, &adapter->if_ops,
+		       sizeof(struct mwifiex_if_ops));
+		mwifiex_shutdown_sw(adapter, adapter->card_sem);
+	}
+}
+EXPORT_SYMBOL_GPL(mwifiex_do_flr);
+
+/*
  * This function adds the card.
  *
  * This function follows the following major steps to set up the device -
@@ -1408,7 +1620,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
 		goto err_registerdev;
 	}
 
-	if (mwifiex_init_hw_fw(adapter)) {
+	if (mwifiex_init_hw_fw(adapter, true)) {
 		pr_err("%s: firmware init failed\n", __func__);
 		goto err_init_fw;
 	}
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index fcc2af35..2d32768 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -829,6 +829,8 @@ struct mwifiex_if_ops {
 	void (*deaggr_pkt)(struct mwifiex_adapter *, struct sk_buff *);
 	void (*multi_port_resync)(struct mwifiex_adapter *);
 	bool (*is_port_ready)(struct mwifiex_private *);
+	void (*down_dev)(struct mwifiex_adapter *);
+	void (*up_dev)(struct mwifiex_adapter *);
 };
 
 struct mwifiex_adapter {
@@ -1628,4 +1630,5 @@ void mwifiex_debugfs_remove(void);
 void mwifiex_dev_debugfs_init(struct mwifiex_private *priv);
 void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv);
 #endif
+void mwifiex_do_flr(struct mwifiex_adapter *adapter, bool prepare);
 #endif /* !_MWIFIEX_MAIN_H_ */
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index a6af85d..81bceef 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -277,6 +277,52 @@ static const struct pci_device_id mwifiex_ids[] = {
 
 MODULE_DEVICE_TABLE(pci, mwifiex_ids);
 
+static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
+{
+	struct mwifiex_adapter *adapter;
+	struct pcie_service_card *card;
+
+	if (!pdev) {
+		pr_err("%s: PCIe device is not specified\n", __func__);
+		return;
+	}
+
+	card = (struct pcie_service_card *)pci_get_drvdata(pdev);
+	if (!card || !card->adapter) {
+		pr_err("%s: Card or adapter structure is not valid (%ld)\n",
+		       __func__, (long)card);
+		return;
+	}
+
+	adapter = card->adapter;
+	mwifiex_dbg(adapter, INFO,
+		    "%s: vendor=0x%4.04x device=0x%4.04x rev=%d %s\n",
+		    __func__, pdev->vendor, pdev->device,
+		    pdev->revision,
+		    prepare ? "Pre-FLR" : "Post-FLR");
+
+	if (prepare) {
+		/* Kernel would be performing FLR after this notification.
+		 * Cleanup all software without cleaning anything related to
+		 * PCIe and HW.
+		 */
+		mwifiex_do_flr(adapter, prepare);
+		adapter->surprise_removed = true;
+	} else {
+		/* Kernel stores and restores PCIe function context before and
+		 * after performing FLR respectively. Reconfigure the software
+		 * and firmware including firmware redownload
+		 */
+		adapter->surprise_removed = false;
+		mwifiex_do_flr(adapter, prepare);
+	}
+	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+}
+
+static const struct pci_error_handlers mwifiex_pcie_err_handler[] = {
+		{ .reset_notify = mwifiex_pcie_reset_notify, },
+};
+
 #ifdef CONFIG_PM_SLEEP
 /* Power Management Hooks */
 static SIMPLE_DEV_PM_OPS(mwifiex_pcie_pm_ops, mwifiex_pcie_suspend,
@@ -295,6 +341,7 @@ static struct pci_driver __refdata mwifiex_pcie = {
 	},
 #endif
 	.shutdown = mwifiex_pcie_shutdown,
+	.err_handler = mwifiex_pcie_err_handler,
 };
 
 /*
@@ -2952,7 +2999,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	const struct mwifiex_pcie_card_reg *reg;
 	struct pci_dev *pdev;
 	int i;
 
@@ -2976,8 +3022,90 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
 			if (card->msi_enable)
 				pci_disable_msi(pdev);
 	       }
+	}
+}
 
-		reg = card->pcie.reg;
+/* This function initializes the PCI-E host memory space, WCB rings, etc.
+ *
+ * The following initializations steps are followed -
+ *      - Allocate TXBD ring buffers
+ *      - Allocate RXBD ring buffers
+ *      - Allocate event BD ring buffers
+ *      - Allocate command response ring buffer
+ *      - Allocate sleep cookie buffer
+ * Part of mwifiex_pcie_init(), not reset the PCIE registers
+ */
+static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	int ret;
+	struct pci_dev *pdev = card->dev;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+	card->cmdrsp_buf = NULL;
+	ret = mwifiex_pcie_create_txbd_ring(adapter);
+	if (ret) {
+		mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n");
+		goto err_cre_txbd;
+	}
+
+	ret = mwifiex_pcie_create_rxbd_ring(adapter);
+	if (ret) {
+		mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n");
+		goto err_cre_rxbd;
+	}
+
+	ret = mwifiex_pcie_create_evtbd_ring(adapter);
+	if (ret) {
+		mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n");
+		goto err_cre_evtbd;
+	}
+
+	ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
+	if (ret) {
+		mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n");
+		goto err_alloc_cmdbuf;
+	}
+
+	if (reg->sleep_cookie) {
+		ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
+		if (ret) {
+			mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n");
+			goto err_alloc_cookie;
+		}
+	} else {
+		card->sleep_cookie_vbase = NULL;
+	}
+	return;
+
+err_alloc_cookie:
+	mwifiex_pcie_delete_cmdrsp_buf(adapter);
+err_alloc_cmdbuf:
+	mwifiex_pcie_delete_evtbd_ring(adapter);
+err_cre_evtbd:
+	mwifiex_pcie_delete_rxbd_ring(adapter);
+err_cre_rxbd:
+	mwifiex_pcie_delete_txbd_ring(adapter);
+err_cre_txbd:
+	pci_iounmap(pdev, card->pci_mmap1);
+}
+
+/* This function cleans up the PCI-E host memory space.
+ * Some code is extracted from mwifiex_unregister_dev()
+ *
+ */
+static void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+	if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
+		mwifiex_dbg(adapter, ERROR, "Failed to write driver not-ready signature\n");
+
+	adapter->seq_num = 0;
+	adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
+
+	if (card) {
 		if (reg->sleep_cookie)
 			mwifiex_pcie_delete_sleep_cookie_buf(adapter);
 
@@ -2987,6 +3115,8 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
 		mwifiex_pcie_delete_txbd_ring(adapter);
 		card->cmdrsp_buf = NULL;
 	}
+
+	return;
 }
 
 static struct mwifiex_if_ops pcie_ops = {
@@ -3013,6 +3143,8 @@ static struct mwifiex_if_ops pcie_ops = {
 	.clean_pcie_ring =		mwifiex_clean_pcie_ring_buf,
 	.reg_dump =			mwifiex_pcie_reg_dump,
 	.device_dump =			mwifiex_pcie_device_dump,
+	.down_dev =			mwifiex_pcie_down_dev,
+	.up_dev =			mwifiex_pcie_up_dev,
 };
 
 /*
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h
index f05061c..f6992f0 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.h
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.h
@@ -37,6 +37,7 @@
 #define PCIEUART8997_FW_NAME_V2 "mrvl/pcieuart8997_combo_v2.bin"
 #define PCIEUSB8997_FW_NAME_Z "mrvl/pcieusb8997_combo.bin"
 #define PCIEUSB8997_FW_NAME_V2 "mrvl/pcieusb8997_combo_v2.bin"
+#define PCIE8997_DEFAULT_WIFIFW_NAME "mrvl/pcie8997_wlan.bin"
 
 #define PCIE_VENDOR_ID_MARVELL              (0x11ab)
 #define PCIE_VENDOR_ID_V2_MARVELL           (0x1b4b)
-- 
1.9.1


^ permalink raw reply related

* Re: [PATCH 5/9] mwifiex: cfg80211 set_default_mgmt_key handler
From: Kalle Valo @ 2016-07-26 15:12 UTC (permalink / raw)
  To: Jouni Malinen
  Cc: Amitkumar Karwar, linux-wireless@vger.kernel.org, Cathy Luo,
	Nishant Sarmukadam
In-Reply-To: <20160721155131.GA6292@w1.fi>

Jouni Malinen <j@w1.fi> writes:

> On Thu, Jul 21, 2016 at 09:18:11AM +0000, Amitkumar Karwar wrote:
>> > From: Kalle Valo [mailto:kvalo@codeaurora.org]
>> > Is it correct to ignore the key index? I see that brcmfmac ignores it as
>> > well but I want to still confirm this.
>> > 
>> > Does this mean that with this patcfh mwifiex properly supports MFP?
>> 
>> Yes. We do pass MFP tests with this patch.
>
> Did you test IGTK rekeying? This patch looks exactly as broken as it did
> the last time it was proposed more than a year ago and after the same
> concern not receiving any reaction..

Indeed, I had already forgetten that this patch was submitted February
2015:

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

Please don't do like this and repost patches without earlier comments
addressed (or at least document the history).

-- 
Kalle Valo

^ permalink raw reply

* Re: [v2, RESEND] qtnfmac: announcement of new FullMAC driver for Quantenna chipsets
From: Kalle Valo @ 2016-07-26 15:15 UTC (permalink / raw)
  To: Igor Mitsyanko
  Cc: johannes, linux-wireless, Avinash Patil, Dmitrii Lebed,
	Sergei Maksimenko, Sergey Matyukevich, Bindu Therthala,
	Huizhao Wang, Kamlesh Rath
In-Reply-To: <c9a9f9f2-2943-14d2-3b5d-c401e870d7a0@quantenna.com>

Igor Mitsyanko <igor.mitsyanko.os@quantenna.com> writes:

>     I applied this to the pending branch so that kbuild bot can run build tests on
>     it. Let's see what it finds.
>
>
>
> Kalle, I think you did that before already, at least I have received a
> following error report a while back:
>
>
> Hi,
>
> [auto build test ERROR on wireless-drivers-next/master]
> [also build test ERROR on v4.7-rc4 next-20160620]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url:    https://github.com/0day-ci/linux/commits/igor-mitsyanko-os-quantenna-com/qtnfmac-announcement-of-new-FullMAC-driver-for-Quantenna-chipsets/20160621-061419
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
> config: m32r-allyesconfig (attached as .config)
> compiler: m32r-linux-gcc (GCC) 4.9.0
> reproduce:
>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         make.cross ARCH=m32r

I suspect that in this case the kbuild bot took the patch from the
mailing list and run some quick tests on that. But AFAIK commits on a
git tree get wider testing.

-- 
Kalle Valo

^ permalink raw reply

* [PATCH] ath10k: fix get rx_status from htt context
From: Ashok Raj Nagarajan @ 2016-07-26 16:45 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, arnagara, Ashok Raj Nagarajan

On handling amsdu on rx path, get the rx_status from htt context. Without this
fix, we are seeing warnings when running DBDC traffic like this.

WARNING: CPU: 0 PID: 0 at net/mac80211/rx.c:4105 ieee80211_rx_napi+0x88/0x7d8 [mac80211]()

[ 1715.878248] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.18.21 #1
[ 1715.878273] [<c001d3f4>] (unwind_backtrace) from [<c001a4b0>] (show_stack+0x10/0x14)
[ 1715.878293] [<c001a4b0>] (show_stack) from [<c01bee64>] (dump_stack+0x70/0xbc)
[ 1715.878315] [<c01bee64>] (dump_stack) from [<c002a61c>] (warn_slowpath_common+0x64/0x88)
[ 1715.878339] [<c002a61c>] (warn_slowpath_common) from [<c002a6d0>] (warn_slowpath_null+0x18/0x20)
[ 1715.878395] [<c002a6d0>] (warn_slowpath_null) from [<bf4caa98>] (ieee80211_rx_napi+0x88/0x7d8 [mac80211])
[ 1715.878474] [<bf4caa98>] (ieee80211_rx_napi [mac80211]) from [<bf568658>] (ath10k_htt_t2h_msg_handler+0xb48/0xbfc [ath10k_core])
[ 1715.878535] [<bf568658>] (ath10k_htt_t2h_msg_handler [ath10k_core]) from [<bf568708>] (ath10k_htt_t2h_msg_handler+0xbf8/0xbfc [ath10k_core])
[ 1715.878597] [<bf568708>] (ath10k_htt_t2h_msg_handler [ath10k_core]) from [<bf569160>] (ath10k_htt_txrx_compl_task+0xa54/0x1170 [ath10k_core])
[ 1715.878639] [<bf569160>] (ath10k_htt_txrx_compl_task [ath10k_core]) from [<c002db14>] (tasklet_action+0xb4/0x130)
[ 1715.878659] [<c002db14>] (tasklet_action) from [<c002d110>] (__do_softirq+0xe0/0x210)
[ 1715.878678] [<c002d110>] (__do_softirq) from [<c002d4b4>] (irq_exit+0x84/0xe0)
[ 1715.878700] [<c002d4b4>] (irq_exit) from [<c005a544>] (__handle_domain_irq+0x98/0xd0)
[ 1715.878722] [<c005a544>] (__handle_domain_irq) from [<c00085f4>] (gic_handle_irq+0x38/0x5c)
[ 1715.878741] [<c00085f4>] (gic_handle_irq) from [<c0009680>] (__irq_svc+0x40/0x74)
[ 1715.878753] Exception stack(0xc05f9f50 to 0xc05f9f98)
[ 1715.878767] 9f40: ffffffed 00000000 00399e1e c000a220
[ 1715.878786] 9f60: 00000000 c05f6780 c05f8000 00000000 c05f5db8 ffffffed c05f8000 c04d1980
[ 1715.878802] 9f80: 00000000 c05f9f98 c0018110 c0018114 60000013 ffffffff
[ 1715.878822] [<c0009680>] (__irq_svc) from [<c0018114>] (arch_cpu_idle+0x2c/0x50)
[ 1715.878844] [<c0018114>] (arch_cpu_idle) from [<c00530d4>] (cpu_startup_entry+0x108/0x234)
[ 1715.878866] [<c00530d4>] (cpu_startup_entry) from [<c05c7be0>] (start_kernel+0x33c/0x3b8)
[ 1715.878879] ---[ end trace 6d5e1cc0fef8ed6a ]---
[ 1715.878899] ------------[ cut here ]------------

Fixes: 18235664e7f9 ("ath10k: cleanup amsdu processing for rx indication")
Signed-off-by: Ashok Raj Nagarajan <arnagara@qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 78db5d6..24c8d65 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1525,7 +1525,7 @@ static void ath10k_htt_rx_h_filter(struct ath10k *ar,
 static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
 {
 	struct ath10k *ar = htt->ar;
-	static struct ieee80211_rx_status rx_status;
+	struct ieee80211_rx_status *rx_status = &htt->rx_status;
 	struct sk_buff_head amsdu;
 	int ret;
 
@@ -1549,11 +1549,11 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
 		return ret;
 	}
 
-	ath10k_htt_rx_h_ppdu(ar, &amsdu, &rx_status, 0xffff);
+	ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
 	ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
-	ath10k_htt_rx_h_filter(ar, &amsdu, &rx_status);
-	ath10k_htt_rx_h_mpdu(ar, &amsdu, &rx_status);
-	ath10k_htt_rx_h_deliver(ar, &amsdu, &rx_status);
+	ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
+	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
+	ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
 
 	return 0;
 }
-- 
1.9.1


^ permalink raw reply related

* Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
From: alexmcwhirter @ 2016-07-26 18:15 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Alan Curry, Al Viro, linux-wireless, netdev, linux-kernel
In-Reply-To: <2589898.190WVraD7Z@debian64>

On 2016-07-26 09:59, Christian Lamparter wrote:
> Thanks, I gave the program a try with my WNDA3100 and a WN821N v2 
> devices.
> I did not see any corruptions in any of the tests though. Can you tell 
> me
> something about your wireless network too? I would like to know what 
> router
> and firmware are you using? Also important: what's your wireless 
> configuration?
> (WPA?, CCMP or TKIP? HT40, HT20 or Legacy rates? ...)
> 
> Probably the quickest and easiest way to get that information is by 
> running
> the following commands as root, when you are connected to your wifi 
> network
> and post the results:
> # iw dev wlan0 link
> # iw dev wlan0 scan dump
> 
> (You can of course remove your device's MACs, but please do it 
> consistently).
> 
> Regards,
> Christian

I wonder if this is something that is only affecting certain NIC's? For 
example, it see this issue on sun4u boxes with tigon3 and hme 
interfaces. But on my sun4v boxes that have e1000 interfaces everything 
works fine.

^ permalink raw reply

* Re: BRCM4339 NVRAM file
From: Arend van Spriel @ 2016-07-26 19:20 UTC (permalink / raw)
  To: Fabio Estevam, frankyl, Arend van Spriel, pieterpg, John Linville
  Cc: linux-wireless
In-Reply-To: <CAOMZO5Dto7bScKrz9tmM5TDg8Tss5xGiO77F4u==V4pLgXZZGw@mail.gmail.com>



On 25-07-16 22:36, Fabio Estevam wrote:
> Hi,
> 
> I am trying to use brcm4339 on a imx6ul-pico board running kernel 4.7.
> 
> According to commit bed89b64bcbc7 (" brcmfmac: add firmware and nvram
> file name for bcm4339") we need to provide brcmfmac4339-sdio.bin and
> brcmfmac4339-sdio.txt files.
> 
> Was able to get the brcmfmac4339-sdio.bin from linux-firmware git
> tree, but could not find the nvram file: brcmfmac4339-sdio.txt.
> 
> Does anyone know where brcmfmac4339-sdio.txt can be found?

I though it would be mentioned in [1], but unfortunately not (will
change that). The nvram is board specific so you will have to ask the
vendor supplying the bcm4339. From what I googled that would be
TechNexion, right?

Regards,
Arend

[1] https://wireless.wiki.kernel.org/en/users/drivers/brcm80211

> Thanks,
> 
> Fabio Estevam
> 

^ permalink raw reply

* Re: BRCM4339 NVRAM file
From: Fabio Estevam @ 2016-07-26 19:25 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: frankyl, Arend van Spriel, pieterpg, John Linville,
	linux-wireless
In-Reply-To: <5797B7FB.4090707@broadcom.com>

Hi Arend,

On Tue, Jul 26, 2016 at 4:20 PM, Arend van Spriel
<arend.vanspriel@broadcom.com> wrote:

> I though it would be mentioned in [1], but unfortunately not (will
> change that). The nvram is board specific so you will have to ask the
> vendor supplying the bcm4339. From what I googled that would be
> TechNexion, right?

That's correct.

Thanks for the clarification.

Regards,

Fabio Estevam

^ permalink raw reply

* brcm4330 fails to load on newer kernels
From: Fabio Estevam @ 2016-07-26 22:35 UTC (permalink / raw)
  To: Arend van Spriel, Hante Meuleman; +Cc: linux-wireless, brcm80211-dev-list

Hi,

On a imx6sl-warp board with a brcm4330 I get the following results
depending on the kernel version:

- Kernel 4.4.15: place brcmfmac4330-sdio.bin and brcmfmac4330-sdio.txt
in the rootfs and the kernel is able to read them correctly. wlan0 is
present. All is fine.

- Kernel 4.5.7: place brcmfmac4330-sdio.bin brcmfmac4330-sdio.txt in
the rootfs and the kernel fails to load them:

brcmfmac mmc1:0001:1: Direct firmware load for
brcm/brcmfmac4330-sdio.bin failed with error -2

Then I build brcmfmac4330-sdio.bin brcmfmac4330-sdio.txt into the
kernel and then firmware is detected and wlan0 appears.

- Kernel 4.7: I can place the firmware and nvram file into the rootfs
or built-i and the following error is seen:

brcmfmac: brcmf_sdio_htclk: HT Avail timeout (1000000): clkctl 0x50
brcmfmac: brcmf_sdio_htclk: HT Avail timeout (1000000): clkctl 0x50
brcmfmac: brcmf_sdio_htclk: HT Avail timeout (1000000): clkctl 0x50

So wlan0 never appears here.

Does anyone have any suggestions about these different behaviours?

Thanks,

Fabio Estevam

^ permalink raw reply

* Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
From: Alan Curry @ 2016-07-27  1:14 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Alan Curry, Al Viro, linux-wireless, netdev, linux-kernel,
	alexmcwhirter
In-Reply-To: <2589898.190WVraD7Z@debian64>

Christian Lamparter wrote:
> Thanks, I gave the program a try with my WNDA3100 and a WN821N v2 devices.
> I did not see any corruptions in any of the tests though. Can you tell me
> something about your wireless network too? I would like to know what router
> and firmware are you using? Also important: what's your wireless configuration?

The router/access-point is a Comcast-issued Technicolor cable modem, model
TC8305C. The only thing I can find on it that looks like it might identify
a firmware version is this:

    System Software Version

    eMTA & DOCSIS Software Version: 01.E6.01.22.25
    Packet Cable: 2.0

I assume Comcast pushes firmware updates whenever they feel like it.

There is possibly another clue. I get this message from the kernel sometimes:

    ieee80211 phy0: invalid plcp cck rate (0).

I had this message appearing long before the data corruption bug started.
It never correlated with any actual problems, so I turned down the priority
level of the message to get it off the console, and forgot about it. I
was unable to discover what a "plcp" or "cck" is so the message means
nothing to me.

> (WPA?, CCMP or TKIP? HT40, HT20 or Legacy rates? ...)
> 
> Probably the quickest and easiest way to get that information is by running
> the following commands as root, when you are connected to your wifi network
> and post the results:
> # iw dev wlan0 link
> # iw dev wlan0 scan dump

Connected to cc:03:fa:bf:e9:ea (on wlan0)
	SSID: HOME-E9EA
	freq: 2462
	RX: 20726719 bytes (106483 packets)
	TX: 5902478 bytes (44707 packets)
	signal: -43 dBm
	tx bitrate: 54.0 MBit/s

	bss flags:	short-slot-time
	dtim period:	1
	beacon int:	100

BSS cc:03:fa:bf:e9:ea(on wlan0) -- associated
	TSF: 236407205748 usec (2d, 17:40:07)
	freq: 2462
	beacon interval: 100 TUs
	capability: ESS Privacy ShortSlotTime (0x0411)
	signal: -33.00 dBm
	last seen: 634452 ms ago
	Information elements from Probe Response frame:
	SSID: HOME-E9EA
	Supported rates: 1.0* 2.0* 5.5* 11.0* 18.0 24.0* 36.0 54.0 
	DS Parameter set: channel 11
	ERP: <no flags>
	ERP D4.0: <no flags>
	RSN:	 * Version: 1
		 * Group cipher: TKIP
		 * Pairwise ciphers: CCMP TKIP
		 * Authentication suites: PSK
		 * Capabilities: 16-PTKSA-RC 1-GTKSA-RC (0x000c)
	Extended supported rates: 6.0* 9.0 12.0* 48.0 
	HT capabilities:
		Capabilities: 0x18bd
			RX LDPC
			HT20
			SM Power Save disabled
			RX Greenfield
			RX HT20 SGI
			TX STBC
			No RX STBC
			Max AMSDU length: 7935 bytes
			DSSS/CCK HT40
		Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
		Minimum RX AMPDU time spacing: 8 usec (0x06)
		HT RX MCS rate indexes supported: 0-23
		HT TX MCS rate indexes are undefined
	HT operation:
		 * primary channel: 11
		 * secondary channel offset: no secondary
		 * STA channel width: 20 MHz
		 * RIFS: 1
		 * HT protection: nonmember
		 * non-GF present: 1
		 * OBSS non-GF present: 1
		 * dual beacon: 0
		 * dual CTS protection: 0
		 * STBC beacon: 0
		 * L-SIG TXOP Prot: 0
		 * PCO active: 0
		 * PCO phase: 0
	WPS:	 * Version: 1.0
		 * Wi-Fi Protected Setup State: 2 (Configured)
		 * Response Type: 3 (AP)
		 * UUID: 6d1b1911-14a9-391c-cdee-89850a5aa1ef
		 * Manufacturer: Technicolor
		 * Model: Technicolor
		 * Model Number: 123456
		 * Serial Number: 0000001
		 * Primary Device Type: 6-0050f204-1
		 * Device name: TechnicolorAP
		 * Config methods: Display
		 * RF Bands: 0x1
		 * Unknown TLV (0x1049, 6 bytes): 00 37 2a 00 01 20
	WPA:	 * Version: 1
		 * Group cipher: TKIP
		 * Pairwise ciphers: CCMP TKIP
		 * Authentication suites: PSK
		 * Capabilities: 16-PTKSA-RC 1-GTKSA-RC (0x000c)
	WMM:	 * Parameter version 1
		 * u-APSD
		 * BE: CW 15-1023, AIFSN 3
		 * BK: CW 15-1023, AIFSN 7
		 * VI: CW 7-15, AIFSN 2, TXOP 3008 usec
		 * VO: CW 3-7, AIFSN 2, TXOP 1504 usec

-- 
Alan Curry

^ permalink raw reply

* Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
From: Kalle Valo @ 2016-07-27  6:39 UTC (permalink / raw)
  To: alexmcwhirter
  Cc: Christian Lamparter, Alan Curry, Al Viro, linux-wireless, netdev,
	linux-kernel
In-Reply-To: <66636d159da5342b1387035fbcfe0d35@triadic.us>

alexmcwhirter@triadic.us writes:

> On 2016-07-26 09:59, Christian Lamparter wrote:
>> Thanks, I gave the program a try with my WNDA3100 and a WN821N v2
>> devices.
>> I did not see any corruptions in any of the tests though. Can you
>> tell me
>> something about your wireless network too? I would like to know what
>> router
>> and firmware are you using? Also important: what's your wireless
>> configuration?
>> (WPA?, CCMP or TKIP? HT40, HT20 or Legacy rates? ...)
>>
>> Probably the quickest and easiest way to get that information is by
>> running
>> the following commands as root, when you are connected to your wifi
>> network
>> and post the results:
>> # iw dev wlan0 link
>> # iw dev wlan0 scan dump
>>
>> (You can of course remove your device's MACs, but please do it
>> consistently).
>>
>> Regards,
>> Christian
>
> I wonder if this is something that is only affecting certain NIC's?
> For example, it see this issue on sun4u boxes with tigon3 and hme
> interfaces. But on my sun4v boxes that have e1000 interfaces
> everything works fine.

Kernel configuration might also make a difference. Trying to find an
Kconfig option which affects this could be useful.

-- 
Kalle Valo

^ permalink raw reply

* [PATCH] ath10k: Allow setting coverage class
From: Benjamin Berg @ 2016-07-27  8:33 UTC (permalink / raw)
  To: Kalle Valo, linux-wireless
  Cc: ath10k, Sebastian Gottschall, Benjamin Berg, Simon Wunderlich,
	Mathias Kretschmer

Unfortunately ath10k does not generally allow modifying the coverage class
with the stock firmware and Qualcomm has so far refused to implement this
feature so that it can be properly supported in ath10k. If we however know
the registers that need to be modified for proper operation with a higher
coverage class, then we can do these modifications from the driver.

This patch implements this hack for first generation cards which are based
on a core that is similar to ath9k. The registers are modified in place and
need to be re-written every time the firmware sets them. To achieve this
the register status is verified after any event from the firmware.

The coverage class may not be modified temporarily right after the card
re-initializes the registers. This is for example the case during scanning.

A warning will be generated if the hack is not supported on the card or
unexpected values are hit. There is no error reporting for userspace
applications though (this is a limitation in the mac80211 driver
interface).

Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
working on a userspace support for this. This patch wouldn't have been
possible without this documentation.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fit.fraunhofer.de>
---
 drivers/net/wireless/ath/ath10k/core.h    |  10 ++
 drivers/net/wireless/ath/ath10k/hw.c      |   9 ++
 drivers/net/wireless/ath/ath10k/hw.h      |  28 +++++-
 drivers/net/wireless/ath/ath10k/mac.c     |  10 ++
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  17 ++++
 drivers/net/wireless/ath/ath10k/wmi.c     | 151 ++++++++++++++++++++++++++++++
 6 files changed, 224 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 9374bcd..781219b 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -935,6 +935,16 @@ struct ath10k {
 	struct ath10k_thermal thermal;
 	struct ath10k_wow wow;
 
+	/* protected by data_lock */
+	struct {
+		s16 coverage_class;
+
+		u32 reg_slottime_conf;
+		u32 reg_slottime_orig;
+		u32 reg_ack_cts_timeout_conf;
+		u32 reg_ack_cts_timeout_orig;
+	} fw_coverage;
+
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index f903d46..82249be 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -22,6 +22,7 @@ const struct ath10k_hw_regs qca988x_regs = {
 	.rtc_soc_base_address		= 0x00004000,
 	.rtc_wmac_base_address		= 0x00005000,
 	.soc_core_base_address		= 0x00009000,
+	.wlan_mac_base_address		= 0x00020000,
 	.ce_wrapper_base_address	= 0x00057000,
 	.ce0_base_address		= 0x00057400,
 	.ce1_base_address		= 0x00057800,
@@ -48,6 +49,7 @@ const struct ath10k_hw_regs qca6174_regs = {
 	.rtc_soc_base_address			= 0x00000800,
 	.rtc_wmac_base_address			= 0x00001000,
 	.soc_core_base_address			= 0x0003a000,
+	.wlan_mac_base_address			= 0x00020000,
 	.ce_wrapper_base_address		= 0x00034000,
 	.ce0_base_address			= 0x00034400,
 	.ce1_base_address			= 0x00034800,
@@ -74,6 +76,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
 	.rtc_soc_base_address			= 0x00080000,
 	.rtc_wmac_base_address			= 0x00000000,
 	.soc_core_base_address			= 0x00082000,
+	.wlan_mac_base_address			= 0x00030000,
 	.ce_wrapper_base_address		= 0x0004d000,
 	.ce0_base_address			= 0x0004a000,
 	.ce1_base_address			= 0x0004a400,
@@ -109,6 +112,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
 const struct ath10k_hw_regs qca4019_regs = {
 	.rtc_soc_base_address                   = 0x00080000,
 	.soc_core_base_address                  = 0x00082000,
+	.wlan_mac_base_address                  = 0x00030000,
 	.ce_wrapper_base_address                = 0x0004d000,
 	.ce0_base_address                       = 0x0004a000,
 	.ce1_base_address                       = 0x0004a400,
@@ -139,6 +143,7 @@ const struct ath10k_hw_regs qca4019_regs = {
 };
 
 const struct ath10k_hw_values qca988x_values = {
+	.mac_core_rev			= ATH10K_HW_MAC_CORE_ATH9K,
 	.rtc_state_val_on		= 3,
 	.ce_count			= 8,
 	.msi_assign_ce_max		= 7,
@@ -148,6 +153,7 @@ const struct ath10k_hw_values qca988x_values = {
 };
 
 const struct ath10k_hw_values qca6174_values = {
+	.mac_core_rev			= ATH10K_HW_MAC_CORE_ATH9K,
 	.rtc_state_val_on		= 3,
 	.ce_count			= 8,
 	.msi_assign_ce_max		= 7,
@@ -157,6 +163,7 @@ const struct ath10k_hw_values qca6174_values = {
 };
 
 const struct ath10k_hw_values qca99x0_values = {
+	.mac_core_rev			= ATH10K_HW_MAC_CORE_WAVE2,
 	.rtc_state_val_on		= 5,
 	.ce_count			= 12,
 	.msi_assign_ce_max		= 12,
@@ -166,6 +173,7 @@ const struct ath10k_hw_values qca99x0_values = {
 };
 
 const struct ath10k_hw_values qca9888_values = {
+	.mac_core_rev			= ATH10K_HW_MAC_CORE_WAVE2,
 	.rtc_state_val_on		= 3,
 	.ce_count			= 12,
 	.msi_assign_ce_max		= 12,
@@ -175,6 +183,7 @@ const struct ath10k_hw_values qca9888_values = {
 };
 
 const struct ath10k_hw_values qca4019_values = {
+	.mac_core_rev                   = ATH10K_HW_MAC_CORE_WAVE2,
 	.ce_count                       = 12,
 	.num_target_ce_config_wlan      = 10,
 	.ce_desc_meta_data_mask         = 0xFFF0,
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index e014cd7..4151326 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -230,6 +230,7 @@ struct ath10k_hw_regs {
 	u32 rtc_soc_base_address;
 	u32 rtc_wmac_base_address;
 	u32 soc_core_base_address;
+	u32 wlan_mac_base_address;
 	u32 ce_wrapper_base_address;
 	u32 ce0_base_address;
 	u32 ce1_base_address;
@@ -257,6 +258,12 @@ extern const struct ath10k_hw_regs qca6174_regs;
 extern const struct ath10k_hw_regs qca99x0_regs;
 extern const struct ath10k_hw_regs qca4019_regs;
 
+enum ath10k_hw_mac_core_rev {
+	ATH10K_HW_MAC_CORE_UNKNOWN = 0,
+	ATH10K_HW_MAC_CORE_ATH9K,
+	ATH10K_HW_MAC_CORE_WAVE2,
+};
+
 struct ath10k_hw_values {
 	u32 rtc_state_val_on;
 	u8 ce_count;
@@ -264,6 +271,7 @@ struct ath10k_hw_values {
 	u8 num_target_ce_config_wlan;
 	u16 ce_desc_meta_data_mask;
 	u8 ce_desc_meta_data_lsb;
+	enum ath10k_hw_mac_core_rev mac_core_rev;
 };
 
 extern const struct ath10k_hw_values qca988x_values;
@@ -545,7 +553,7 @@ enum ath10k_hw_cc_wraparound_type {
 #define WLAN_SI_BASE_ADDRESS			0x00010000
 #define WLAN_GPIO_BASE_ADDRESS			0x00014000
 #define WLAN_ANALOG_INTF_BASE_ADDRESS		0x0001c000
-#define WLAN_MAC_BASE_ADDRESS			0x00020000
+#define WLAN_MAC_BASE_ADDRESS			ar->regs->wlan_mac_base_address
 #define EFUSE_BASE_ADDRESS			0x00030000
 #define FPGA_REG_BASE_ADDRESS			0x00039000
 #define WLAN_UART2_BASE_ADDRESS			0x00054c00
@@ -745,4 +753,22 @@ enum ath10k_hw_cc_wraparound_type {
 
 #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
 
+/* Register definitions for ath10k cards that include a MAC which is based
+ * on ATH9k. This ath9k based MAC still has the same or at least similar
+ * registers.
+ * These registers are usually managed by the ath10k firmware. However by
+ * overriding them it is possible to support a few additional features; in this
+ * case setting the coverage class.
+ */
+#define ATH9K_MAC_TIME_OUT		0x8014
+#define ATH9K_MAC_TIME_OUT_MAX		0x00003FFF
+#define ATH9K_MAC_TIME_OUT_ACK		0x00003FFF
+#define ATH9K_MAC_TIME_OUT_ACK_S	0
+#define ATH9K_MAC_TIME_OUT_CTS		0x3FFF0000
+#define ATH9K_MAC_TIME_OUT_CTS_S	16
+
+#define ATH9K_MAC_IFS_SLOT		0x1070
+#define ATH9K_MAC_IFS_SLOT_M		0x0000FFFF
+#define ATH9K_MAC_IFS_SLOT_RESV0	0xFFFF0000
+
 #endif /* _HW_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 55c823f..a9b587e 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5372,6 +5372,15 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_set_coverage_class(struct ieee80211_hw *hw,
+				      s16 value)
+{
+	struct ath10k *ar = hw->priv;
+
+	if (ath10k_wmi_pdev_set_coverage_class(ar, value) == -EOPNOTSUPP)
+		ath10k_warn(ar, "Modification of coverage class is not supported!\n");
+}
+
 static int ath10k_hw_scan(struct ieee80211_hw *hw,
 			  struct ieee80211_vif *vif,
 			  struct ieee80211_scan_request *hw_req)
@@ -7397,6 +7406,7 @@ static const struct ieee80211_ops ath10k_ops = {
 	.remove_interface		= ath10k_remove_interface,
 	.configure_filter		= ath10k_configure_filter,
 	.bss_info_changed		= ath10k_bss_info_changed,
+	.set_coverage_class		= ath10k_set_coverage_class,
 	.hw_scan			= ath10k_hw_scan,
 	.cancel_hw_scan			= ath10k_cancel_hw_scan,
 	.set_key			= ath10k_set_key,
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 64ebd30..3ebc57e 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -52,6 +52,8 @@ struct wmi_ops {
 	int (*pull_wow_event)(struct ath10k *ar, struct sk_buff *skb,
 			      struct wmi_wow_ev_arg *arg);
 	enum wmi_txbf_conf (*get_txbf_conf_scheme)(struct ath10k *ar);
+	void (*set_pdev_coverage_class)(struct ath10k *ar,
+					s16 value);
 
 	struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt);
 	struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar);
@@ -1012,6 +1014,21 @@ ath10k_wmi_pdev_get_temperature(struct ath10k *ar)
 }
 
 static inline int
+ath10k_wmi_pdev_set_coverage_class(struct ath10k *ar,
+				   s16 value)
+{
+	if (!ar->wmi.ops->set_pdev_coverage_class)
+		return -EOPNOTSUPP;
+
+	if (value < 0)
+		value = 0;
+
+	ar->wmi.ops->set_pdev_coverage_class(ar, value);
+
+	return 0;
+}
+
+static inline int
 ath10k_wmi_addba_clear_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac)
 {
 	struct sk_buff *skb;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 169cd2e7..7f30e70 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -28,6 +28,7 @@
 #include "wmi-ops.h"
 #include "p2p.h"
 #include "hw.h"
+#include "hif.h"
 
 /* MAIN WMI cmd track */
 static struct wmi_cmd_map wmi_cmd_map = {
@@ -3096,6 +3097,121 @@ ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
+static void
+ath10k_ath9k_set_pdev_coverage_class(struct ath10k *ar, s16 value)
+{
+	u32 slottime_reg;
+	u32 slottime;
+	u32 timeout_reg;
+	u32 timeout;
+	u32 counters_freq_mhz = ar->hw_params.channel_counters_freq_hz / 1000;
+
+	/* The firmware does not support setting the coverage class. Instead
+	 * this function monitors and modifies the corresponding MAC registers.
+	 */
+
+	spin_lock_bh(&ar->data_lock);
+
+	/* Retrieve the current values of the two registers that need to be
+	 * adjusted.
+	 */
+	slottime_reg = ath10k_hif_read32(ar, WLAN_MAC_BASE_ADDRESS +
+					     ATH9K_MAC_IFS_SLOT);
+	timeout_reg = ath10k_hif_read32(ar, WLAN_MAC_BASE_ADDRESS +
+					    ATH9K_MAC_TIME_OUT);
+
+	if (value < 0)
+		value = ar->fw_coverage.coverage_class;
+
+	/* Break out if the coverage class and registers have the expected
+	 * value.
+	 */
+	if (value == ar->fw_coverage.coverage_class &&
+	    slottime_reg == ar->fw_coverage.reg_slottime_conf &&
+	    timeout_reg == ar->fw_coverage.reg_ack_cts_timeout_conf)
+		goto unlock;
+
+	/* Store new initial register values from the firmware. */
+	if (slottime_reg != ar->fw_coverage.reg_slottime_conf)
+		ar->fw_coverage.reg_slottime_orig = slottime_reg;
+	if (timeout_reg != ar->fw_coverage.reg_ack_cts_timeout_conf)
+		ar->fw_coverage.reg_ack_cts_timeout_orig = timeout_reg;
+
+	/* Calculat new value based on the (original) firmware calculation. */
+	slottime_reg = ar->fw_coverage.reg_slottime_orig;
+	timeout_reg = ar->fw_coverage.reg_ack_cts_timeout_orig;
+
+	/* Do some sanity checks on the slottime register. */
+	if (unlikely(slottime_reg % counters_freq_mhz)) {
+		ath10k_warn(ar,
+			    "Not adjusting coverage class timeouts, expected an integer microsecond slot time in HW register\n");
+
+		goto store_regs;
+	}
+
+	slottime = (slottime_reg & ATH9K_MAC_IFS_SLOT_M) / counters_freq_mhz;
+	if (unlikely(slottime != 9 && slottime != 20)) {
+		ath10k_warn(ar,
+			    "Not adjusting coverage class timeouts, expected a slot time of 9 or 20us in HW register. It is %uus.\n",
+			    slottime);
+
+		goto store_regs;
+	}
+
+	/* Recalculate the register values by adding the additional propagation
+	 * delay (3us per coverage class).
+	 */
+
+	slottime = (slottime_reg & ATH9K_MAC_IFS_SLOT_M);
+	slottime += value * 3 * counters_freq_mhz;
+	slottime = min_t(u32, slottime, ATH9K_MAC_IFS_SLOT_M);
+	slottime_reg = (slottime_reg & ~ATH9K_MAC_IFS_SLOT_M) | slottime;
+
+	/* Update ack timeout (lower halfword). */
+	timeout = (timeout_reg & ATH9K_MAC_TIME_OUT_ACK);
+	timeout = timeout >> ATH9K_MAC_TIME_OUT_ACK_S;
+	timeout += 3 * value * counters_freq_mhz;
+	timeout = min_t(u32, timeout, ATH9K_MAC_TIME_OUT_MAX);
+	timeout = (timeout << ATH9K_MAC_TIME_OUT_ACK_S)
+	timeout = timeout & ATH9K_MAC_TIME_OUT_ACK;
+	timeout_reg = (timeout_reg & ~ATH9K_MAC_TIME_OUT_ACK) | timeout;
+
+	/* Update cts timeout (upper halfword). */
+	timeout = (timeout_reg & ATH9K_MAC_TIME_OUT_CTS)
+	timeout = timeout >> ATH9K_MAC_TIME_OUT_CTS_S;
+	timeout += 3 * value * counters_freq_mhz;
+	timeout = min_t(u32, timeout, ATH9K_MAC_TIME_OUT_MAX);
+	timeout = (timeout << ATH9K_MAC_TIME_OUT_CTS_S)
+	timeout = timeout & ATH9K_MAC_TIME_OUT_CTS;
+	timeout_reg = (timeout_reg & ~ATH9K_MAC_TIME_OUT_CTS) | timeout;
+
+	ath10k_hif_write32(ar, WLAN_MAC_BASE_ADDRESS + 0x1070, slottime_reg);
+	ath10k_hif_write32(ar, WLAN_MAC_BASE_ADDRESS + 0x8014, timeout_reg);
+
+store_regs:
+	/* After an error we will not retry setting the coverage class. */
+	ar->fw_coverage.coverage_class = value;
+	ar->fw_coverage.reg_slottime_conf = slottime_reg;
+	ar->fw_coverage.reg_ack_cts_timeout_conf = timeout_reg;
+
+unlock:
+	spin_unlock_bh(&ar->data_lock);
+}
+
+static void
+ath10k_wmi_op_set_pdev_coverage_class(struct ath10k *ar, s16 value)
+{
+	switch (ar->hw_values->mac_core_rev) {
+	case ATH10K_HW_MAC_CORE_ATH9K:
+		ath10k_ath9k_set_pdev_coverage_class(ar, value);
+		break;
+	default:
+		if (value != -1)
+			ath10k_warn(ar, "Setting the coverage class is not supported for this chipset.");
+		break;
+	}
+}
+
 void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_peer_kick_ev_arg arg = {};
@@ -4992,6 +5108,12 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	ath10k_wmi_op_set_pdev_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -5116,6 +5238,12 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	ath10k_wmi_op_set_pdev_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -5240,6 +5368,12 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	ath10k_wmi_op_set_pdev_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -5323,6 +5457,12 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	ath10k_wmi_op_set_pdev_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -6017,6 +6157,7 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar,
 		| WMI_SCAN_EVENT_COMPLETED
 		| WMI_SCAN_EVENT_BSS_CHANNEL
 		| WMI_SCAN_EVENT_FOREIGN_CHANNEL
+		| WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT
 		| WMI_SCAN_EVENT_DEQUEUED;
 	arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT;
 	arg->n_bssids = 1;
@@ -7666,6 +7807,8 @@ static const struct wmi_ops wmi_ops = {
 	.pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats,
 	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
 
+	.set_pdev_coverage_class = ath10k_wmi_op_set_pdev_coverage_class,
+
 	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
 	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
 	.gen_pdev_set_rd = ath10k_wmi_op_gen_pdev_set_rd,
@@ -7739,6 +7882,8 @@ static const struct wmi_ops wmi_10_1_ops = {
 	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
 	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
 
+	.set_pdev_coverage_class = ath10k_wmi_op_set_pdev_coverage_class,
+
 	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
 	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
 	.gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
@@ -7808,6 +7953,8 @@ static const struct wmi_ops wmi_10_2_ops = {
 	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
 	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
 
+	.set_pdev_coverage_class = ath10k_wmi_op_set_pdev_coverage_class,
+
 	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
 	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
 	.gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
@@ -7874,6 +8021,8 @@ static const struct wmi_ops wmi_10_2_4_ops = {
 	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
 	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
 
+	.set_pdev_coverage_class = ath10k_wmi_op_set_pdev_coverage_class,
+
 	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
 	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
 	.gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
@@ -7938,6 +8087,8 @@ static const struct wmi_ops wmi_10_4_ops = {
 	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
 	.get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme,
 
+	.set_pdev_coverage_class = ath10k_wmi_op_set_pdev_coverage_class,
+
 	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
 	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
 	.gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
-- 
2.8.1


^ permalink raw reply related


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