2019-04-17 19:15:28

by Erik Stromdahl

[permalink] [raw]
Subject: [PATCH v2 0/5] ath10k: SDIO and high latency patches from Silex

This series adds a few more fixes for SDIO and high latency devices.

I have had these on my private tree for quite some time now so they
should be considered fairly well tested.

changes since v1:

Patch "ath10k: use clean packet headers" was renamed to
"ath10k: add initialization of HTC header" and PLL stuff was removed.

Patch "ath10k: sdio: add MSDU ID allocation in HTT TX path"
was removed since it became redundant after I had added Kalle's and
Wen's patches to my tree.

Patch "ath10k: sdio: replace skb_trim with explicit set of skb->len"
was rewritten and renamed to "ath10k: sdio: remove skb_trim in TX path"

Alagu Sankar (3):
ath10k: add initialization of HTC header
ath10k: high latency fixes for beacon buffer
ath10k: sdio: read RX packets in bundles

Erik Stromdahl (2):
ath10k: sdio: add missing error check
ath10k: sdio: remove skb_trim in TX path

drivers/net/wireless/ath/ath10k/htc.c | 1 +
drivers/net/wireless/ath/ath10k/mac.c | 31 ++++++--
drivers/net/wireless/ath/ath10k/sdio.c | 103 ++++++++++++++++++++-----
drivers/net/wireless/ath/ath10k/sdio.h | 4 +
4 files changed, 112 insertions(+), 27 deletions(-)

--
2.19.1



2019-04-17 19:15:31

by Erik Stromdahl

[permalink] [raw]
Subject: [PATCH v2 2/5] ath10k: high latency fixes for beacon buffer

From: Alagu Sankar <[email protected]>

Beacon buffer for high latency devices does not use DMA. other similar
buffer allocation methods in the driver have already been modified for
high latency path. Fix the beacon buffer allocation left out in the
earlier high latency changes.

Signed-off-by: Alagu Sankar <[email protected]>
Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 31 ++++++++++++++++++++-------
1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index c9e700b844f8..2dd99ce44453 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -953,8 +953,12 @@ static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
ath10k_mac_vif_beacon_free(arvif);

if (arvif->beacon_buf) {
- dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- arvif->beacon_buf, arvif->beacon_paddr);
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ kfree(arvif->beacon_buf);
+ else
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf,
+ arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}
}
@@ -5210,10 +5214,17 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
vif->type == NL80211_IFTYPE_AP) {
- arvif->beacon_buf = dma_alloc_coherent(ar->dev,
- IEEE80211_MAX_FRAME_LEN,
- &arvif->beacon_paddr,
- GFP_ATOMIC);
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL) {
+ arvif->beacon_buf = kmalloc(IEEE80211_MAX_FRAME_LEN,
+ GFP_KERNEL);
+ arvif->beacon_paddr = (dma_addr_t)arvif->beacon_buf;
+ } else {
+ arvif->beacon_buf =
+ dma_alloc_coherent(ar->dev,
+ IEEE80211_MAX_FRAME_LEN,
+ &arvif->beacon_paddr,
+ GFP_ATOMIC);
+ }
if (!arvif->beacon_buf) {
ret = -ENOMEM;
ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
@@ -5424,8 +5435,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,

err:
if (arvif->beacon_buf) {
- dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- arvif->beacon_buf, arvif->beacon_paddr);
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ kfree(arvif->beacon_buf);
+ else
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf,
+ arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}

--
2.19.1


2019-04-17 19:15:31

by Erik Stromdahl

[permalink] [raw]
Subject: [PATCH v2 1/5] ath10k: add initialization of HTC header

From: Alagu Sankar <[email protected]>

HTC header carries junk values that may be interpreted by the firmware
differently. Enable credit update only if flow control is enabled for
the corresponding endpoint.

Signed-off-by: Alagu Sankar <[email protected]>
Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/htc.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 805a7f8a04f2..1d4d1a1992fe 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -73,6 +73,7 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
struct ath10k_htc_hdr *hdr;

hdr = (struct ath10k_htc_hdr *)skb->data;
+ memset(hdr, 0, sizeof(struct ath10k_htc_hdr));

hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
--
2.19.1


2019-04-17 19:15:34

by Erik Stromdahl

[permalink] [raw]
Subject: [PATCH v2 4/5] ath10k: sdio: add missing error check

Although not likely, the bundle allocation might fail.
Add proper error check and warning print.

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/sdio.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index b89732aad97c..b8b3059721ee 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -586,6 +586,11 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
act_len,
&bndl_cnt);

