* 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: [PATCH] netlink: fix station_info pertid memory leak
From: Kalle Valo @ 2019-05-27 4:16 UTC (permalink / raw)
To: Andy Strohman; +Cc: johannes, linux-wireless, Andy Strohman
In-Reply-To: <20190525062729.8504-1-andy@uplevelsystems.com>
Andy Strohman <andrew@andrewstrohman.com> writes:
> When dumping stations, memory allocated for station_info's
> pertid member will leak if the nl80211 header cannot be added to
> the sk_buff due to insufficient tail room.
>
> I noticed this leak in the kmalloc-2048 cache.
>
> Fixes: 8689c051a201 ("cfg80211: dynamically allocate per-tid stats for station info")
> Signed-off-by: Andy Strohman <andy@uplevelsystems.com>
> ---
> net/wireless/nl80211.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
The correct prefix should be "nl80211:".
--
Kalle Valo
^ 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-26 19:58 UTC (permalink / raw)
To: Arend Van Spriel
Cc: Adrian Hunter, 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: <e8c049ce-07e1-8b34-678d-41b3d6d41983@broadcom.com>
[-- Attachment #1: Type: text/plain, Size: 7013 bytes --]
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.
> >
> > When the brcmfmac driver is loaded, the firmware is requested from disk,
> > and that's when the deadlock occurs in 5.2rc1. Specifically:
> >
> > 1) brcmf_sdio_download_firmware() in
> > drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c calls
> > sdio_claim_host()
> >
> > 2) brcmf_sdio_firmware_callback() is called and brcmf_sdiod_ramrw()
> > tries to claim the host, but has to wait since its already claimed
> > in #1 and the deadlock occurs.
>
> This does not make any sense to me. brcmf_sdio_download_firmware() is called
> from brcmf_sdio_firmware_callback() so they are in the same context. So #2
> is not waiting for #1, but something else I would say. Also #2 calls
> sdio_claim_host() after brcmf_sdio_download_firmware has completed so
> definitely not waiting for #1.
I attached a patch that shows how I was able to determine what had
already claimed the host. It's messy; please don't judge me negatively
for this. :) Anyways, sdio_claim_host() is mostly a wrapper for
__mmc_claim_host() and there is a mmc_ctx structure that contains a
task struct. This context can be NULL. I added a description field
to the context structure and put the function name that claimed the
host in there. The mmc_host structure already contained a 'claimer'
member, so that made it easy.
I see the following messages in dmesg that shows what has already
claimed the host when loading the brcmfmac module in 5.2rc1:
cfg80211: Loading compiled-in X.509 certificates for regulatory database
cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
cfg80211: failed to load regulatory.db
brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4339-sdio for chip BCM4339/2
brcmfmac mmc1:0001:1: Direct firmware load for brcm/brcmfmac4339-sdio.lge,hammerhead.txt failed with error -2
------------[ cut here ]------------
WARNING: CPU: 0 PID: 5 at drivers/mmc/core/core.c:819 __mmc_claim_host+0x28c/0x2c0
Modules linked in: brcmfmac brcmutil cfg80211 dm_mod
CPU: 0 PID: 5 Comm: kworker/0:0 Not tainted 5.2.0-rc1-00175-g9899510d2cd1-dirty #420
Hardware name: Generic DT based system
Workqueue: events request_firmware_work_func
[<c03122dc>] (unwind_backtrace) from [<c030d5dc>] (show_stack+0x10/0x14)
[<c030d5dc>] (show_stack) from [<c0ac284c>] (dump_stack+0x78/0x8c)
[<c0ac284c>] (dump_stack) from [<c0321438>] (__warn.part.3+0xb8/0xd4)
[<c0321438>] (__warn.part.3) from [<c03215b0>] (warn_slowpath_null+0x44/0x4c)
[<c03215b0>] (warn_slowpath_null) from [<c093e608>] (__mmc_claim_host+0x28c/0x2c0)
[<c093e608>] (__mmc_claim_host) from [<bf115018>] (brcmf_sdiod_ramrw+0x9c/0x200 [brcmfmac])
[<bf115018>] (brcmf_sdiod_ramrw [brcmfmac]) from [<bf110508>] (brcmf_sdio_firmware_callback+0xe8/0x7b4 [brcmfmac])
[<bf110508>] (brcmf_sdio_firmware_callback [brcmfmac]) from [<bf108830>] (brcmf_fw_request_done+0xf0/0x110 [brcmfmac])
[<bf108830>] (brcmf_fw_request_done [brcmfmac]) from [<c081a4e8>] (request_firmware_work_func+0x4c/0x88)
[<c081a4e8>] (request_firmware_work_func) from [<c033c260>] (process_one_work+0x1fc/0x564)
[<c033c260>] (process_one_work) from [<c033ceb8>] (worker_thread+0x44/0x584)
[<c033ceb8>] (worker_thread) from [<c034226c>] (kthread+0x148/0x150)
[<c034226c>] (kthread) from [<c03010e8>] (ret_from_fork+0x14/0x2c)
Exception stack(0xee8bdfb0 to 0xee8bdff8)
dfa0: 00000000 00000000 00000000 00000000
dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
---[ end trace 4ab1b01efc876120 ]---
mmc_host mmc1: __mmc_claim_host: FIXME - before schedule() - descr=brcmf_sdiod_ramrw, claimer=brcmf_sdio_download_firmware
The 'after schedule()' line is not shown and WiFi doesn't work.
> > I tried to release the host before the firmware is requested, however
> > parts of brcmf_chip_set_active() needs the host to be claimed, and a
> > similar deadlock occurs in brcmf_sdiod_ramrw() if I claim the host
> > before calling brcmf_chip_set_active().
> >
> > I started to look at moving the sdio_{claim,release}_host() calls out of
> > brcmf_sdiod_ramrw() but there's a fair number of callers, so I'd like to
> > get feedback about the best course of action here.
>
> Long ago Franky reworked the sdio critical sections requiring sdio
> claim/release and I am pretty sure they are correct.
>
> Could you try with lockdep kernel and see if that brings any more
> information. In the mean time I will update my dev branch to 5.2-rc1 and see
> if I can find any clues.
My .config has CONFIG_LOCKDEP_SUPPORT enabled. I haven't used lockdep
but my understanding is that it should print something in dmesg if a
deadlock occurs. I assume it won't pick up cases like this where
schedule() is called.
Brian
[-- Attachment #2: 0001-troubleshoot-broadcom-wireless-lockup-in-5.2rc1.patch --]
[-- Type: text/x-diff, Size: 18268 bytes --]
From 496c4deaa3787bf619baff58493142e11cd6757f 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
Signed-off-by: Brian Masney <masneyb@onstation.org>
---
drivers/mmc/core/core.c | 15 ++++
.../broadcom/brcm80211/brcmfmac/bcmsdh.c | 32 ++++---
.../broadcom/brcm80211/brcmfmac/sdio.c | 85 ++++++++++++-------
include/linux/mmc/host.h | 1 +
4 files changed, 93 insertions(+), 40 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..aa947fcea736 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
@@ -59,6 +61,16 @@
#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */
+static void sdio_claim_host_with_descr(struct sdio_func *func,
+ const char *descr)
+{
+ struct mmc_ctx mmc_ctx;
+
+ mmc_ctx.task = NULL;
+ mmc_ctx.descr = descr;
+ __mmc_claim_host(func->card->host, &mmc_ctx, NULL);
+}
+
struct brcmf_sdiod_freezer {
atomic_t freezing;
atomic_t thread_count;
@@ -132,7 +144,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
}
sdiodev->irq_wake = true;
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) {
/* assign GPIO to SDIO core */
@@ -162,7 +174,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
sdio_release_host(sdiodev->func1);
} else {
brcmf_dbg(SDIO, "Entering\n");
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(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);
@@ -183,7 +195,7 @@ 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);
+ sdio_claim_host_with_descr(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);
@@ -199,7 +211,7 @@ void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
}
if (sdiodev->sd_irq_requested) {
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
sdio_release_irq(sdiodev->func2);
sdio_release_irq(sdiodev->func1);
sdio_release_host(sdiodev->func1);
@@ -695,7 +707,7 @@ brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
else
dsize = size;
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
/* Do the transfer(s) */
while (size) {
@@ -827,7 +839,7 @@ 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);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
res = brcmf_sdio_sleep(sdiodev->bus, true);
sdio_release_host(sdiodev->func1);
return res;
@@ -835,7 +847,7 @@ static int brcmf_sdiod_freezer_on(struct brcmf_sdio_dev *sdiodev)
static void brcmf_sdiod_freezer_off(struct brcmf_sdio_dev *sdiodev)
{
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
brcmf_sdio_sleep(sdiodev->bus, false);
sdio_release_host(sdiodev->func1);
atomic_set(&sdiodev->freezer->freezing, 0);
@@ -887,12 +899,12 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
brcmf_sdiod_freezer_detach(sdiodev);
/* Disable Function 2 */
- sdio_claim_host(sdiodev->func2);
+ sdio_claim_host_with_descr(sdiodev->func2, __func__);
sdio_disable_func(sdiodev->func2);
sdio_release_host(sdiodev->func2);
/* Disable Function 1 */
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
sdio_disable_func(sdiodev->func1);
sdio_release_host(sdiodev->func1);
@@ -915,7 +927,7 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
ret = sdio_set_block_size(sdiodev->func1, SDIO_FUNC1_BLOCKSIZE);
if (ret) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 22b73da42822..31acdb347e59 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,16 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012)
};
+static void sdio_claim_host_with_descr(struct sdio_func *func,
+ const char *descr)
+{
+ struct mmc_ctx mmc_ctx;
+
+ mmc_ctx.task = NULL;
+ mmc_ctx.descr = descr;
+ __mmc_claim_host(func->card->host, &mmc_ctx, NULL);
+}
+
static void pkt_align(struct sk_buff *p, int len, int align)
{
uint datalign;
@@ -995,7 +1007,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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
brcmf_sdio_bus_sleep(bus, false, false);
/*
@@ -1583,7 +1595,7 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
&bus->glom, dlen);
sdio_release_host(bus->sdiodev->func1);
@@ -1594,7 +1606,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, true, false);
bus->sdcnt.rxglomfail++;
brcmf_sdio_free_glom(bus);
@@ -1608,7 +1621,7 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new,
BRCMF_SDIO_FT_SUPER);
sdio_release_host(bus->sdiodev->func1);
@@ -1626,7 +1639,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new,
BRCMF_SDIO_FT_SUB);
sdio_release_host(bus->sdiodev->func1);
@@ -1638,7 +1652,8 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
if (errcode) {
/* Terminate frame on error */
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, true, false);
bus->sdcnt.rxglomfail++;
brcmf_sdio_free_glom(bus);
@@ -1849,7 +1864,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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (!rd->len) {
ret = brcmf_sdiod_recv_buf(bus->sdiodev,
bus->rxhdr, BRCMF_FIRSTREAD);
@@ -1916,7 +1931,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, true,
RETRYCHAN(rd->channel));
sdio_release_host(bus->sdiodev->func1);
@@ -1930,7 +1946,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
BRCMF_SDIO_FT_NORMAL)) {
rd->len = 0;
@@ -1963,7 +1980,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, false, true);
sdio_release_host(bus->sdiodev->func1);
brcmu_pkt_buf_free_skb(pkt);
@@ -1988,7 +2006,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_rxfail(bus, false, false);
sdio_release_host(bus->sdiodev->func1);
}
@@ -2267,7 +2286,7 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
if (ret)
goto done;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
bus->sdcnt.f2txdata++;
@@ -2330,7 +2349,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
intstatus = brcmf_sdiod_readl(bus->sdiodev,
intstat_addr, &ret);
sdio_release_host(bus->sdiodev->func1);
@@ -2442,7 +2462,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
}
if (sdiodev->state != BRCMF_SDIOD_NOMEDIUM) {
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
/* Enable clock for device interrupts */
brcmf_sdio_bus_sleep(bus, false, false);
@@ -2552,7 +2572,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_dbg(SDIO, "Enter\n");
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
/* If waiting for HTAVAIL, check status */
if (!bus->sr_enabled && bus->clkstate == CLK_PENDING) {
@@ -2658,7 +2678,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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (bus->ctrl_frame_stat) {
err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
bus->ctrl_frame_len);
@@ -2682,7 +2702,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
if (bus->ctrl_frame_stat) {
bus->ctrl_frame_err = -ENODEV;
wmb();
@@ -2904,7 +2925,7 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (bus->ctrl_frame_stat) {
brcmf_dbg(SDIO, "ctrl_frame timeout\n");
bus->ctrl_frame_stat = false;
@@ -3048,7 +3069,7 @@ static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus,
return 0;
}
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
if (sh->assert_file_addr != 0) {
error = brcmf_sdiod_ramrw(bus->sdiodev, false,
sh->assert_file_addr, (u8 *)file, 80);
@@ -3340,7 +3361,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
int bcmerror;
u32 rstvec;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
rstvec = get_unaligned_le32(fw->data);
@@ -3564,7 +3585,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);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
while (offset < mem_size) {
len = ((offset + MEMBLOCK) < mem_size) ? MEMBLOCK :
mem_size - offset;
@@ -3637,7 +3658,8 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
if (!bus->dpc_triggered) {
u8 devpend;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
devpend = brcmf_sdiod_func0_rb(bus->sdiodev,
SDIO_CCCR_INTx, NULL);
sdio_release_host(bus->sdiodev->func1);
@@ -3666,7 +3688,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
/* Make sure backplane clock is on */
brcmf_sdio_bus_sleep(bus, false, false);
if (brcmf_sdio_readconsole(bus) < 0)
@@ -3685,7 +3708,8 @@ 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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1,
+ __func__);
brcmf_sdio_wd_timer(bus, false);
bus->idlecount = 0;
brcmf_sdio_bus_sleep(bus, true, false);
@@ -3903,7 +3927,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
u32 drivestrength;
sdiodev = bus->sdiodev;
- sdio_claim_host(sdiodev->func1);
+ sdio_claim_host_with_descr(sdiodev->func1, __func__);
pr_debug("F1 signature read @0x18000000=0x%4x\n",
brcmf_sdiod_readl(sdiodev, SI_ENUM_BASE, NULL));
@@ -4147,7 +4171,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);
+ sdio_claim_host_with_descr(sdiod->func1, __func__);
/* Make sure backplane clock is on, needed to generate F2 interrupt */
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
@@ -4255,7 +4279,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);
+ sdio_claim_host_with_descr(sdiod->func1, __func__);
goto checkdied;
}
@@ -4361,7 +4385,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);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
/* Disable F2 to clear any intermediate frame state on the dongle */
sdio_disable_func(bus->sdiodev->func2);
@@ -4428,7 +4452,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);
+ sdio_claim_host_with_descr(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
@@ -4485,7 +4510,7 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep)
{
int ret;
- sdio_claim_host(bus->sdiodev->func1);
+ sdio_claim_host_with_descr(bus->sdiodev->func1, __func__);
ret = brcmf_sdio_bus_sleep(bus, sleep, false);
sdio_release_host(bus->sdiodev->func1);
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: Arend Van Spriel @ 2019-05-26 18:42 UTC (permalink / raw)
To: Brian Masney, Adrian Hunter, Franky Lin, Hante Meuleman,
Chi-Hsien Lin, Wright Feng
Cc: 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: <20190526122136.GA26456@basecamp>
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.
>
> When the brcmfmac driver is loaded, the firmware is requested from disk,
> and that's when the deadlock occurs in 5.2rc1. Specifically:
>
> 1) brcmf_sdio_download_firmware() in
> drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c calls
> sdio_claim_host()
>
> 2) brcmf_sdio_firmware_callback() is called and brcmf_sdiod_ramrw()
> tries to claim the host, but has to wait since its already claimed
> in #1 and the deadlock occurs.
This does not make any sense to me. brcmf_sdio_download_firmware() is
called from brcmf_sdio_firmware_callback() so they are in the same
context. So #2 is not waiting for #1, but something else I would say.
Also #2 calls sdio_claim_host() after brcmf_sdio_download_firmware has
completed so definitely not waiting for #1.
> I tried to release the host before the firmware is requested, however
> parts of brcmf_chip_set_active() needs the host to be claimed, and a
> similar deadlock occurs in brcmf_sdiod_ramrw() if I claim the host
> before calling brcmf_chip_set_active().
>
> I started to look at moving the sdio_{claim,release}_host() calls out of
> brcmf_sdiod_ramrw() but there's a fair number of callers, so I'd like to
> get feedback about the best course of action here.
Long ago Franky reworked the sdio critical sections requiring sdio
claim/release and I am pretty sure they are correct.
Could you try with lockdep kernel and see if that brings any more
information. In the mean time I will update my dev branch to 5.2-rc1 and
see if I can find any clues.
Regards,
Arend
^ permalink raw reply
* [PATCH 4/4] mt76: mt7615: rearrange locking in mt7615_config
From: Lorenzo Bianconi @ 2019-05-26 14:05 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, linux-wireless, ryder.lee, royluo
In-Reply-To: <cover.1558879234.git.lorenzo@kernel.org>
Since all the routines in mt7615_config grub mt76.mutex moves
mutex_lock/mutex_unlock at the beginning/end of mt7615_config
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt7615/main.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index cedc4c25f34d..c8411750f62b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -191,31 +191,28 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
struct mt7615_dev *dev = hw->priv;
int ret = 0;
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- mutex_lock(&dev->mt76.mutex);
+ mutex_lock(&dev->mt76.mutex);
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ieee80211_stop_queues(hw);
ret = mt7615_set_channel(dev, &hw->conf.chandef);
ieee80211_wake_queues(hw);
-
- mutex_unlock(&dev->mt76.mutex);
}
if (changed & IEEE80211_CONF_CHANGE_POWER)
ret = mt7615_mcu_set_tx_power(dev);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- mutex_lock(&dev->mt76.mutex);
-
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
dev->mt76.rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
else
dev->mt76.rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter);
-
- mutex_unlock(&dev->mt76.mutex);
}
+
+ mutex_unlock(&dev->mt76.mutex);
+
return ret;
}
--
2.21.0
^ permalink raw reply related
* [PATCH 3/4] mt76: mt7615: init get_txpower mac80211 callback
From: Lorenzo Bianconi @ 2019-05-26 14:05 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, linux-wireless, ryder.lee, royluo
In-Reply-To: <cover.1558879234.git.lorenzo@kernel.org>
Initialize get_txpower mac80211 callback to mt76_get_txpower
in order to report the configured tx power to mac80211
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 72bdb871ca13..cedc4c25f34d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -493,4 +493,5 @@ const struct ieee80211_ops mt7615_ops = {
.sw_scan_start = mt7615_sw_scan,
.sw_scan_complete = mt7615_sw_scan_complete,
.release_buffered_frames = mt76_release_buffered_frames,
+ .get_txpower = mt76_get_txpower,
};
--
2.21.0
^ permalink raw reply related
* [PATCH 2/4] mt76: mt7615: add the capability to configure tx power
From: Lorenzo Bianconi @ 2019-05-26 14:05 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, linux-wireless, ryder.lee, royluo
In-Reply-To: <cover.1558879234.git.lorenzo@kernel.org>
Introduce mt7615_mcu_set_tx_power routine in order to cap tx power
according to the value configured by the user
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../wireless/mediatek/mt76/mt7615/eeprom.c | 34 ++++++++++
.../wireless/mediatek/mt76/mt7615/eeprom.h | 35 ++++++++++
.../net/wireless/mediatek/mt76/mt7615/main.c | 3 +
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 64 +++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7615/mcu.h | 1 +
.../wireless/mediatek/mt76/mt7615/mt7615.h | 3 +
6 files changed, 140 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
index 714590878d65..023c8bbc767d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
@@ -110,6 +110,40 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
}
}
+int mt7615_eeprom_get_power_index(struct ieee80211_channel *chan,
+ u8 chain_idx)
+{
+ int index;
+
+ if (chain_idx > 3)
+ return -EINVAL;
+
+ if (chan->band == NL80211_BAND_2GHZ) {
+ index = MT_EE_TX0_2G_TARGET_POWER + chain_idx * 6;
+ } else {
+ int group = mt7615_get_channel_group(chan->hw_value);
+
+ switch (chain_idx) {
+ case 1:
+ index = MT_EE_TX1_5G_G0_TARGET_POWER;
+ break;
+ case 2:
+ index = MT_EE_TX2_5G_G0_TARGET_POWER;
+ break;
+ case 3:
+ index = MT_EE_TX3_5G_G0_TARGET_POWER;
+ break;
+ case 0:
+ default:
+ index = MT_EE_TX0_5G_G0_TARGET_POWER;
+ break;
+ }
+ index += 5 * group;
+ }
+
+ return index;
+}
+
int mt7615_eeprom_init(struct mt7615_dev *dev)
{
int ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
index b422e395d6ee..3c9086b67f51 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
@@ -12,6 +12,11 @@ enum mt7615_eeprom_field {
MT_EE_MAC_ADDR = 0x004,
MT_EE_NIC_CONF_0 = 0x034,
MT_EE_WIFI_CONF = 0x03e,
+ MT_EE_TX0_2G_TARGET_POWER = 0x058,
+ MT_EE_TX0_5G_G0_TARGET_POWER = 0x070,
+ MT_EE_TX1_5G_G0_TARGET_POWER = 0x098,
+ MT_EE_TX2_5G_G0_TARGET_POWER = 0x142,
+ MT_EE_TX3_5G_G0_TARGET_POWER = 0x16a,
__MT_EE_MAX = 0x3bf
};
@@ -24,4 +29,34 @@ enum mt7615_eeprom_band {
MT_EE_DBDC,
};
+enum mt7615_channel_group {
+ MT_CH_5G_JAPAN,
+ MT_CH_5G_UNII_1,
+ MT_CH_5G_UNII_2A,
+ MT_CH_5G_UNII_2B,
+ MT_CH_5G_UNII_2E_1,
+ MT_CH_5G_UNII_2E_2,
+ MT_CH_5G_UNII_2E_3,
+ MT_CH_5G_UNII_3,
+ __MT_CH_MAX
+};
+
+static inline enum mt7615_channel_group
+mt7615_get_channel_group(int channel)
+{
+ if (channel >= 184 && channel <= 196)
+ return MT_CH_5G_JAPAN;
+ if (channel <= 48)
+ return MT_CH_5G_UNII_1;
+ if (channel <= 64)
+ return MT_CH_5G_UNII_2A;
+ if (channel <= 114)
+ return MT_CH_5G_UNII_2E_1;
+ if (channel <= 144)
+ return MT_CH_5G_UNII_2E_2;
+ if (channel <= 161)
+ return MT_CH_5G_UNII_2E_3;
+ return MT_CH_5G_UNII_3;
+}
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index b0bb7cc12385..72bdb871ca13 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -201,6 +201,9 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
mutex_unlock(&dev->mt76.mutex);
}
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ ret = mt7615_mcu_set_tx_power(dev);
+
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
mutex_lock(&dev->mt76.mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 43f70195244c..0e12e9f05f95 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -1151,6 +1151,70 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
&req, sizeof(req), true);
}
+int mt7615_mcu_set_tx_power(struct mt7615_dev *dev)
+{
+ int i, ret, n_chains = hweight8(dev->mt76.antenna_mask);
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+ u8 *req, *data, *eep = (u8 *)dev->mt76.eeprom.data;
+ struct ieee80211_hw *hw = mt76_hw(dev);
+ int freq = chandef->center_freq1, len;
+ struct {
+ u8 center_chan;
+ u8 dbdc_idx;
+ u8 band;
+ u8 rsv;
+ } __packed req_hdr = {
+ .center_chan = ieee80211_frequency_to_channel(freq),
+ .band = chandef->chan->band,
+ };
+ s8 tx_power;
+
+ len = sizeof(req_hdr) + __MT_EE_MAX - MT_EE_NIC_CONF_0;
+ req = kzalloc(len, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ memcpy(req, &req_hdr, sizeof(req_hdr));
+ data = req + sizeof(req_hdr);
+ memcpy(data, eep + MT_EE_NIC_CONF_0,
+ __MT_EE_MAX - MT_EE_NIC_CONF_0);
+
+ tx_power = hw->conf.power_level * 2;
+ switch (n_chains) {
+ case 4:
+ tx_power -= 12;
+ break;
+ case 3:
+ tx_power -= 8;
+ break;
+ case 2:
+ tx_power -= 6;
+ break;
+ default:
+ break;
+ }
+ tx_power = max_t(s8, tx_power, 0);
+ dev->mt76.txpower_cur = tx_power;
+
+ for (i = 0; i < n_chains; i++) {
+ int index = -MT_EE_NIC_CONF_0;
+
+ ret = mt7615_eeprom_get_power_index(chandef->chan, i);
+ if (ret < 0)
+ goto out;
+
+ index += ret;
+ data[index] = min_t(u8, data[index], tx_power);
+ }
+
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
+ req, len, true);
+out:
+ kfree(req);
+
+ return ret;
+}
+
int mt7615_mcu_set_channel(struct mt7615_dev *dev)
{
struct cfg80211_chan_def *chdef = &dev->mt76.chandef;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
index e96efb13fa4d..cca11737693c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
@@ -70,6 +70,7 @@ enum {
enum {
MCU_EXT_CMD_PM_STATE_CTRL = 0x07,
MCU_EXT_CMD_CHANNEL_SWITCH = 0x08,
+ MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11,
MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21,
MCU_EXT_CMD_STA_REC_UPDATE = 0x25,
MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 09c48dfbef3c..7c08d3b93a2a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -105,6 +105,8 @@ u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr);
int mt7615_register_device(struct mt7615_dev *dev);
void mt7615_unregister_device(struct mt7615_dev *dev);
int mt7615_eeprom_init(struct mt7615_dev *dev);
+int mt7615_eeprom_get_power_index(struct ieee80211_channel *chan,
+ u8 chain_idx);
int mt7615_dma_init(struct mt7615_dev *dev);
void mt7615_dma_cleanup(struct mt7615_dev *dev);
int mt7615_mcu_init(struct mt7615_dev *dev);
@@ -167,6 +169,7 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
int mt7615_mcu_init_mac(struct mt7615_dev *dev);
int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val);
int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter);
+int mt7615_mcu_set_tx_power(struct mt7615_dev *dev);
void mt7615_mcu_exit(struct mt7615_dev *dev);
int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
--
2.21.0
^ permalink raw reply related
* [PATCH 1/4] mt76: generalize mt76_get_txpower for 4x4:4 devices
From: Lorenzo Bianconi @ 2019-05-26 14:05 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, linux-wireless, ryder.lee, royluo
In-Reply-To: <cover.1558879234.git.lorenzo@kernel.org>
Genralize mt76_get_txpower routine for 4x4:4 capable devices
in order to be reused in mt7615 driver
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index e70507a4b14d..f9e83971902e 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -766,10 +766,21 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
*dbm = DIV_ROUND_UP(dev->txpower_cur, 2);
/* convert from per-chain power to combined
- * output on 2x2 devices
+ * output power
*/
- if (n_chains > 1)
+ switch (n_chains) {
+ case 4:
+ *dbm += 6;
+ break;
+ case 3:
+ *dbm += 4;
+ break;
+ case 2:
*dbm += 3;
+ break;
+ default:
+ break;
+ }
return 0;
}
--
2.21.0
^ permalink raw reply related
* [PATCH 0/4] add tx power configuration support to mt7615 driver
From: Lorenzo Bianconi @ 2019-05-26 14:05 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, linux-wireless, ryder.lee, royluo
Cap tx power according to the value configured by the user.
Initialize get_txpower mac80211 callback in order to report the
configured tx power to mac80211
Lorenzo Bianconi (4):
mt76: generalize mt76_get_txpower for 4x4:4 devices
mt76: mt7615: add the capability to configure tx power
mt76: mt7615: init get_txpower mac80211 callback
mt76: mt7615: rearrange locking in mt7615_config
drivers/net/wireless/mediatek/mt76/mac80211.c | 15 ++++-
.../wireless/mediatek/mt76/mt7615/eeprom.c | 34 ++++++++++
.../wireless/mediatek/mt76/mt7615/eeprom.h | 35 ++++++++++
.../net/wireless/mediatek/mt76/mt7615/main.c | 17 ++---
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 64 +++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7615/mcu.h | 1 +
.../wireless/mediatek/mt76/mt7615/mt7615.h | 3 +
7 files changed, 159 insertions(+), 10 deletions(-)
--
2.21.0
^ permalink raw reply
* Issue with Broadcom wireless in 5.2rc1 (was Re: [PATCH] mmc: sdhci: queue work after sdhci_defer_done())
From: Brian Masney @ 2019-05-26 12:21 UTC (permalink / raw)
To: Adrian Hunter, Arend van Spriel, Franky Lin, Hante Meuleman,
Chi-Hsien Lin, Wright Feng
Cc: 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: <20190524154958.GB16322@basecamp>
+ 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.
When the brcmfmac driver is loaded, the firmware is requested from disk,
and that's when the deadlock occurs in 5.2rc1. Specifically:
1) brcmf_sdio_download_firmware() in
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c calls
sdio_claim_host()
2) brcmf_sdio_firmware_callback() is called and brcmf_sdiod_ramrw()
tries to claim the host, but has to wait since its already claimed
in #1 and the deadlock occurs.
I tried to release the host before the firmware is requested, however
parts of brcmf_chip_set_active() needs the host to be claimed, and a
similar deadlock occurs in brcmf_sdiod_ramrw() if I claim the host
before calling brcmf_chip_set_active().
I started to look at moving the sdio_{claim,release}_host() calls out of
brcmf_sdiod_ramrw() but there's a fair number of callers, so I'd like to
get feedback about the best course of action here.
Brian
^ permalink raw reply
* [PATCH] iwlwifi: fix warning iwl-trans.h is included more than once
From: Hariprasad Kelam @ 2019-05-26 11:38 UTC (permalink / raw)
To: Johannes Berg, Emmanuel Grumbach, Luca Coelho,
Intel Linux Wireless, Kalle Valo, David S. Miller, linux-wireless,
netdev, linux-kernel
remove duplication include of iwl-trans.h
issue identified by includecheck
Signed-off-by: Hariprasad Kelam <hariprasad.kelam@gmail.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
index fc649b2..f5a56c5 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
@@ -86,7 +86,6 @@ static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans,
#include <linux/tracepoint.h>
#include <linux/device.h>
-#include "iwl-trans.h"
#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
--
2.7.4
^ permalink raw reply related
* [PATCH] rtlwifi: btcoex: remove unused function exhalbtc_stack_operation_notify
From: YueHaibing @ 2019-05-25 14:48 UTC (permalink / raw)
To: pkshih, kvalo, davem; +Cc: linux-kernel, netdev, linux-wireless, YueHaibing
There is no callers in tree, so can be removed.
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
.../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 24 -------------------
.../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 -
2 files changed, 25 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
index 041326e6dd2f..152242ac0aa5 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -1741,30 +1741,6 @@ void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type)
}
}
-void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
-{
- u8 stack_op_type;
-
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
- btcoexist->statistics.cnt_stack_operation_notify++;
- if (btcoexist->manual_control)
- return;
-
- if ((type == HCI_BT_OP_INQUIRY_START) ||
- (type == HCI_BT_OP_PAGING_START) ||
- (type == HCI_BT_OP_PAIRING_START)) {
- stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_START;
- } else if ((type == HCI_BT_OP_INQUIRY_FINISH) ||
- (type == HCI_BT_OP_PAGING_SUCCESS) ||
- (type == HCI_BT_OP_PAGING_UNSUCCESS) ||
- (type == HCI_BT_OP_PAIRING_FINISH)) {
- stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_FINISH;
- } else {
- stack_op_type = BTC_STACK_OP_NONE;
- }
-}
-
void exhalbtc_halt_notify(struct btc_coexist *btcoexist)
{
if (!halbtc_is_bt_coexist_available(btcoexist))
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
index ee9aeddf1ebc..8c0a7fdbf200 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -764,7 +764,6 @@ void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
u8 length);
void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type);
-void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
--
2.17.1
^ permalink raw reply related
* [PATCH] rtlwifi: btcoex: Remove set but not used variable 'len' and 'asso_type_v2'
From: YueHaibing @ 2019-05-25 14:46 UTC (permalink / raw)
To: pkshih, kvalo, davem; +Cc: linux-kernel, netdev, linux-wireless, YueHaibing
Fixes gcc '-Wunused-but-set-variable' warning:
drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c: In function rtl_btc_btmpinfo_notify:
drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c:319:17: warning: variable len set but not used [-Wunused-but-set-variable]
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c: In function exhalbtc_connect_notify:
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c:1581:16: warning: variable asso_type_v2 set but not used [-Wunused-but-set-variable]
'len' is never used since commit 6aad6075ccd5 ("rtlwifi:
Add BT_MP_INFO to c2h handler.") so can be removed.
'asso_type_v2' is not used since introduction in
commit 0843e98a3b9a ("rtlwifi: btcoex: add assoc
type v2 to connection notify")
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
.../wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 11 +++--------
.../net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 3 +--
2 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
index 2ac0481b29ef..041326e6dd2f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -1578,7 +1578,7 @@ void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg,
void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
{
- u8 asso_type, asso_type_v2;
+ u8 asso_type;
bool wifi_under_5g;
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -1589,15 +1589,10 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
- if (action) {
+ if (action)
asso_type = BTC_ASSOCIATE_START;
- asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_START :
- BTC_ASSOCIATE_START;
- } else {
+ else
asso_type = BTC_ASSOCIATE_FINISH;
- asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_FINISH :
- BTC_ASSOCIATE_FINISH;
- }
halbtc_leave_low_power(btcoexist);
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
index 0e509c33e9e6..b8c4536af6c0 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
@@ -316,7 +316,7 @@ void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
{
struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
- u8 extid, seq, len;
+ u8 extid, seq;
u16 bt_real_fw_ver;
u8 bt_fw_ver;
u8 *data;
@@ -332,7 +332,6 @@ void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
if (extid != 1) /* C2H_TRIG_BY_BT_FW = 1 */
return;
- len = tmp_buf[1] >> 4;
seq = tmp_buf[2] >> 4;
data = &tmp_buf[3];
--
2.17.1
^ permalink raw reply related
* [PATCH] rtlwifi: rtl8821ae: Remove set but not used variables 'cur_txokcnt' and 'b_last_is_cur_rdl_state'
From: YueHaibing @ 2019-05-25 14:43 UTC (permalink / raw)
To: pkshih, kvalo, davem; +Cc: linux-kernel, netdev, linux-wireless, YueHaibing
Fixes gcc '-Wunused-but-set-variable' warning:
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c: In function rtl8821ae_dm_check_rssi_monitor:
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c:658:6: warning: variable cur_txokcnt set but not used [-Wunused-but-set-variable]
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c: In function rtl8821ae_dm_check_edca_turbo:
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c:2657:7: warning: variable b_last_is_cur_rdl_state set but not used [-Wunused-but-set-variable]
They are never used so can be removed.
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
index 49d05b631ba1..84b30464964d 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
@@ -655,10 +655,9 @@ static void rtl8821ae_dm_check_rssi_monitor(struct ieee80211_hw *hw)
u8 h2c_parameter[4] = { 0 };
long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
u8 stbc_tx = 0;
- u64 cur_txokcnt = 0, cur_rxokcnt = 0;
+ u64 cur_rxokcnt = 0;
static u64 last_txokcnt = 0, last_rxokcnt;
- cur_txokcnt = rtlpriv->stats.txbytesunicast - last_txokcnt;
cur_rxokcnt = rtlpriv->stats.rxbytesunicast - last_rxokcnt;
last_txokcnt = rtlpriv->stats.txbytesunicast;
last_rxokcnt = rtlpriv->stats.rxbytesunicast;
@@ -2654,7 +2653,6 @@ static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
u32 edca_be = 0x5ea42b;
u8 iot_peer = 0;
bool *pb_is_cur_rdl_state = NULL;
- bool b_last_is_cur_rdl_state = false;
bool b_bias_on_rx = false;
bool b_edca_turbo_on = false;
@@ -2672,7 +2670,6 @@ static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
* list paramter for different platform
*===============================
*/
- b_last_is_cur_rdl_state = rtlpriv->dm.is_cur_rdlstate;
pb_is_cur_rdl_state = &rtlpriv->dm.is_cur_rdlstate;
cur_tx_ok_cnt = rtlpriv->stats.txbytesunicast - rtldm->last_tx_ok_cnt;
--
2.17.1
^ permalink raw reply related
* [PATCH] netlink: fix station_info pertid memory leak
From: Andy Strohman @ 2019-05-25 6:27 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Andy Strohman
When dumping stations, memory allocated for station_info's
pertid member will leak if the nl80211 header cannot be added to
the sk_buff due to insufficient tail room.
I noticed this leak in the kmalloc-2048 cache.
Fixes: 8689c051a201 ("cfg80211: dynamically allocate per-tid stats for station info")
Signed-off-by: Andy Strohman <andy@uplevelsystems.com>
---
net/wireless/nl80211.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fffe4b371e23..a82ecfe14d8d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4855,8 +4855,10 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
struct nlattr *sinfoattr, *bss_param;
hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
- if (!hdr)
+ if (!hdr) {
+ cfg80211_sinfo_release_content(sinfo);
return -1;
+ }
if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
--
2.17.1
^ permalink raw reply related
* [PATCH v2] mac80211: mesh: fix RCU warning
From: Thomas Pedersen @ 2019-05-25 4:16 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Thomas Pedersen
ifmsh->csa is an RCU-protected pointer. The writer context
in ieee80211_mesh_finish_csa() is already mutually
exclusive with wdev->sdata.mtx, but the RCU checker did
not know this. Use rcu_dereference_protected() to avoid a
warning.
fixes the following warning:
[ 12.519089] =============================
[ 12.520042] WARNING: suspicious RCU usage
[ 12.520652] 5.1.0-rc7-wt+ #16 Tainted: G W
[ 12.521409] -----------------------------
[ 12.521972] net/mac80211/mesh.c:1223 suspicious rcu_dereference_check() usage!
[ 12.522928] other info that might help us debug this:
[ 12.523984] rcu_scheduler_active = 2, debug_locks = 1
[ 12.524855] 5 locks held by kworker/u8:2/152:
[ 12.525438] #0: 00000000057be08c ((wq_completion)phy0){+.+.}, at: process_one_work+0x1a2/0x620
[ 12.526607] #1: 0000000059c6b07a ((work_completion)(&sdata->csa_finalize_work)){+.+.}, at: process_one_work+0x1a2/0x620
[ 12.528001] #2: 00000000f184ba7d (&wdev->mtx){+.+.}, at: ieee80211_csa_finalize_work+0x2f/0x90
[ 12.529116] #3: 00000000831a1f54 (&local->mtx){+.+.}, at: ieee80211_csa_finalize_work+0x47/0x90
[ 12.530233] #4: 00000000fd06f988 (&local->chanctx_mtx){+.+.}, at: ieee80211_csa_finalize_work+0x51/0x90
Signed-off-by: Thomas Pedersen <thomas@eero.com>
---
v2: rcu_read_lock() doesn't make sense. Use rcu_dereference_protected() (Johannes)
---
net/mac80211/mesh.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 766e5e5..d5aba50 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1220,7 +1220,8 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
ifmsh->chsw_ttl = 0;
/* Remove the CSA and MCSP elements from the beacon */
- tmp_csa_settings = rcu_dereference(ifmsh->csa);
+ tmp_csa_settings = rcu_dereference_protected(ifmsh->csa,
+ lockdep_is_held(&sdata->wdev.mtx));
RCU_INIT_POINTER(ifmsh->csa, NULL);
if (tmp_csa_settings)
kfree_rcu(tmp_csa_settings, rcu_head);
@@ -1242,6 +1243,8 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct mesh_csa_settings *tmp_csa_settings;
int ret = 0;
+ lockdep_assert_held(&sdata->wdev.mtx);
+
tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
GFP_ATOMIC);
if (!tmp_csa_settings)
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] mac80211: mesh: fix RCU warning
From: Thomas Pedersen @ 2019-05-25 3:46 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Peter Oh
In-Reply-To: <6e162d98ba05a71577c623fe1e8e06a7051eb01c.camel@sipsolutions.net>
On Fri, May 24, 2019 at 1:29 AM Johannes Berg <johannes@sipsolutions.net> wrote:
>
> On Wed, 2019-05-15 at 15:21 -0700, Thomas Pedersen wrote:
> > ifmsh->csa was being dereferenced without the RCU read
> > lock held.
>
> > +++ b/net/mac80211/mesh.c
> > @@ -1220,10 +1220,12 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
> > ifmsh->chsw_ttl = 0;
> >
> > /* Remove the CSA and MCSP elements from the beacon */
> > + rcu_read_lock();
> > tmp_csa_settings = rcu_dereference(ifmsh->csa);
> > RCU_INIT_POINTER(ifmsh->csa, NULL);
> > if (tmp_csa_settings)
> > kfree_rcu(tmp_csa_settings, rcu_head);
> > + rcu_read_unlock();
>
> This seems wrong to me.
>
> Really this code is the *writer* side, so you should do something like
> this:
Thanks this looks correct. I should've thought about this a tiny bit more ;)
> diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
> index 766e5e5bab8a..d578147ad7e8 100644
> --- a/net/mac80211/mesh.c
> +++ b/net/mac80211/mesh.c
> @@ -1220,7 +1220,8 @@ int ieee80211_mesh_finish_csa(struct
> ieee80211_sub_if_data *sdata)
> ifmsh->chsw_ttl = 0;
>
> /* Remove the CSA and MCSP elements from the beacon */
> - tmp_csa_settings = rcu_dereference(ifmsh->csa);
> + tmp_csa_settings = rcu_dereference_protected(ifmsh->csa,
> + lockdep_is_held(&sdata->wdev.mtx));
> RCU_INIT_POINTER(ifmsh->csa, NULL);
> if (tmp_csa_settings)
> kfree_rcu(tmp_csa_settings, rcu_head);
> @@ -1242,6 +1243,8 @@ int ieee80211_mesh_csa_beacon(struct
> ieee80211_sub_if_data *sdata,
> struct mesh_csa_settings *tmp_csa_settings;
> int ret = 0;
>
> + lockdep_assert_held(&sdata->wdev.mtx);
> +
> tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
> GFP_ATOMIC);
> if (!tmp_csa_settings)
>
>
> Can you test that and send a proper patch?
>
> johannes
>
--
thomas
^ permalink raw reply
* [PATCH] p54: Support boottime in scan results
From: Christian Lamparter @ 2019-05-24 21:33 UTC (permalink / raw)
To: linux-wireless; +Cc: Kalle Valo
This patch fixes an issue with wpa_supplicant dropping all scan
results because their where considered to be "too old" (e.g.:
"skip - scan result not recent enough (121056.086325 seconds too old)")
which is very weird because this looks like that the scan results have
been received before a scan started. This is due to the inaccuracy of
the default timing mechanism for calculating the BSS entry age.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
drivers/net/wireless/intersil/p54/txrx.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c
index 5bf1c19ecced..f80c5056ccb7 100644
--- a/drivers/net/wireless/intersil/p54/txrx.c
+++ b/drivers/net/wireless/intersil/p54/txrx.c
@@ -334,6 +334,7 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
u16 freq = le16_to_cpu(hdr->freq);
size_t header_len = sizeof(*hdr);
u32 tsf32;
+ __le16 fc;
u8 rate = hdr->rate & 0xf;
/*
@@ -382,6 +383,11 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
skb_pull(skb, header_len);
skb_trim(skb, le16_to_cpu(hdr->len));
+
+ fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
+ if (ieee80211_is_probe_resp(fc) || ieee80211_is_beacon(fc))
+ rx_status->boottime_ns = ktime_get_boot_ns();
+
if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
p54_pspoll_workaround(priv, skb);
--
2.20.1
^ permalink raw reply related
* Re: [PATCH] network: wireless: p54u: Fix race between disconnect and firmware loading
From: Christian Lamparter @ 2019-05-24 21:19 UTC (permalink / raw)
To: Alan Stern
Cc: syzbot, kvalo, davem, andreyknvl, syzkaller-bugs,
Kernel development list, USB list, linux-wireless, netdev
In-Reply-To: <Pine.LNX.4.44L0.1905201042110.1498-100000@iolanthe.rowland.org>
On Monday, May 20, 2019 4:44:21 PM CEST Alan Stern wrote:
> The syzbot fuzzer found a bug in the p54 USB wireless driver. The
> issue involves a race between disconnect and the firmware-loader
> callback routine, and it has several aspects.
>
> One big problem is that when the firmware can't be loaded, the
> callback routine tries to unbind the driver from the USB _device_ (by
> calling device_release_driver) instead of from the USB _interface_ to
> which it is actually bound (by calling usb_driver_release_interface).
>
> The race involves access to the private data structure. The driver's
> disconnect handler waits for a completion that is signalled by the
> firmware-loader callback routine. As soon as the completion is
> signalled, you have to assume that the private data structure may have
> been deallocated by the disconnect handler -- even if the firmware was
> loaded without errors. However, the callback routine does access the
> private data several times after that point.
>
> Another problem is that, in order to ensure that the USB device
> structure hasn't been freed when the callback routine runs, the driver
> takes a reference to it. This isn't good enough any more, because now
> that the callback routine calls usb_driver_release_interface, it has
> to ensure that the interface structure hasn't been freed.
>
> Finally, the driver takes an unnecessary reference to the USB device
> structure in the probe function and drops the reference in the
> disconnect handler. This extra reference doesn't accomplish anything,
> because the USB core already guarantees that a device structure won't
> be deallocated while a driver is still bound to any of its interfaces.
>
> To fix these problems, this patch makes the following changes:
>
> Call usb_driver_release_interface() rather than
> device_release_driver().
>
> Don't signal the completion until after the important
> information has been copied out of the private data structure,
> and don't refer to the private data at all thereafter.
>
> Lock udev (the interface's parent) before unbinding the driver
> instead of locking udev->parent.
>
> During the firmware loading process, take a reference to the
> USB interface instead of the USB device.
>
> Don't take an unnecessary reference to the device during probe
> (and then don't drop it during disconnect).
>
> Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
> Reported-and-tested-by: syzbot+200d4bb11b23d929335f@syzkaller.appspotmail.com
> CC: <stable@vger.kernel.org>
Finally I'm at home where I have the device. Did some test with replugging
and module unloading, all seems fine. Thanks!
Acked-by: Christian Lamparter <chunkeey@gmail.com>
^ permalink raw reply
* Re: [RFC 0/8] nl80211: add 6GHz band support
From: Arend Van Spriel @ 2019-05-24 18:38 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <df53f969297fea1f3c8101cd2c1571a957985d2a.camel@sipsolutions.net>
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?
Agree that most functional requirements for 6 GHz are same as 5 GHz. There
are some 6 GHz specifics about beaconing as well.
> The channel numbers problem came up, of course, but for nl80211 it's not
> that relevant since we deal with frequencies only, and we thought inside
> the kernel it'd be better to disambiguate them with operating classes,
> where needed - only few places really deal with channel numbers to start
> with.
>
> Do you have any reason to think that it's better as a separate band enum
No specific reason. Just that the few cfg80211-based drivers tend to use
channel number as hwvalue.
> (which I notice you put before 60 GHz thus breaking the API/ABI :P)?
Right. Now I feel wet behind the ears :-p
I will go with 6G being additional 5G range and see how that works for us.
Gr. AvS
^ permalink raw reply
* Re: [RFC 0/8] nl80211: add 6GHz band support
From: Johannes Berg @ 2019-05-24 11:56 UTC (permalink / raw)
To: Arend van Spriel; +Cc: linux-wireless
In-Reply-To: <1558353645-18119-1-git-send-email-arend.vanspriel@broadcom.com>
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.
The channel numbers problem came up, of course, but for nl80211 it's not
that relevant since we deal with frequencies only, and we thought inside
the kernel it'd be better to disambiguate them with operating classes,
where needed - only few places really deal with channel numbers to start
with.
Do you have any reason to think that it's better as a separate band enum
(which I notice you put before 60 GHz thus breaking the API/ABI :P)?
Thanks,
johannes
^ permalink raw reply
* Re: [PATCH v2] wlcore: sdio: Fix a memory leaking bug in wl1271_probe()
From: Jon Hunter @ 2019-05-24 9:28 UTC (permalink / raw)
To: Gen Zhang, Kalle Valo; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20190524024307.GA5639@zhanggen-UX430UQ>
On 24/05/2019 03:43, Gen Zhang wrote:
> In wl1271_probe(), 'glue->core' is allocated by platform_device_alloc(),
> when this allocation fails, ENOMEM is returned. However, 'pdev_data'
> and 'glue' are allocated by devm_kzalloc() before 'glue->core'. When
> platform_device_alloc() returns NULL, we should also free 'pdev_data'
> and 'glue' before wl1271_probe() ends to prevent leaking memory.
No, devm_kzalloc() automatically frees memory on failure.
> Similarly, we should free 'pdev_data' when 'glue' is NULL. And we
> should free 'pdev_data' and 'glue' when 'ret' is error.
>
> Further, we shoulf free 'glue->dev', 'pdev_data' and 'glue' when this
> function normally ends to prevent memory leaking.
Why?
> Signed-off-by: Gen Zhang <blackgod016574@gmail.com>
> ---
> diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
> index 4d4b0770..9110891 100644
> --- a/drivers/net/wireless/ti/wlcore/sdio.c
> +++ b/drivers/net/wireless/ti/wlcore/sdio.c
> @@ -298,8 +298,10 @@ static int wl1271_probe(struct sdio_func *func,
> pdev_data->if_ops = &sdio_ops;
>
> glue = devm_kzalloc(&func->dev, sizeof(*glue), GFP_KERNEL);
> - if (!glue)
> - return -ENOMEM;
> + if (!glue) {
> + ret = -ENOMEM;
> + goto out_free1;
> + }
>
> glue->dev = &func->dev;
>
> @@ -311,7 +313,7 @@ static int wl1271_probe(struct sdio_func *func,
>
> ret = wlcore_probe_of(&func->dev, &irq, &wakeirq, pdev_data);
> if (ret)
> - goto out;
> + goto out_free2;
>
> /* if sdio can keep power while host is suspended, enable wow */
> mmcflags = sdio_get_host_pm_caps(func);
> @@ -340,7 +342,7 @@ static int wl1271_probe(struct sdio_func *func,
> if (!glue->core) {
> dev_err(glue->dev, "can't allocate platform_device");
> ret = -ENOMEM;
> - goto out;
> + goto out_free2;
> }
>
> glue->core->dev.parent = &func->dev;
> @@ -380,12 +382,17 @@ static int wl1271_probe(struct sdio_func *func,
> dev_err(glue->dev, "can't add platform device\n");
> goto out_dev_put;
> }
> - return 0;
> + ret = 0;
This is completely wrong.
> out_dev_put:
> platform_device_put(glue->core);
>
> -out:
> +out_free2:
> + devm_kfree(&func->dev, glue);
> +
> +out_free1:
> + devm_kfree(&func->dev, pdev_data);
> +
> return ret;
> }
>
> ---
Jon
--
nvpublic
^ permalink raw reply
* Re: [PATCH] mac80211: mesh: fix RCU warning
From: Johannes Berg @ 2019-05-24 8:29 UTC (permalink / raw)
To: Thomas Pedersen, linux-wireless; +Cc: peter.oh
In-Reply-To: <1557958906-1432-1-git-send-email-thomas@eero.com>
On Wed, 2019-05-15 at 15:21 -0700, Thomas Pedersen wrote:
> ifmsh->csa was being dereferenced without the RCU read
> lock held.
> +++ b/net/mac80211/mesh.c
> @@ -1220,10 +1220,12 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
> ifmsh->chsw_ttl = 0;
>
> /* Remove the CSA and MCSP elements from the beacon */
> + rcu_read_lock();
> tmp_csa_settings = rcu_dereference(ifmsh->csa);
> RCU_INIT_POINTER(ifmsh->csa, NULL);
> if (tmp_csa_settings)
> kfree_rcu(tmp_csa_settings, rcu_head);
> + rcu_read_unlock();
This seems wrong to me.
Really this code is the *writer* side, so you should do something like
this:
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 766e5e5bab8a..d578147ad7e8 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1220,7 +1220,8 @@ int ieee80211_mesh_finish_csa(struct
ieee80211_sub_if_data *sdata)
ifmsh->chsw_ttl = 0;
/* Remove the CSA and MCSP elements from the beacon */
- tmp_csa_settings = rcu_dereference(ifmsh->csa);
+ tmp_csa_settings = rcu_dereference_protected(ifmsh->csa,
+ lockdep_is_held(&sdata->wdev.mtx));
RCU_INIT_POINTER(ifmsh->csa, NULL);
if (tmp_csa_settings)
kfree_rcu(tmp_csa_settings, rcu_head);
@@ -1242,6 +1243,8 @@ int ieee80211_mesh_csa_beacon(struct
ieee80211_sub_if_data *sdata,
struct mesh_csa_settings *tmp_csa_settings;
int ret = 0;
+ lockdep_assert_held(&sdata->wdev.mtx);
+
tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
GFP_ATOMIC);
if (!tmp_csa_settings)
Can you test that and send a proper patch?
johannes
^ permalink raw reply related
* [PATCH v2] ath10k: fix fw crash by moving chip reset after napi disabled
From: Miaoqing Pan @ 2019-05-24 3:16 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Miaoqing Pan
On SMP platform, when continuously running wifi up/down, the napi
poll can be scheduled during chip reset, which will call
ath10k_pci_has_fw_crashed() to check the fw status. But in the reset
period, the value from FW_INDICATOR_ADDRESS register will return
0xdeadbeef, which also be treated as fw crash. Fix the issue by
moving chip reset after napi disabled.
ath10k_pci 0000:01:00.0: firmware crashed! (guid 73b30611-5b1e-4bdd-90b4-64c81eb947b6)
ath10k_pci 0000:01:00.0: qca9984/qca9994 hw1.0 target 0x01000000 chip_id 0x00000000 sub 168c:cafe
ath10k_pci 0000:01:00.0: htt-ver 2.2 wmi-op 6 htt-op 4 cal otp max-sta 512 raw 0 hwcrypto 1
ath10k_pci 0000:01:00.0: failed to get memcpy hi address for firmware address 4: -16
ath10k_pci 0000:01:00.0: failed to read firmware dump area: -16
ath10k_pci 0000:01:00.0: Copy Engine register dump:
ath10k_pci 0000:01:00.0: [00]: 0x0004a000 0 0 0 0
ath10k_pci 0000:01:00.0: [01]: 0x0004a400 0 0 0 0
ath10k_pci 0000:01:00.0: [02]: 0x0004a800 0 0 0 0
ath10k_pci 0000:01:00.0: [03]: 0x0004ac00 0 0 0 0
ath10k_pci 0000:01:00.0: [04]: 0x0004b000 0 0 0 0
ath10k_pci 0000:01:00.0: [05]: 0x0004b400 0 0 0 0
ath10k_pci 0000:01:00.0: [06]: 0x0004b800 0 0 0 0
ath10k_pci 0000:01:00.0: [07]: 0x0004bc00 1 0 1 0
ath10k_pci 0000:01:00.0: [08]: 0x0004c000 0 0 0 0
ath10k_pci 0000:01:00.0: [09]: 0x0004c400 0 0 0 0
ath10k_pci 0000:01:00.0: [10]: 0x0004c800 0 0 0 0
ath10k_pci 0000:01:00.0: [11]: 0x0004cc00 0 0 0 0
Tested HW: QCA9984,QCA9887,WCN3990
Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
---
Changes since v1:
- update commit message
---
drivers/net/wireless/ath/ath10k/pci.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 2bd6cba..80bcb2e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2059,6 +2059,11 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
+ ath10k_pci_irq_disable(ar);
+ ath10k_pci_irq_sync(ar);
+ napi_synchronize(&ar->napi);
+ napi_disable(&ar->napi);
+
/* Most likely the device has HTT Rx ring configured. The only way to
* prevent the device from accessing (and possible corrupting) host
* memory is to reset the chip now.
@@ -2072,10 +2077,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
*/
ath10k_pci_safe_chip_reset(ar);
- ath10k_pci_irq_disable(ar);
- ath10k_pci_irq_sync(ar);
- napi_synchronize(&ar->napi);
- napi_disable(&ar->napi);
ath10k_pci_flush(ar);
spin_lock_irqsave(&ar_pci->ps_lock, flags);
--
1.9.1
^ permalink raw reply related
* [PATCH] wlcore: spi: Fix a memory leaking bug in wl1271_probe()
From: Gen Zhang @ 2019-05-24 3:02 UTC (permalink / raw)
To: kvalo, davem; +Cc: linux-wireless, netdev, linux-kernel
In wl1271_probe(), 'glue->core' is allocated by platform_device_alloc(),
when this allocation fails, ENOMEM is returned. However, 'pdev_data'
and 'glue' are allocated by devm_kzalloc() before 'glue->core'. When
platform_device_alloc() returns NULL, we should also free 'pdev_data'
and 'glue' before wl1271_probe() ends to prevent leaking memory.
Similarly, we shoulf free 'pdev_data' when 'glue' is NULL. And we should
free 'pdev_data' and 'glue' when 'glue->reg' is error and when 'ret' is
error.
Further, we should free 'glue->core', 'pdev_data' and 'glue' when this
function normally ends to prevent leaking memory.
Signed-off-by: Gen Zhang <blackgod016574@gmail.com>
---
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index 62ce54a..ea0ec26 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -480,7 +480,7 @@ static int wl1271_probe(struct spi_device *spi)
struct wl12xx_spi_glue *glue;
struct wlcore_platdev_data *pdev_data;
struct resource res[1];
- int ret;
+ int ret = -ENOMEM;
pdev_data = devm_kzalloc(&spi->dev, sizeof(*pdev_data), GFP_KERNEL);
if (!pdev_data)
@@ -491,7 +491,8 @@ static int wl1271_probe(struct spi_device *spi)
glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&spi->dev, "can't allocate glue\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_free1;
}
glue->dev = &spi->dev;
@@ -503,31 +504,35 @@ static int wl1271_probe(struct spi_device *spi)
spi->bits_per_word = 32;
glue->reg = devm_regulator_get(&spi->dev, "vwlan");
- if (PTR_ERR(glue->reg) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ if (PTR_ERR(glue->reg) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto out_free2;
+ }
if (IS_ERR(glue->reg)) {
dev_err(glue->dev, "can't get regulator\n");
- return PTR_ERR(glue->reg);
+ ret = PTR_ERR(glue->reg);
+ goto out_free2;
}
ret = wlcore_probe_of(spi, glue, pdev_data);
if (ret) {
dev_err(glue->dev,
"can't get device tree parameters (%d)\n", ret);
- return ret;
+ goto out_free2;
}
ret = spi_setup(spi);
if (ret < 0) {
dev_err(glue->dev, "spi_setup failed\n");
- return ret;
+ goto out_free2;
}
glue->core = platform_device_alloc(pdev_data->family->name,
PLATFORM_DEVID_AUTO);
if (!glue->core) {
dev_err(glue->dev, "can't allocate platform_device\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_free2;
}
glue->core->dev.parent = &spi->dev;
@@ -557,10 +562,14 @@ static int wl1271_probe(struct spi_device *spi)
goto out_dev_put;
}
- return 0;
+ ret = 0;
out_dev_put:
platform_device_put(glue->core);
+out_free2:
+ devm_kfree(&func->dev, glue);
+out_free1:
+ devm_kfree(&func->dev, pdev_data);
return ret;
}
---
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox