Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [RFC PATCH 2/2] rtl8xxxu: Add watchdog to update rate mask by signal strength
From: Chris Chiu @ 2019-05-27  6:38 UTC (permalink / raw)
  To: Daniel Drake
  Cc: Jes Sorensen, Kalle Valo, David Miller, linux-wireless, netdev,
	Linux Kernel, Linux Upstreaming Team, Larry Finger
In-Reply-To: <CAD8Lp47K0Jn2wotANdQV3kT9yPP7bLnVd0eYhWui-vNDOEXBTA@mail.gmail.com>

On Wed, May 22, 2019 at 2:38 AM Daniel Drake <drake@endlessm.com> wrote:
>
> On Fri, May 10, 2019 at 2:37 AM Chris Chiu <chiu@endlessm.com> wrote:
> > I've verified that multiple virtual interface can not work simultaneously in
> > STA mode. I assigned different mac address for different vifs, I can only
> > bring only one interface up. If I want to bring the second vif up, it always
> > complains "SIOCSIFFLAGS: Device or resource busy".
>
> Interesting. Can you go deeper into that so that we can be more
> confident of this limitation?
>
> ieee80211_open() is the starting point.
> ieee80211_check_concurrent_iface() is one candidate to generate -EBUSY
> but from inspection, I don't think that's happening in this case,
> perhaps you can keep following through in order to figure out which
> part of the code is not allowing the 2nd STA interface to come up.
>
> Daniel

The -EBUSY is returned by the ieee80211_check_combinations() in the
ieee80211_check_concurrent_iface() function which is invoked each time
doing ieee80211_open().
The ieee80211_check_combinations() returns the -EBUSY because of
cfg80211_check_combinations() will iterate all interfaces of different types
then checks the combination is valid or not, which in this case the number
of interface combination accumulated by cfg80211_iter_sum_ifcombos is 0
when I'm trying to bring up the second station interface.

Chris

^ permalink raw reply

* Re: Issue with Broadcom wireless in 5.2rc1 (was Re: [PATCH] mmc: sdhci: queue work after sdhci_defer_done())
From: Adrian Hunter @ 2019-05-27  7:48 UTC (permalink / raw)
  To: Brian Masney, Arend Van Spriel
  Cc: Franky Lin, Hante Meuleman, Chi-Hsien Lin, Wright Feng,
	ulf.hansson, faiz_abbas, linux-mmc, linux-kernel, linux-arm-msm,
	Kalle Valo, linux-wireless, brcm80211-dev-list.pdl,
	brcm80211-dev-list, netdev
In-Reply-To: <20190526195819.GA29665@basecamp>

On 26/05/19 10:58 PM, Brian Masney wrote:
> On Sun, May 26, 2019 at 08:42:21PM +0200, Arend Van Spriel wrote:
>> On 5/26/2019 2:21 PM, Brian Masney wrote:
>>> + Broadcom wireless maintainers
>>>
>>> On Fri, May 24, 2019 at 11:49:58AM -0400, Brian Masney wrote:
>>>> On Fri, May 24, 2019 at 03:17:13PM +0300, Adrian Hunter wrote:
>>>>> On 24/05/19 2:10 PM, Brian Masney wrote:
>>>>>> WiFi stopped working on the LG Nexus 5 phone and the issue was bisected
>>>>>> to the commit c07a48c26519 ("mmc: sdhci: Remove finish_tasklet") that
>>>>>> moved from using a tasklet to a work queue. That patch also changed
>>>>>> sdhci_irq() to return IRQ_WAKE_THREAD instead of finishing the work when
>>>>>> sdhci_defer_done() is true. Change it to queue work to the complete work
>>>>>> queue if sdhci_defer_done() is true so that the functionality is
>>>>>> equilivent to what was there when the finish_tasklet was present. This
>>>>>> corrects the WiFi breakage on the Nexus 5 phone.
>>>>>>
>>>>>> Signed-off-by: Brian Masney <masneyb@onstation.org>
>>>>>> Fixes: c07a48c26519 ("mmc: sdhci: Remove finish_tasklet")
>>>>>> ---
>>>>>> [ ... ]
>>>>>>
>>>>>>   drivers/mmc/host/sdhci.c | 2 +-
>>>>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>>>> index 97158344b862..3563c3bc57c9 100644
>>>>>> --- a/drivers/mmc/host/sdhci.c
>>>>>> +++ b/drivers/mmc/host/sdhci.c
>>>>>> @@ -3115,7 +3115,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
>>>>>>   			continue;
>>>>>>   		if (sdhci_defer_done(host, mrq)) {
>>>>>> -			result = IRQ_WAKE_THREAD;
>>>>>> +			queue_work(host->complete_wq, &host->complete_work);
>>>>>
>>>>> The IRQ thread has a lot less latency than the work queue, which is why it
>>>>> is done that way.
>>>>>
>>>>> I am not sure why you say this change is equivalent to what was there
>>>>> before, nor why it fixes your problem.
>>>>>
>>>>> Can you explain some more?
>>>>
>>>> [ ... ]
>>>>
>>>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c calls
>>>> sdio_claim_host() and it appears to never return.

This is because SDHCI is using the IRQ thread to process the SDIO card
interrupt (sdio_run_irqs()).  When the card driver tries to use the card, it
causes interrupts which deadlocks since c07a48c26519 ("mmc: sdhci: Remove
finish_tasklet") has moved the tasklet processing to the IRQ thread.

I would expect to be able to use the IRQ thread to complete requests, and it
is desirable to do so because it is lower latency.

Probably, SDHCI should use sdio_signal_irq() which queues a work item, and
is what other drivers are doing.

I will investigate some more and send a patch.

^ permalink raw reply

* Re: Issue with Broadcom wireless in 5.2rc1 (was Re: [PATCH] mmc: sdhci: queue work after sdhci_defer_done())
From: Brian Masney @ 2019-05-27  9:37 UTC (permalink / raw)
  To: Arend Van Spriel, Adrian Hunter
  Cc: Franky Lin, Hante Meuleman, Chi-Hsien Lin, Wright Feng,
	ulf.hansson, faiz_abbas, linux-mmc, linux-kernel, linux-arm-msm,
	Kalle Valo, linux-wireless, brcm80211-dev-list.pdl,
	brcm80211-dev-list, netdev
In-Reply-To: <20190526195819.GA29665@basecamp>

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

On Sun, May 26, 2019 at 03:58:19PM -0400, Brian Masney wrote:
> I attached a patch that shows how I was able to determine what had
> already claimed the host.

I realized this morning that I had a flaw with my test patch that
diagnosed what was deadlocked. The mmc_ctx structure was allocated on
the stack. I attached a second version of that patch that uses
kmalloc() for that structure. It didn't change what I reported
yesterday: brcmf_sdiod_ramrw is deadlocked by
brcmf_sdio_download_firmware.


On Mon, May 27, 2019 at 10:48:24AM +0300, Adrian Hunter wrote:
> This is because SDHCI is using the IRQ thread to process the SDIO card
> interrupt (sdio_run_irqs()).  When the card driver tries to use the card, it
> causes interrupts which deadlocks since c07a48c26519 ("mmc: sdhci: Remove
> finish_tasklet") has moved the tasklet processing to the IRQ thread.
> 
> I would expect to be able to use the IRQ thread to complete requests, and it
> is desirable to do so because it is lower latency.
> 
> Probably, SDHCI should use sdio_signal_irq() which queues a work item, and
> is what other drivers are doing.
> 
> I will investigate some more and send a patch.

Thank you!

Brian


[-- Attachment #2: 0001-troubleshoot-broadcom-wireless-lockup-in-5.2rc1-v2.patch --]
[-- Type: text/x-diff, Size: 28427 bytes --]

From acc78b5e581d2c3ebc994a6ad6e7b367f2b81935 Mon Sep 17 00:00:00 2001
From: Brian Masney <masneyb@onstation.org>
Date: Sun, 26 May 2019 15:36:40 -0400
Subject: [PATCH] troubleshoot broadcom wireless lockup in 5.2rc1 (v2)

Signed-off-by: Brian Masney <masneyb@onstation.org>
---
 drivers/mmc/core/core.c                       |  15 ++
 .../broadcom/brcm80211/brcmfmac/bcmsdh.c      |  46 ++---
 .../broadcom/brcm80211/brcmfmac/sdio.c        | 160 ++++++++++--------
 .../broadcom/brcm80211/brcmfmac/sdio.h        |   3 +
 include/linux/mmc/host.h                      |   1 +
 5 files changed, 136 insertions(+), 89 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 6db36dc870b5..768acabf029b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -814,7 +814,22 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
 		if (stop || !host->claimed || mmc_ctx_matches(host, ctx, task))
 			break;
 		spin_unlock_irqrestore(&host->lock, flags);
+
+		if (ctx != NULL && ctx->descr != NULL) {
+			WARN_ON(1);
+			dev_info(&host->class_dev, "%s: FIXME - before schedule() - descr=%s, claimer=%s\n",
+				 __func__, ctx->descr,
+				 host->claimer != NULL ? host->claimer->descr : NULL);
+		}
+
 		schedule();
+
+		if (ctx != NULL && ctx->descr != NULL) {
+			dev_info(&host->class_dev, "%s: FIXME - after schedule() - descr=%s, claimer=%s\n",
+				 __func__, ctx->descr,
+				 host->claimer != NULL ? host->claimer->descr : NULL);
+		}
+
 		spin_lock_irqsave(&host->lock, flags);
 	}
 	set_current_state(TASK_RUNNING);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index 60aede5abb4d..fdeaeb1353af 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -47,6 +47,8 @@
 #include "sdio.h"
 #include "core.h"
 #include "common.h"
+#include "../../../../../mmc/core/host.h"
+#include "../../../../../mmc/core/core.h"
 
 #define SDIOH_API_ACCESS_RETRY_LIMIT	2
 
@@ -132,7 +134,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
 		}
 		sdiodev->irq_wake = true;
 
-		sdio_claim_host(sdiodev->func1);
+		brcmf_sdio_claim_host(sdiodev->func1, __func__);
 
 		if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) {
 			/* assign GPIO to SDIO core */
@@ -159,13 +161,13 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
 			data |= SDIO_CCCR_BRCM_SEPINT_ACT_HI;
 		brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_BRCM_SEPINT,
 				     data, &ret);
-		sdio_release_host(sdiodev->func1);
+		brcmf_sdio_release_host(sdiodev->func1);
 	} else {
 		brcmf_dbg(SDIO, "Entering\n");
-		sdio_claim_host(sdiodev->func1);
+		brcmf_sdio_claim_host(sdiodev->func1, __func__);
 		sdio_claim_irq(sdiodev->func1, brcmf_sdiod_ib_irqhandler);
 		sdio_claim_irq(sdiodev->func2, brcmf_sdiod_dummy_irqhandler);
-		sdio_release_host(sdiodev->func1);
+		brcmf_sdio_release_host(sdiodev->func1);
 		sdiodev->sd_irq_requested = true;
 	}
 
@@ -183,10 +185,10 @@ void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
 		struct brcmfmac_sdio_pd *pdata;
 
 		pdata = &sdiodev->settings->bus.sdio;
-		sdio_claim_host(sdiodev->func1);
+		brcmf_sdio_claim_host(sdiodev->func1, __func__);
 		brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
 		brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
-		sdio_release_host(sdiodev->func1);
+		brcmf_sdio_release_host(sdiodev->func1);
 
 		sdiodev->oob_irq_requested = false;
 		if (sdiodev->irq_wake) {
@@ -199,10 +201,10 @@ void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
 	}
 
 	if (sdiodev->sd_irq_requested) {
-		sdio_claim_host(sdiodev->func1);
+		brcmf_sdio_claim_host(sdiodev->func1, __func__);
 		sdio_release_irq(sdiodev->func2);
 		sdio_release_irq(sdiodev->func1);
-		sdio_release_host(sdiodev->func1);
+		brcmf_sdio_release_host(sdiodev->func1);
 		sdiodev->sd_irq_requested = false;
 	}
 }
@@ -695,7 +697,7 @@ brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
 	else
 		dsize = size;
 
-	sdio_claim_host(sdiodev->func1);
+	brcmf_sdio_claim_host(sdiodev->func1, __func__);
 
 	/* Do the transfer(s) */
 	while (size) {
@@ -742,7 +744,7 @@ brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
 
 	dev_kfree_skb(pkt);
 
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 
 	return err;
 }
@@ -827,17 +829,17 @@ static int brcmf_sdiod_freezer_on(struct brcmf_sdio_dev *sdiodev)
 	brcmf_sdio_trigger_dpc(sdiodev->bus);
 	wait_event(sdiodev->freezer->thread_freeze,
 		   atomic_read(expect) == sdiodev->freezer->frozen_count);
-	sdio_claim_host(sdiodev->func1);
+	brcmf_sdio_claim_host(sdiodev->func1, __func__);
 	res = brcmf_sdio_sleep(sdiodev->bus, true);
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 	return res;
 }
 
 static void brcmf_sdiod_freezer_off(struct brcmf_sdio_dev *sdiodev)
 {
-	sdio_claim_host(sdiodev->func1);
+	brcmf_sdio_claim_host(sdiodev->func1, __func__);
 	brcmf_sdio_sleep(sdiodev->bus, false);
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 	atomic_set(&sdiodev->freezer->freezing, 0);
 	complete_all(&sdiodev->freezer->resumed);
 }
@@ -887,14 +889,14 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
 	brcmf_sdiod_freezer_detach(sdiodev);
 
 	/* Disable Function 2 */
-	sdio_claim_host(sdiodev->func2);
+	brcmf_sdio_claim_host(sdiodev->func2, __func__);
 	sdio_disable_func(sdiodev->func2);
-	sdio_release_host(sdiodev->func2);
+	brcmf_sdio_release_host(sdiodev->func2);
 
 	/* Disable Function 1 */
-	sdio_claim_host(sdiodev->func1);
+	brcmf_sdio_claim_host(sdiodev->func1, __func__);
 	sdio_disable_func(sdiodev->func1);
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 
 	sg_free_table(&sdiodev->sgtable);
 	sdiodev->sbwad = 0;
@@ -915,18 +917,18 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
 {
 	int ret = 0;
 
-	sdio_claim_host(sdiodev->func1);
+	brcmf_sdio_claim_host(sdiodev->func1, __func__);
 
 	ret = sdio_set_block_size(sdiodev->func1, SDIO_FUNC1_BLOCKSIZE);
 	if (ret) {
 		brcmf_err("Failed to set F1 blocksize\n");
-		sdio_release_host(sdiodev->func1);
+		brcmf_sdio_release_host(sdiodev->func1);
 		goto out;
 	}
 	ret = sdio_set_block_size(sdiodev->func2, SDIO_FUNC2_BLOCKSIZE);
 	if (ret) {
 		brcmf_err("Failed to set F2 blocksize\n");
-		sdio_release_host(sdiodev->func1);
+		brcmf_sdio_release_host(sdiodev->func1);
 		goto out;
 	}
 
@@ -935,7 +937,7 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
 
 	/* Enable Function 1 */
 	ret = sdio_enable_func(sdiodev->func1);
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 	if (ret) {
 		brcmf_err("Failed to enable F1: err=%d\n", ret);
 		goto out;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 22b73da42822..ba836aa5da78 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -45,6 +45,8 @@
 #include "core.h"
 #include "common.h"
 #include "bcdc.h"
+#include "../../../../../mmc/core/host.h"
+#include "../../../../../mmc/core/core.h"
 
 #define DCMD_RESP_TIMEOUT	msecs_to_jiffies(2500)
 #define CTL_DONE_TIMEOUT	msecs_to_jiffies(2500)
@@ -651,6 +653,25 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
 	BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012)
 };
 
+void brcmf_sdio_claim_host(struct sdio_func *func, const char *descr)
+{
+	struct mmc_ctx *mmc_ctx;
+
+	mmc_ctx = kmalloc(sizeof(*mmc_ctx), GFP_KERNEL);
+	mmc_ctx->task = NULL;
+	mmc_ctx->descr = descr;
+	__mmc_claim_host(func->card->host, mmc_ctx, NULL);
+}
+
+void brcmf_sdio_release_host(struct sdio_func *func)
+{
+	struct mmc_ctx *tofree;
+
+	tofree = func->card->host->claimer;
+	sdio_release_host(func);
+	kfree(tofree);
+}
+
 static void pkt_align(struct sk_buff *p, int len, int align)
 {
 	uint datalign;
@@ -995,7 +1016,7 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
 	struct sdpcm_shared_le sh_le;
 	__le32 addr_le;
 
-	sdio_claim_host(bus->sdiodev->func1);
+	brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 	brcmf_sdio_bus_sleep(bus, false, false);
 
 	/*
@@ -1029,7 +1050,7 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
 	if (rv < 0)
 		goto fail;
 
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 
 	/* Endianness */
 	sh->flags = le32_to_cpu(sh_le.flags);
@@ -1051,7 +1072,7 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
 fail:
 	brcmf_err("unable to obtain sdpcm_shared info: rv=%d (addr=0x%x)\n",
 		  rv, addr);
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 	return rv;
 }
 
@@ -1583,10 +1604,10 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 		 * read directly into the chained packet, or allocate a large
 		 * packet and and copy into the chain.
 		 */
-		sdio_claim_host(bus->sdiodev->func1);
+		brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 		errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
 						 &bus->glom, dlen);
-		sdio_release_host(bus->sdiodev->func1);
+		brcmf_sdio_release_host(bus->sdiodev->func1);
 		bus->sdcnt.f2rxdata++;
 
 		/* On failure, kill the superframe */
@@ -1594,11 +1615,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			brcmf_err("glom read of %d bytes failed: %d\n",
 				  dlen, errcode);
 
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			brcmf_sdio_rxfail(bus, true, false);
 			bus->sdcnt.rxglomfail++;
 			brcmf_sdio_free_glom(bus);
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 			return 0;
 		}
 
@@ -1608,10 +1629,10 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 
 		rd_new.seq_num = rxseq;
 		rd_new.len = dlen;
-		sdio_claim_host(bus->sdiodev->func1);
+		brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 		errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new,
 					     BRCMF_SDIO_FT_SUPER);
-		sdio_release_host(bus->sdiodev->func1);
+		brcmf_sdio_release_host(bus->sdiodev->func1);
 		bus->cur_read.len = rd_new.len_nxtfrm << 4;
 
 		/* Remove superframe header, remember offset */
@@ -1626,10 +1647,10 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 
 			rd_new.len = pnext->len;
 			rd_new.seq_num = rxseq++;
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new,
 						     BRCMF_SDIO_FT_SUB);
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 			brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
 					   pnext->data, 32, "subframe:\n");
 
@@ -1638,11 +1659,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 
 		if (errcode) {
 			/* Terminate frame on error */
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			brcmf_sdio_rxfail(bus, true, false);
 			bus->sdcnt.rxglomfail++;
 			brcmf_sdio_free_glom(bus);
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 			bus->cur_read.len = 0;
 			return 0;
 		}
@@ -1849,7 +1870,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 
 		rd->len_left = rd->len;
 		/* read header first for unknow frame length */
-		sdio_claim_host(bus->sdiodev->func1);
+		brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 		if (!rd->len) {
 			ret = brcmf_sdiod_recv_buf(bus->sdiodev,
 						   bus->rxhdr, BRCMF_FIRSTREAD);
@@ -1859,7 +1880,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 					  ret);
 				bus->sdcnt.rx_hdrfail++;
 				brcmf_sdio_rxfail(bus, true, true);
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 				continue;
 			}
 
@@ -1869,7 +1890,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 
 			if (brcmf_sdio_hdparse(bus, bus->rxhdr, rd,
 					       BRCMF_SDIO_FT_NORMAL)) {
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 				if (!bus->rxpending)
 					break;
 				else
@@ -1885,7 +1906,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 				rd->len_nxtfrm = 0;
 				/* treat all packet as event if we don't know */
 				rd->channel = SDPCM_EVENT_CHANNEL;
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 				continue;
 			}
 			rd->len_left = rd->len > BRCMF_FIRSTREAD ?
@@ -1902,7 +1923,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 			brcmf_err("brcmu_pkt_buf_get_skb failed\n");
 			brcmf_sdio_rxfail(bus, false,
 					    RETRYCHAN(rd->channel));
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 			continue;
 		}
 		skb_pull(pkt, head_read);
@@ -1910,16 +1931,16 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 
 		ret = brcmf_sdiod_recv_pkt(bus->sdiodev, pkt);
 		bus->sdcnt.f2rxdata++;
-		sdio_release_host(bus->sdiodev->func1);
+		brcmf_sdio_release_host(bus->sdiodev->func1);
 
 		if (ret < 0) {
 			brcmf_err("read %d bytes from channel %d failed: %d\n",
 				  rd->len, rd->channel, ret);
 			brcmu_pkt_buf_free_skb(pkt);
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			brcmf_sdio_rxfail(bus, true,
 					    RETRYCHAN(rd->channel));
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 			continue;
 		}
 
@@ -1930,7 +1951,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 		} else {
 			memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
 			rd_new.seq_num = rd->seq_num;
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
 					       BRCMF_SDIO_FT_NORMAL)) {
 				rd->len = 0;
@@ -1943,11 +1964,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 					  roundup(rd_new.len, 16) >> 4);
 				rd->len = 0;
 				brcmf_sdio_rxfail(bus, true, true);
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 				brcmu_pkt_buf_free_skb(pkt);
 				continue;
 			}
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 			rd->len_nxtfrm = rd_new.len_nxtfrm;
 			rd->channel = rd_new.channel;
 			rd->dat_offset = rd_new.dat_offset;
@@ -1963,9 +1984,10 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 					  rd_new.seq_num);
 				/* Force retry w/normal header read */
 				rd->len = 0;
-				sdio_claim_host(bus->sdiodev->func1);
+				brcmf_sdio_claim_host(bus->sdiodev->func1,
+						      __func__);
 				brcmf_sdio_rxfail(bus, false, true);
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 				brcmu_pkt_buf_free_skb(pkt);
 				continue;
 			}
@@ -1988,9 +2010,10 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 			} else {
 				brcmf_err("%s: glom superframe w/o "
 					  "descriptor!\n", __func__);
-				sdio_claim_host(bus->sdiodev->func1);
+				brcmf_sdio_claim_host(bus->sdiodev->func1,
+						      __func__);
 				brcmf_sdio_rxfail(bus, false, false);
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 			}
 			/* prepare the descriptor for the next read */
 			rd->len = rd->len_nxtfrm << 4;
@@ -2267,14 +2290,14 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 	if (ret)
 		goto done;
 
-	sdio_claim_host(bus->sdiodev->func1);
+	brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 	ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
 	bus->sdcnt.f2txdata++;
 
 	if (ret < 0)
 		brcmf_sdio_txfail(bus);
 
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 
 done:
 	brcmf_sdio_txpkt_postp(bus, pktq);
@@ -2330,10 +2353,10 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 		/* In poll mode, need to check for other events */
 		if (!bus->intr) {
 			/* Check device status, signal pending interrupt */
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			intstatus = brcmf_sdiod_readl(bus->sdiodev,
 						      intstat_addr, &ret);
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 
 			bus->sdcnt.f2txdata++;
 			if (ret != 0)
@@ -2442,7 +2465,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
 	}
 
 	if (sdiodev->state != BRCMF_SDIOD_NOMEDIUM) {
-		sdio_claim_host(sdiodev->func1);
+		brcmf_sdio_claim_host(sdiodev->func1, __func__);
 
 		/* Enable clock for device interrupts */
 		brcmf_sdio_bus_sleep(bus, false, false);
@@ -2477,7 +2500,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
 		brcmf_sdiod_writel(sdiodev, core->base + SD_REG(intstatus),
 				   local_hostintmask, NULL);
 
-		sdio_release_host(sdiodev->func1);
+		brcmf_sdio_release_host(sdiodev->func1);
 	}
 	/* Clear the data packet queues */
 	brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
@@ -2552,7 +2575,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 
 	brcmf_dbg(SDIO, "Enter\n");
 
-	sdio_claim_host(bus->sdiodev->func1);
+	brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 
 	/* If waiting for HTAVAIL, check status */
 	if (!bus->sr_enabled && bus->clkstate == CLK_PENDING) {
@@ -2615,7 +2638,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 		intstatus |= brcmf_sdio_hostmail(bus);
 	}
 
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 
 	/* Generally don't ask for these, can get CRC errors... */
 	if (intstatus & I_WR_OOSYNC) {
@@ -2658,7 +2681,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 
 	if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
 	    data_ok(bus)) {
-		sdio_claim_host(bus->sdiodev->func1);
+		brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 		if (bus->ctrl_frame_stat) {
 			err = brcmf_sdio_tx_ctrlframe(bus,  bus->ctrl_frame_buf,
 						      bus->ctrl_frame_len);
@@ -2666,7 +2689,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 			wmb();
 			bus->ctrl_frame_stat = false;
 		}
-		sdio_release_host(bus->sdiodev->func1);
+		brcmf_sdio_release_host(bus->sdiodev->func1);
 		brcmf_sdio_wait_event_wakeup(bus);
 	}
 	/* Send queued frames (limit 1 if rx may still be pending) */
@@ -2682,14 +2705,14 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 		brcmf_err("failed backplane access over SDIO, halting operation\n");
 		atomic_set(&bus->intstatus, 0);
 		if (bus->ctrl_frame_stat) {
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			if (bus->ctrl_frame_stat) {
 				bus->ctrl_frame_err = -ENODEV;
 				wmb();
 				bus->ctrl_frame_stat = false;
 				brcmf_sdio_wait_event_wakeup(bus);
 			}
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 		}
 	} else if (atomic_read(&bus->intstatus) ||
 		   atomic_read(&bus->ipend) > 0 ||
@@ -2904,13 +2927,13 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 					 CTL_DONE_TIMEOUT);
 	ret = 0;
 	if (bus->ctrl_frame_stat) {
-		sdio_claim_host(bus->sdiodev->func1);
+		brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 		if (bus->ctrl_frame_stat) {
 			brcmf_dbg(SDIO, "ctrl_frame timeout\n");
 			bus->ctrl_frame_stat = false;
 			ret = -ETIMEDOUT;
 		}
-		sdio_release_host(bus->sdiodev->func1);
+		brcmf_sdio_release_host(bus->sdiodev->func1);
 	}
 	if (!ret) {
 		brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
@@ -3048,7 +3071,7 @@ static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus,
 		return 0;
 	}
 
-	sdio_claim_host(bus->sdiodev->func1);
+	brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 	if (sh->assert_file_addr != 0) {
 		error = brcmf_sdiod_ramrw(bus->sdiodev, false,
 					  sh->assert_file_addr, (u8 *)file, 80);
@@ -3061,7 +3084,7 @@ static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus,
 		if (error < 0)
 			return error;
 	}
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 
 	seq_printf(seq, "dongle assert: %s:%d: assert(%s)\n",
 		   file, sh->assert_line, expr);
@@ -3340,7 +3363,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
 	int bcmerror;
 	u32 rstvec;
 
-	sdio_claim_host(bus->sdiodev->func1);
+	brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 	brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
 
 	rstvec = get_unaligned_le32(fw->data);
@@ -3369,7 +3392,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
 
 err:
 	brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 	return bcmerror;
 }
 
@@ -3564,7 +3587,7 @@ static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data,
 
 	address = bus->ci->rambase;
 	offset = err = 0;
-	sdio_claim_host(sdiodev->func1);
+	brcmf_sdio_claim_host(sdiodev->func1, __func__);
 	while (offset < mem_size) {
 		len = ((offset + MEMBLOCK) < mem_size) ? MEMBLOCK :
 		      mem_size - offset;
@@ -3580,7 +3603,7 @@ static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data,
 	}
 
 done:
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 	return err;
 }
 
@@ -3637,10 +3660,11 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
 			if (!bus->dpc_triggered) {
 				u8 devpend;
 
-				sdio_claim_host(bus->sdiodev->func1);
+				brcmf_sdio_claim_host(bus->sdiodev->func1,
+						      __func__);
 				devpend = brcmf_sdiod_func0_rb(bus->sdiodev,
 						  SDIO_CCCR_INTx, NULL);
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 				intstatus = devpend & (INTR_STATUS_FUNC1 |
 						       INTR_STATUS_FUNC2);
 			}
@@ -3666,13 +3690,13 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
 		bus->console.count += jiffies_to_msecs(BRCMF_WD_POLL);
 		if (bus->console.count >= bus->console_interval) {
 			bus->console.count -= bus->console_interval;
-			sdio_claim_host(bus->sdiodev->func1);
+			brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 			/* Make sure backplane clock is on */
 			brcmf_sdio_bus_sleep(bus, false, false);
 			if (brcmf_sdio_readconsole(bus) < 0)
 				/* stop on error */
 				bus->console_interval = 0;
-			sdio_release_host(bus->sdiodev->func1);
+			brcmf_sdio_release_host(bus->sdiodev->func1);
 		}
 	}
 #endif				/* DEBUG */
@@ -3685,11 +3709,12 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
 			bus->idlecount++;
 			if (bus->idlecount > bus->idletime) {
 				brcmf_dbg(SDIO, "idle\n");
-				sdio_claim_host(bus->sdiodev->func1);
+				brcmf_sdio_claim_host(bus->sdiodev->func1,
+						      __func__);
 				brcmf_sdio_wd_timer(bus, false);
 				bus->idlecount = 0;
 				brcmf_sdio_bus_sleep(bus, true, false);
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 			}
 		} else {
 			bus->idlecount = 0;
@@ -3903,7 +3928,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 	u32 drivestrength;
 
 	sdiodev = bus->sdiodev;
-	sdio_claim_host(sdiodev->func1);
+	brcmf_sdio_claim_host(sdiodev->func1, __func__);
 
 	pr_debug("F1 signature read @0x18000000=0x%4x\n",
 		 brcmf_sdiod_readl(sdiodev, SI_ENUM_BASE, NULL));
@@ -4010,7 +4035,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 	if (err)
 		goto fail;
 
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 
 	brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
 
@@ -4031,7 +4056,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 	return true;
 
 fail:
-	sdio_release_host(sdiodev->func1);
+	brcmf_sdio_release_host(sdiodev->func1);
 	return false;
 }
 
@@ -4147,7 +4172,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
 	bus->sdcnt.tickcnt = 0;
 	brcmf_sdio_wd_timer(bus, true);
 
-	sdio_claim_host(sdiod->func1);
+	brcmf_sdio_claim_host(sdiod->func1, __func__);
 
 	/* Make sure backplane clock is on, needed to generate F2 interrupt */
 	brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
@@ -4243,7 +4268,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
 		goto checkdied;
 	}
 
-	sdio_release_host(sdiod->func1);
+	brcmf_sdio_release_host(sdiod->func1);
 
 	/* Assign bus interface call back */
 	sdiod->bus_if->dev = sdiod->dev;
@@ -4255,7 +4280,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
 	err = brcmf_attach(sdiod->dev, sdiod->settings);
 	if (err != 0) {
 		brcmf_err("brcmf_attach failed\n");
-		sdio_claim_host(sdiod->func1);
+		brcmf_sdio_claim_host(sdiod->func1, __func__);
 		goto checkdied;
 	}
 
@@ -4265,7 +4290,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
 checkdied:
 	brcmf_sdio_checkdied(bus);
 release:
-	sdio_release_host(sdiod->func1);
+	brcmf_sdio_release_host(sdiod->func1);
 fail:
 	brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err);
 	device_release_driver(&sdiod->func2->dev);
@@ -4361,7 +4386,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 	bus->blocksize = bus->sdiodev->func2->cur_blksize;
 	bus->roundup = min(max_roundup, bus->blocksize);
 
-	sdio_claim_host(bus->sdiodev->func1);
+	brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 
 	/* Disable F2 to clear any intermediate frame state on the dongle */
 	sdio_disable_func(bus->sdiodev->func2);
@@ -4371,7 +4396,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 	/* Done with backplane-dependent accesses, can drop clock... */
 	brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
 
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 
 	/* ...and initialize clock/power states */
 	bus->clkstate = CLK_SDONLY;
@@ -4428,7 +4453,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
 
 		if (bus->ci) {
 			if (bus->sdiodev->state != BRCMF_SDIOD_NOMEDIUM) {
-				sdio_claim_host(bus->sdiodev->func1);
+				brcmf_sdio_claim_host(bus->sdiodev->func1,
+						      __func__);
 				brcmf_sdio_wd_timer(bus, false);
 				brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
 				/* Leave the device in state where it is
@@ -4438,7 +4464,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
 				msleep(20);
 				brcmf_chip_set_passive(bus->ci);
 				brcmf_sdio_clkctl(bus, CLK_NONE, false);
-				sdio_release_host(bus->sdiodev->func1);
+				brcmf_sdio_release_host(bus->sdiodev->func1);
 			}
 			brcmf_chip_detach(bus->ci);
 		}
@@ -4485,9 +4511,9 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep)
 {
 	int ret;
 
-	sdio_claim_host(bus->sdiodev->func1);
+	brcmf_sdio_claim_host(bus->sdiodev->func1, __func__);
 	ret = brcmf_sdio_bus_sleep(bus, sleep, false);
-	sdio_release_host(bus->sdiodev->func1);
+	brcmf_sdio_release_host(bus->sdiodev->func1);
 
 	return ret;
 }
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
index 34b031154da9..51ade937f5b0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -388,4 +388,7 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
 int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep);
 void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
 
+void brcmf_sdio_claim_host(struct sdio_func *func, const char *descr);
+void brcmf_sdio_release_host(struct sdio_func *func);
+
 #endif /* BRCMFMAC_SDIO_H */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 43d0f0c496f6..6ccc76150f45 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -267,6 +267,7 @@ struct mmc_supply {
 };
 
 struct mmc_ctx {
+	const char *descr;
 	struct task_struct *task;
 };
 
-- 
2.20.1


^ permalink raw reply related

* Re: Issue with Broadcom wireless in 5.2rc1 (was Re: [PATCH] mmc: sdhci: queue work after sdhci_defer_done())
From: Adrian Hunter @ 2019-05-27 12:08 UTC (permalink / raw)
  To: Brian Masney, Arend Van Spriel
  Cc: Franky Lin, Hante Meuleman, Chi-Hsien Lin, Wright Feng,
	ulf.hansson, faiz_abbas, linux-mmc, linux-kernel, linux-arm-msm,
	Kalle Valo, linux-wireless, brcm80211-dev-list.pdl,
	brcm80211-dev-list, netdev
In-Reply-To: <20190527093711.GA853@basecamp>

On 27/05/19 12:37 PM, Brian Masney wrote:
> On Sun, May 26, 2019 at 03:58:19PM -0400, Brian Masney wrote:
>> I attached a patch that shows how I was able to determine what had
>> already claimed the host.
> On Mon, May 27, 2019 at 10:48:24AM +0300, Adrian Hunter wrote:
>> This is because SDHCI is using the IRQ thread to process the SDIO card
>> interrupt (sdio_run_irqs()).  When the card driver tries to use the card, it
>> causes interrupts which deadlocks since c07a48c26519 ("mmc: sdhci: Remove
>> finish_tasklet") has moved the tasklet processing to the IRQ thread.
>>
>> I would expect to be able to use the IRQ thread to complete requests, and it
>> is desirable to do so because it is lower latency.
>>
>> Probably, SDHCI should use sdio_signal_irq() which queues a work item, and
>> is what other drivers are doing.
>>
>> I will investigate some more and send a patch.

Please try the patch below:

From: Adrian Hunter <adrian.hunter@intel.com>
Date: Mon, 27 May 2019 14:45:55 +0300
Subject: [PATCH] mmc: sdhci: Fix SDIO IRQ thread deadlock

Since commit c07a48c26519 ("mmc: sdhci: Remove finish_tasklet"), the IRQ
thread might be used to complete requests, but the IRQ thread is also used
to process SDIO card interrupts. This can cause a deadlock when the SDIO
processing tries to access the card since that would also require the IRQ
thread. Change SDHCI to use sdio_signal_irq() to schedule a work item
instead. That also requires implementing the ->ack_sdio_irq() mmc host op.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Fixes: c07a48c26519 ("mmc: sdhci: Remove finish_tasklet")
---
 drivers/mmc/host/sdhci.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 97158344b862..0cd5f2ce98df 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2137,6 +2137,17 @@ void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 }
 EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq);
 
+static void sdhci_ack_sdio_irq(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+		sdhci_enable_sdio_irq_nolock(host, true);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
 int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 				      struct mmc_ios *ios)
 {
@@ -2585,6 +2596,7 @@ static const struct mmc_host_ops sdhci_ops = {
 	.get_ro		= sdhci_get_ro,
 	.hw_reset	= sdhci_hw_reset,
 	.enable_sdio_irq = sdhci_enable_sdio_irq,
+	.ack_sdio_irq    = sdhci_ack_sdio_irq,
 	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
 	.prepare_hs400_tuning		= sdhci_prepare_hs400_tuning,
 	.execute_tuning			= sdhci_execute_tuning,
@@ -3087,8 +3099,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 		if ((intmask & SDHCI_INT_CARD_INT) &&
 		    (host->ier & SDHCI_INT_CARD_INT)) {
 			sdhci_enable_sdio_irq_nolock(host, false);
-			host->thread_isr |= SDHCI_INT_CARD_INT;
-			result = IRQ_WAKE_THREAD;
+			sdio_signal_irq(host->mmc);
 		}
 
 		intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
@@ -3160,15 +3171,6 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
 		mmc_detect_change(mmc, msecs_to_jiffies(200));
 	}
 
-	if (isr & SDHCI_INT_CARD_INT) {
-		sdio_run_irqs(host->mmc);
-
-		spin_lock_irqsave(&host->lock, flags);
-		if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
-			sdhci_enable_sdio_irq_nolock(host, true);
-		spin_unlock_irqrestore(&host->lock, flags);
-	}
-
 	return IRQ_HANDLED;
 }
 
-- 
2.17.1

^ permalink raw reply related

* Re: Issue with Broadcom wireless in 5.2rc1 (was Re: [PATCH] mmc: sdhci: queue work after sdhci_defer_done())
From: Brian Masney @ 2019-05-27 12:50 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arend Van Spriel, Franky Lin, Hante Meuleman, Chi-Hsien Lin,
	Wright Feng, ulf.hansson, faiz_abbas, linux-mmc, linux-kernel,
	linux-arm-msm, Kalle Valo, linux-wireless, brcm80211-dev-list.pdl,
	brcm80211-dev-list, netdev
In-Reply-To: <ead7f268-b730-3541-31f7-4499556efec0@intel.com>

On Mon, May 27, 2019 at 03:08:07PM +0300, Adrian Hunter wrote:
> On 27/05/19 12:37 PM, Brian Masney wrote:
> > On Sun, May 26, 2019 at 03:58:19PM -0400, Brian Masney wrote:
> >> I attached a patch that shows how I was able to determine what had
> >> already claimed the host.
> > On Mon, May 27, 2019 at 10:48:24AM +0300, Adrian Hunter wrote:
> >> This is because SDHCI is using the IRQ thread to process the SDIO card
> >> interrupt (sdio_run_irqs()).  When the card driver tries to use the card, it
> >> causes interrupts which deadlocks since c07a48c26519 ("mmc: sdhci: Remove
> >> finish_tasklet") has moved the tasklet processing to the IRQ thread.
> >>
> >> I would expect to be able to use the IRQ thread to complete requests, and it
> >> is desirable to do so because it is lower latency.
> >>
> >> Probably, SDHCI should use sdio_signal_irq() which queues a work item, and
> >> is what other drivers are doing.
> >>
> >> I will investigate some more and send a patch.
> 
> Please try the patch below:
> 
> From: Adrian Hunter <adrian.hunter@intel.com>
> Date: Mon, 27 May 2019 14:45:55 +0300
> Subject: [PATCH] mmc: sdhci: Fix SDIO IRQ thread deadlock
> 
> Since commit c07a48c26519 ("mmc: sdhci: Remove finish_tasklet"), the IRQ
> thread might be used to complete requests, but the IRQ thread is also used
> to process SDIO card interrupts. This can cause a deadlock when the SDIO
> processing tries to access the card since that would also require the IRQ
> thread. Change SDHCI to use sdio_signal_irq() to schedule a work item
> instead. That also requires implementing the ->ack_sdio_irq() mmc host op.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Fixes: c07a48c26519 ("mmc: sdhci: Remove finish_tasklet")

Yes, this fixes the issue for me. You can add my:

Reported-by: Brian Masney <masneyb@onstation.org>
Tested-by: Brian Masney <masneyb@onstation.org>

Thanks,

Brian

^ permalink raw reply

* cellular modem APIs - take 2
From: Johannes Berg @ 2019-05-27 13:20 UTC (permalink / raw)
  To: netdev, linux-wireless
  Cc: Subash Abhinov Kasiviswanathan, Dan Williams, Sean Tranchetti,
	Daniele Palmas, Aleksander Morgado, Bjørn Mork

Hi all,

Sorry for the long delay in getting back to this. I'm meaning to write
some code soon also for this, to illustrate better, but I figured I'd
still get some thoughts out before I do that.

After more discussion (@Intel) and the previous thread(s), I've pretty
much come to the conclusion that we should have a small subsystem for
WWAN, rather than fudging everything like we previously did.

We can debate whether or not that should use 'real' netlink or generic
netlink - personally I know the latter better and I think it has some
real advantages like easier message parsing (it's automatic more or
less) including strict checking and automatic policy introspection (I
recently wrote the code for this and it's plugged into generic netlink
family, for other netlink families it needs more hand-written code). But
I could possibly be convinced of doing something else, and/or perhaps
building more infrastructure for 'real' netlink to realize those
benefits there as well.


In terms of what I APIs are needed, the kernel-driver side and userspace
side go pretty much hand in hand (the wwan subsystem just providing the
glue), so what I say below is pretty much both a method/function call
(kernel internal API) or a netlink message (userspace API).

1) I think a generic abstraction of WWAN device that is not a netdev
   is needed. Yes, on the one hand it's quite nice to be able to work on
   top of a given netdev, but it's also limiting because it requires the
   data flow to go through there, and packets that are tagged in some
   way be exchanged there.
   For VLANs this can be out-of-band (in a sense) with hw-accel, but for
   rmnet-style it's in-band, and that limits what we can do.

   Now, of course this doesn't mean there shouldn't be a netdev created
   by default in most cases, but it gives us a way to do additional
   things that we cannot do with *just* a netdev.

   From a driver POV though, it would register a new "wwan_device", and
   then get some generic callback to create a netdev on top, maybe by
   default from the subsystem or from the user.

2) Clearly, one needs to be able to create PDN netdevs, with the PDN
   given to the command. Here's another advantage: If these are created
   on top of another abstraction, not another netdev, they can have
   their own queues, multiqueue RX etc. much more easily.

   Also, things like the "if I have just a single channel, drop the mux
   headers" can then be entirely done in the driver, and the default
   netdev no longer has the possibility of muxed and IP frames on the
   same datapath.

   This also enables more things like handling checksum offload directly
   in the driver, which doesn't behave so well with VLANs I think.

   All of that will just be easier for 5G too, I believe, with
   acceleration being handled per PDN, multi-queue working without
   ndo_select_queue, etc.

   Quite possibly there might be some additional (vendor-dependent?)
   configuration for when such netdevs are created, but we need to
   figure out if that really needs to be at creation time, or just
   ethtool later or something like that. I guess it depends on how
   generic it needs to be.

3) Separately, we need to have an ability to create "generalized control
   channels". I'm thinking there would be a general command "create
   control channel" with a given type (e.g. ATCMD, RPC, MBIM, GNSS) plus
   a list of vendor-specific channels (e.g. for tracing).

   I'm unsure where this channel should really go - somehow it seems to
   me that for many (most?) of these registering them as a serial line
   would be most appropriate, but some, especially vendor-defined
   channels like tracing, would probably better use a transport that's
   higher bandwidth than, e.g. netdevs.

   One way I thought of doing this was to create an abstraction in the
   wwan framework that lets the driver use SKBs anyway (i.e. TX and RX
   on these channels using SKBs) and then translate them to some channel
   in the framework - that way, we can even select at runtime if we want
   a netdev (not really plugged into the network stack, ARPHDR_VOID?) or
   some other kind of transport. Building that would allow us to add
   transport types in the future too.

   I guess such a channel should also be created by default, if it's
   not already created by the driver in some out-of-band way anyway (and
   most likely it shouldn't be, but I guess drivers might have some
   entirely different communication channels for AT CMDs?)

4) There was a question about something like pure IP channels that
   belong to another PDN and apparently now separate netdevs might be
   used, but it seems to me that could just be a queue reserved on the
   regular netdevs and then when you say ("enable video streaming on
   wwan1 interface") that can do some magic to classify the video
   packets (DSCP?) to another hardware queue for better QoS.



Anyway, if all of this doesn't seem completely outlandish I'll try to
write some code to illustrate it (sooner, rather than later).

Thanks,
johannes


^ permalink raw reply

* [RFC PATCH 1/2] mac80211_hwsim: Register support for HE meshpoint
From: Sven Eckelmann @ 2019-05-27 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: Sven Eckelmann

From: Sven Eckelmann <seckelmann@datto.com>

Some features of 802.11ax without central organizing (AP) STA can also be
used in mesh mode. hwsim can be used to assist initial development of these
features without having access to HW.

Signed-off-by: Sven Eckelmann <seckelmann@datto.com>
---
 drivers/net/wireless/mac80211_hwsim.c | 283 +++++++++++++++++---------
 1 file changed, 189 insertions(+), 94 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 524eb5805995..e4d542f08b7c 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2501,116 +2501,211 @@ static void hwsim_mcast_new_radio(int id, struct genl_info *info,
 	nlmsg_free(mcast_skb);
 }
 
-static const struct ieee80211_sband_iftype_data he_capa_2ghz = {
-	/* TODO: should we support other types, e.g., P2P?*/
-	.types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP),
-	.he_cap = {
-		.has_he = true,
-		.he_cap_elem = {
-			.mac_cap_info[0] =
-				IEEE80211_HE_MAC_CAP0_HTC_HE,
-			.mac_cap_info[1] =
-				IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
-				IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
-			.mac_cap_info[2] =
-				IEEE80211_HE_MAC_CAP2_BSR |
-				IEEE80211_HE_MAC_CAP2_MU_CASCADING |
-				IEEE80211_HE_MAC_CAP2_ACK_EN,
-			.mac_cap_info[3] =
-				IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
-				IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
-			.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
-			.phy_cap_info[1] =
-				IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
-				IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
-				IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
-				IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
-			.phy_cap_info[2] =
-				IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
-				IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
-				IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
-				IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
-				IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO,
-
-			/* Leave all the other PHY capability bytes unset, as
-			 * DCM, beam forming, RU and PPE threshold information
-			 * are not supported
-			 */
+static const struct ieee80211_sband_iftype_data he_capa_2ghz[] = {
+	{
+		/* TODO: should we support other types, e.g., P2P?*/
+		.types_mask = BIT(NL80211_IFTYPE_STATION) |
+			      BIT(NL80211_IFTYPE_AP),
+		.he_cap = {
+			.has_he = true,
+			.he_cap_elem = {
+				.mac_cap_info[0] =
+					IEEE80211_HE_MAC_CAP0_HTC_HE,
+				.mac_cap_info[1] =
+					IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
+					IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
+				.mac_cap_info[2] =
+					IEEE80211_HE_MAC_CAP2_BSR |
+					IEEE80211_HE_MAC_CAP2_MU_CASCADING |
+					IEEE80211_HE_MAC_CAP2_ACK_EN,
+				.mac_cap_info[3] =
+					IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
+					IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
+				.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
+				.phy_cap_info[1] =
+					IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
+					IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
+					IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
+					IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
+				.phy_cap_info[2] =
+					IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
+					IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
+					IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
+					IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
+					IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO,
+
+				/* Leave all the other PHY capability bytes
+				 * unset, as DCM, beam forming, RU and PPE
+				 * threshold information are not supported
+				 */
+			},
+			.he_mcs_nss_supp = {
+				.rx_mcs_80 = cpu_to_le16(0xfffa),
+				.tx_mcs_80 = cpu_to_le16(0xfffa),
+				.rx_mcs_160 = cpu_to_le16(0xffff),
+				.tx_mcs_160 = cpu_to_le16(0xffff),
+				.rx_mcs_80p80 = cpu_to_le16(0xffff),
+				.tx_mcs_80p80 = cpu_to_le16(0xffff),
+			},
 		},
-		.he_mcs_nss_supp = {
-			.rx_mcs_80 = cpu_to_le16(0xfffa),
-			.tx_mcs_80 = cpu_to_le16(0xfffa),
-			.rx_mcs_160 = cpu_to_le16(0xffff),
-			.tx_mcs_160 = cpu_to_le16(0xffff),
-			.rx_mcs_80p80 = cpu_to_le16(0xffff),
-			.tx_mcs_80p80 = cpu_to_le16(0xffff),
+	},
+#ifdef CONFIG_MAC80211_MESH
+	{
+		/* TODO: should we support other types, e.g., IBSS?*/
+		.types_mask = BIT(NL80211_IFTYPE_MESH_POINT),
+		.he_cap = {
+			.has_he = true,
+			.he_cap_elem = {
+				.mac_cap_info[0] =
+					IEEE80211_HE_MAC_CAP0_HTC_HE,
+				.mac_cap_info[1] =
+					IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
+				.mac_cap_info[2] =
+					IEEE80211_HE_MAC_CAP2_ACK_EN,
+				.mac_cap_info[3] =
+					IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
+					IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
+				.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
+				.phy_cap_info[1] =
+					IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
+					IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
+					IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
+					IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
+				.phy_cap_info[2] = 0,
+
+				/* Leave all the other PHY capability bytes
+				 * unset, as DCM, beam forming, RU and PPE
+				 * threshold information are not supported
+				 */
+			},
+			.he_mcs_nss_supp = {
+				.rx_mcs_80 = cpu_to_le16(0xfffa),
+				.tx_mcs_80 = cpu_to_le16(0xfffa),
+				.rx_mcs_160 = cpu_to_le16(0xffff),
+				.tx_mcs_160 = cpu_to_le16(0xffff),
+				.rx_mcs_80p80 = cpu_to_le16(0xffff),
+				.tx_mcs_80p80 = cpu_to_le16(0xffff),
+			},
 		},
 	},
+#endif
 };
 
-static const struct ieee80211_sband_iftype_data he_capa_5ghz = {
-	/* TODO: should we support other types, e.g., P2P?*/
-	.types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP),
-	.he_cap = {
-		.has_he = true,
-		.he_cap_elem = {
-			.mac_cap_info[0] =
-				IEEE80211_HE_MAC_CAP0_HTC_HE,
-			.mac_cap_info[1] =
-				IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
-				IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
-			.mac_cap_info[2] =
-				IEEE80211_HE_MAC_CAP2_BSR |
-				IEEE80211_HE_MAC_CAP2_MU_CASCADING |
-				IEEE80211_HE_MAC_CAP2_ACK_EN,
-			.mac_cap_info[3] =
-				IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
-				IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
-			.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
-			.phy_cap_info[0] =
-				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
-				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
-				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
-			.phy_cap_info[1] =
-				IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
-				IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
-				IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
-				IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
-			.phy_cap_info[2] =
-				IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
-				IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
-				IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
-				IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
-				IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO,
-
-			/* Leave all the other PHY capability bytes unset, as
-			 * DCM, beam forming, RU and PPE threshold information
-			 * are not supported
-			 */
+static const struct ieee80211_sband_iftype_data he_capa_5ghz[] = {
+	{
+		/* TODO: should we support other types, e.g., P2P?*/
+		.types_mask = BIT(NL80211_IFTYPE_STATION) |
+			      BIT(NL80211_IFTYPE_AP),
+		.he_cap = {
+			.has_he = true,
+			.he_cap_elem = {
+				.mac_cap_info[0] =
+					IEEE80211_HE_MAC_CAP0_HTC_HE,
+				.mac_cap_info[1] =
+					IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
+					IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
+				.mac_cap_info[2] =
+					IEEE80211_HE_MAC_CAP2_BSR |
+					IEEE80211_HE_MAC_CAP2_MU_CASCADING |
+					IEEE80211_HE_MAC_CAP2_ACK_EN,
+				.mac_cap_info[3] =
+					IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
+					IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
+				.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
+				.phy_cap_info[0] =
+					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
+				.phy_cap_info[1] =
+					IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
+					IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
+					IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
+					IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
+				.phy_cap_info[2] =
+					IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
+					IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
+					IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
+					IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
+					IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO,
+
+				/* Leave all the other PHY capability bytes
+				 * unset, as DCM, beam forming, RU and PPE
+				 * threshold information are not supported
+				 */
+			},
+			.he_mcs_nss_supp = {
+				.rx_mcs_80 = cpu_to_le16(0xfffa),
+				.tx_mcs_80 = cpu_to_le16(0xfffa),
+				.rx_mcs_160 = cpu_to_le16(0xfffa),
+				.tx_mcs_160 = cpu_to_le16(0xfffa),
+				.rx_mcs_80p80 = cpu_to_le16(0xfffa),
+				.tx_mcs_80p80 = cpu_to_le16(0xfffa),
+			},
 		},
-		.he_mcs_nss_supp = {
-			.rx_mcs_80 = cpu_to_le16(0xfffa),
-			.tx_mcs_80 = cpu_to_le16(0xfffa),
-			.rx_mcs_160 = cpu_to_le16(0xfffa),
-			.tx_mcs_160 = cpu_to_le16(0xfffa),
-			.rx_mcs_80p80 = cpu_to_le16(0xfffa),
-			.tx_mcs_80p80 = cpu_to_le16(0xfffa),
+	},
+#ifdef CONFIG_MAC80211_MESH
+	{
+		/* TODO: should we support other types, e.g., IBSS?*/
+		.types_mask = BIT(NL80211_IFTYPE_MESH_POINT),
+		.he_cap = {
+			.has_he = true,
+			.he_cap_elem = {
+				.mac_cap_info[0] =
+					IEEE80211_HE_MAC_CAP0_HTC_HE,
+				.mac_cap_info[1] =
+					IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
+				.mac_cap_info[2] =
+					IEEE80211_HE_MAC_CAP2_ACK_EN,
+				.mac_cap_info[3] =
+					IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
+					IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
+				.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
+				.phy_cap_info[0] =
+					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
+				.phy_cap_info[1] =
+					IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
+					IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
+					IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
+					IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
+				.phy_cap_info[2] = 0,
+
+				/* Leave all the other PHY capability bytes
+				 * unset, as DCM, beam forming, RU and PPE
+				 * threshold information are not supported
+				 */
+			},
+			.he_mcs_nss_supp = {
+				.rx_mcs_80 = cpu_to_le16(0xfffa),
+				.tx_mcs_80 = cpu_to_le16(0xfffa),
+				.rx_mcs_160 = cpu_to_le16(0xfffa),
+				.tx_mcs_160 = cpu_to_le16(0xfffa),
+				.rx_mcs_80p80 = cpu_to_le16(0xfffa),
+				.tx_mcs_80p80 = cpu_to_le16(0xfffa),
+			},
 		},
 	},
+#endif
 };
 
 static void mac80211_hswim_he_capab(struct ieee80211_supported_band *sband)
 {
-	if (sband->band == NL80211_BAND_2GHZ)
+	u16 n_iftype_data;
+
+	if (sband->band == NL80211_BAND_2GHZ) {
+		n_iftype_data = ARRAY_SIZE(he_capa_2ghz);
 		sband->iftype_data =
-			(struct ieee80211_sband_iftype_data *)&he_capa_2ghz;
-	else if (sband->band == NL80211_BAND_5GHZ)
+			(struct ieee80211_sband_iftype_data *)he_capa_2ghz;
+	} else if (sband->band == NL80211_BAND_5GHZ) {
+		n_iftype_data = ARRAY_SIZE(he_capa_5ghz);
 		sband->iftype_data =
-			(struct ieee80211_sband_iftype_data *)&he_capa_5ghz;
-	else
+			(struct ieee80211_sband_iftype_data *)he_capa_5ghz;
+	} else {
 		return;
+	}
 
-	sband->n_iftype_data = 1;
+	sband->n_iftype_data = n_iftype_data;
 }
 
 #ifdef CONFIG_MAC80211_MESH
-- 
2.20.1


^ permalink raw reply related

* [RFC PATCH 2/2] mac80211: implement HE support for mesh
From: Sven Eckelmann @ 2019-05-27 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: Sven Eckelmann
In-Reply-To: <20190527135340.15600-1-sven@narfation.org>

From: Sven Eckelmann <seckelmann@datto.com>

Implement the basics required for supporting high efficiency with mesh:
include HE information elements in beacons, probe responses, and peering
action frames, and check for compatible HE configurations when peering.

Signed-off-by: Sven Eckelmann <seckelmann@datto.com>
---
 include/net/cfg80211.h     | 19 ++++++++++++
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/mesh.c        | 61 ++++++++++++++++++++++++++++++++++++++
 net/mac80211/mesh.h        |  4 +++
 net/mac80211/mesh_plink.c  | 11 ++++++-
 net/mac80211/util.c        | 52 ++++++++++++++++++++++++++++++++
 6 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 13bfeb712d36..9caa0ca5020d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -399,6 +399,25 @@ ieee80211_get_he_sta_cap(const struct ieee80211_supported_band *sband)
 	return NULL;
 }
 
+/**
+ * ieee80211_get_he_mesh_cap - return HE capabilities for an sband's mesh STA
+ * @sband: the sband to search for the mesh STA on
+ *
+ * Return: pointer to the struct ieee80211_sta_he_cap, or NULL is none found
+ */
+static inline const struct ieee80211_sta_he_cap *
+ieee80211_get_he_mesh_cap(const struct ieee80211_supported_band *sband)
+{
+	const struct ieee80211_sband_iftype_data *data =
+		ieee80211_get_sband_iftype_data(sband,
+						NL80211_IFTYPE_MESH_POINT);
+
+	if (data && data->he_cap.has_he)
+		return &data->he_cap;
+
+	return NULL;
+}
+
 /**
  * wiphy_read_of_freq_limits - read frequency limits from device tree
  *
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e170f986d226..dea736cdf60b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2126,9 +2126,11 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 			       u32 cap);
 u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 				const struct cfg80211_chan_def *chandef);
+u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata);
 u8 *ieee80211_ie_build_he_cap(u8 *pos,
 			      const struct ieee80211_sta_he_cap *he_cap,
 			      u8 *end);
+u8 *ieee80211_ie_build_he_oper(u8 *pos);
 int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
 			     const struct ieee80211_supported_band *sband,
 			     const u8 *srates, int srates_len, u32 *rates);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 766e5e5bab8a..47ef885c4060 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -535,6 +535,61 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
 	return 0;
 }
 
+int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata,
+		       struct sk_buff *skb, u8 ie_len)
+{
+	const struct ieee80211_sta_he_cap *he_cap;
+	struct ieee80211_supported_band *sband;
+	u8 *pos;
+
+	sband = ieee80211_get_sband(sdata);
+	if (!sband)
+		return -EINVAL;
+
+	he_cap = ieee80211_get_he_mesh_cap(sband);
+
+	if (!he_cap ||
+	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
+	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
+		return 0;
+
+	if (skb_tailroom(skb) < ie_len)
+		return -ENOMEM;
+
+	pos = skb_put(skb, ie_len);
+	ieee80211_ie_build_he_cap(pos, he_cap, pos + ie_len);
+
+	return 0;
+}
+
+int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
+			struct sk_buff *skb)
+{
+	const struct ieee80211_sta_he_cap *he_cap;
+	struct ieee80211_supported_band *sband;
+	u8 *pos;
+
+	sband = ieee80211_get_sband(sdata);
+	if (!sband)
+		return -EINVAL;
+
+	he_cap = ieee80211_get_he_mesh_cap(sband);
+	if (!he_cap ||
+	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
+	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
+		return 0;
+
+	if (skb_tailroom(skb) < 2 + 1 + sizeof(struct ieee80211_he_operation))
+		return -ENOMEM;
+
+	pos = skb_put(skb, 2 + 1 + sizeof(struct ieee80211_he_operation));
+	ieee80211_ie_build_he_oper(pos);
+
+	return 0;
+}
+
 static void ieee80211_mesh_path_timer(struct timer_list *t)
 {
 	struct ieee80211_sub_if_data *sdata =
@@ -680,6 +735,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 	struct ieee80211_chanctx_conf *chanctx_conf;
 	struct mesh_csa_settings *csa;
 	enum nl80211_band band;
+	u8 ie_len_he_cap;
 	u8 *pos;
 	struct ieee80211_sub_if_data *sdata;
 	int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon);
@@ -690,6 +746,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 	band = chanctx_conf->def.chan->band;
 	rcu_read_unlock();
 
+	ie_len_he_cap = ieee80211_ie_len_he_cap(sdata);
 	head_len = hdr_len +
 		   2 + /* NULL SSID */
 		   /* Channel Switch Announcement */
@@ -709,6 +766,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 		   2 + sizeof(__le16) + /* awake window */
 		   2 + sizeof(struct ieee80211_vht_cap) +
 		   2 + sizeof(struct ieee80211_vht_operation) +
+		   ie_len_he_cap +
+		   2 + 1 + sizeof(struct ieee80211_he_operation) +
 		   ifmsh->ie_len;
 
 	bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
@@ -826,6 +885,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 	    mesh_add_awake_window_ie(sdata, skb) ||
 	    mesh_add_vht_cap_ie(sdata, skb) ||
 	    mesh_add_vht_oper_ie(sdata, skb) ||
+	    mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) ||
+	    mesh_add_he_oper_ie(sdata, skb) ||
 	    mesh_add_vendor_ies(sdata, skb))
 		goto out_free;
 
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 574c3891c4b2..af1d9154b255 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -221,6 +221,10 @@ int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
 			struct sk_buff *skb);
 int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
 			 struct sk_buff *skb);
+int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata,
+		       struct sk_buff *skb, u8 ie_len);
+int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
+			struct sk_buff *skb);
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 8afd0ece94c9..e18e433fde29 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -221,9 +221,11 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 	bool include_plid = false;
 	u16 peering_proto = 0;
 	u8 *pos, ie_len = 4;
+	u8 ie_len_he_cap;
 	int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot);
 	int err = -ENOMEM;
 
+	ie_len_he_cap = ieee80211_ie_len_he_cap(sdata);
 	skb = dev_alloc_skb(local->tx_headroom +
 			    hdr_len +
 			    2 + /* capability info */
@@ -236,6 +238,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 			    2 + sizeof(struct ieee80211_ht_operation) +
 			    2 + sizeof(struct ieee80211_vht_cap) +
 			    2 + sizeof(struct ieee80211_vht_operation) +
+			    ie_len_he_cap +
+			    2 + 1 + sizeof(struct ieee80211_he_operation) +
 			    2 + 8 + /* peering IE */
 			    sdata->u.mesh.ie_len);
 	if (!skb)
@@ -324,7 +328,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 		if (mesh_add_ht_cap_ie(sdata, skb) ||
 		    mesh_add_ht_oper_ie(sdata, skb) ||
 		    mesh_add_vht_cap_ie(sdata, skb) ||
-		    mesh_add_vht_oper_ie(sdata, skb))
+		    mesh_add_vht_oper_ie(sdata, skb) ||
+		    mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) ||
+		    mesh_add_he_oper_ie(sdata, skb))
 			goto free;
 	}
 
@@ -436,6 +442,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
 	ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
 					    elems->vht_cap_elem, sta);
 
+	ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap,
+					  elems->he_cap_len, sta);
+
 	if (bw != sta->sta.bandwidth)
 		changed |= IEEE80211_RC_BW_CHANGED;
 
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4c1655972565..d86925438b5f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2663,6 +2663,30 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 	return pos;
 }
 
+u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata)
+{
+	const struct ieee80211_sta_he_cap *he_cap;
+	struct ieee80211_supported_band *sband;
+	u8 ie_len;
+	u8 n;
+
+	sband = ieee80211_get_sband(sdata);
+	if (!sband)
+		return 0;
+
+	he_cap = ieee80211_get_he_mesh_cap(sband);
+	if (!he_cap)
+		return 0;
+
+	n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem);
+	ie_len = 2 + 1 +
+		 sizeof(he_cap->he_cap_elem) + n +
+		 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
+				       he_cap->he_cap_elem.phy_cap_info);
+
+	return ie_len;
+}
+
 u8 *ieee80211_ie_build_he_cap(u8 *pos,
 			      const struct ieee80211_sta_he_cap *he_cap,
 			      u8 *end)
@@ -2852,6 +2876,34 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 	return pos + sizeof(struct ieee80211_vht_operation);
 }
 
+u8 *ieee80211_ie_build_he_oper(u8 *pos)
+{
+	struct ieee80211_he_operation *he_oper;
+	u32 he_oper_params;
+
+	*pos++ = WLAN_EID_EXTENSION;
+	*pos++ = 1 + sizeof(struct ieee80211_he_operation);
+	*pos++ = WLAN_EID_EXT_HE_OPERATION;
+
+	he_oper_params = 0;
+	he_oper_params |= u32_encode_bits(1023, /* disabled */
+				IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
+	he_oper_params |= u32_encode_bits(1,
+				IEEE80211_HE_OPERATION_ER_SU_DISABLE);
+	he_oper_params |= u32_encode_bits(1,
+				IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED);
+
+	he_oper = (struct ieee80211_he_operation *)pos;
+	he_oper->he_oper_params = cpu_to_le32(he_oper_params);
+
+	/* don't require special HE peer rates */
+	he_oper->he_mcs_nss_set = cpu_to_le16(0xffff);
+
+	/* TODO add VHT operational and 6GHz operational subelement? */
+
+	return pos + sizeof(struct ieee80211_vht_operation);
+}
+
 bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
 			       struct cfg80211_chan_def *chandef)
 {
-- 
2.20.1


^ permalink raw reply related

* Re: [RFC PATCH 2/2] rtl8xxxu: Add watchdog to update rate mask by signal strength
From: Daniel Drake @ 2019-05-27 16:40 UTC (permalink / raw)
  To: Chris Chiu
  Cc: Jes Sorensen, Kalle Valo, David Miller, linux-wireless, netdev,
	Linux Kernel, Linux Upstreaming Team, Larry Finger
In-Reply-To: <CAB4CAwf7O9tyUwc+gPSZrBES+Bt7iTjhE1fbbVxYKqzjtmZBxw@mail.gmail.com>

On Mon, May 27, 2019 at 12:38 AM Chris Chiu <chiu@endlessm.com> wrote:
> The -EBUSY is returned by the ieee80211_check_combinations() in the
> ieee80211_check_concurrent_iface() function which is invoked each time
> doing ieee80211_open().
> The ieee80211_check_combinations() returns the -EBUSY because of
> cfg80211_check_combinations() will iterate all interfaces of different types
> then checks the combination is valid or not, which in this case the number
> of interface combination accumulated by cfg80211_iter_sum_ifcombos is 0
> when I'm trying to bring up the second station interface.

Thanks for clarifying. I see, rtl8xxxu does not provide any
iface_combinations so the default is to reject parallel interfaces.

Given that we can now confidently say that multiple interfaces are not
supported, I think that inside rtl8xxxu_add_interface() you could
store a pointer to the vif inside the rtl8xxxu_priv structure (and
clear it in rtl8xxxu_remove_interface). Plus for clarity, add a
comment pointing out that only a single interface is supported, and
make rtl8xxxu_add_interface() acually fail if we already had a
non-NULL pointer stored in the priv structure.

Then you can simplify the patch to remove the ugly storing of vif
inside rtl8xxxu_watchdog. You can store the delayed_work in the main
priv struct too, dropping rtl8xxxu_watchdog altogether.

Daniel

^ permalink raw reply

* Re: [RFC 0/8] nl80211: add 6GHz band support
From: Arend Van Spriel @ 2019-05-27 20:46 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <16aeb2310e8.2764.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com>

On 5/24/2019 8:38 PM, Arend Van Spriel wrote:
> On May 24, 2019 1:56:43 PM Johannes Berg <johannes@sipsolutions.net> wrote:
> 
>> Hi Arend,
>>
>> On Mon, 2019-05-20 at 14:00 +0200, Arend van Spriel wrote:
>>> In 802.11ax D4.0 a new band has been proposed. This series contains
>>> changes to cfg80211 for supporting this band. With 2GHz and 5GHz there
>>> was no overlap in channel number. However, this new band has channel
>>> numbers with a range from 1 up to 253.
>>
>> At the wireless workshop in Prague, we looked at this and sort of
>> decided that it'd be better to put all the 6 GHz channels into the 5 GHz
>> "band" in nl80211, to avoid all the "5 || 6" since they're really the
>> same except for very specific places like scanning.
> 
> Would have liked to be there, but attending is no longer an option for 
> me. We now have two autistic, non-verbal children and I am the primary 
> caregiver for the oldest because my wife can't handle him. Guess I 
> should have checked the workshop notes before working on this :-) Do you 
> have URL?

Found the netdev wifi workshop page and looked over the slides quickly, 
but the notes page is pretty empty ;-)

> Agree that most functional requirements for 6 GHz are same as 5 GHz. 
> There are some 6 GHz specifics about beaconing as well.

This came up in discussion with my colleagues today and I would say from 
mac80211 perspective there is more to it than just scanning. In short 
the 6GHz band is for HE-only operation so for example only HE rates may 
be used. As the bitrates are in ieee80211_supported_band having a 
separate 6GHz band seems to have a (slight?) advantage.

Regards,
Arend

^ permalink raw reply

* linux-next: Fixes tag needs some work in the wireless-drivers-next tree
From: Stephen Rothwell @ 2019-05-27 21:48 UTC (permalink / raw)
  To: Kalle Valo, Wireless
  Cc: Linux Next Mailing List, Linux Kernel Mailing List,
	Surabhi Vishnoi, Pradeep kumar Chitrapu, Zhi Chen

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

Hi all,

In commit

  9280f4fc06f4 ("ath10k: Fix the wrong value of enums for wmi tlv stats id")

Fixes tag

  Fixes: f40a307eb92c ("ath10k: Fill rx duration for each peer in fw_stats for WCN3990)

has these problem(s):

  - Subject has leading but no trailing quotes

In commit

  93ee3d108fc7 ("ath10k: fix incorrect multicast/broadcast rate setting")

Fixes tag

  Fixes: cd93b83ad92 ("ath10k: support for multicast rate control")

has these problem(s):

  - SHA1 should be at least 12 digits long
    Can be fixed by setting core.abbrev to 12 (or more) or (for git v2.11
    or later) just making sure it is not set (or set to "auto").

-- 
Cheers,
Stephen Rothwell

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [PATCH] mac80211: Do not use stack memory with scatterlist for GMAC
From: Jouni Malinen @ 2019-05-27 22:46 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Jouni Malinen

ieee80211_aes_gmac() uses the mic argument directly in sg_set_buf() and
that does not allow use of stack memory (e.g., BUG_ON() is hit in
sg_set_buf() with CONFIG_DEBUG_SG). BIP GMAC TX side is fine for this
since it can use the skb data buffer, but the RX side was using a stack
variable for deriving the local MIC value to compare against the
received one.

Fix this by allocating heap memory for the mic buffer.

This was found with hwsim test case ap_cipher_bip_gmac_128 hitting that
BUG_ON() and kernel panic.

Signed-off-by: Jouni Malinen <j@w1.fi>
---
 net/mac80211/wpa.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 58d0b258b684..5dd48f0a4b1b 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -1175,7 +1175,7 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx)
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	struct ieee80211_key *key = rx->key;
 	struct ieee80211_mmie_16 *mmie;
-	u8 aad[GMAC_AAD_LEN], mic[GMAC_MIC_LEN], ipn[6], nonce[GMAC_NONCE_LEN];
+	u8 aad[GMAC_AAD_LEN], *mic, ipn[6], nonce[GMAC_NONCE_LEN];
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
 	if (!ieee80211_is_mgmt(hdr->frame_control))
@@ -1206,13 +1206,18 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx)
 		memcpy(nonce, hdr->addr2, ETH_ALEN);
 		memcpy(nonce + ETH_ALEN, ipn, 6);
 
+		mic = kmalloc(GMAC_MIC_LEN, GFP_ATOMIC);
+		if (!mic)
+			return RX_DROP_UNUSABLE;
 		if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce,
 				       skb->data + 24, skb->len - 24,
 				       mic) < 0 ||
 		    crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) {
 			key->u.aes_gmac.icverrors++;
+			kfree(mic);
 			return RX_DROP_UNUSABLE;
 		}
+		kfree(mic);
 	}
 
 	memcpy(key->u.aes_gmac.rx_pn, ipn, 6);
-- 
2.20.1


^ permalink raw reply related

* [PATCH] ath10k: fix failure to set multiple fixed rate
From: Miaoqing Pan @ 2019-05-28  1:38 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Miaoqing Pan

Currently, below fixed rate commands are broken,
iw wlanx set bitrates legacy-<2.4|5> ht-mcs-<2.4|5> vht-mcs-<2.4|5> \
<NSS:MCSx>
iw wlanx set bitrates legacy-<2.4|5> <legacy rate> ht-mcs-<2.4|5> \
<MCS index> vht-mcs-<2.4|5>
iw wlanx set bitrates legacy-<2.4|5> <legacy rate> ht-mcs-<2.4|5> \
vht-mcs-<2.4|5> <NSS:MCSx>

There are two methods to set fixed rate, both failed,
- Use vdev fixed rate command
  This command only support one single rate, but it's broken due to
  mac80211 change commit e8e4f5280ddd ("mac80211: reject/clear user
  rate mask if not usable"), which requires user to specify at least
  one legacy rate. So we can't use this command to set ht/vht single
  rate any more.
- Use peer_assoc command
  This command can update rx capability for multiple rates, it will
  work fine for ht mcs rates, as each supported mcs can be advertised
  in ht_mcs index mask. But this will not work with vht rates because,
  as per the vht mcs capability advertisement, there are only two bits
  to indicate the supported mcs. E.g. only support 0-7, 0-8, 0-9.

So introduced new WMI command: WMI_PEER_PARAM_FIXED_RATE. After peer
assoc, the peer fixed rate cmd will work for that specific peer.
Remaining peers will use auto rate. If both vdev fixed rate and peer
fixed rates are given, peer fixed rate will take effect to peers for
which this cmd is given. Remaining peers in that vdev, will use vdev
fixed rate.

Tested HW: QCA9984
Tested FW: 10.4-3.9.0.2-00035

Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/core.c |   1 +
 drivers/net/wireless/ath/ath10k/core.h |   7 +++
 drivers/net/wireless/ath/ath10k/mac.c  | 111 +++++++++++++++++++++++++++++----
 drivers/net/wireless/ath/ath10k/wmi.h  |   1 +
 4 files changed, 108 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 61ef903..811cf38 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -612,6 +612,7 @@
 	[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
 	[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",
 	[ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel",
+	[ATH10K_FW_FEATURE_PEER_FIXED_RATE] = "peer-fixed-rate",
 };
 
 static unsigned int ath10k_core_get_fw_feature_str(char *buf,
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 2d109c0..fe6e88d 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -579,6 +579,10 @@ struct ath10k_vif {
 	struct work_struct ap_csa_work;
 	struct delayed_work connection_loss_work;
 	struct cfg80211_bitrate_mask bitrate_mask;
+
+	/* For setting VHT peer fixed rate, protected by conf_mutex */
+	int vht_num_rates;
+	u8 vht_pfr;
 };
 
 struct ath10k_vif_iter {
@@ -770,6 +774,9 @@ enum ath10k_fw_features {
 	/* Firmware sends only one chan_info event per channel */
 	ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL = 20,
 
+	/* Firmware allows setting peer fixed rate */
+	ATH10K_FW_FEATURE_PEER_FIXED_RATE = 21,
+
 	/* keep last */
 	ATH10K_FW_FEATURE_COUNT,
 };
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b500fd4..e555a22 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7107,18 +7107,23 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
 static bool
 ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
 					enum nl80211_band band,
-					const struct cfg80211_bitrate_mask *mask)
+					const struct cfg80211_bitrate_mask *mask,
+					int *vht_num_rates)
 {
 	int num_rates = 0;
-	int i;
+	int i, tmp;
 
 	num_rates += hweight32(mask->control[band].legacy);
 
 	for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
 		num_rates += hweight8(mask->control[band].ht_mcs[i]);
 
-	for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
-		num_rates += hweight16(mask->control[band].vht_mcs[i]);
+	*vht_num_rates = 0;
+	for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+		tmp = hweight16(mask->control[band].vht_mcs[i]);
+		num_rates += tmp;
+		*vht_num_rates += tmp;
+	}
 
 	return num_rates == 1;
 }
@@ -7176,7 +7181,7 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
 ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
 					enum nl80211_band band,
 					const struct cfg80211_bitrate_mask *mask,
-					u8 *rate, u8 *nss)
+					u8 *rate, u8 *nss, bool vht_only)
 {
 	int rate_idx;
 	int i;
@@ -7184,6 +7189,9 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
 	u8 preamble;
 	u8 hw_rate;
 
+	if (vht_only)
+		goto next;
+
 	if (hweight32(mask->control[band].legacy) == 1) {
 		rate_idx = ffs(mask->control[band].legacy) - 1;
 
@@ -7217,6 +7225,7 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
 		}
 	}
 
+next:
 	for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
 		if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
 			*nss = i + 1;
@@ -7278,7 +7287,8 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
 static bool
 ath10k_mac_can_set_bitrate_mask(struct ath10k *ar,
 				enum nl80211_band band,
-				const struct cfg80211_bitrate_mask *mask)
+				const struct cfg80211_bitrate_mask *mask,
+				bool allow_pfr)
 {
 	int i;
 	u16 vht_mcs;
@@ -7297,7 +7307,8 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
 		case BIT(10) - 1:
 			break;
 		default:
-			ath10k_warn(ar, "refusing bitrate mask with missing 0-7 VHT MCS rates\n");
+			if (!allow_pfr)
+				ath10k_warn(ar, "refusing bitrate mask with missing 0-7 VHT MCS rates\n");
 			return false;
 		}
 	}
@@ -7305,6 +7316,26 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
 	return true;
 }
 
+static bool ath10k_mac_set_vht_bitrate_mask_fixup(struct ath10k *ar,
+						  struct ath10k_vif *arvif,
+						  struct ieee80211_sta *sta)
+{
+	int err;
+	u8 rate = arvif->vht_pfr;
+
+	/* skip non vht and multiple rate peers */
+	if (!sta->vht_cap.vht_supported || arvif->vht_num_rates != 1)
+		return false;
+
+	err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+					WMI_PEER_PARAM_FIXED_RATE, rate);
+	if (err)
+		ath10k_warn(ar, "failed to eanble STA %pM peer fixed rate: %d\n",
+			    sta->addr, err);
+
+	return true;
+}
+
 static void ath10k_mac_set_bitrate_mask_iter(void *data,
 					     struct ieee80211_sta *sta)
 {
@@ -7315,6 +7346,9 @@ static void ath10k_mac_set_bitrate_mask_iter(void *data,
 	if (arsta->arvif != arvif)
 		return;
 
+	if (ath10k_mac_set_vht_bitrate_mask_fixup(ar, arvif, sta))
+		return;
+
 	spin_lock_bh(&ar->data_lock);
 	arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
 	spin_unlock_bh(&ar->data_lock);
@@ -7322,6 +7356,26 @@ static void ath10k_mac_set_bitrate_mask_iter(void *data,
 	ieee80211_queue_work(ar->hw, &arsta->update_wk);
 }
 
+static void ath10k_mac_clr_bitrate_mask_iter(void *data,
+					     struct ieee80211_sta *sta)
+{
+	struct ath10k_vif *arvif = data;
+	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+	struct ath10k *ar = arvif->ar;
+	int err;
+
+	/* clear vht peers only */
+	if (arsta->arvif != arvif || !sta->vht_cap.vht_supported)
+		return;
+
+	err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+					WMI_PEER_PARAM_FIXED_RATE,
+					WMI_FIXED_RATE_NONE);
+	if (err)
+		ath10k_warn(ar, "failed to clear STA %pM peer fixed rate: %d\n",
+			    sta->addr, err);
+}
+
 static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 					  struct ieee80211_vif *vif,
 					  const struct cfg80211_bitrate_mask *mask)
@@ -7338,6 +7392,9 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 	u8 ldpc;
 	int single_nss;
 	int ret;
+	int vht_num_rates, allow_pfr;
+	u8 vht_pfr;
+	bool update_bitrate_mask = true;
 
 	if (ath10k_mac_vif_chan(vif, &def))
 		return -EPERM;
@@ -7351,9 +7408,21 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 	if (sgi == NL80211_TXRATE_FORCE_LGI)
 		return -EINVAL;
 
-	if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask)) {
+	allow_pfr = test_bit(ATH10K_FW_FEATURE_PEER_FIXED_RATE,
+			     ar->normal_mode_fw.fw_file.fw_features);
+	if (allow_pfr) {
+		mutex_lock(&ar->conf_mutex);
+		ieee80211_iterate_stations_atomic(ar->hw,
+						  ath10k_mac_clr_bitrate_mask_iter,
+						  arvif);
+		mutex_unlock(&ar->conf_mutex);
+	}
+
+	if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask,
+						    &vht_num_rates)) {
 		ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
-							      &rate, &nss);
+							      &rate, &nss,
+							      false);
 		if (ret) {
 			ath10k_warn(ar, "failed to get single rate for vdev %i: %d\n",
 				    arvif->vdev_id, ret);
@@ -7369,12 +7438,30 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 			  max(ath10k_mac_max_ht_nss(ht_mcs_mask),
 			      ath10k_mac_max_vht_nss(vht_mcs_mask)));
 
-		if (!ath10k_mac_can_set_bitrate_mask(ar, band, mask))
-			return -EINVAL;
+		if (!ath10k_mac_can_set_bitrate_mask(ar, band, mask,
+						     allow_pfr)) {
+			u8 vht_nss;
+
+			if (!allow_pfr || vht_num_rates != 1)
+				return -EINVAL;
+
+			/* Reach here, firmware supports peer fixed rate and has
+			 * single vht rate, and don't update vif birate_mask, as
+			 * the rate only for specific peer.
+			 */
+			ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
+								&vht_pfr,
+								&vht_nss,
+								true);
+			update_bitrate_mask = false;
+		}
 
 		mutex_lock(&ar->conf_mutex);
 
-		arvif->bitrate_mask = *mask;
+		if (update_bitrate_mask)
+			arvif->bitrate_mask = *mask;
+		arvif->vht_num_rates = vht_num_rates;
+		arvif->vht_pfr = vht_pfr;
 		ieee80211_iterate_stations_atomic(ar->hw,
 						  ath10k_mac_set_bitrate_mask_iter,
 						  arvif);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 12f57f9..bd54da6 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6260,6 +6260,7 @@ enum wmi_peer_param {
 	WMI_PEER_CHAN_WIDTH = 0x4,
 	WMI_PEER_NSS        = 0x5,
 	WMI_PEER_USE_4ADDR  = 0x6,
+	WMI_PEER_PARAM_FIXED_RATE = 0x9,
 	WMI_PEER_DEBUG      = 0xa,
 	WMI_PEER_PHYMODE    = 0xd,
 	WMI_PEER_DUMMY_VAR  = 0xff, /* dummy parameter for STA PS workaround */
-- 
1.9.1


^ permalink raw reply related

* RE: [PATCH] ath10k: add support for simulate crash on SDIO chip
From: Wen Gong @ 2019-05-28  2:25 UTC (permalink / raw)
  To: Nicolas Boichat, Wen Gong
  Cc: Claire Chang, linux-wireless@vger.kernel.org,
	ath10k@lists.infradead.org
In-Reply-To: <CANMq1KBjupZeuw3hmQHbYui4G9+Ni7SPPE1SNqG9=89iVhFjgg@mail.gmail.com>

> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Nicolas
> Boichat
> Sent: Monday, April 29, 2019 1:21 PM
> To: Wen Gong <wgong@codeaurora.org>
> Cc: Claire Chang <tientzu@chromium.org>; linux-wireless@vger.kernel.org;
> ath10k@lists.infradead.org
> Subject: [EXT] Re: [PATCH] ath10k: add support for simulate crash on SDIO
> chip
> 
> Err, so you consider _any_ CPU interrupt to be caused by the FW
> crashing? Is that correct? If so, please at least add a comment.
> 
> Otherwise, maybe you should run this only if
> MBOX_CPU_STATUS_ENABLE_ASSERT_MASK is set in cpu_int_status?
> 
> >         return ret;
> >  }
> >

Hi Nicolas,
New patch has uploaded for the change
https://patchwork.kernel.org/patch/10921341/
[v2] ath10k: add support for simulate crash on SDIO chip

https://patchwork.kernel.org/patch/10955189/
[v3] ath10k: add support for firmware crash recovery on SDIO chip

^ permalink raw reply

* [PATCH] ath10k: add report MIC error for sdio chip
From: Wen Gong @ 2019-05-28  2:27 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless

Firmware will report flag with HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR
if MIC error, the flag will be used in mac80211.

ieee80211_rx_h_michael_mic_verify will check the flag and start TKIP
countermeasures.

Now countermeasure tests pass both with WPA only and WPA2/WPA mixed
mode.

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/htt_rx.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index a20ea27..c0b0061 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2101,7 +2101,9 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 			    num_mpdu_ranges);
 
 	if (mpdu_ranges->mpdu_range_status !=
-	    HTT_RX_IND_MPDU_STATUS_OK) {
+	    HTT_RX_IND_MPDU_STATUS_OK &&
+	    mpdu_ranges->mpdu_range_status !=
+	    HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR) {
 		ath10k_warn(ar, "MPDU range status: %d\n",
 			    mpdu_ranges->mpdu_range_status);
 		goto err;
@@ -2162,6 +2164,9 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
 				   RX_FLAG_MMIC_STRIPPED;
 	}
 
+	if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
+		rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
 	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: [PATCH v3] ath10k: add support for firmware crash recovery on SDIO chip
From: Nicolas Boichat @ 2019-05-28  2:32 UTC (permalink / raw)
  To: Claire Chang; +Cc: Wen Gong, ath10k, open list:NETWORKING DRIVERS (WIRELESS)
In-Reply-To: <CALiNf28PQFtAM6uZVPhh-_ASnYeeAtm8kWpP0b8k_P6zGwxbcQ@mail.gmail.com>

Change to the interrupt handler since v1 sounds good to me.

Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>

On Thu, May 23, 2019 at 4:53 PM Claire Chang <tientzu@google.com> wrote:
>
> Tested-by: Claire Chang <tientzu@chromium.org>

^ permalink raw reply

* RE: [PATCH] ath10k: Remove ATH10K_STATE_RESTARTED in simulate fw crash
From: Wen Gong @ 2019-05-28  2:49 UTC (permalink / raw)
  To: Brian Norris
  Cc: Michał Kazior, linux-wireless, ath10k@lists.infradead.org,
	Wen Gong
In-Reply-To: <b073fa90e9a3437c9846ce2d22fab15f@aptaiexm02f.ap.qualcomm.com>

> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Wen Gong
> Sent: Wednesday, April 10, 2019 10:45 AM
> To: Brian Norris <briannorris@chromium.org>
> Cc: Michał Kazior <kazikcz@gmail.com>; linux-wireless <linux-
> wireless@vger.kernel.org>; ath10k@lists.infradead.org; Wen Gong
> <wgong@codeaurora.org>
> Subject: [EXT] RE: [PATCH] ath10k: Remove ATH10K_STATE_RESTARTED in
> simulate fw crash
> 
> If ChromeOS is easy to change tool,
> I think I will change the mechanism of the simulate_fw_crash.
> Then all tools will work normally.
> 
New patch uploaded
https://patchwork.kernel.org/patch/10897587/
[v2] ath10k: Remove ATH10K_STATE_RESTARTED in simulate fw crash

^ permalink raw reply

* RE: [PATCH v2] ath10k: add support for simulate crash on SDIO chip
From: Wen Gong @ 2019-05-28  2:54 UTC (permalink / raw)
  To: Claire Chang, Wen Gong
  Cc: open list:NETWORKING DRIVERS (WIRELESS),
	ath10k@lists.infradead.org
In-Reply-To: <5b1f1d8619524128894e5f31ca4733af@aptaiexm02f.ap.qualcomm.com>

> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Wen Gong
> Sent: Wednesday, May 22, 2019 2:24 PM
> To: Claire Chang <tientzu@google.com>; Wen Gong
> <wgong@codeaurora.org>
> Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> wireless@vger.kernel.org>; ath10k@lists.infradead.org
> Subject: [EXT] RE: [PATCH v2] ath10k: add support for simulate crash on SDIO
> chip
> > Tested-by: Claire Chang <tientzu@chromium.org>
> >
> > If this patch adds support for detecting the real firmware assert,
> > maybe the title should be "add support for _crash recovery_ on SDIO
> > chip"
> Yes, seems this title is more appropriate.
Hi Claire
New patch has uploaded for the change
https://patchwork.kernel.org/patch/10955189/
[v3] ath10k: add support for firmware crash recovery on SDIO chip

^ permalink raw reply

* [PATCH V2] iw: print HE capabilities
From: John Crispin @ 2019-05-28  6:58 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, John Crispin, Shashidhar Lakkavalli

Print the HE MAC/PHY capabilities and MCS/NSS sets.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
Changes in V2
* add a missing ',' in the iftypes name list

 info.c |   6 ++
 iw.h   |   1 +
 util.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 238 insertions(+)

diff --git a/info.c b/info.c
index 92c7d1d..e6270c8 100644
--- a/info.c
+++ b/info.c
@@ -162,7 +162,13 @@ static int print_phy_handler(struct nl_msg *msg, void *arg)
 			    tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])
 				print_vht_info(nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]),
 					       nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]));
+			if (tb_band[NL80211_BAND_ATTR_IFTYPE_DATA]) {
+				struct nlattr *nl_iftype;
+				int rem_band;
 
+				nla_for_each_nested(nl_iftype, tb_band[NL80211_BAND_ATTR_IFTYPE_DATA], rem_band)
+					print_he_info(nl_iftype);
+			}
 			if (tb_band[NL80211_BAND_ATTR_FREQS]) {
 				if (!band_had_freq) {
 					printf("\t\tFrequencies:\n");
diff --git a/iw.h b/iw.h
index ca8a0ff..bc0b3ac 100644
--- a/iw.h
+++ b/iw.h
@@ -197,6 +197,7 @@ void print_ampdu_length(__u8 exponent);
 void print_ampdu_spacing(__u8 spacing);
 void print_ht_capability(__u16 cap);
 void print_vht_info(__u32 capa, const __u8 *mcs);
+void print_he_info(struct nlattr *nl_iftype);
 
 char *channel_width_name(enum nl80211_chan_width width);
 const char *iftype_name(enum nl80211_iftype iftype);
diff --git a/util.c b/util.c
index 2fa0b74..bb34fd3 100644
--- a/util.c
+++ b/util.c
@@ -1101,6 +1101,237 @@ void print_vht_info(__u32 capa, const __u8 *mcs)
 	printf("\t\tVHT TX highest supported: %d Mbps\n", tmp & 0x1fff);
 }
 
+void print_he_info(struct nlattr *nl_iftype)
+{
+	struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
+	struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
+	char *iftypes[NUM_NL80211_IFTYPES] = {
+		"Unspec", "Adhoc", "Station", "AP", "AP/VLAN", "WDS", "Monitor",
+		"Mesh", "P2P/Client", "P2P/Go", "P2P/Device", "OCB", "NAN",
+	};
+	__u16 mac_cap[3] = { 0 };
+	__u16 phy_cap[6] = { 0 };
+	__u16 mcs_set[6] = { 0 };
+	__u8 ppet[25] = { 0 };
+	size_t len;
+	int i;
+
+	#define PRINT_HE_CAP(_var, _idx, _bit, _str) \
+	do { \
+		if (_var[_idx] & BIT(_bit)) \
+			printf("\t\t\t\t" _str "\n"); \
+	} while (0)
+
+	#define PRINT_HE_CAP_MASK(_var, _idx, _shift, _mask, _str) \
+	do { \
+		if ((_var[_idx] >> _shift) & _mask) \
+			printf("\t\t\t\t" _str ": %d\n", (_var[_idx] >> _shift) & _mask); \
+	} while (0)
+
+	#define PRINT_HE_MAC_CAP(...) PRINT_HE_CAP(mac_cap, __VA_ARGS__)
+	#define PRINT_HE_MAC_CAP_MASK(...) PRINT_HE_CAP_MASK(mac_cap, __VA_ARGS__)
+	#define PRINT_HE_PHY_CAP(...) PRINT_HE_CAP(phy_cap, __VA_ARGS__)
+	#define PRINT_HE_PHY_CAP0(_idx, _bit, ...) PRINT_HE_CAP(phy_cap, _idx, _bit + 8, __VA_ARGS__)
+	#define PRINT_HE_PHY_CAP_MASK(...) PRINT_HE_CAP_MASK(phy_cap, __VA_ARGS__)
+
+	nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
+		  nla_data(nl_iftype), nla_len(nl_iftype), NULL);
+
+	if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
+		return;
+
+	if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
+			     tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
+		return;
+
+	printf("\t\tHE Iftypes:");
+	for (i = 0; i < NUM_NL80211_IFTYPES; i++)
+		if (nla_get_flag(tb_flags[i]) && iftypes[i])
+			printf(" %s", iftypes[i]);
+	printf("\n");
+
+	if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) {
+		len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]);
+		if (len > sizeof(mac_cap))
+			len = sizeof(mac_cap);
+		memcpy(mac_cap,
+		       nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]),
+		       len);
+	}
+	printf("\t\t\tHE MAC Capabilities (0x");
+	for (i = 0; i < 3; i++)
+		printf("%04x", mac_cap[i]);
+	printf("):\n");
+
+	PRINT_HE_MAC_CAP(0, 0, "+HTC HE Supported");
+	PRINT_HE_MAC_CAP(0, 1, "TWT Requester");
+	PRINT_HE_MAC_CAP(0, 2, "TWT Responder");
+	PRINT_HE_MAC_CAP_MASK(0, 3, 0x3, "Dynamic BA Fragmentation Level");
+	PRINT_HE_MAC_CAP_MASK(0, 5, 0x7, "Maximum number of MSDUS Fragments");
+	PRINT_HE_MAC_CAP_MASK(0, 8, 0x3, "Minimum Payload size of 128 bytes");
+	PRINT_HE_MAC_CAP_MASK(0, 10, 0x3, "Trigger Frame MAC Padding Duration");
+	PRINT_HE_MAC_CAP_MASK(0, 12, 0x7, "Multi-TID Aggregation Support");
+
+	PRINT_HE_MAC_CAP(1, 1, "All Ack");
+	PRINT_HE_MAC_CAP(1, 2, "TRS");
+	PRINT_HE_MAC_CAP(1, 3, "BSR");
+	PRINT_HE_MAC_CAP(1, 4, "Broadcast TWT");
+	PRINT_HE_MAC_CAP(1, 5, "32-bit BA Bitmap");
+	PRINT_HE_MAC_CAP(1, 6, "MU Cascading");
+	PRINT_HE_MAC_CAP(1, 7, "Ack-Enabled Aggregation");
+	PRINT_HE_MAC_CAP(1, 9, "OM Control");
+	PRINT_HE_MAC_CAP(1, 10, "OFDMA RA");
+	PRINT_HE_MAC_CAP_MASK(1, 11, 0x3, "Maximum A-MPDU Length Exponent");
+	PRINT_HE_MAC_CAP(1, 13, "A-MSDU Fragmentation");
+	PRINT_HE_MAC_CAP(1, 14, "Flexible TWT Scheduling");
+	PRINT_HE_MAC_CAP(1, 15, "RX Control Frame to MultiBSS");
+
+	PRINT_HE_MAC_CAP(2, 0, "BSRP BQRP A-MPDU Aggregation");
+	PRINT_HE_MAC_CAP(2, 1, "QTP");
+	PRINT_HE_MAC_CAP(2, 2, "BQR");
+	PRINT_HE_MAC_CAP(2, 3, "SRP Responder Role");
+	PRINT_HE_MAC_CAP(2, 4, "NDP Feedback Report");
+	PRINT_HE_MAC_CAP(2, 5, "OPS");
+	PRINT_HE_MAC_CAP(2, 6, "A-MSDU in A-MPDU");
+	PRINT_HE_MAC_CAP_MASK(2, 7, 7, "Multi-TID Aggregation TX");
+	PRINT_HE_MAC_CAP(2, 10, "HE Subchannel Selective Transmission");
+	PRINT_HE_MAC_CAP(2, 11, "UL 2x996-Tone RU");
+	PRINT_HE_MAC_CAP(2, 12, "OM Control UL MU Data Disable RX");
+
+	if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) {
+		len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]);
+
+		if (len > sizeof(phy_cap) - 1)
+			len = sizeof(phy_cap) - 1;
+		memcpy(&((__u8 *)phy_cap)[1],
+		       nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]),
+		       len);
+	}
+	printf("\t\t\tHE PHY Capabilities: (0x");
+	for (i = 0; i < 11; i++)
+		printf("%02x", ((__u8 *)phy_cap)[i + 1]);
+	printf("):\n");
+
+	PRINT_HE_PHY_CAP0(0, 1, "HE40/2.4GHz");
+	PRINT_HE_PHY_CAP0(0, 2, "HE40/HE80/5GHz");
+	PRINT_HE_PHY_CAP0(0, 3, "HE160/5GHz");
+	PRINT_HE_PHY_CAP0(0, 4, "HE160/HE80+80/5GHz");
+	PRINT_HE_PHY_CAP0(0, 5, "242 tone RUs/2.4GHz");
+	PRINT_HE_PHY_CAP0(0, 6, "242 tone RUs/5GHz");
+
+	PRINT_HE_PHY_CAP_MASK(1, 0, 0xf, "Punctured Preamble RX");
+	PRINT_HE_PHY_CAP_MASK(1, 4, 0x1, "Device Class");
+	PRINT_HE_PHY_CAP(1, 5, "LDPC Coding in Payload");
+	PRINT_HE_PHY_CAP(1, 6, "HE SU PPDU with 1x HE-LTF and 0.8us GI");
+	PRINT_HE_PHY_CAP_MASK(1, 7, 0x3, "Midamble Rx Max NSTS");
+	PRINT_HE_PHY_CAP(1, 9, "NDP with 4x HE-LTF and 3.2us GI");
+	PRINT_HE_PHY_CAP(1, 10, "STBC Tx <= 80MHz");
+	PRINT_HE_PHY_CAP(1, 11, "STBC Rx <= 80MHz");
+	PRINT_HE_PHY_CAP(1, 12, "Doppler Tx");
+	PRINT_HE_PHY_CAP(1, 13, "Doppler Rx");
+	PRINT_HE_PHY_CAP(1, 14, "Full Bandwidth UL MU-MIMO");
+	PRINT_HE_PHY_CAP(1, 15, "Partial Bandwidth UL MU-MIMO");
+
+	PRINT_HE_PHY_CAP_MASK(2, 0, 0x3, "DCM Max Constellation");
+	PRINT_HE_PHY_CAP_MASK(2, 2, 0x1, "DCM Max NSS Tx");
+	PRINT_HE_PHY_CAP_MASK(2, 3, 0x3, "DCM Max Constellation Rx");
+	PRINT_HE_PHY_CAP_MASK(2, 5, 0x1, "DCM Max NSS Rx");
+	PRINT_HE_PHY_CAP(2, 6, "Rx HE MU PPDU from Non-AP STA");
+	PRINT_HE_PHY_CAP(2, 7, "SU Beamformer");
+	PRINT_HE_PHY_CAP(2, 8, "SU Beamformee");
+	PRINT_HE_PHY_CAP(2, 9, "MU Beamformer");
+	PRINT_HE_PHY_CAP_MASK(2, 10, 0x7, "Beamformee STS <= 80Mhz");
+	PRINT_HE_PHY_CAP_MASK(2, 13, 0x7, "Beamformee STS > 80Mhz");
+
+	PRINT_HE_PHY_CAP_MASK(3, 0, 0x7, "Sounding Dimensions <= 80Mhz");
+	PRINT_HE_PHY_CAP_MASK(3, 3, 0x7, "Sounding Dimensions > 80Mhz");
+	PRINT_HE_PHY_CAP(3, 6, "Ng = 16 SU Feedback");
+	PRINT_HE_PHY_CAP(3, 7, "Ng = 16 MU Feedback");
+	PRINT_HE_PHY_CAP(3, 8, "Codebook Size SU Feedback");
+	PRINT_HE_PHY_CAP(3, 9, "Codebook Size MU Feedback");
+	PRINT_HE_PHY_CAP(3, 10, "Triggered SU Beamforming Feedback");
+	PRINT_HE_PHY_CAP(3, 11, "Triggered MU Beamforming Feedback");
+	PRINT_HE_PHY_CAP(3, 12, "Triggered CQI Feedback");
+	PRINT_HE_PHY_CAP(3, 13, "Partial Bandwidth Extended Range");
+	PRINT_HE_PHY_CAP(3, 14, "Partial Bandwidth DL MU-MIMO");
+	PRINT_HE_PHY_CAP(3, 15, "PPE Threshold Present");
+
+	PRINT_HE_PHY_CAP(4, 0, "SRP-based SR");
+	PRINT_HE_PHY_CAP(4, 1, "Power Boost Factor ar");
+	PRINT_HE_PHY_CAP(4, 2, "HE SU PPDU & HE PPDU 4x HE-LTF 0.8us GI");
+	PRINT_HE_PHY_CAP_MASK(4, 3, 0x7, "Max NC");
+	PRINT_HE_PHY_CAP(4, 6, "STBC Tx > 80MHz");
+	PRINT_HE_PHY_CAP(4, 7, "STBC Rx > 80MHz");
+	PRINT_HE_PHY_CAP(4, 8, "HE ER SU PPDU 4x HE-LTF 0.8us GI");
+	PRINT_HE_PHY_CAP(4, 9, "20MHz in 40MHz HE PPDU 2.4GHz");
+	PRINT_HE_PHY_CAP(4, 10, "20MHz in 160/80+80MHz HE PPDU");
+	PRINT_HE_PHY_CAP(4, 11, "80MHz in 160/80+80MHz HE PPDU");
+	PRINT_HE_PHY_CAP(4, 12, "HE ER SU PPDU 1x HE-LTF 0.8us GI");
+	PRINT_HE_PHY_CAP(4, 13, "Midamble Rx 2x & 1x HE-LTF");
+	PRINT_HE_PHY_CAP_MASK(4, 14, 0x3, "DCM Max BW");
+
+	PRINT_HE_PHY_CAP(5, 0, "Longer Than 16HE SIG-B OFDM Symbols");
+	PRINT_HE_PHY_CAP(5, 1, "Non-Triggered CQI Feedback");
+	PRINT_HE_PHY_CAP(5, 2, "TX 1024-QAM");
+	PRINT_HE_PHY_CAP(5, 3, "RX 1024-QAM");
+	PRINT_HE_PHY_CAP(5, 4, "RX Full BW SU Using HE MU PPDU with Compression SIGB");
+	PRINT_HE_PHY_CAP(5, 5, "RX Full BW SU Using HE MU PPDU with Non-Compression SIGB");
+
+	if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]) {
+		len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]);
+		if (len > sizeof(mcs_set))
+			len = sizeof(mcs_set);
+		memcpy(mcs_set,
+		       nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]),
+		       len);
+	}
+
+	for (i = 0; i < 3; i++) {
+		__u8 phy_cap_support[] = { BIT(1) | BIT(2), BIT(3), BIT(4) };
+		char *bw[] = { "<= 80", "160", "80+80" };
+		int j;
+
+		if ((phy_cap[0] & (phy_cap_support[i] << 8)) == 0)
+			continue;
+
+		for (j = 0; j < 2; j++) {
+			int k;
+			printf("\t\t\tHE %s MCS and NSS set %s MHz\n", j ? "TX" : "RX", bw[i]);
+			for (k = 0; k < 8; k++) {
+				__u16 mcs = mcs_set[(i * 2) + j];
+				mcs >>= k * 2;
+				mcs &= 0x3;
+				printf("\t\t\t\t\t %d streams: ", k + 1);
+				if (mcs == 3)
+					printf("not supported\n");
+				else
+					printf("MCS 0-%d\n", 7 + (mcs * 2));
+			}
+
+		}
+	}
+
+	len = 0;
+	if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]) {
+		len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]);
+		if (len > sizeof(ppet))
+			len = sizeof(ppet);
+		memcpy(ppet,
+		       nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
+		       len);
+	}
+
+	if (len && (phy_cap[3] & BIT(15))) {
+		size_t i;
+
+		printf("\t\t\tPPE Threshold ");
+		for (i = 0; i < len; i++)
+			if (ppet[i])
+				printf("0x%02x ", ppet[i]);
+		printf("\n");
+	}
+}
+
 void iw_hexdump(const char *prefix, const __u8 *buf, size_t size)
 {
 	size_t i;
-- 
2.20.1


^ permalink raw reply related

* Re: [PATCH V2] iw: print HE capabilities
From: Sven Eckelmann @ 2019-05-28  7:02 UTC (permalink / raw)
  To: John Crispin; +Cc: Johannes Berg, linux-wireless, Shashidhar Lakkavalli
In-Reply-To: <20190528065828.25356-1-john@phrozen.org>

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

On Tuesday, 28 May 2019 08:58:28 CEST John Crispin wrote:
> Print the HE MAC/PHY capabilities and MCS/NSS sets.
> 
> Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
> Signed-off-by: John Crispin <john@phrozen.org>
> ---
> Changes in V2
> * add a missing ',' in the iftypes name list

The patch was already added with the bugfix [1].

Kind regards,
	Sven

[1] https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/commit/?id=c741be9f6ca34411c4dbeb03dd13e0dd794713a5

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

^ permalink raw reply

* Re: [PATCH V2] iw: print HE capabilities
From: John Crispin @ 2019-05-28  7:03 UTC (permalink / raw)
  To: Sven Eckelmann; +Cc: Johannes Berg, linux-wireless, Shashidhar Lakkavalli
In-Reply-To: <2100673.vGQeuS8Cl6@bentobox>


On 28/05/2019 09:02, Sven Eckelmann wrote:
> On Tuesday, 28 May 2019 08:58:28 CEST John Crispin wrote:
>> Print the HE MAC/PHY capabilities and MCS/NSS sets.
>>
>> Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
>> Signed-off-by: John Crispin <john@phrozen.org>
>> ---
>> Changes in V2
>> * add a missing ',' in the iftypes name list
> The patch was already added with the bugfix [1].
>
> Kind regards,
> 	Sven
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/commit/?id=c741be9f6ca34411c4dbeb03dd13e0dd794713a5


oh great, Thanks !



^ permalink raw reply

* brcmfmac support for BCM4359 sdio on arm64
From: Christian Hewitt @ 2019-05-28  7:19 UTC (permalink / raw)
  To: arend.vanspriel
  Cc: linux-wireless, brcm80211-dev-list.pdl, brcm80211-dev-list,
	Wright.Feng, Neil Armstrong, Christoph Muellner

Hello Arend,

Last October Christoph Müllner reported BCM4359 SDIO issues here: https://www.spinics.net/lists/linux-wireless/msg178783.html but the investigation stalled after the needs/timescale of his project forced a change to an alternate (working) module.

BCM4359 is also being used in an increasing number of Amlogic devices the Kodi focussed distro LibreELEC supports. I’m one of the maintainers for the distro and I’d like to assist/resume the investigation.

To recap: using changes from Wright Feng that can be found here https://github.com/RobertCNelson/ti-linux-kernel-dev/blob/65f17112e1c883d3c9f3fa68837e5f9b5eb7cfad/patches/cypress/v4.14.52-2018_0928/cypress-patch/0050-brcmfmac-Add-support-for-BCM4359-SDIO-chipset.patch results in the BCM4359 device being identified but firmware loading fails:

[    8.557929] brcmfmac: F1 signature read @0x18000000=0x17294359
[    8.562087] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4359-sdio for chip BCM4359/9
[    8.775655] brcmfmac: brcmf_sdiod_ramrw: membytes transfer failed
[    8.775667] brcmfmac: brcmf_sdio_verifymemory: error -84 on reading 2048 membytes at 0x0025f0c0
[    8.775670] brcmfmac: brcmf_sdio_download_firmware: dongle nvram file download failed

See: http://ix.io/1KfY for the full dmesg output on 5.1-rc1 kernel including a splat that may or may not be related/relevant. I am using the firmware and nvram files from https://github.com/LibreELEC/brcmfmac_sdio-firmware which match files found in several other github and public repo locations. The firmware/nvram are reported working in Android. 

BCMDHD is also reported working with the last few commits here: https://gitlab.com/baylibre/amlogic/atv/linux/commits/narmstrong/v5.1/aml/integ-5.1-bcmdhd but LibreELEC needs to support many different boards (with many different SDIO modules) from a single OS image, so BCMDHD is not the solution we need.

One additional patch I spotted mentioning BCM4359 (also from Wright Feng) was https://github.com/RobertCNelson/ti-linux-kernel-dev/blob/65f17112e1c883d3c9f3fa68837e5f9b5eb7cfad/patches/cypress/v4.14.52-2018_0928/cypress-patch/0073-non-upstream-reset-two-D11-cores-if-chip-has-two-D11.patch but it makes no difference (the dmesg log above is with this patch applied).

I’m happy building test kernels but I don’t write code so I can be fed patches and can provide logs/output as long as the instructions are fairly explicit. I’ve also CC’d LibreELEC colleague and linux-amlogic maintainer Neil Armstrong who has vastly superior skills to myself and can assist. NB: If direct access to hardware would help progress things I can easily organise remote access or get board samples shipped.

How to resume things again?

Christian


^ permalink raw reply

* Re: brcmfmac support for BCM4359 sdio on arm64
From: Neil Armstrong @ 2019-05-28  7:28 UTC (permalink / raw)
  To: Christian Hewitt, arend.vanspriel
  Cc: linux-wireless, brcm80211-dev-list.pdl, brcm80211-dev-list,
	Wright.Feng, Christoph Muellner
In-Reply-To: <9B1E511E-A6F7-4907-953B-537EC7F75EEE@gmail.com>

Hi,

On 28/05/2019 09:19, Christian Hewitt wrote:
> Hello Arend,
> 
> Last October Christoph Müllner reported BCM4359 SDIO issues here: https://www.spinics.net/lists/linux-wireless/msg178783.html but the investigation stalled after the needs/timescale of his project forced a change to an alternate (working) module.

Following Mullner's thread, this is what I collected with various fixes found on other repos :
===========><===================================================
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index d2f788d88668..aa434b787953 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -971,6 +971,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
+	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373),
 	{ /* end: all zeroes */ }
 };
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index 927d62b3d41b..21e947fb1537 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -681,7 +681,6 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
 	case BRCM_CC_43569_CHIP_ID:
 	case BRCM_CC_43570_CHIP_ID:
 	case BRCM_CC_4358_CHIP_ID:
-	case BRCM_CC_4359_CHIP_ID:
 	case BRCM_CC_43602_CHIP_ID:
 	case BRCM_CC_4371_CHIP_ID:
 		return 0x180000;
@@ -691,6 +690,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
 	case BRCM_CC_4366_CHIP_ID:
 	case BRCM_CC_43664_CHIP_ID:
 		return 0x200000;
+	case BRCM_CC_4359_CHIP_ID:
 	case CY_CC_4373_CHIP_ID:
 		return 0x160000;
 	default:
@@ -1339,6 +1339,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
 	switch (pub->chip) {
 	case BRCM_CC_4354_CHIP_ID:
 	case BRCM_CC_4356_CHIP_ID:
+	case BRCM_CC_4359_CHIP_ID:
 	case BRCM_CC_4345_CHIP_ID:
 		/* explicitly check SR engine enable bit */
 		pmu_cc3_mask = BIT(2);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index a907d7b065fa..cf90a87bda60 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -617,6 +617,7 @@ BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio");
 BRCMF_FW_DEF(43455, "brcmfmac43455-sdio");
 BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
 BRCMF_FW_DEF(4356, "brcmfmac4356-sdio");
+BRCMF_FW_DEF(4359, "brcmfmac4359-sdio");
 BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");

 static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
@@ -637,6 +638,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
 	BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
 	BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
 	BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
+	BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
 	BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373)
 };

diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
index 4224902a8e22..00e3f624baf2 100644
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -41,6 +41,7 @@
 #define SDIO_DEVICE_ID_BROADCOM_43455		0xa9bf
 #define SDIO_DEVICE_ID_BROADCOM_4354		0x4354
 #define SDIO_DEVICE_ID_BROADCOM_4356		0x4356
+#define SDIO_DEVICE_ID_BROADCOM_4359		0x4359
 #define SDIO_DEVICE_ID_CYPRESS_4373		0x4373

 #define SDIO_VENDOR_ID_INTEL			0x0089
===========><===================================================

But the driver stalls, without any errors.
I haven't activated debug traces in the brcmfmac driver to investigate further.

Neil

> 
> BCM4359 is also being used in an increasing number of Amlogic devices the Kodi focussed distro LibreELEC supports. I’m one of the maintainers for the distro and I’d like to assist/resume the investigation.
> 
> To recap: using changes from Wright Feng that can be found here https://github.com/RobertCNelson/ti-linux-kernel-dev/blob/65f17112e1c883d3c9f3fa68837e5f9b5eb7cfad/patches/cypress/v4.14.52-2018_0928/cypress-patch/0050-brcmfmac-Add-support-for-BCM4359-SDIO-chipset.patch results in the BCM4359 device being identified but firmware loading fails:
> 
> [    8.557929] brcmfmac: F1 signature read @0x18000000=0x17294359
> [    8.562087] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4359-sdio for chip BCM4359/9
> [    8.775655] brcmfmac: brcmf_sdiod_ramrw: membytes transfer failed
> [    8.775667] brcmfmac: brcmf_sdio_verifymemory: error -84 on reading 2048 membytes at 0x0025f0c0
> [    8.775670] brcmfmac: brcmf_sdio_download_firmware: dongle nvram file download failed
> 
> See: http://ix.io/1KfY for the full dmesg output on 5.1-rc1 kernel including a splat that may or may not be related/relevant. I am using the firmware and nvram files from https://github.com/LibreELEC/brcmfmac_sdio-firmware which match files found in several other github and public repo locations. The firmware/nvram are reported working in Android. 
> 
> BCMDHD is also reported working with the last few commits here: https://gitlab.com/baylibre/amlogic/atv/linux/commits/narmstrong/v5.1/aml/integ-5.1-bcmdhd but LibreELEC needs to support many different boards (with many different SDIO modules) from a single OS image, so BCMDHD is not the solution we need.
> 
> One additional patch I spotted mentioning BCM4359 (also from Wright Feng) was https://github.com/RobertCNelson/ti-linux-kernel-dev/blob/65f17112e1c883d3c9f3fa68837e5f9b5eb7cfad/patches/cypress/v4.14.52-2018_0928/cypress-patch/0073-non-upstream-reset-two-D11-cores-if-chip-has-two-D11.patch but it makes no difference (the dmesg log above is with this patch applied).
> 
> I’m happy building test kernels but I don’t write code so I can be fed patches and can provide logs/output as long as the instructions are fairly explicit. I’ve also CC’d LibreELEC colleague and linux-amlogic maintainer Neil Armstrong who has vastly superior skills to myself and can assist. NB: If direct access to hardware would help progress things I can easily organise remote access or get board samples shipped.
> 
> How to resume things again?
> 
> Christian
> 


^ permalink raw reply related

* [PATCH 1/3][V2] lib: fix match_string() helper on -1 array size
From: Alexandru Ardelean @ 2019-05-28  7:39 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel, linux-ide, linux-clk,
	linux-rpi-kernel, linux-arm-kernel, linux-rockchip, linux-pm,
	linux-gpio, dri-devel, intel-gfx, linux-omap, linux-mmc,
	linux-wireless, netdev, linux-pci, linux-tegra, devel, linux-usb,
	kvm, linux-fbdev, linux-mtd, cgroups, linux-mm,
	linux-security-module, linux-integrity, alsa-devel
  Cc: heikki.krogerus, gregkh, andriy.shevchenko, Alexandru Ardelean
In-Reply-To: <20190508112842.11654-1-alexandru.ardelean@analog.com>

The documentation the `_match_string()` helper mentions that `n`
should be:
 * @n: number of strings in the array or -1 for NULL terminated arrays

The behavior of the function is different, in the sense that it exits on
the first NULL element in the array, regardless of whether `n` is -1 or a
positive number.

This patch changes the behavior, to exit the loop when a NULL element is
found and n == -1. Essentially, this aligns the behavior with the
doc-string.

There are currently many users of `match_string()`, and so, in order to go
through them, the next patches in the series will focus on doing some
cosmetic changes, which are aimed at grouping the users of
`match_string()`.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---

Changelog v1 -> v2:
* split the initial series into just 3 patches that fix the
  `match_string()` helper and start introducing a new version of this
  helper, which computes array-size of static arrays

 lib/string.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/string.c b/lib/string.c
index 6016eb3ac73d..e2cf5acc83bd 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -681,8 +681,11 @@ int match_string(const char * const *array, size_t n, const char *string)
 
 	for (index = 0; index < n; index++) {
 		item = array[index];
-		if (!item)
+		if (!item) {
+			if (n != (size_t)-1)
+				continue;
 			break;
+		}
 		if (!strcmp(item, string))
 			return index;
 	}
-- 
2.20.1


^ permalink raw reply related

* [PATCH 3/3][V2] lib: re-introduce new match_string() helper/macro
From: Alexandru Ardelean @ 2019-05-28  7:39 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel, linux-ide, linux-clk,
	linux-rpi-kernel, linux-arm-kernel, linux-rockchip, linux-pm,
	linux-gpio, dri-devel, intel-gfx, linux-omap, linux-mmc,
	linux-wireless, netdev, linux-pci, linux-tegra, devel, linux-usb,
	kvm, linux-fbdev, linux-mtd, cgroups, linux-mm,
	linux-security-module, linux-integrity, alsa-devel
  Cc: heikki.krogerus, gregkh, andriy.shevchenko, Alexandru Ardelean
In-Reply-To: <20190528073932.25365-1-alexandru.ardelean@analog.com>

This change re-introduces `match_string()` as a macro that uses
ARRAY_SIZE() to compute the size of the array.

After this change, work can start on migrating subsystems to use this new
helper. Since the original helper is pretty used, migrating to this new one
will take a while, and will be reviewed by each subsystem.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
 include/linux/string.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index 7149fcdf62df..34491b075449 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -198,6 +198,15 @@ static inline int strtobool(const char *s, bool *res)
 int __match_string(const char * const *array, size_t n, const char *string);
 int __sysfs_match_string(const char * const *array, size_t n, const char *s);
 
+/**
+ * match_string - matches given string in an array
+ * @_a: array of strings
+ * @_s: string to match with
+ *
+ * Helper for __match_string(). Calculates the size of @a automatically.
+ */
+#define match_string(_a, _s) __match_string(_a, ARRAY_SIZE(_a), _s)
+
 /**
  * sysfs_match_string - matches given string in an array
  * @_a: array of strings
-- 
2.20.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