+ if (ret) {
+ ath10k_warn(ar, "alloc_bundle error %d\n", ret);
+ goto err;
+ }
+
n_lookaheads += bndl_cnt;
i += bndl_cnt;
/*Next buffer will be the last in the bundle */
--
2.19.1


2019-04-17 19:15:33

by Erik Stromdahl

[permalink] [raw]
Subject: [PATCH v2 3/5] ath10k: sdio: read RX packets in bundles

From: Alagu Sankar <[email protected]>

The existing implementation of initiating multiple sdio transfers for
receive bundling is slowing down the receive speed.

Instead of having one sdio transfer for each packet in the bundle, we
read all packets in one sdio transfer.

This results in significant performance improvement on some targets.

On an imx6dl together with a QCA9377 SDIO device, the following
performance increase was obtained with iperf:

Before:

[ 3] 0.0- 1.0 sec 3.38 MBytes 28.3 Mbits/sec

After:

[ 3] 0.0- 1.0 sec 7.12 MBytes 59.8 Mbits/sec

Co-developed-by: Erik Stromdahl <[email protected]>
Signed-off-by: Alagu Sankar <[email protected]>
Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/sdio.c | 71 +++++++++++++++++++++-----
drivers/net/wireless/ath/ath10k/sdio.h | 2 +
2 files changed, 60 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index d5073fac9509..b89732aad97c 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -24,6 +24,8 @@
#include "trace.h"
#include "sdio.h"

+#define ATH10K_SDIO_READ_BUF_SIZE (32 * 1024)
+
/* inlined helper functions */

static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
@@ -618,41 +620,73 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
return ret;
}

-static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
- struct ath10k_sdio_rx_data *pkt)
+static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_data *pkt = &ar_sdio->rx_pkts[0];
struct sk_buff *skb = pkt->skb;
int ret;

- ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
- skb->data, pkt->alloc_len);
+ ret = ath10k_sdio_read(ar, ar_sdio->mbox_info.htc_addr,
+ skb->data, pkt->alloc_len);
+ if (ret) {
+ ath10k_warn(ar, "sdio_read error %d\n", ret);
+ goto err;
+ }
+
pkt->status = ret;
- if (!ret)
- skb_put(skb, pkt->act_len);
+ skb_put(skb, pkt->act_len);

+ return 0;
+
+err:
+ ar_sdio->n_rx_pkts = 0;
+ ath10k_sdio_mbox_free_rx_pkt(pkt);
return ret;
}

-static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
+static int ath10k_sdio_mbox_rx_fetch_bundle(struct ath10k *ar)
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_data *pkt;
int ret, i;
+ u32 pkt_offset = 0, pkt_bundle_len = 0;
+
+ for (i = 0; i < ar_sdio->n_rx_pkts; i++)
+ pkt_bundle_len += ar_sdio->rx_pkts[i].alloc_len;
+
+ if (pkt_bundle_len > ATH10K_SDIO_READ_BUF_SIZE) {
+ ret = -ENOSPC;
+ ath10k_warn(ar, "bundle size (%d) exceeding limit %d\n",
+ pkt_bundle_len, ATH10K_SDIO_READ_BUF_SIZE);
+ goto err;
+ }
+
+ ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
+ ar_sdio->sdio_read_buf, pkt_bundle_len);
+ if (ret)
+ goto err;

for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
- ret = ath10k_sdio_mbox_rx_packet(ar,
- &ar_sdio->rx_pkts[i]);
- if (ret)
- goto err;
+ struct sk_buff *skb = ar_sdio->rx_pkts[i].skb;
+
+ pkt = &ar_sdio->rx_pkts[i];
+ skb_put(skb, pkt->act_len);
+ memcpy(skb->data, ar_sdio->sdio_read_buf + pkt_offset,
+ pkt->alloc_len);
+ pkt->status = 0;
+ pkt_offset += pkt->alloc_len;
}

return 0;

err:
/* Free all packets that was not successfully fetched. */
- for (; i < ar_sdio->n_rx_pkts; i++)
+ for (i = 0; i < ar_sdio->n_rx_pkts; i++)
ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]);

+ ar_sdio->n_rx_pkts = 0;
+
return ret;
}

@@ -695,7 +729,10 @@ static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar,
*/
*done = false;

- ret = ath10k_sdio_mbox_rx_fetch(ar);
+ if (ar_sdio->n_rx_pkts > 1)
+ ret = ath10k_sdio_mbox_rx_fetch_bundle(ar);
+ else
+ ret = ath10k_sdio_mbox_rx_fetch(ar);

/* Process fetched packets. This will potentially update
* n_lookaheads depending on if the packets contain lookahead
@@ -2001,6 +2038,14 @@ static int ath10k_sdio_probe(struct sdio_func *func,
goto err_core_destroy;
}

+ ar_sdio->sdio_read_buf = devm_kzalloc(ar->dev,
+ ATH10K_SDIO_READ_BUF_SIZE,
+ GFP_KERNEL);
+ if (!ar_sdio->sdio_read_buf) {
+ ret = -ENOMEM;
+ goto err_core_destroy;
+ }
+
ar_sdio->func = func;
sdio_set_drvdata(func, ar_sdio);

diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index b8c7ac0330bd..07e2cc6a3bd8 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -196,6 +196,8 @@ struct ath10k_sdio {
struct ath10k *ar;
struct ath10k_sdio_irq_data irq_data;

+ u8 *sdio_read_buf;
+
/* temporary buffer for BMI requests */
u8 *bmi_buf;

--
2.19.1


2019-04-17 19:15:35

by Erik Stromdahl

[permalink] [raw]
Subject: [PATCH v2 5/5] ath10k: sdio: remove skb_trim in TX path

This patch fixes a bug with padding of the skb data buffer.
Since skb_trim can only be used to reduce the skb len, it is useless when
we pad (increase the length of) the skb. Instead we allocate a new
buffer with enough space to contain both the TX data and padding.

Since some skb's have multiple references, we can't use skb_put_padto()
to extend and pad skb->data (since it causes a panic if there is more
than one reference).

Also, in order to avoid the following possible deadlock issue (reported by
lockdep):

[ 26.508508] Possible interrupt unsafe locking scenario:
[ 26.508508]
[ 26.515314] CPU0 CPU1
[ 26.519862] ---- ----
[ 26.524408] lock(fs_reclaim);
[ 26.527573] local_irq_disable();
[ 26.533508] lock(_xmit_ETHER#2);
[ 26.539453] lock(fs_reclaim);
[ 26.545135] <Interrupt>
[ 26.547769] lock(_xmit_ETHER#2);
[ 26.551370]
[ 26.551370] *** DEADLOCK ***

... we use the GFP_NOFS flag with kzalloc()

Signed-off-by: Erik Stromdahl <[email protected]>
---
drivers/net/wireless/ath/ath10k/sdio.c | 27 ++++++++++++++++++++------
drivers/net/wireless/ath/ath10k/sdio.h | 2 ++
2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index b8b3059721ee..68d8e2d1b2ed 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1279,6 +1279,7 @@ static void ath10k_sdio_free_bus_req(struct ath10k *ar,
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);

+ kfree(bus_req->buf);
memset(bus_req, 0, sizeof(*bus_req));

spin_lock_bh(&ar_sdio->lock);
@@ -1294,7 +1295,7 @@ static void __ath10k_sdio_write_async(struct ath10k *ar,
int ret;

skb = req->skb;
- ret = ath10k_sdio_write(ar, req->address, skb->data, skb->len);
+ ret = ath10k_sdio_write(ar, req->address, req->buf, req->buf_len);
if (ret)
ath10k_warn(ar, "failed to write skb to 0x%x asynchronously: %d",
req->address, ret);
@@ -1330,6 +1331,7 @@ static void ath10k_sdio_write_async_work(struct work_struct *work)

static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr,
struct sk_buff *skb,
+ size_t alloc_len,
struct completion *comp,
bool htc_msg, enum ath10k_htc_ep_id eid)
{
@@ -1343,9 +1345,17 @@ static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr,
if (!bus_req) {
ath10k_warn(ar,
"unable to allocate bus request for async request\n");
- return -ENOMEM;
+ goto err;
}

+ bus_req->buf_len = alloc_len;
+ bus_req->buf = kzalloc(alloc_len, GFP_NOFS);
+ if (!bus_req->buf) {
+ ath10k_warn(ar,
+ "unable to allocate data buffer for bus request\n");
+ goto err_free_bus_req;
+ }
+ memcpy(bus_req->buf, skb->data, skb->len);
bus_req->skb = skb;
bus_req->eid = eid;
bus_req->address = addr;
@@ -1357,6 +1367,11 @@ static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr,
spin_unlock_bh(&ar_sdio->wr_async_lock);

return 0;
+
+err_free_bus_req:
+ ath10k_sdio_free_bus_req(ar, bus_req);
+err:
+ return -ENOMEM;
}

/* IRQ handler */
@@ -1501,12 +1516,11 @@ static int ath10k_sdio_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
skb = items[i].transfer_context;
padded_len = ath10k_sdio_calc_txrx_padded_len(ar_sdio,
skb->len);
- skb_trim(skb, padded_len);

/* Write TX data to the end of the mbox address space */
address = ar_sdio->mbox_addr[eid] + ar_sdio->mbox_size[eid] -
- skb->len;
- ret = ath10k_sdio_prep_async_req(ar, address, skb,
+ padded_len;
+ ret = ath10k_sdio_prep_async_req(ar, address, skb, padded_len,
NULL, true, eid);
if (ret)
return ret;
@@ -1761,7 +1775,8 @@ static void ath10k_sdio_irq_disable(struct ath10k *ar)

init_completion(&irqs_disabled_comp);
ret = ath10k_sdio_prep_async_req(ar, MBOX_INT_STATUS_ENABLE_ADDRESS,
- skb, &irqs_disabled_comp, false, 0);
+ skb, skb->len, &irqs_disabled_comp,
+ false, 0);
if (ret)
goto out;

diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index 07e2cc6a3bd8..5a727993fbda 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -105,6 +105,8 @@ struct ath10k_sdio_bus_request {
u32 address;

struct sk_buff *skb;
+ u8 *buf;
+ size_t buf_len;
enum ath10k_htc_ep_id eid;
int status;
/* Specifies if the current request is an HTC message.
--
2.19.1


2019-04-23 13:26:51

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v2 1/5] ath10k: add initialization of HTC header

Erik Stromdahl <[email protected]> wrote:

> HTC header carries junk values that may be interpreted by the firmware
> differently. Enable credit update only if flow control is enabled for
> the corresponding endpoint.
>
> Signed-off-by: Alagu Sankar <[email protected]>
> Signed-off-by: Erik Stromdahl <[email protected]>
> Signed-off-by: Kalle Valo <[email protected]>

2 patches applied to ath-next branch of ath.git, thanks.

fbd428a5b828 ath10k: add initialization of HTC header
f91b63b0e3b2 ath10k: sdio: add missing error check

--
https://patchwork.kernel.org/patch/10906001/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


2019-09-26 09:13:45

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v2 3/5] ath10k: sdio: read RX packets in bundles

Kalle Valo <[email protected]> writes:

> Erik Stromdahl <[email protected]> wrote:
>
>> From: Alagu Sankar <[email protected]>
>>
>> The existing implementation of initiating multiple sdio transfers for
>> receive bundling is slowing down the receive speed.
>>
>> Instead of having one sdio transfer for each packet in the bundle, we
>> read all packets in one sdio transfer.
>>
>> This results in significant performance improvement on some targets.
>>
>> On an imx6dl together with a QCA9377 SDIO device, the following
>> performance increase was obtained with iperf:
>>
>> Before:
>>
>> [ 3] 0.0- 1.0 sec 3.38 MBytes 28.3 Mbits/sec
>>
>> After:
>>
>> [ 3] 0.0- 1.0 sec 7.12 MBytes 59.8 Mbits/sec
>>
>> Co-developed-by: Erik Stromdahl <[email protected]>
>> Signed-off-by: Alagu Sankar <[email protected]>
>> Signed-off-by: Erik Stromdahl <[email protected]>
>
> Wen is working on this:
>
> [v5,2/8] ath10k: enable RX bundle receive for sdio
>
> https://patchwork.kernel.org/patch/11132661/
>
> So I'll drop this version. Patch set to Superseded.

There were invalid characters and linux-wireless dropped my mail,
resending now.

--
Kalle Valo

2019-10-01 12:26:10

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v2 5/5] ath10k: sdio: remove skb_trim in TX path

Erik Stromdahl <[email protected]> writes:

> This patch fixes a bug with padding of the skb data buffer.
> Since skb_trim can only be used to reduce the skb len, it is useless when
> we pad (increase the length of) the skb. Instead we allocate a new
> buffer with enough space to contain both the TX data and padding.
>
> Since some skb's have multiple references, we can't use skb_put_padto()
> to extend and pad skb->data (since it causes a panic if there is more
> than one reference).
>
> Also, in order to avoid the following possible deadlock issue (reported by
> lockdep):
>
> [ 26.508508] Possible interrupt unsafe locking scenario:
> [ 26.508508]
> [ 26.515314] CPU0 CPU1
> [ 26.519862] ---- ----
> [ 26.524408] lock(fs_reclaim);
> [ 26.527573] local_irq_disable();
> [ 26.533508] lock(_xmit_ETHER#2);
> [ 26.539453] lock(fs_reclaim);
> [ 26.545135] <Interrupt>
> [ 26.547769] lock(_xmit_ETHER#2);
> [ 26.551370]
> [ 26.551370] *** DEADLOCK ***
>
> ... we use the GFP_NOFS flag with kzalloc()
>
> Signed-off-by: Erik Stromdahl <[email protected]>

I replied to v1 about using skb_pad(), let's discuss more there:

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

--
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches