The bottleneck of throughout on sdio chip is the bus bandwidth, to the
patches are all to increase the use ratio of sdio bus.
udp-rx udp-tx tcp-rx tcp-tx
without patches(Mbps) 320 180 170 151
with patches(Mbps) 450 410 400 320
These patches only affect sdio bus chip, explanation is mentioned in each
patch's commit log.
Alagu Sankar (1):
ath10k: enable RX bundle receive for sdio
Wen Gong (6):
ath10k: change max RX bundle size from 8 to 32 for sdio
ath10k: add workqueue for RX path of sdio
ath10k: disable TX complete indication of htt for sdio
ath10k: add htt TX bundle for sdio
ath10k: enable alt data of TX path for sdio
ath10k: enable napi on RX path for sdio
drivers/net/wireless/ath/ath10k/core.c | 36 ++-
drivers/net/wireless/ath/ath10k/core.h | 4 +-
drivers/net/wireless/ath/ath10k/hif.h | 9 +
drivers/net/wireless/ath/ath10k/htc.c | 375 ++++++++++++++++++++++++++++---
drivers/net/wireless/ath/ath10k/htc.h | 37 ++-
drivers/net/wireless/ath/ath10k/htt.c | 15 ++
drivers/net/wireless/ath/ath10k/htt.h | 21 +-
drivers/net/wireless/ath/ath10k/htt_rx.c | 85 ++++++-
drivers/net/wireless/ath/ath10k/htt_tx.c | 37 ++-
drivers/net/wireless/ath/ath10k/hw.h | 2 +-
drivers/net/wireless/ath/ath10k/sdio.c | 281 ++++++++++++++++++++---
drivers/net/wireless/ath/ath10k/sdio.h | 31 ++-
12 files changed, 846 insertions(+), 87 deletions(-)
--
1.9.1
The max bundle size support by firmware is 32, change it from 8 to 32
will help performance. This results in significant performance
improvement on RX path.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <[email protected]>
---
drivers/net/wireless/ath/ath10k/htc.h | 2 +-
drivers/net/wireless/ath/ath10k/sdio.c | 5 +++--
drivers/net/wireless/ath/ath10k/sdio.h | 4 ++--
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index f55d3ca..8c79b9e 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -39,7 +39,7 @@
* 4-byte aligned.
*/
-#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 8
+#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
enum ath10k_htc_tx_flags {
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index d9395f0..baa6051 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -24,8 +24,8 @@
#include "trace.h"
#include "sdio.h"
-#define ATH10K_SDIO_DMA_BUF_SIZE (32 * 1024)
-#define ATH10K_SDIO_VSG_BUF_SIZE (32 * 1024)
+#define ATH10K_SDIO_DMA_BUF_SIZE (64 * 1024)
+#define ATH10K_SDIO_VSG_BUF_SIZE (64 * 1024)
/* inlined helper functions */
@@ -501,6 +501,7 @@ static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
int ret, i;
*bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr->flags);
+ *bndl_cnt += (FIELD_GET(GENMASK(3, 2), htc_hdr->flags) << 4);
if (*bndl_cnt > HTC_HOST_MAX_MSG_PER_RX_BUNDLE) {
ath10k_warn(ar,
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index 4896eca..3ca76c7 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -89,10 +89,10 @@
* to the maximum value (HTC_HOST_MAX_MSG_PER_RX_BUNDLE).
*
* in this case the driver must allocate
- * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE) skb's.
+ * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2) skb's.
*/
#define ATH10K_SDIO_MAX_RX_MSGS \
- (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE)
+ (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2)
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
--
1.9.1
The thread of read rx message by sdio bus from firmware is
synchronous, it will cost much time for process the left part
of rx message which includes indicate the rx packet to uppper
net stack. It will reduce the time of read from sdio.
This patch move the indication to a workqueue, it results in
significant performance improvement on RX path.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <[email protected]>
---
drivers/net/wireless/ath/ath10k/sdio.c | 117 ++++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/sdio.h | 20 ++++++
2 files changed, 134 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index baa6051..f42aca6 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -417,6 +417,67 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
return 0;
}
+static struct ath10k_sdio_rx_request
+*ath10k_sdio_alloc_rx_req(struct ath10k *ar)
+{
+ struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_request *rx_req;
+
+ spin_lock_bh(&ar_sdio->rx_lock);
+
+ if (list_empty(&ar_sdio->rx_req_freeq)) {
+ rx_req = NULL;
+ ath10k_dbg(ar, ATH10K_DBG_SDIO, "rx_req alloc fail\n");
+ goto out;
+ }
+
+ rx_req = list_first_entry(&ar_sdio->rx_req_freeq,
+ struct ath10k_sdio_rx_request, list);
+ list_del(&rx_req->list);
+
+out:
+ spin_unlock_bh(&ar_sdio->rx_lock);
+ return rx_req;
+}
+
+static void ath10k_sdio_free_rx_req(struct ath10k *ar,
+ struct ath10k_sdio_rx_request *rx_req)
+{
+ struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+
+ memset(rx_req, 0, sizeof(*rx_req));
+
+ spin_lock_bh(&ar_sdio->rx_lock);
+ list_add_tail(&rx_req->list, &ar_sdio->rx_req_freeq);
+ spin_unlock_bh(&ar_sdio->rx_lock);
+}
+
+static int ath10k_sdio_prep_async_rx_req(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_htc_ep *ep)
+{
+ struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_request *rx_req;
+
+ /* Allocate a rx request for the message and queue it on the
+ * SDIO rx workqueue.
+ */
+ rx_req = ath10k_sdio_alloc_rx_req(ar);
+ if (!rx_req) {
+ ath10k_warn(ar, "unable to allocate rx request for async request\n");
+ return -ENOMEM;
+ }
+
+ rx_req->skb = skb;
+ rx_req->ep = ep;
+
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+ list_add_tail(&rx_req->list, &ar_sdio->wr_asyncq_rx);
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+
+ return 0;
+}
+
static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
u32 lookaheads[],
int *n_lookahead)
@@ -470,10 +531,16 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
if (ret)
goto out;
- if (!pkt->trailer_only)
- ep->ep_ops.ep_rx_complete(ar_sdio->ar, pkt->skb);
- else
+ if (!pkt->trailer_only) {
+ ret = ath10k_sdio_prep_async_rx_req(ar, pkt->skb, ep);
+ if (ret)
+ kfree_skb(pkt->skb);
+ else
+ queue_work(ar->workqueue_aux,
+ &ar_sdio->wr_async_work_rx);
+ } else {
kfree_skb(pkt->skb);
+ }
/* The RX complete handler now owns the skb...*/
pkt->skb = NULL;
@@ -1322,6 +1389,26 @@ static void __ath10k_sdio_write_async(struct ath10k *ar,
ath10k_sdio_free_bus_req(ar, req);
}
+static void ath10k_rx_indication_async_work(struct work_struct *work)
+{
+ struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio,
+ wr_async_work_rx);
+ struct ath10k *ar = ar_sdio->ar;
+ struct ath10k_sdio_rx_request *req, *tmp_req;
+
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+
+ list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq_rx, list) {
+ list_del(&req->list);
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+ req->ep->ep_ops.ep_rx_complete(ar, req->skb);
+ ath10k_sdio_free_rx_req(ar, req);
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+ }
+
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+}
+
static void ath10k_sdio_write_async_work(struct work_struct *work)
{
struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio,
@@ -1810,10 +1897,24 @@ static void ath10k_sdio_irq_disable(struct ath10k *ar)
static void ath10k_sdio_hif_stop(struct ath10k *ar)
{
struct ath10k_sdio_bus_request *req, *tmp_req;
+ struct ath10k_sdio_rx_request *rx_req, *tmp_rx_req;
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
ath10k_sdio_irq_disable(ar);
+ cancel_work_sync(&ar_sdio->wr_async_work_rx);
+
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+
+ /* Free all RX requests that have not been handled */
+ list_for_each_entry_safe(rx_req, tmp_rx_req, &ar_sdio->wr_asyncq_rx, list) {
+ list_del(&rx_req->list);
+ rx_req->ep->ep_ops.ep_rx_complete(ar, rx_req->skb);
+ ath10k_sdio_free_rx_req(ar, rx_req);
+ }
+
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+
cancel_work_sync(&ar_sdio->wr_async_work);
spin_lock_bh(&ar_sdio->wr_async_lock);
@@ -2092,6 +2193,16 @@ static int ath10k_sdio_probe(struct sdio_func *func,
for (i = 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++)
ath10k_sdio_free_bus_req(ar, &ar_sdio->bus_req[i]);
+ spin_lock_init(&ar_sdio->rx_lock);
+ spin_lock_init(&ar_sdio->wr_async_lock_rx);
+ INIT_LIST_HEAD(&ar_sdio->rx_req_freeq);
+ INIT_LIST_HEAD(&ar_sdio->wr_asyncq_rx);
+
+ INIT_WORK(&ar_sdio->wr_async_work_rx, ath10k_rx_indication_async_work);
+
+ for (i = 0; i < ARRAY_SIZE(ar_sdio->rx_req); i++)
+ ath10k_sdio_free_rx_req(ar, &ar_sdio->rx_req[i]);
+
dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, id->device);
switch (dev_id_base) {
case QCA_MANUFACTURER_ID_AR6005_BASE:
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index 3ca76c7..9bb438e 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -38,6 +38,7 @@
#define ATH10K_HIF_MBOX_NUM_MAX 4
#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM 64
+#define ATH10K_SDIO_RX_REQUEST_MAX_NUM 1024
#define ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ (100 * HZ)
@@ -98,6 +99,12 @@
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000
+struct ath10k_sdio_rx_request {
+ struct list_head list;
+ struct sk_buff *skb;
+ struct ath10k_htc_ep *ep;
+};
+
struct ath10k_sdio_bus_request {
struct list_head list;
@@ -187,9 +194,17 @@ struct ath10k_sdio {
struct ath10k_sdio_bus_request bus_req[ATH10K_SDIO_BUS_REQUEST_MAX_NUM];
/* free list of bus requests */
struct list_head bus_req_freeq;
+
/* protects access to bus_req_freeq */
spinlock_t lock;
+ /* available rx requests */
+ struct ath10k_sdio_rx_request rx_req[ATH10K_SDIO_RX_REQUEST_MAX_NUM];
+ /* free list of rx requests */
+ struct list_head rx_req_freeq;
+ /* protects access to rx_req_freeq */
+ spinlock_t rx_lock;
+
struct ath10k_sdio_rx_data rx_pkts[ATH10K_SDIO_MAX_RX_MSGS];
size_t n_rx_pkts;
@@ -209,6 +224,11 @@ struct ath10k_sdio {
struct list_head wr_asyncq;
/* protects access to wr_asyncq */
spinlock_t wr_async_lock;
+
+ struct work_struct wr_async_work_rx;
+ struct list_head wr_asyncq_rx;
+ /* protects access to wr_asyncq_rx */
+ spinlock_t wr_async_lock_rx;
};
static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar)
--
1.9.1
Tx complete message from firmware cost bus bandwidth of sdio, and bus
bandwidth is the bollteneck of throughput, it will effect the bandwidth
occupancy of data packet of TX and RX.
This patch disable TX complete indication from firmware for htt data
packet, it results in significant performance improvement on TX path.
The downside of this patch is ath10k will not know the TX status of
the data packet for poor signal situation. Although upper network stack
or application layer have retry mechanism, the retry will be later than
ath10k get the TX fail status if not disable TX complete.
This patch only effect sdio chip, it will not effect PCI, SNOC etc.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 6 +++++
drivers/net/wireless/ath/ath10k/hif.h | 9 ++++++++
drivers/net/wireless/ath/ath10k/htc.c | 11 +++++++++
drivers/net/wireless/ath/ath10k/htc.h | 3 +++
drivers/net/wireless/ath/ath10k/htt.c | 5 +++++
drivers/net/wireless/ath/ath10k/htt.h | 13 ++++++++++-
drivers/net/wireless/ath/ath10k/htt_rx.c | 38 +++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/htt_tx.c | 30 +++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/hw.h | 2 +-
drivers/net/wireless/ath/ath10k/sdio.c | 28 +++++++++++++++++++++++
10 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index dc45d16..762bba0 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -30,6 +30,7 @@
static unsigned int ath10k_cryptmode_param;
static bool uart_print;
+static bool disable_tx_comp = true;
static bool skip_otp;
static bool rawmode;
static bool fw_diag_log;
@@ -41,6 +42,9 @@
module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
module_param(uart_print, bool, 0644);
+
+/* If upper layer need the TX complete status, it can enable tx complete */
+module_param(disable_tx_comp, bool, 0644);
module_param(skip_otp, bool, 0644);
module_param(rawmode, bool, 0644);
module_param(fw_diag_log, bool, 0644);
@@ -689,6 +693,8 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
* is used for SDIO. disable it until fixed
*/
param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
+ if (disable_tx_comp)
+ param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
/* Alternate credit size of 1544 as used by SDIO firmware is
* not big enough for mac80211 / native wifi frames. disable it
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 496ee34..0dd8973 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -56,6 +56,8 @@ struct ath10k_hif_ops {
int (*swap_mailbox)(struct ath10k *ar);
+ int (*get_htt_tx_complete)(struct ath10k *ar);
+
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe);
@@ -144,6 +146,13 @@ static inline int ath10k_hif_swap_mailbox(struct ath10k *ar)
return 0;
}
+static inline int ath10k_hif_get_htt_tx_complete(struct ath10k *ar)
+{
+ if (ar->hif.ops->get_htt_tx_complete)
+ return ar->hif.ops->get_htt_tx_complete(ar);
+ return 0;
+}
+
static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 1d4d1a1..7357a5a 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -660,6 +660,17 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
return 0;
}
+void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
+ enum ath10k_htc_ep_id eid,
+ bool enable)
+{
+ struct ath10k *ar = htc->ar;
+ struct ath10k_htc_ep *ep;
+
+ ep = &ar->htc.endpoint[eid];
+ ep->tx_credit_flow_enabled = enable;
+}
+
int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
struct ath10k_htc_svc_conn_resp *conn_resp)
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 8c79b9e..78bc3ae 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -367,6 +367,9 @@ struct ath10k_htc {
int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
struct ath10k_htc_svc_conn_resp *conn_resp);
+void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
+ enum ath10k_htc_ep_id eid,
+ bool enable);
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
struct sk_buff *packet);
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 7b75200..88f3321 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -10,6 +10,7 @@
#include "htt.h"
#include "core.h"
#include "debug.h"
+#include "hif.h"
static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
[HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
@@ -153,6 +154,10 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
htt->eid = conn_resp.eid;
+ htt->disable_tx_comple = ath10k_hif_get_htt_tx_complete(htt->ar);
+ if (htt->disable_tx_comple)
+ ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 30c0800..cf97be5 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -150,9 +150,19 @@ enum htt_data_tx_desc_flags1 {
HTT_DATA_TX_DESC_FLAGS1_MORE_IN_BATCH = 1 << 12,
HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD = 1 << 13,
HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD = 1 << 14,
- HTT_DATA_TX_DESC_FLAGS1_RSVD1 = 1 << 15
+ HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE = 1 << 15
};
+#define HTT_TX_CREDIT_DELTA_ABS_M 0xffff0000
+#define HTT_TX_CREDIT_DELTA_ABS_S 16
+#define HTT_TX_CREDIT_DELTA_ABS_GET(word) \
+ (((word) & HTT_TX_CREDIT_DELTA_ABS_M) >> HTT_TX_CREDIT_DELTA_ABS_S)
+
+#define HTT_TX_CREDIT_SIGN_BIT_M 0x00000100
+#define HTT_TX_CREDIT_SIGN_BIT_S 8
+#define HTT_TX_CREDIT_SIGN_BIT_GET(word) \
+ (((word) & HTT_TX_CREDIT_SIGN_BIT_M) >> HTT_TX_CREDIT_SIGN_BIT_S)
+
enum htt_data_tx_ext_tid {
HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST = 16,
HTT_DATA_TX_EXT_TID_MGMT = 17,
@@ -2019,6 +2029,7 @@ struct ath10k_htt {
bool tx_mem_allocated;
const struct ath10k_htt_tx_ops *tx_ops;
const struct ath10k_htt_rx_ops *rx_ops;
+ bool disable_tx_comple;
};
struct ath10k_htt_tx_ops {
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 83a7fb6..d808824 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -3691,6 +3691,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
}
case HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION: {
struct htt_tx_done tx_done = {};
+ struct ath10k_htt *htt = &ar->htt;
+ struct ath10k_htc *htc = &ar->htc;
+ struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
int status = __le32_to_cpu(resp->mgmt_tx_completion.status);
int info = __le32_to_cpu(resp->mgmt_tx_completion.info);
@@ -3716,6 +3719,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
+ if (htt->disable_tx_comple) {
+ spin_lock_bh(&htc->tx_lock);
+ ep->tx_credits++;
+ spin_unlock_bh(&htc->tx_lock);
+ }
+
status = ath10k_txrx_tx_unref(htt, &tx_done);
if (!status) {
spin_lock_bh(&htt->tx_lock);
@@ -3790,7 +3799,34 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
return false;
}
- case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
+ case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:{
+ struct ath10k_htt *htt = &ar->htt;
+ struct ath10k_htc *htc = &ar->htc;
+ struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
+ u32 *msg_word;
+ u32 htt_credit_delta_abs;
+ int htt_credit_delta;
+ int sign;
+
+ msg_word = (u32 *)resp;
+ htt_credit_delta_abs = HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word);
+ sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1;
+ htt_credit_delta = sign * htt_credit_delta_abs;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "credit update: abs:%d, sign:%d, delta:%d\n",
+ htt_credit_delta_abs, sign, htt_credit_delta);
+
+ if (htt->disable_tx_comple) {
+ spin_lock_bh(&htc->tx_lock);
+ ep->tx_credits += htt_credit_delta;
+ spin_unlock_bh(&htc->tx_lock);
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "credit total:%d\n",
+ ep->tx_credits);
+ }
+ break;
+ }
break;
case HTT_T2H_MSG_TYPE_CHAN_CHANGE: {
u32 phymode = __le32_to_cpu(resp->chan_change.phymode);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 2ef717f1..cda8a59 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -543,7 +543,33 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
{
+ struct ath10k_htt *htt = &ar->htt;
+ struct htt_tx_done tx_done = {0};
+ struct htt_cmd_hdr *htt_hdr;
+ struct htt_data_tx_desc *desc_hdr;
+ u16 flags1;
+
dev_kfree_skb_any(skb);
+
+ if (htt->disable_tx_comple) {
+ htt_hdr = (struct htt_cmd_hdr *)skb->data;
+ if (htt_hdr->msg_type == HTT_H2T_MSG_TYPE_TX_FRM) {
+ desc_hdr = (struct htt_data_tx_desc *)
+ (skb->data + sizeof(*htt_hdr));
+ flags1 = __le16_to_cpu(desc_hdr->flags1);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "ath10k_htt_htc_tx_complete msdu id:%u ,flags1:%x\n",
+ __le16_to_cpu(desc_hdr->id), flags1);
+
+ if (flags1 & HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE)
+ return;
+
+ tx_done.status = HTT_TX_COMPL_STATE_ACK;
+ tx_done.msdu_id = __le16_to_cpu(desc_hdr->id);
+ ath10k_txrx_tx_unref(&ar->htt, &tx_done);
+ }
+ }
}
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb)
@@ -1260,6 +1286,10 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
case ATH10K_HW_TXRX_MGMT:
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+
+ if (htt->disable_tx_comple)
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE;
+
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 2ae57c1..6349665 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -759,7 +759,7 @@ struct ath10k_hw_ops {
#define TARGET_TLV_NUM_TDLS_VDEVS 1
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
-#define TARGET_TLV_NUM_MSDU_DESC_HL 64
+#define TARGET_TLV_NUM_MSDU_DESC_HL 1024
#define TARGET_TLV_NUM_WOW_PATTERNS 22
#define TARGET_TLV_MGMT_NUM_MSDU_DESC (50)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index f42aca6..4d6da04 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1790,6 +1790,33 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
return 0;
}
+static int ath10k_sdio_get_htt_tx_complete(struct ath10k *ar)
+{
+ u32 addr, val;
+ int ret = 0;
+
+ addr = host_interest_item_address(HI_ITEM(hi_acs_flags));
+
+ ret = ath10k_sdio_hif_diag_read32(ar, addr, &val);
+ if (ret) {
+ ath10k_warn(ar,
+ "unable to read hi_acs_flags for htt tx comple : %d\n", ret);
+ return ret;
+ }
+
+ if (val & HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK) {
+ ath10k_dbg(ar, ATH10K_DBG_SDIO,
+ "sdio reduce tx comple fw ack\n");
+ ret = 1;
+ } else {
+ ath10k_dbg(ar, ATH10K_DBG_SDIO,
+ "sdio reduce tx comple fw not ack\n");
+ ret = 0;
+ }
+
+ return ret;
+}
+
/* HIF start/stop */
static int ath10k_sdio_hif_start(struct ath10k *ar)
@@ -2073,6 +2100,7 @@ static void ath10k_sdio_hif_send_complete_check(struct ath10k *ar,
.start = ath10k_sdio_hif_start,
.stop = ath10k_sdio_hif_stop,
.swap_mailbox = ath10k_sdio_hif_swap_mailbox,
+ .get_htt_tx_complete = ath10k_sdio_get_htt_tx_complete,
.map_service_to_pipe = ath10k_sdio_hif_map_service_to_pipe,
.get_default_pipe = ath10k_sdio_hif_get_default_pipe,
.send_complete_check = ath10k_sdio_hif_send_complete_check,
--
1.9.1
The default credit size is 1792 bytes, but the IP mtu is 1500 bytes,
then it has about 290 bytes's waste for each data packet on sdio
transfer path for TX bundle, it will reduce the transmission utilization
ratio for data packet.
This patch enable the small credit size in firmware, firmware will use
the new credit size 1556 bytes, it will increase the transmission
utilization ratio for data packet on TX patch. It results in significant
performance improvement on TX path.
This patch only effect sdio chip, it will not effect PCI, SNOC etc.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00017-QCARMSWP-1.
Signed-off-by: Wen Gong <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 16 ++++++++++++++++
drivers/net/wireless/ath/ath10k/htc.c | 11 +++++++++--
drivers/net/wireless/ath/ath10k/htc.h | 11 +++++++++--
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 351f4ed..7593d19 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -31,6 +31,7 @@
static unsigned int ath10k_cryptmode_param;
static bool uart_print;
static bool disable_tx_comp = true;
+static bool alt_data = true;
static bool skip_otp;
static bool rawmode;
static bool fw_diag_log;
@@ -45,6 +46,15 @@
/* If upper layer need the TX complete status, it can enable tx complete */
module_param(disable_tx_comp, bool, 0644);
+
+/* alt_data is only used for sdio chip, for previous version of firmware, its
+ * alt data size is 1544 which is not enough for native wifi, so it need to
+ * alt_data for the firmware.
+ * If the firmware has changed alt data size to 1556, then it can enable
+ * alt_data for the firmware.
+ * alt_data will not effect PCI, SNOC etc.
+ */
+module_param(alt_data, bool, 0644);
module_param(skip_otp, bool, 0644);
module_param(rawmode, bool, 0644);
module_param(fw_diag_log, bool, 0644);
@@ -701,6 +711,12 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
*/
param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
+ /* If alternate credit size of 1556 as used by SDIO firmware is
+ * big enough for mac80211 / native wifi frames. enable it
+ */
+ if (alt_data && mode == ATH10K_FIRMWARE_MODE_NORMAL)
+ param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
+
if (mode == ATH10K_FIRMWARE_MODE_UTF)
param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
else
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 96b620f..2db7f1a 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -938,12 +938,15 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
*/
if (htc->control_resp_len >=
sizeof(msg->hdr) + sizeof(msg->ready_ext)) {
+ htc->alt_data_credit_size =
+ __le16_to_cpu(msg->ready_ext.reserved) & 0x0fff;
htc->max_msgs_per_htc_bundle =
min_t(u8, msg->ready_ext.max_msgs_per_htc_bundle,
HTC_HOST_MAX_MSG_PER_RX_BUNDLE);
ath10k_dbg(ar, ATH10K_DBG_HTC,
- "Extended ready message. RX bundle size: %d\n",
- htc->max_msgs_per_htc_bundle);
+ "Extended ready message. RX bundle size: %d, alt size:%d\n",
+ htc->max_msgs_per_htc_bundle,
+ htc->alt_data_credit_size);
}
INIT_WORK(&ar->bundle_tx_work, ath10k_htc_bundle_tx_work);
@@ -1096,6 +1099,10 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
ep->tx_credits = tx_alloc;
ep->tx_credit_size = htc->target_credit_size;
+ if (conn_req->service_id == ATH10K_HTC_SVC_ID_HTT_DATA_MSG &&
+ htc->alt_data_credit_size != 0)
+ ep->tx_credit_size = htc->alt_data_credit_size;
+
/* copy all the callbacks */
ep->ep_ops = conn_req->ep_ops;
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 621ac89..f965b5b 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -135,8 +135,14 @@ struct ath10k_htc_ready_extended {
struct ath10k_htc_ready base;
u8 htc_version; /* @enum ath10k_htc_version */
u8 max_msgs_per_htc_bundle;
- u8 pad0;
- u8 pad1;
+ union {
+ __le16 reserved;
+ struct {
+ u8 pad0;
+ u8 pad1;
+ } __packed;
+ } __packed;
+
} __packed;
struct ath10k_htc_conn_svc {
@@ -373,6 +379,7 @@ struct ath10k_htc {
int total_transmit_credits;
int target_credit_size;
u8 max_msgs_per_htc_bundle;
+ int alt_data_credit_size;
};
int ath10k_htc_init(struct ath10k *ar);
--
1.9.1
The transmission utilization ratio for sdio bus for small packet is
slow, because the space and time cost for sdio bus is same for large
length packet and small length packet. So the speed of data for large
length packet is higher than small length.
Test result of different length of data:
data packet(byte) cost time(us) calculated rate(Mbps)
256 28 73
512 33 124
1024 35 234
1792 45 318
14336 168 682
28672 333 688
57344 660 695
This patch change the TX packet from single packet to a large length
bundle packet, max size is 32, it results in significant performance
improvement on TX path.
This patch only effect sdio chip, it will not effect PCI, SNOC etc.
It only enable bundle for sdio chip.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 14 +-
drivers/net/wireless/ath/ath10k/core.h | 4 +-
drivers/net/wireless/ath/ath10k/htc.c | 353 ++++++++++++++++++++++++++++---
drivers/net/wireless/ath/ath10k/htc.h | 21 +-
drivers/net/wireless/ath/ath10k/htt.c | 8 +
drivers/net/wireless/ath/ath10k/htt.h | 5 +
drivers/net/wireless/ath/ath10k/htt_rx.c | 1 +
drivers/net/wireless/ath/ath10k/htt_tx.c | 9 +-
8 files changed, 377 insertions(+), 38 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 762bba0..351f4ed 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -3194,6 +3194,11 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
if (!ar->workqueue_aux)
goto err_free_wq;
+ ar->workqueue_tx_complete =
+ create_singlethread_workqueue("ath10k_tx_complete_wq");
+ if (!ar->workqueue_tx_complete)
+ goto err_free_aux_wq;
+
mutex_init(&ar->conf_mutex);
mutex_init(&ar->dump_mutex);
spin_lock_init(&ar->data_lock);
@@ -3219,7 +3224,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ret = ath10k_coredump_create(ar);
if (ret)
- goto err_free_aux_wq;
+ goto err_free_tx_complete;
ret = ath10k_debug_create(ar);
if (ret)
@@ -3229,12 +3234,12 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
err_free_coredump:
ath10k_coredump_destroy(ar);
-
+err_free_tx_complete:
+ destroy_workqueue(ar->workqueue_tx_complete);
err_free_aux_wq:
destroy_workqueue(ar->workqueue_aux);
err_free_wq:
destroy_workqueue(ar->workqueue);
-
err_free_mac:
ath10k_mac_destroy(ar);
@@ -3250,6 +3255,9 @@ void ath10k_core_destroy(struct ath10k *ar)
flush_workqueue(ar->workqueue_aux);
destroy_workqueue(ar->workqueue_aux);
+ flush_workqueue(ar->workqueue_tx_complete);
+ destroy_workqueue(ar->workqueue_tx_complete);
+
ath10k_debug_destroy(ar);
ath10k_coredump_destroy(ar);
ath10k_htt_tx_destroy(&ar->htt);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4d7db07..be9eb37 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1079,7 +1079,7 @@ struct ath10k {
struct workqueue_struct *workqueue;
/* Auxiliary workqueue */
struct workqueue_struct *workqueue_aux;
-
+ struct workqueue_struct *workqueue_tx_complete;
/* prevents concurrent FW reconfiguration */
struct mutex conf_mutex;
@@ -1120,6 +1120,8 @@ struct ath10k {
struct work_struct register_work;
struct work_struct restart_work;
+ struct work_struct bundle_tx_work;
+ struct work_struct tx_complete_work;
/* cycle count is reported twice for each visited channel during scan.
* access protected by data_lock
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 7357a5a..96b620f 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -51,10 +51,12 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
struct sk_buff *skb)
{
struct ath10k *ar = ep->htc->ar;
+ struct ath10k_htc_hdr *hdr;
ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %pK\n", __func__,
ep->eid, skb);
+ hdr = (struct ath10k_htc_hdr *)skb->data;
ath10k_htc_restore_tx_skb(ep->htc, skb);
if (!ep->ep_ops.ep_tx_complete) {
@@ -63,6 +65,11 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
return;
}
+ if (hdr->flags & ATH10K_HTC_FLAG_SEND_BUNDLE) {
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
ep->ep_ops.ep_tx_complete(ep->htc->ar, skb);
}
EXPORT_SYMBOL(ath10k_htc_notify_tx_completion);
@@ -78,7 +85,7 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
hdr->flags = 0;
- if (ep->tx_credit_flow_enabled)
+ if (ep->tx_credit_flow_enabled && !ep->bundle_tx)
hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
spin_lock_bh(&ep->htc->tx_lock);
@@ -86,6 +93,59 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
spin_unlock_bh(&ep->htc->tx_lock);
}
+static int ath10k_htc_consume_credit(struct ath10k_htc_ep *ep,
+ unsigned int len,
+ bool consume)
+{
+ int credits;
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ enum ath10k_htc_ep_id eid = ep->eid;
+
+ if (ep->tx_credit_flow_enabled) {
+ credits = DIV_ROUND_UP(len, ep->tx_credit_size);
+ spin_lock_bh(&htc->tx_lock);
+
+ if (ep->tx_credits < credits) {
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "htc insufficient credits ep %d required %d available %d consume %d\n",
+ eid, credits, ep->tx_credits, consume);
+ spin_unlock_bh(&htc->tx_lock);
+ return -EAGAIN;
+ }
+ if (consume) {
+ ep->tx_credits -= credits;
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "htc ep %d consumed %d credits (total %d)\n",
+ eid, credits, ep->tx_credits);
+ }
+ spin_unlock_bh(&htc->tx_lock);
+ }
+
+ return 0;
+}
+
+static void ath10k_htc_release_credit(struct ath10k_htc_ep *ep, unsigned int len)
+{
+ int credits;
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ enum ath10k_htc_ep_id eid = ep->eid;
+
+ if (ep->tx_credit_flow_enabled) {
+ credits = DIV_ROUND_UP(len, ep->tx_credit_size);
+ spin_lock_bh(&htc->tx_lock);
+ ep->tx_credits += credits;
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "htc ep %d reverted %d credits back (total %d)\n",
+ eid, credits, ep->tx_credits);
+ spin_unlock_bh(&htc->tx_lock);
+
+ if (ep->ep_ops.ep_tx_credits)
+ ep->ep_ops.ep_tx_credits(htc->ar);
+ }
+}
+
int ath10k_htc_send(struct ath10k_htc *htc,
enum ath10k_htc_ep_id eid,
struct sk_buff *skb)
@@ -95,8 +155,8 @@ int ath10k_htc_send(struct ath10k_htc *htc,
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct ath10k_hif_sg_item sg_item;
struct device *dev = htc->ar->dev;
- int credits = 0;
int ret;
+ unsigned int skb_len;
if (htc->ar->state == ATH10K_STATE_WEDGED)
return -ECOMM;
@@ -108,23 +168,10 @@ int ath10k_htc_send(struct ath10k_htc *htc,
skb_push(skb, sizeof(struct ath10k_htc_hdr));
- if (ep->tx_credit_flow_enabled) {
- credits = DIV_ROUND_UP(skb->len, htc->target_credit_size);
- spin_lock_bh(&htc->tx_lock);
- if (ep->tx_credits < credits) {
- ath10k_dbg(ar, ATH10K_DBG_HTC,
- "htc insufficient credits ep %d required %d available %d\n",
- eid, credits, ep->tx_credits);
- spin_unlock_bh(&htc->tx_lock);
- ret = -EAGAIN;
- goto err_pull;
- }
- ep->tx_credits -= credits;
- ath10k_dbg(ar, ATH10K_DBG_HTC,
- "htc ep %d consumed %d credits (total %d)\n",
- eid, credits, ep->tx_credits);
- spin_unlock_bh(&htc->tx_lock);
- }
+ skb_len = skb->len;
+ ret = ath10k_htc_consume_credit(ep, skb_len, true);
+ if (ret)
+ goto err_pull;
ath10k_htc_prepare_tx_skb(ep, skb);
@@ -155,17 +202,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)
dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
err_credits:
- if (ep->tx_credit_flow_enabled) {
- spin_lock_bh(&htc->tx_lock);
- ep->tx_credits += credits;
- ath10k_dbg(ar, ATH10K_DBG_HTC,
- "htc ep %d reverted %d credits back (total %d)\n",
- eid, credits, ep->tx_credits);
- spin_unlock_bh(&htc->tx_lock);
-
- if (ep->ep_ops.ep_tx_credits)
- ep->ep_ops.ep_tx_credits(htc->ar);
- }
+ ath10k_htc_release_credit(ep, skb_len);
err_pull:
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
return ret;
@@ -581,6 +618,258 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc,
return allocation;
}
+static int ath10k_htc_send_bundle(struct ath10k_htc_ep *ep,
+ struct sk_buff *bundle_skb,
+ struct sk_buff_head *tx_save_head)
+{
+ struct ath10k_hif_sg_item sg_item;
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ struct sk_buff *skb;
+ int ret = 0;
+ int cn = 0;
+ unsigned int skb_len;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle skb: len:%d\n", bundle_skb->len);
+ skb_len = bundle_skb->len;
+ ret = ath10k_htc_consume_credit(ep, skb_len, true);
+
+ if (!ret) {
+ sg_item.transfer_id = ep->eid;
+ sg_item.transfer_context = bundle_skb;
+ sg_item.vaddr = bundle_skb->data;
+ sg_item.len = bundle_skb->len;
+
+ ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1);
+ if (ret)
+ ath10k_htc_release_credit(ep, skb_len);
+ }
+
+ if (ret)
+ dev_kfree_skb_any(bundle_skb);
+
+ while (true) {
+ skb = skb_dequeue_tail(tx_save_head);
+ if (!skb)
+ break;
+
+ cn++;
+ if (ret) {
+ skb_pull(skb, sizeof(struct ath10k_htc_hdr));
+ skb_queue_head(&ep->tx_req_head, skb);
+ } else {
+ skb_queue_tail(&ep->tx_complete_head, skb);
+ }
+ }
+
+ if (!ret)
+ queue_work(ar->workqueue_tx_complete, &ar->tx_complete_work);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "bundle tx status:%d, eid:%d, req count:%d, count:%d, len:%d\n",
+ ret, ep->eid, skb_queue_len(&ep->tx_req_head), cn, bundle_skb->len);
+ return ret;
+}
+
+static void ath10k_htc_send_one_skb(struct ath10k_htc_ep *ep, struct sk_buff *skb)
+{
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ int ret;
+
+ ret = ath10k_htc_send(htc, ep->eid, skb);
+
+ if (ret)
+ skb_queue_head(&ep->tx_req_head, skb);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "tx one status:%d, eid:%d, len:%d, pending count:%d\n",
+ ret, ep->eid, skb->len, skb_queue_len(&ep->tx_req_head));
+}
+
+static int ath10k_htc_send_bundle_skbs(struct ath10k_htc_ep *ep)
+{
+ int ret = 0;
+ struct ath10k_htc *htc = ep->htc;
+ struct sk_buff *bundle_skb, *skb;
+ struct sk_buff_head tx_save_head;
+ struct ath10k_htc_hdr *hdr;
+ u8 *bundle_buf;
+ int credit_pad, credit_remainder, trans_len, bundles_left = 0;
+
+ if (htc->ar->state == ATH10K_STATE_WEDGED)
+ return -ECOMM;
+
+ if (ep->tx_credit_flow_enabled &&
+ ep->tx_credits < HTC_HOST_MIN_CREDIT_PER_TX_BUNDLE)
+ return 0;
+
+ bundles_left = HTC_HOST_MAX_MSG_PER_TX_BUNDLE * ep->tx_credit_size;
+ bundle_skb = dev_alloc_skb(bundles_left);
+
+ if (!bundle_skb)
+ return -ENOMEM;
+
+ bundle_buf = bundle_skb->data;
+ skb_queue_head_init(&tx_save_head);
+
+ while (true) {
+ skb = skb_dequeue(&ep->tx_req_head);
+ if (!skb)
+ break;
+
+ credit_pad = 0;
+ trans_len = skb->len + sizeof(*hdr);
+ credit_remainder = trans_len % ep->tx_credit_size;
+
+ if (credit_remainder != 0) {
+ credit_pad = ep->tx_credit_size - credit_remainder;
+ trans_len += credit_pad;
+ }
+
+ ret = ath10k_htc_consume_credit(ep,
+ bundle_buf + trans_len - bundle_skb->data,
+ false);
+ if (ret) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ break;
+ }
+
+ if (bundles_left < trans_len) {
+ bundle_skb->len = bundle_buf - bundle_skb->data;
+ ret = ath10k_htc_send_bundle(ep, bundle_skb, &tx_save_head);
+
+ if (ret) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ return ret;
+ }
+
+ if (skb_queue_len(&ep->tx_req_head) == 0) {
+ ath10k_htc_send_one_skb(ep, skb);
+ return ret;
+ }
+
+ if (ep->tx_credit_flow_enabled &&
+ ep->tx_credits < HTC_HOST_MIN_CREDIT_PER_TX_BUNDLE) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ return 0;
+ }
+
+ bundles_left =
+ HTC_HOST_MAX_MSG_PER_TX_BUNDLE * ep->tx_credit_size;
+ bundle_skb = dev_alloc_skb(bundles_left);
+
+ if (!bundle_skb) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ return -ENOMEM;
+ }
+ bundle_buf = bundle_skb->data;
+ skb_queue_head_init(&tx_save_head);
+ }
+
+ skb_push(skb, sizeof(struct ath10k_htc_hdr));
+ ath10k_htc_prepare_tx_skb(ep, skb);
+
+ memcpy(bundle_buf, skb->data, skb->len);
+ hdr = (struct ath10k_htc_hdr *)bundle_buf;
+ hdr->flags |= ATH10K_HTC_FLAG_SEND_BUNDLE;
+ hdr->pad_len = __cpu_to_le16(credit_pad);
+ bundle_buf += trans_len;
+ bundles_left -= trans_len;
+ skb_queue_tail(&tx_save_head, skb);
+ }
+
+ if (bundle_buf != bundle_skb->data) {
+ bundle_skb->len = bundle_buf - bundle_skb->data;
+ ret = ath10k_htc_send_bundle(ep, bundle_skb, &tx_save_head);
+ } else {
+ dev_kfree_skb_any(bundle_skb);
+ }
+
+ return ret;
+}
+
+static void ath10k_htc_bundle_tx_work(struct work_struct *work)
+{
+ struct ath10k *ar = container_of(work, struct ath10k, bundle_tx_work);
+ int i;
+ struct ath10k_htc_ep *ep;
+ enum ath10k_htc_ep_id eid;
+ struct sk_buff *skb;
+
+ for (i = 0; i < ARRAY_SIZE(ar->htc.endpoint); i++) {
+ ep = &ar->htc.endpoint[i];
+ eid = ep->eid;
+ if (ep->bundle_tx) {
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle tx work, eid:%d, count:%d\n",
+ ep->eid, skb_queue_len(&ep->tx_req_head));
+
+ if (skb_queue_len(&ep->tx_req_head) >=
+ HTC_HOST_MIN_MSG_PER_TX_BUNDLE) {
+ ath10k_htc_send_bundle_skbs(ep);
+ } else {
+ skb = skb_dequeue(&ep->tx_req_head);
+
+ if (!skb)
+ continue;
+ ath10k_htc_send_one_skb(ep, skb);
+ }
+ }
+ }
+}
+
+static void ath10k_htc_tx_complete_work(struct work_struct *work)
+{
+ struct ath10k *ar = container_of(work, struct ath10k, tx_complete_work);
+ int i;
+ struct ath10k_htc_ep *ep;
+ enum ath10k_htc_ep_id eid;
+ struct sk_buff *skb;
+
+ for (i = 0; i < ARRAY_SIZE(ar->htc.endpoint); i++) {
+ ep = &ar->htc.endpoint[i];
+ eid = ep->eid;
+ if (ep->bundle_tx && eid == ar->htt.eid) {
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle tx complete, eid:%d, pending complete count:%d\n",
+ ep->eid, skb_queue_len(&ep->tx_complete_head));
+
+ while (true) {
+ skb = skb_dequeue(&ep->tx_complete_head);
+ if (!skb)
+ break;
+ ath10k_htc_notify_tx_completion(ep, skb);
+ }
+ }
+ }
+}
+
+int ath10k_htc_send_hl(struct ath10k_htc *htc,
+ enum ath10k_htc_ep_id eid,
+ struct sk_buff *skb)
+{
+ struct ath10k_htc_ep *ep = &htc->endpoint[eid];
+ struct ath10k *ar = htc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc send hl: eid:%d, bundle:%d, tx count:%d, len:%d\n",
+ eid, ep->bundle_tx, skb_queue_len(&ep->tx_req_head), skb->len);
+
+ if (ep->bundle_tx) {
+ skb_queue_tail(&ep->tx_req_head, skb);
+ queue_work(ar->workqueue, &ar->bundle_tx_work);
+ return 0;
+ } else {
+ return ath10k_htc_send(htc, eid, skb);
+ }
+}
+
+void ath10k_htc_setup_tx_req(struct ath10k_htc_ep *ep)
+{
+ if (ep->htc->max_msgs_per_htc_bundle >= HTC_HOST_MIN_MSG_PER_TX_BUNDLE) {
+ ep->bundle_tx = true;
+ skb_queue_head_init(&ep->tx_req_head);
+ skb_queue_head_init(&ep->tx_complete_head);
+ }
+}
+
int ath10k_htc_wait_target(struct ath10k_htc *htc)
{
struct ath10k *ar = htc->ar;
@@ -657,6 +946,9 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
htc->max_msgs_per_htc_bundle);
}
+ INIT_WORK(&ar->bundle_tx_work, ath10k_htc_bundle_tx_work);
+ INIT_WORK(&ar->tx_complete_work, ath10k_htc_tx_complete_work);
+
return 0;
}
@@ -802,6 +1094,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
ep->max_tx_queue_depth = conn_req->max_send_queue_depth;
ep->max_ep_message_len = __le16_to_cpu(resp_msg->max_msg_size);
ep->tx_credits = tx_alloc;
+ ep->tx_credit_size = htc->target_credit_size;
/* copy all the callbacks */
ep->ep_ops = conn_req->ep_ops;
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 78bc3ae..621ac89 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -40,6 +40,9 @@
*/
#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
+#define HTC_HOST_MAX_MSG_PER_TX_BUNDLE 32
+#define HTC_HOST_MIN_MSG_PER_TX_BUNDLE 2
+#define HTC_HOST_MIN_CREDIT_PER_TX_BUNDLE 2
enum ath10k_htc_tx_flags {
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
@@ -64,8 +67,14 @@ struct ath10k_htc_hdr {
u8 seq_no; /* for tx */
u8 control_byte1;
} __packed;
- u8 pad0;
- u8 pad1;
+ union {
+ __le16 pad_len;
+ struct {
+ u8 pad0;
+ u8 pad1;
+ } __packed;
+ } __packed;
+
} __packed __aligned(4);
enum ath10k_ath10k_htc_msg_id {
@@ -334,7 +343,12 @@ struct ath10k_htc_ep {
u8 seq_no; /* for debugging */
int tx_credits;
+ int tx_credit_size;
bool tx_credit_flow_enabled;
+ bool bundle_tx;
+ struct sk_buff_head tx_req_head;
+ struct sk_buff_head tx_complete_head;
+
};
struct ath10k_htc_svc_tx_credits {
@@ -363,6 +377,7 @@ struct ath10k_htc {
int ath10k_htc_init(struct ath10k *ar);
int ath10k_htc_wait_target(struct ath10k_htc *htc);
+void ath10k_htc_setup_tx_req(struct ath10k_htc_ep *ep);
int ath10k_htc_start(struct ath10k_htc *htc);
int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
@@ -372,6 +387,8 @@ void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
bool enable);
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
struct sk_buff *packet);
+int ath10k_htc_send_hl(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
+ struct sk_buff *packet);
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 88f3321..38b5141 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -135,6 +135,8 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
{
struct ath10k_htc_svc_conn_req conn_req;
struct ath10k_htc_svc_conn_resp conn_resp;
+ struct ath10k *ar = htt->ar;
+ struct ath10k_htc_ep *ep;
int status;
memset(&conn_req, 0, sizeof(conn_req));
@@ -142,6 +144,7 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
conn_req.ep_ops.ep_tx_complete = ath10k_htt_htc_tx_complete;
conn_req.ep_ops.ep_rx_complete = ath10k_htt_htc_t2h_msg_handler;
+ conn_req.ep_ops.ep_tx_credits = ath10k_htt_op_ep_tx_credits;
/* connect to control service */
conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG;
@@ -154,6 +157,11 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
htt->eid = conn_resp.eid;
+ if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) {
+ ep = &ar->htc.endpoint[htt->eid];
+ ath10k_htc_setup_tx_req(ep);
+ }
+
htt->disable_tx_comple = ath10k_hif_get_htt_tx_complete(htt->ar);
if (htt->disable_tx_comple)
ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index cf97be5..d2e5ea6 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -2030,6 +2030,10 @@ struct ath10k_htt {
const struct ath10k_htt_tx_ops *tx_ops;
const struct ath10k_htt_rx_ops *rx_ops;
bool disable_tx_comple;
+ bool bundle_tx;
+ struct sk_buff_head tx_req_head;
+ struct sk_buff_head tx_complete_head;
+
};
struct ath10k_htt_tx_ops {
@@ -2276,6 +2280,7 @@ int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
__le16 fetch_seq_num,
struct htt_tx_fetch_record *records,
size_t num_records);
+void ath10k_htt_op_ep_tx_credits(struct ath10k *ar);
void ath10k_htt_tx_txq_update(struct ieee80211_hw *hw,
struct ieee80211_txq *txq);
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index d808824..8651a3b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -3824,6 +3824,7 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_HTT,
"credit total:%d\n",
ep->tx_credits);
+ ep->ep_ops.ep_tx_credits(htc->ar);
}
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index cda8a59..2894920 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -541,6 +541,11 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
ath10k_htt_tx_destroy(htt);
}
+void ath10k_htt_op_ep_tx_credits(struct ath10k *ar)
+{
+ queue_work(ar->workqueue, &ar->bundle_tx_work);
+}
+
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
@@ -559,7 +564,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
flags1 = __le16_to_cpu(desc_hdr->flags1);
ath10k_dbg(ar, ATH10K_DBG_HTT,
- "ath10k_htt_htc_tx_complete msdu id:%u ,flags1:%x\n",
+ "htt htc tx complete msdu id:%u ,flags1:%x\n",
__le16_to_cpu(desc_hdr->id), flags1);
if (flags1 & HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE)
@@ -1356,7 +1361,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
*/
tx_desc->peerid = __cpu_to_le32(HTT_INVALID_PEERID);
- res = ath10k_htc_send(&htt->ar->htc, htt->eid, msdu);
+ res = ath10k_htc_send_hl(&htt->ar->htc, htt->eid, msdu);
out:
return res;
--
1.9.1
For tcp RX, the quantity of tcp acks to remote is 1/2 of the quantity
of tcp data from remote, then it will have many small length packets
on TX path of sdio bus, then it reduce the RX packets's bandwidth of
tcp.
This patch enable napi on RX path, then the RX packet of tcp will not
feed to tcp stack immeditely from mac80211 since GRO is enabled by
default, it will feed to tcp stack after napi complete, if rx bundle
is enabled, then it will feed to tcp stack one time for each bundle
of RX. For example, RX bundle size is 32, then tcp stack will receive
one large length packet, its length is neary 1500*32, then tcp stack
will send a tcp ack for this large packet, this will reduce the tcp
acks ratio from 1/2 to 1/32. This results in significant performance
improvement for tcp RX.
Tcp rx throughout is 240Mbps without this patch, and it arrive 390Mbps
with this patch. The cpu usage has no obvious difference with and
without NAPI.
call stack for each RX packet on GRO path:
(skb length is about 1500 bytes)
skb_gro_receive ([kernel.kallsyms])
tcp4_gro_receive ([kernel.kallsyms])
inet_gro_receive ([kernel.kallsyms])
dev_gro_receive ([kernel.kallsyms])
napi_gro_receive ([kernel.kallsyms])
ieee80211_deliver_skb ([mac80211])
ieee80211_rx_handlers ([mac80211])
ieee80211_prepare_and_rx_handle ([mac80211])
ieee80211_rx_napi ([mac80211])
ath10k_htt_rx_proc_rx_ind_hl ([ath10k_core])
ath10k_htt_rx_pktlog_completion_handler ([ath10k_core])
ath10k_sdio_napi_poll ([ath10k_sdio])
net_rx_action ([kernel.kallsyms])
softirqentry_text_start ([kernel.kallsyms])
do_softirq ([kernel.kallsyms])
call stack for napi complete and send tcp ack from tcp stack:
(skb length is about 1500*32 bytes)
_tcp_ack_snd_check ([kernel.kallsyms])
tcp_v4_do_rcv ([kernel.kallsyms])
tcp_v4_rcv ([kernel.kallsyms])
local_deliver_finish ([kernel.kallsyms])
ip_local_deliver ([kernel.kallsyms])
ip_rcv_finish ([kernel.kallsyms])
ip_rcv ([kernel.kallsyms])
netif_receive_skb_core ([kernel.kallsyms])
netif_receive_skb_one_core([kernel.kallsyms])
netif_receive_skb ([kernel.kallsyms])
netif_receive_skb_internal ([kernel.kallsyms])
napi_gro_complete ([kernel.kallsyms])
napi_gro_flush ([kernel.kallsyms])
napi_complete_done ([kernel.kallsyms])
ath10k_sdio_napi_poll ([ath10k_sdio])
net_rx_action ([kernel.kallsyms])
__softirqentry_text_start ([kernel.kallsyms])
do_softirq ([kernel.kallsyms])
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <[email protected]>
---
drivers/net/wireless/ath/ath10k/htt.c | 2 ++
drivers/net/wireless/ath/ath10k/htt.h | 3 +++
drivers/net/wireless/ath/ath10k/htt_rx.c | 46 ++++++++++++++++++++++++++------
drivers/net/wireless/ath/ath10k/sdio.c | 33 +++++++++++++++++++++++
4 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 38b5141..04ca13c 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -157,6 +157,8 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
htt->eid = conn_resp.eid;
+ skb_queue_head_init(&htt->rx_indication_head);
+
if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) {
ep = &ar->htc.endpoint[htt->eid];
ath10k_htc_setup_tx_req(ep);
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index d2e5ea6..321bd2c 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1879,6 +1879,8 @@ struct ath10k_htt {
struct ath10k *ar;
enum ath10k_htc_ep_id eid;
+ struct sk_buff_head rx_indication_head;
+
u8 target_version_major;
u8 target_version_minor;
struct completion target_version_received;
@@ -2299,6 +2301,7 @@ int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
struct sk_buff *skb);
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget);
+int ath10k_htt_rx_hl_indication(struct ath10k *ar, int budget);
void ath10k_htt_set_tx_ops(struct ath10k_htt *htt);
void ath10k_htt_set_rx_ops(struct ath10k_htt *htt);
#endif
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 8651a3b..7a01d12 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2263,7 +2263,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
rx_status->flag |= RX_FLAG_MMIC_ERROR;
- ieee80211_rx_ni(ar->hw, skb);
+ ieee80211_rx_napi(ar->hw, NULL, skb, &ar->napi);
/* We have delivered the skb to the upper layers (mac80211) so we
* must not free it.
@@ -3664,14 +3664,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_RX_IND:
- if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL)
- return ath10k_htt_rx_proc_rx_ind_hl(htt,
- &resp->rx_ind_hl,
- skb,
- HTT_RX_PN_CHECK,
- HTT_RX_NON_TKIP_MIC);
- else
+ if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL) {
ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind);
+ } else {
+ skb_queue_tail(&htt->rx_indication_head, skb);
+ return false;
+ }
break;
case HTT_T2H_MSG_TYPE_PEER_MAP: {
struct htt_peer_map_event ev = {
@@ -3898,6 +3896,38 @@ static int ath10k_htt_rx_deliver_msdu(struct ath10k *ar, int quota, int budget)
return quota;
}
+int ath10k_htt_rx_hl_indication(struct ath10k *ar, int budget)
+{
+ struct htt_resp *resp;
+ struct ath10k_htt *htt = &ar->htt;
+ struct sk_buff *skb;
+ bool release;
+ int quota = 0;
+
+ while (quota < budget) {
+ skb = skb_dequeue(&htt->rx_indication_head);
+ if (!skb)
+ break;
+
+ resp = (struct htt_resp *)skb->data;
+
+ release = ath10k_htt_rx_proc_rx_ind_hl(htt,
+ &resp->rx_ind_hl,
+ skb,
+ HTT_RX_PN_CHECK,
+ HTT_RX_NON_TKIP_MIC);
+
+ if (release)
+ dev_kfree_skb_any(skb);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "rx indication poll pending count:%d\n",
+ skb_queue_len(&htt->rx_indication_head));
+ quota++;
+ }
+ return quota;
+}
+EXPORT_SYMBOL(ath10k_htt_rx_hl_indication);
+
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
{
struct ath10k_htt *htt = &ar->htt;
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 4d6da04..e6ff129 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1406,6 +1406,9 @@ static void ath10k_rx_indication_async_work(struct work_struct *work)
spin_lock_bh(&ar_sdio->wr_async_lock_rx);
}
+ if (test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
+ napi_schedule(&ar->napi);
+
spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
}
@@ -1824,6 +1827,8 @@ static int ath10k_sdio_hif_start(struct ath10k *ar)
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
int ret;
+ napi_enable(&ar->napi);
+
/* Sleep 20 ms before HIF interrupts are disabled.
* This will give target plenty of time to process the BMI done
* request before interrupts are disabled.
@@ -1962,6 +1967,9 @@ static void ath10k_sdio_hif_stop(struct ath10k *ar)
}
spin_unlock_bh(&ar_sdio->wr_async_lock);
+
+ napi_synchronize(&ar->napi);
+ napi_disable(&ar->napi);
}
#ifdef CONFIG_PM
@@ -2138,6 +2146,26 @@ static SIMPLE_DEV_PM_OPS(ath10k_sdio_pm_ops, ath10k_sdio_pm_suspend,
#endif /* CONFIG_PM_SLEEP */
+static int ath10k_sdio_napi_poll(struct napi_struct *ctx, int budget)
+{
+ struct ath10k *ar = container_of(ctx, struct ath10k, napi);
+ int done = 0;
+
+ done = ath10k_htt_rx_hl_indication(ar, budget);
+ ath10k_dbg(ar, ATH10K_DBG_SDIO, "napi poll: done: %d,budget:%d\n", done, budget);
+
+ if (done < budget)
+ napi_complete_done(ctx, done);
+
+ return done;
+}
+
+void ath10k_sdio_init_napi(struct ath10k *ar)
+{
+ netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_sdio_napi_poll,
+ ATH10K_NAPI_BUDGET);
+}
+
static int ath10k_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -2163,6 +2191,8 @@ static int ath10k_sdio_probe(struct sdio_func *func,
return -ENOMEM;
}
+ ath10k_sdio_init_napi(ar);
+
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
func->num, func->vendor, func->device,
@@ -2283,6 +2313,9 @@ static void ath10k_sdio_remove(struct sdio_func *func)
func->num, func->vendor, func->device);
ath10k_core_unregister(ar);
+
+ netif_napi_del(&ar->napi);
+
ath10k_core_destroy(ar);
flush_workqueue(ar_sdio->workqueue);
--
1.9.1
From: Alagu Sankar <[email protected]>
The existing implementation of initiating multiple sdio transfers for
receive bundling is slowing down the receive speed. Combining the
transfers using a bundle method would be ideal.
The transmission utilization ratio for sdio bus for small packet is
slow, because the space and time cost for sdio bus is same for large
length packet and small length packet. So the speed of data for large
length packet is higher than small length.
Test result of different length of data:
data packet(byte) cost time(us) calculated rate(Mbps)
256 28 73
512 33 124
1024 35 234
1792 45 318
14336 168 682
28672 333 688
57344 660 695
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Alagu Sankar <[email protected]>
Signed-off-by: Wen Gong <[email protected]>
---
drivers/net/wireless/ath/ath10k/sdio.c | 101 ++++++++++++++++++++++++---------
drivers/net/wireless/ath/ath10k/sdio.h | 7 ++-
2 files changed, 79 insertions(+), 29 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 8ed4fbd..d9395f0 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -24,6 +24,9 @@
#include "trace.h"
#include "sdio.h"
+#define ATH10K_SDIO_DMA_BUF_SIZE (32 * 1024)
+#define ATH10K_SDIO_VSG_BUF_SIZE (32 * 1024)
+
/* inlined helper functions */
static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
@@ -489,11 +492,11 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
return ret;
}
-static int ath10k_sdio_mbox_alloc_pkt_bundle(struct ath10k *ar,
- struct ath10k_sdio_rx_data *rx_pkts,
- struct ath10k_htc_hdr *htc_hdr,
- size_t full_len, size_t act_len,
- size_t *bndl_cnt)
+static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
+ struct ath10k_sdio_rx_data *rx_pkts,
+ struct ath10k_htc_hdr *htc_hdr,
+ size_t full_len, size_t act_len,
+ size_t *bndl_cnt)
{
int ret, i;
@@ -534,6 +537,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
size_t full_len, act_len;
bool last_in_bundle;
int ret, i;
+ int pkt_cnt = 0;
if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) {
ath10k_warn(ar,
@@ -577,20 +581,22 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
*/
size_t bndl_cnt;
- ret = ath10k_sdio_mbox_alloc_pkt_bundle(ar,
- &ar_sdio->rx_pkts[i],
- htc_hdr,
- full_len,
- act_len,
- &bndl_cnt);
+ struct ath10k_sdio_rx_data *rx_pkts =
+ &ar_sdio->rx_pkts[pkt_cnt];
+
+ ret = ath10k_sdio_mbox_alloc_bundle(ar,
+ rx_pkts,
+ htc_hdr,
+ full_len,
+ act_len,
+ &bndl_cnt);
if (ret) {
ath10k_warn(ar, "alloc_bundle error %d\n", ret);
goto err;
}
- n_lookaheads += bndl_cnt;
- i += bndl_cnt;
+ pkt_cnt += bndl_cnt;
/*Next buffer will be the last in the bundle */
last_in_bundle = true;
}
@@ -602,7 +608,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
if (htc_hdr->flags & ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK)
full_len += ATH10K_HIF_MBOX_BLOCK_SIZE;
- ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[i],
+ ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[pkt_cnt],
act_len,
full_len,
last_in_bundle,
@@ -611,9 +617,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
ath10k_warn(ar, "alloc_rx_pkt error %d\n", ret);
goto err;
}
+ pkt_cnt++;
}
- ar_sdio->n_rx_pkts = i;
+ ar_sdio->n_rx_pkts = pkt_cnt;
return 0;
@@ -627,41 +634,72 @@ 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 sk_buff *skb = pkt->skb;
+ struct ath10k_sdio_rx_data *pkt = &ar_sdio->rx_pkts[0];
+ struct sk_buff *skb;
int ret;
+ skb = pkt->skb;
ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
skb->data, pkt->alloc_len);
- pkt->status = ret;
- if (!ret)
+
+ if (ret) {
+ ar_sdio->n_rx_pkts = 0;
+ ath10k_sdio_mbox_free_rx_pkt(pkt);
+ } else {
+ pkt->status = ret;
skb_put(skb, pkt->act_len);
+ }
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, virt_pkt_len;
+ virt_pkt_len = 0;
for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
- ret = ath10k_sdio_mbox_rx_packet(ar,
- &ar_sdio->rx_pkts[i]);
- if (ret)
+ virt_pkt_len += ar_sdio->rx_pkts[i].alloc_len;
+ }
+
+ if (virt_pkt_len < ATH10K_SDIO_DMA_BUF_SIZE) {
+ ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
+ ar_sdio->vsg_buffer, virt_pkt_len);
+ if (ret) {
+ i = 0;
goto err;
+ }
+ } else {
+ ath10k_err(ar, "size exceeding limit %d\n", virt_pkt_len);
+ }
+
+ pkt_offset = 0;
+ for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
+ struct sk_buff *skb = ar_sdio->rx_pkts[i].skb;
+
+ pkt = &ar_sdio->rx_pkts[i];
+ memcpy(skb->data, ar_sdio->vsg_buffer + pkt_offset,
+ pkt->alloc_len);
+ pkt->status = 0;
+ skb_put(skb, pkt->act_len);
+ 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;
}
@@ -704,7 +742,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
@@ -1112,7 +1153,7 @@ static int ath10k_sdio_bmi_get_rx_lookahead(struct ath10k *ar)
MBOX_HOST_INT_STATUS_ADDRESS,
&rx_word);
if (ret) {
- ath10k_warn(ar, "unable to read RX_LOOKAHEAD_VALID: %d\n", ret);
+ ath10k_warn(ar, "unable to read rx_lookahd: %d\n", ret);
return ret;
}
@@ -2007,6 +2048,12 @@ static int ath10k_sdio_probe(struct sdio_func *func,
goto err_core_destroy;
}
+ ar_sdio->vsg_buffer = devm_kmalloc(ar->dev, ATH10K_SDIO_VSG_BUF_SIZE, GFP_KERNEL);
+ if (!ar_sdio->vsg_buffer) {
+ ret = -ENOMEM;
+ goto err_core_destroy;
+ }
+
ar_sdio->irq_data.irq_en_reg =
devm_kzalloc(ar->dev, sizeof(struct ath10k_sdio_irq_enable_regs),
GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index b8c7ac0..4896eca 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -138,8 +138,8 @@ struct ath10k_sdio_irq_proc_regs {
u8 rx_lookahead_valid;
u8 host_int_status2;
u8 gmbox_rx_avail;
- __le32 rx_lookahead[2];
- __le32 rx_gmbox_lookahead_alias[2];
+ __le32 rx_lookahead[2 * ATH10K_HIF_MBOX_NUM_MAX];
+ __le32 int_status_enable;
};
struct ath10k_sdio_irq_enable_regs {
@@ -196,6 +196,9 @@ struct ath10k_sdio {
struct ath10k *ar;
struct ath10k_sdio_irq_data irq_data;
+ /* temporary buffer for sdio read */
+ u8 *vsg_buffer;
+
/* temporary buffer for BMI requests */
u8 *bmi_buf;
--
1.9.1
Wen Gong <[email protected]> writes:
> The max bundle size support by firmware is 32, change it from 8 to 32
> will help performance. This results in significant performance
> improvement on RX path.
What happens when the hardware doesn't have enough data to fill a
bundle? Does it send a smaller one, or does it wait until it can fill
it?
-Toke
Wen Gong <[email protected]> writes:
> Tx complete message from firmware cost bus bandwidth of sdio, and bus
> bandwidth is the bollteneck of throughput, it will effect the bandwidth
> occupancy of data packet of TX and RX.
>
> This patch disable TX complete indication from firmware for htt data
> packet, it results in significant performance improvement on TX path.
Wait, how does that work? Am I understanding it correctly that this
replaces a per-packet TX completion with a periodic one sent out of
band?
And could you explain what the credits thing is for, please? :)
-Toke
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Toke
> H?iland-J?rgensen
> Sent: Tuesday, August 20, 2019 8:23 PM
> To: Wen Gong <[email protected]>; [email protected]
> Cc: [email protected]
> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
> 32 for sdio
>
> Wen Gong <[email protected]> writes:
>
> > The max bundle size support by firmware is 32, change it from 8 to 32
> > will help performance. This results in significant performance
> > improvement on RX path.
>
> What happens when the hardware doesn't have enough data to fill a
> bundle? Does it send a smaller one, or does it wait until it can fill
> it?
>
The bundle is filled by firmware.
It will not wait until it can fill it.
For example, if you do ping per second, it will have only 1 ping packet
In the bundle.
> -Toke
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Toke
> H?iland-J?rgensen
> Sent: Tuesday, August 20, 2019 8:24 PM
> To: Wen Gong <[email protected]>; [email protected]
> Cc: [email protected]
> Subject: [EXT] Re: [PATCH 4/7] ath10k: disable TX complete indication of htt
> for sdio
>
> Wen Gong <[email protected]> writes:
>
> > Tx complete message from firmware cost bus bandwidth of sdio, and bus
> > bandwidth is the bollteneck of throughput, it will effect the bandwidth
> > occupancy of data packet of TX and RX.
> >
> > This patch disable TX complete indication from firmware for htt data
> > packet, it results in significant performance improvement on TX path.
>
> Wait, how does that work? Am I understanding it correctly that this
> replaces a per-packet TX completion with a periodic one sent out of
> band?
When this patch applied, firmware will not indicate tx complete for tx
Data, it only indicate HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
This htt msg will tell how many data tx complete without status(status maybe success/fail).
>
> And could you explain what the credits thing is for, please? :)
For high latency bus chip, all the tx data's content(include ip/udp/tcp header
and payload) will be transfer to firmware's memory via bus.
And firmware has limited memory for tx data, the tx data's content must
Saved in firmware memory before it tx complete, if ath10k transfer tx
data more than the limit, firmware will occur error. The credit is used
to avoid ath10k exceed the limit.
>
> -Toke
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
Wen Gong <[email protected]> writes:
>> -----Original Message-----
>> From: ath10k <[email protected]> On Behalf Of Toke
>> Høiland-Jørgensen
>> Sent: Tuesday, August 20, 2019 8:23 PM
>> To: Wen Gong <[email protected]>; [email protected]
>> Cc: [email protected]
>> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
>> 32 for sdio
>>
>> Wen Gong <[email protected]> writes:
>>
>> > The max bundle size support by firmware is 32, change it from 8 to 32
>> > will help performance. This results in significant performance
>> > improvement on RX path.
>>
>> What happens when the hardware doesn't have enough data to fill a
>> bundle? Does it send a smaller one, or does it wait until it can fill
>> it?
>>
>
> The bundle is filled by firmware.
> It will not wait until it can fill it.
> For example, if you do ping per second, it will have only 1 ping packet
> In the bundle.
Right, cool.
-Toke
Wen Gong <[email protected]> writes:
>> -----Original Message-----
>> From: ath10k <[email protected]> On Behalf Of Toke
>> Høiland-Jørgensen
>> Sent: Tuesday, August 20, 2019 8:24 PM
>> To: Wen Gong <[email protected]>; [email protected]
>> Cc: [email protected]
>> Subject: [EXT] Re: [PATCH 4/7] ath10k: disable TX complete indication of htt
>> for sdio
>>
>> Wen Gong <[email protected]> writes:
>>
>> > Tx complete message from firmware cost bus bandwidth of sdio, and bus
>> > bandwidth is the bollteneck of throughput, it will effect the bandwidth
>> > occupancy of data packet of TX and RX.
>> >
>> > This patch disable TX complete indication from firmware for htt data
>> > packet, it results in significant performance improvement on TX path.
>>
>> Wait, how does that work? Am I understanding it correctly that this
>> replaces a per-packet TX completion with a periodic one sent out of
>> band?
> When this patch applied, firmware will not indicate tx complete for tx
> Data, it only indicate HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
> This htt msg will tell how many data tx complete without status(status maybe success/fail).
Ah, so this is basically a counter of how much data is currently queued
in the firmware?
>> And could you explain what the credits thing is for, please? :)
> For high latency bus chip, all the tx data's content(include ip/udp/tcp header
> and payload) will be transfer to firmware's memory via bus.
> And firmware has limited memory for tx data, the tx data's content must
> Saved in firmware memory before it tx complete, if ath10k transfer tx
> data more than the limit, firmware will occur error. The credit is used
> to avoid ath10k exceed the limit.
What's a typical limit in the firmware?
-Toke
> -----Original Message-----
> From: Toke Høiland-Jørgensen <[email protected]>
> Sent: Wednesday, August 21, 2019 6:10 PM
> To: Wen Gong <[email protected]>; Wen Gong
> <[email protected]>; [email protected]
> Cc: [email protected]
> Subject: [EXT] RE: [PATCH 4/7] ath10k: disable TX complete indication of htt
> for sdio
>
> Wen Gong <[email protected]> writes:
>
> >> -----Original Message-----
> >> From: ath10k <[email protected]> On Behalf Of Toke
> >> Høiland-Jørgensen
> >> Sent: Tuesday, August 20, 2019 8:24 PM
> >> To: Wen Gong <[email protected]>; [email protected]
> >> Cc: [email protected]
> >> Subject: [EXT] Re: [PATCH 4/7] ath10k: disable TX complete indication of
> htt
> > When this patch applied, firmware will not indicate tx complete for tx
> > Data, it only indicate HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
> > This htt msg will tell how many data tx complete without status(status
> maybe success/fail).
>
> Ah, so this is basically a counter of how much data is currently queued
> in the firmware?
Yes.
>
> >> And could you explain what the credits thing is for, please? :)
> > For high latency bus chip, all the tx data's content(include ip/udp/tcp
> header
> > and payload) will be transfer to firmware's memory via bus.
> > And firmware has limited memory for tx data, the tx data's content must
> > Saved in firmware memory before it tx complete, if ath10k transfer tx
> > data more than the limit, firmware will occur error. The credit is used
> > to avoid ath10k exceed the limit.
>
> What's a typical limit in the firmware?
It is 96 data packet in my test. It can changed in firmware code.
>
> -Toke
Wen Gong <[email protected]> writes:
>> -----Original Message-----
>> From: Toke Høiland-Jørgensen <[email protected]>
>> Sent: Wednesday, August 21, 2019 6:10 PM
>> To: Wen Gong <[email protected]>; Wen Gong
>> <[email protected]>; [email protected]
>> Cc: [email protected]
>> Subject: [EXT] RE: [PATCH 4/7] ath10k: disable TX complete indication of htt
>> for sdio
>>
>> Wen Gong <[email protected]> writes:
>>
>> >> -----Original Message-----
>> >> From: ath10k <[email protected]> On Behalf Of Toke
>> >> Høiland-Jørgensen
>> >> Sent: Tuesday, August 20, 2019 8:24 PM
>> >> To: Wen Gong <[email protected]>; [email protected]
>> >> Cc: [email protected]
>> >> Subject: [EXT] Re: [PATCH 4/7] ath10k: disable TX complete indication of
>> htt
>> > When this patch applied, firmware will not indicate tx complete for tx
>> > Data, it only indicate HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
>> > This htt msg will tell how many data tx complete without status(status
>> maybe success/fail).
>>
>> Ah, so this is basically a counter of how much data is currently queued
>> in the firmware?
> Yes.
>>
>> >> And could you explain what the credits thing is for, please? :)
>> > For high latency bus chip, all the tx data's content(include ip/udp/tcp
>> header
>> > and payload) will be transfer to firmware's memory via bus.
>> > And firmware has limited memory for tx data, the tx data's content must
>> > Saved in firmware memory before it tx complete, if ath10k transfer tx
>> > data more than the limit, firmware will occur error. The credit is used
>> > to avoid ath10k exceed the limit.
>>
>> What's a typical limit in the firmware?
> It is 96 data packet in my test. It can changed in firmware code.
Right, I see. Is this counter available in all ath10k firmware, or is it
SDIO only?
I'm asking because this could also be a way of implementing something
like Byte Queue Limits (though I'm not sure how effective it would be).
-Toke
> -----Original Message-----
> From: Toke Høiland-Jørgensen <[email protected]>
> Sent: Thursday, August 22, 2019 8:12 PM
> To: Wen Gong <[email protected]>; Wen Gong
> <[email protected]>; [email protected]
> Cc: [email protected]
> Subject: [EXT] RE: [PATCH 4/7] ath10k: disable TX complete indication of htt
> for sdio
> >> What's a typical limit in the firmware?
> > It is 96 data packet in my test. It can changed in firmware code.
>
> Right, I see. Is this counter available in all ath10k firmware, or is it
> SDIO only?
>
It is only for SDIO.
For PCIE, it does not have credit limit, firmware memory only need to save
The tx descriptor, not need for palyload.
> I'm asking because this could also be a way of implementing something
> like Byte Queue Limits (though I'm not sure how effective it would be).
>
> -Toke
Wen Gong <[email protected]> writes:
>> -----Original Message-----
>> From: Toke Høiland-Jørgensen <[email protected]>
>> Sent: Thursday, August 22, 2019 8:12 PM
>> To: Wen Gong <[email protected]>; Wen Gong
>> <[email protected]>; [email protected]
>> Cc: [email protected]
>> Subject: [EXT] RE: [PATCH 4/7] ath10k: disable TX complete indication of htt
>> for sdio
>> >> What's a typical limit in the firmware?
>> > It is 96 data packet in my test. It can changed in firmware code.
>>
>> Right, I see. Is this counter available in all ath10k firmware, or is it
>> SDIO only?
>>
> It is only for SDIO.
> For PCIE, it does not have credit limit, firmware memory only need to save
> The tx descriptor, not need for palyload.
OK, too bad. Thanks for the explanations :)
-Toke
On Tue, Aug 20, 2019 at 7:55 PM Wen Gong <[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. Combining the
> transfers using a bundle method would be ideal.
>
> The transmission utilization ratio for sdio bus for small packet is
> slow, because the space and time cost for sdio bus is same for large
> length packet and small length packet. So the speed of data for large
> length packet is higher than small length.
>
> Test result of different length of data:
> data packet(byte) cost time(us) calculated rate(Mbps)
> 256 28 73
> 512 33 124
> 1024 35 234
> 1792 45 318
> 14336 168 682
> 28672 333 688
> 57344 660 695
>
> Tested with QCA6174 SDIO with firmware
> WLAN.RMH.4.4.1-00007-QCARMSWP-1.
>
> Signed-off-by: Alagu Sankar <[email protected]>
> Signed-off-by: Wen Gong <[email protected]>
> ---
> drivers/net/wireless/ath/ath10k/sdio.c | 101 ++++++++++++++++++++++++---------
> drivers/net/wireless/ath/ath10k/sdio.h | 7 ++-
> 2 files changed, 79 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
> index 8ed4fbd..d9395f0 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.c
> +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> @@ -24,6 +24,9 @@
> #include "trace.h"
> #include "sdio.h"
>
> +#define ATH10K_SDIO_DMA_BUF_SIZE (32 * 1024)
> +#define ATH10K_SDIO_VSG_BUF_SIZE (32 * 1024)
> +
> /* inlined helper functions */
>
> static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
> @@ -489,11 +492,11 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
> return ret;
> }
>
> -static int ath10k_sdio_mbox_alloc_pkt_bundle(struct ath10k *ar,
> - struct ath10k_sdio_rx_data *rx_pkts,
> - struct ath10k_htc_hdr *htc_hdr,
> - size_t full_len, size_t act_len,
> - size_t *bndl_cnt)
> +static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
> + struct ath10k_sdio_rx_data *rx_pkts,
> + struct ath10k_htc_hdr *htc_hdr,
> + size_t full_len, size_t act_len,
> + size_t *bndl_cnt)
> {
> int ret, i;
>
> @@ -534,6 +537,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
> size_t full_len, act_len;
> bool last_in_bundle;
> int ret, i;
> + int pkt_cnt = 0;
>
> if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) {
> ath10k_warn(ar,
> @@ -577,20 +581,22 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
> */
> size_t bndl_cnt;
>
> - ret = ath10k_sdio_mbox_alloc_pkt_bundle(ar,
> - &ar_sdio->rx_pkts[i],
> - htc_hdr,
> - full_len,
> - act_len,
> - &bndl_cnt);
> + struct ath10k_sdio_rx_data *rx_pkts =
> + &ar_sdio->rx_pkts[pkt_cnt];
> +
> + ret = ath10k_sdio_mbox_alloc_bundle(ar,
> + rx_pkts,
> + htc_hdr,
> + full_len,
> + act_len,
> + &bndl_cnt);
>
> if (ret) {
> ath10k_warn(ar, "alloc_bundle error %d\n", ret);
> goto err;
> }
>
> - n_lookaheads += bndl_cnt;
> - i += bndl_cnt;
> + pkt_cnt += bndl_cnt;
> /*Next buffer will be the last in the bundle */
> last_in_bundle = true;
> }
> @@ -602,7 +608,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
> if (htc_hdr->flags & ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK)
> full_len += ATH10K_HIF_MBOX_BLOCK_SIZE;
>
> - ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[i],
> + ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[pkt_cnt],
> act_len,
> full_len,
> last_in_bundle,
> @@ -611,9 +617,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
> ath10k_warn(ar, "alloc_rx_pkt error %d\n", ret);
> goto err;
> }
> + pkt_cnt++;
> }
>
> - ar_sdio->n_rx_pkts = i;
> + ar_sdio->n_rx_pkts = pkt_cnt;
>
> return 0;
>
> @@ -627,41 +634,72 @@ 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 sk_buff *skb = pkt->skb;
> + struct ath10k_sdio_rx_data *pkt = &ar_sdio->rx_pkts[0];
> + struct sk_buff *skb;
> int ret;
>
> + skb = pkt->skb;
The code was a bit more compat before, why not keep this?
struct sk_buff *skb = pkt->skb;
> ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
> skb->data, pkt->alloc_len);
> - pkt->status = ret;
> - if (!ret)
> +
> + if (ret) {
> + ar_sdio->n_rx_pkts = 0;
> + ath10k_sdio_mbox_free_rx_pkt(pkt);
> + } else {
> + pkt->status = ret;
> skb_put(skb, pkt->act_len);
> + }
>
> 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, virt_pkt_len;
>
> + virt_pkt_len = 0;
> for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
> - ret = ath10k_sdio_mbox_rx_packet(ar,
> - &ar_sdio->rx_pkts[i]);
> - if (ret)
> + virt_pkt_len += ar_sdio->rx_pkts[i].alloc_len;
> + }
> +
> + if (virt_pkt_len < ATH10K_SDIO_DMA_BUF_SIZE) {
> + ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
> + ar_sdio->vsg_buffer, virt_pkt_len);
> + if (ret) {
> + i = 0;
> goto err;
> + }
> + } else {
> + ath10k_err(ar, "size exceeding limit %d\n", virt_pkt_len);
> + }
> +
> + pkt_offset = 0;
> + for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
> + struct sk_buff *skb = ar_sdio->rx_pkts[i].skb;
> +
> + pkt = &ar_sdio->rx_pkts[i];
> + memcpy(skb->data, ar_sdio->vsg_buffer + pkt_offset,
> + pkt->alloc_len);
Why do you copy alloc_len if you only plan to use act_len?
Actually, just use skb_put_data.
Also, do you have the same issue as
https://patchwork.kernel.org/patch/11116215/ w.r.t. act_len being
incorrect?
> + pkt->status = 0;
> + skb_put(skb, pkt->act_len);
> + 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;
> }
>
> @@ -704,7 +742,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
> @@ -1112,7 +1153,7 @@ static int ath10k_sdio_bmi_get_rx_lookahead(struct ath10k *ar)
> MBOX_HOST_INT_STATUS_ADDRESS,
> &rx_word);
> if (ret) {
> - ath10k_warn(ar, "unable to read RX_LOOKAHEAD_VALID: %d\n", ret);
> + ath10k_warn(ar, "unable to read rx_lookahd: %d\n", ret);
> return ret;
> }
>
> @@ -2007,6 +2048,12 @@ static int ath10k_sdio_probe(struct sdio_func *func,
> goto err_core_destroy;
> }
>
> + ar_sdio->vsg_buffer = devm_kmalloc(ar->dev, ATH10K_SDIO_VSG_BUF_SIZE, GFP_KERNEL);
> + if (!ar_sdio->vsg_buffer) {
> + ret = -ENOMEM;
> + goto err_core_destroy;
> + }
> +
> ar_sdio->irq_data.irq_en_reg =
> devm_kzalloc(ar->dev, sizeof(struct ath10k_sdio_irq_enable_regs),
> GFP_KERNEL);
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
> index b8c7ac0..4896eca 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.h
> +++ b/drivers/net/wireless/ath/ath10k/sdio.h
> @@ -138,8 +138,8 @@ struct ath10k_sdio_irq_proc_regs {
> u8 rx_lookahead_valid;
> u8 host_int_status2;
> u8 gmbox_rx_avail;
> - __le32 rx_lookahead[2];
> - __le32 rx_gmbox_lookahead_alias[2];
> + __le32 rx_lookahead[2 * ATH10K_HIF_MBOX_NUM_MAX];
> + __le32 int_status_enable;
> };
>
> struct ath10k_sdio_irq_enable_regs {
> @@ -196,6 +196,9 @@ struct ath10k_sdio {
> struct ath10k *ar;
> struct ath10k_sdio_irq_data irq_data;
>
> + /* temporary buffer for sdio read */
> + u8 *vsg_buffer;
> +
> /* temporary buffer for BMI requests */
> u8 *bmi_buf;
>
> --
> 1.9.1
>
On Tue, Aug 20, 2019 at 7:55 PM Wen Gong <[email protected]> wrote:
>
> The max bundle size support by firmware is 32, change it from 8 to 32
> will help performance. This results in significant performance
> improvement on RX path.
>
> Tested with QCA6174 SDIO with firmware
> WLAN.RMH.4.4.1-00007-QCARMSWP-1.
>
> Signed-off-by: Wen Gong <[email protected]>
> ---
> drivers/net/wireless/ath/ath10k/htc.h | 2 +-
> drivers/net/wireless/ath/ath10k/sdio.c | 5 +++--
> drivers/net/wireless/ath/ath10k/sdio.h | 4 ++--
> 3 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
> index f55d3ca..8c79b9e 100644
> --- a/drivers/net/wireless/ath/ath10k/htc.h
> +++ b/drivers/net/wireless/ath/ath10k/htc.h
> @@ -39,7 +39,7 @@
> * 4-byte aligned.
> */
>
> -#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 8
> +#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
>
> enum ath10k_htc_tx_flags {
> ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
> index d9395f0..baa6051 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.c
> +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> @@ -24,8 +24,8 @@
> #include "trace.h"
> #include "sdio.h"
>
> -#define ATH10K_SDIO_DMA_BUF_SIZE (32 * 1024)
> -#define ATH10K_SDIO_VSG_BUF_SIZE (32 * 1024)
> +#define ATH10K_SDIO_DMA_BUF_SIZE (64 * 1024)
> +#define ATH10K_SDIO_VSG_BUF_SIZE (64 * 1024)
>
> /* inlined helper functions */
>
> @@ -501,6 +501,7 @@ static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
> int ret, i;
>
> *bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr->flags);
> + *bndl_cnt += (FIELD_GET(GENMASK(3, 2), htc_hdr->flags) << 4);
GENMASK(3, 2): Please define this macro somewhere.
Also, I'd merge the 2 lines in 1.
>
> if (*bndl_cnt > HTC_HOST_MAX_MSG_PER_RX_BUNDLE) {
> ath10k_warn(ar,
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
> index 4896eca..3ca76c7 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.h
> +++ b/drivers/net/wireless/ath/ath10k/sdio.h
> @@ -89,10 +89,10 @@
> * to the maximum value (HTC_HOST_MAX_MSG_PER_RX_BUNDLE).
> *
> * in this case the driver must allocate
> - * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE) skb's.
> + * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2) skb's.
> */
> #define ATH10K_SDIO_MAX_RX_MSGS \
> - (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE)
> + (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2)
>
> #define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u
> #define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
> --
> 1.9.1
>
On Tue, Aug 27, 2019 at 4:03 PM Wen Gong <[email protected]> wrote:
>
> > -----Original Message-----
> > From: ath10k <[email protected]> On Behalf Of Nicolas
> > Boichat
> > Sent: Tuesday, August 27, 2019 3:41 PM
> > To: Wen Gong <[email protected]>
> > Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> > [email protected]>; [email protected]
> > Subject: [EXT] Re: [PATCH 1/7] ath10k: enable RX bundle receive for sdio
> >
> > > -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, virt_pkt_len;
> > >
> > > + virt_pkt_len = 0;
> > > for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
> > > - ret = ath10k_sdio_mbox_rx_packet(ar,
> > > - &ar_sdio->rx_pkts[i]);
> > > - if (ret)
> > > + virt_pkt_len += ar_sdio->rx_pkts[i].alloc_len;
> > > + }
> > > +
> > > + if (virt_pkt_len < ATH10K_SDIO_DMA_BUF_SIZE) {
> > > + ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
> > > + ar_sdio->vsg_buffer, virt_pkt_len);
> > > + if (ret) {
> > > + i = 0;
> > > goto err;
> > > + }
> > > + } else {
> > > + ath10k_err(ar, "size exceeding limit %d\n", virt_pkt_len);
> > > + }
> > > +
> > > + pkt_offset = 0;
> > > + for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
> > > + struct sk_buff *skb = ar_sdio->rx_pkts[i].skb;
> > > +
> > > + pkt = &ar_sdio->rx_pkts[i];
> > > + memcpy(skb->data, ar_sdio->vsg_buffer + pkt_offset,
> > > + pkt->alloc_len);
> >
> > Why do you copy alloc_len if you only plan to use act_len?
> alloc_len is aligned to block size(256), and act_len maybe not same for each packet in the bundle.
> Eg a bundle:
> Packet 1 len 240, alloc_len: 256, 1st time: act_len 240, left padding size is 16,
> Packet 1 len 250, alloc_len: 256, 1st time: act_len 240, left padding size is 6,
> Packet 1 len 230, alloc_len: 256, 1st time: act_len 240, left padding size is 26,
>
> The bundled buffer len is 256 * 3 = 768, it has 256 bytes for each packet, the left size is padding which
> Is not needed, but the left padding is not same for each packet, before read all the buffer from sdio bus,
> It does not know each packet's act len, it only know the 1st packet's act len.
> So it need to copy all the alloc_len's buffer to ensure it will not lose data.
Gotcha, thanks.
> > Actually, just use skb_put_data.
> >
> > Also, do you have the same issue as
> > https://patchwork.kernel.org/patch/11116215/ w.r.t. act_len being
> > incorrect?
> >
> > > + pkt->status = 0;
> > > + skb_put(skb, pkt->act_len);
So I guess this is incorrect, see patchwork linked above.
> > > + pkt_offset += pkt->alloc_len;
> > > }
> > >
> > > return 0;
> > >
> >
> > _______________________________________________
> > ath10k mailing list
> > [email protected]
> > http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Nicolas
> Boichat
> Sent: Tuesday, August 27, 2019 3:41 PM
> To: Wen Gong <[email protected]>
> Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> [email protected]>; [email protected]
> Subject: [EXT] Re: [PATCH 1/7] ath10k: enable RX bundle receive for sdio
>
> > -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, virt_pkt_len;
> >
> > + virt_pkt_len = 0;
> > for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
> > - ret = ath10k_sdio_mbox_rx_packet(ar,
> > - &ar_sdio->rx_pkts[i]);
> > - if (ret)
> > + virt_pkt_len += ar_sdio->rx_pkts[i].alloc_len;
> > + }
> > +
> > + if (virt_pkt_len < ATH10K_SDIO_DMA_BUF_SIZE) {
> > + ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
> > + ar_sdio->vsg_buffer, virt_pkt_len);
> > + if (ret) {
> > + i = 0;
> > goto err;
> > + }
> > + } else {
> > + ath10k_err(ar, "size exceeding limit %d\n", virt_pkt_len);
> > + }
> > +
> > + pkt_offset = 0;
> > + for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
> > + struct sk_buff *skb = ar_sdio->rx_pkts[i].skb;
> > +
> > + pkt = &ar_sdio->rx_pkts[i];
> > + memcpy(skb->data, ar_sdio->vsg_buffer + pkt_offset,
> > + pkt->alloc_len);
>
> Why do you copy alloc_len if you only plan to use act_len?
alloc_len is aligned to block size(256), and act_len maybe not same for each packet in the bundle.
Eg a bundle:
Packet 1 len 240, alloc_len: 256, 1st time: act_len 240, left padding size is 16,
Packet 1 len 250, alloc_len: 256, 1st time: act_len 240, left padding size is 6,
Packet 1 len 230, alloc_len: 256, 1st time: act_len 240, left padding size is 26,
The bundled buffer len is 256 * 3 = 768, it has 256 bytes for each packet, the left size is padding which
Is not needed, but the left padding is not same for each packet, before read all the buffer from sdio bus,
It does not know each packet's act len, it only know the 1st packet's act len.
So it need to copy all the alloc_len's buffer to ensure it will not lose data.
> Actually, just use skb_put_data.
>
> Also, do you have the same issue as
> https://patchwork.kernel.org/patch/11116215/ w.r.t. act_len being
> incorrect?
>
> > + pkt->status = 0;
> > + skb_put(skb, pkt->act_len);
> > + pkt_offset += pkt->alloc_len;
> > }
> >
> > return 0;
> >
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
On Tue, Aug 20, 2019 at 7:55 PM Wen Gong <[email protected]> wrote:
>
> Tx complete message from firmware cost bus bandwidth of sdio, and bus
> bandwidth is the bollteneck of throughput, it will effect the bandwidth
> occupancy of data packet of TX and RX.
>
> This patch disable TX complete indication from firmware for htt data
> packet, it results in significant performance improvement on TX path.
>
> The downside of this patch is ath10k will not know the TX status of
> the data packet for poor signal situation. Although upper network stack
> or application layer have retry mechanism, the retry will be later than
> ath10k get the TX fail status if not disable TX complete.
>
> This patch only effect sdio chip, it will not effect PCI, SNOC etc.
>
> Tested with QCA6174 SDIO with firmware
> WLAN.RMH.4.4.1-00007-QCARMSWP-1.
>
> Signed-off-by: Wen Gong <[email protected]>
> ---
> drivers/net/wireless/ath/ath10k/core.c | 6 +++++
> drivers/net/wireless/ath/ath10k/hif.h | 9 ++++++++
> drivers/net/wireless/ath/ath10k/htc.c | 11 +++++++++
> drivers/net/wireless/ath/ath10k/htc.h | 3 +++
> drivers/net/wireless/ath/ath10k/htt.c | 5 +++++
> drivers/net/wireless/ath/ath10k/htt.h | 13 ++++++++++-
> drivers/net/wireless/ath/ath10k/htt_rx.c | 38 +++++++++++++++++++++++++++++++-
> drivers/net/wireless/ath/ath10k/htt_tx.c | 30 +++++++++++++++++++++++++
> drivers/net/wireless/ath/ath10k/hw.h | 2 +-
> drivers/net/wireless/ath/ath10k/sdio.c | 28 +++++++++++++++++++++++
> 10 files changed, 142 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
> index dc45d16..762bba0 100644
> --- a/drivers/net/wireless/ath/ath10k/core.c
> +++ b/drivers/net/wireless/ath/ath10k/core.c
> @@ -30,6 +30,7 @@
>
> static unsigned int ath10k_cryptmode_param;
> static bool uart_print;
> +static bool disable_tx_comp = true;
Instead of a disable_x = true variable, maybe you're better off using
a enable_tx_comp variable, with a default value of 0?
> static bool skip_otp;
> static bool rawmode;
> static bool fw_diag_log;
> @@ -41,6 +42,9 @@
> module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
> module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
> module_param(uart_print, bool, 0644);
> +
> +/* If upper layer need the TX complete status, it can enable tx complete */
> +module_param(disable_tx_comp, bool, 0644);
> module_param(skip_otp, bool, 0644);
> module_param(rawmode, bool, 0644);
> module_param(fw_diag_log, bool, 0644);
> @@ -689,6 +693,8 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
> * is used for SDIO. disable it until fixed
> */
> param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
> + if (disable_tx_comp)
> + param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
>
> /* Alternate credit size of 1544 as used by SDIO firmware is
> * not big enough for mac80211 / native wifi frames. disable it
> diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
> index 496ee34..0dd8973 100644
> --- a/drivers/net/wireless/ath/ath10k/hif.h
> +++ b/drivers/net/wireless/ath/ath10k/hif.h
> @@ -56,6 +56,8 @@ struct ath10k_hif_ops {
>
> int (*swap_mailbox)(struct ath10k *ar);
>
> + int (*get_htt_tx_complete)(struct ath10k *ar);
> +
> int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
> u8 *ul_pipe, u8 *dl_pipe);
>
> @@ -144,6 +146,13 @@ static inline int ath10k_hif_swap_mailbox(struct ath10k *ar)
> return 0;
> }
>
> +static inline int ath10k_hif_get_htt_tx_complete(struct ath10k *ar)
> +{
> + if (ar->hif.ops->get_htt_tx_complete)
> + return ar->hif.ops->get_htt_tx_complete(ar);
> + return 0;
> +}
> +
> static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
> u16 service_id,
> u8 *ul_pipe, u8 *dl_pipe)
> diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
> index 1d4d1a1..7357a5a 100644
> --- a/drivers/net/wireless/ath/ath10k/htc.c
> +++ b/drivers/net/wireless/ath/ath10k/htc.c
> @@ -660,6 +660,17 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
> return 0;
> }
>
> +void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
> + enum ath10k_htc_ep_id eid,
> + bool enable)
> +{
> + struct ath10k *ar = htc->ar;
> + struct ath10k_htc_ep *ep;
> +
> + ep = &ar->htc.endpoint[eid];
Merge this with the variable declaration.
> + ep->tx_credit_flow_enabled = enable;
> +}
> +
> int ath10k_htc_connect_service(struct ath10k_htc *htc,
> struct ath10k_htc_svc_conn_req *conn_req,
> struct ath10k_htc_svc_conn_resp *conn_resp)
> diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
> index 8c79b9e..78bc3ae 100644
> --- a/drivers/net/wireless/ath/ath10k/htc.h
> +++ b/drivers/net/wireless/ath/ath10k/htc.h
> @@ -367,6 +367,9 @@ struct ath10k_htc {
> int ath10k_htc_connect_service(struct ath10k_htc *htc,
> struct ath10k_htc_svc_conn_req *conn_req,
> struct ath10k_htc_svc_conn_resp *conn_resp);
> +void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
> + enum ath10k_htc_ep_id eid,
> + bool enable);
> int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
> struct sk_buff *packet);
> struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
> diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
> index 7b75200..88f3321 100644
> --- a/drivers/net/wireless/ath/ath10k/htt.c
> +++ b/drivers/net/wireless/ath/ath10k/htt.c
> @@ -10,6 +10,7 @@
> #include "htt.h"
> #include "core.h"
> #include "debug.h"
> +#include "hif.h"
>
> static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
> [HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
> @@ -153,6 +154,10 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
>
> htt->eid = conn_resp.eid;
>
> + htt->disable_tx_comple = ath10k_hif_get_htt_tx_complete(htt->ar);
> + if (htt->disable_tx_comple)
> + ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
> +
> return 0;
> }
>
> diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
> index 30c0800..cf97be5 100644
> --- a/drivers/net/wireless/ath/ath10k/htt.h
> +++ b/drivers/net/wireless/ath/ath10k/htt.h
> @@ -150,9 +150,19 @@ enum htt_data_tx_desc_flags1 {
> HTT_DATA_TX_DESC_FLAGS1_MORE_IN_BATCH = 1 << 12,
> HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD = 1 << 13,
> HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD = 1 << 14,
> - HTT_DATA_TX_DESC_FLAGS1_RSVD1 = 1 << 15
> + HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE = 1 << 15
> };
>
> +#define HTT_TX_CREDIT_DELTA_ABS_M 0xffff0000
> +#define HTT_TX_CREDIT_DELTA_ABS_S 16
> +#define HTT_TX_CREDIT_DELTA_ABS_GET(word) \
> + (((word) & HTT_TX_CREDIT_DELTA_ABS_M) >> HTT_TX_CREDIT_DELTA_ABS_S)
> +
> +#define HTT_TX_CREDIT_SIGN_BIT_M 0x00000100
> +#define HTT_TX_CREDIT_SIGN_BIT_S 8
> +#define HTT_TX_CREDIT_SIGN_BIT_GET(word) \
> + (((word) & HTT_TX_CREDIT_SIGN_BIT_M) >> HTT_TX_CREDIT_SIGN_BIT_S)
> +
> enum htt_data_tx_ext_tid {
> HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST = 16,
> HTT_DATA_TX_EXT_TID_MGMT = 17,
> @@ -2019,6 +2029,7 @@ struct ath10k_htt {
> bool tx_mem_allocated;
> const struct ath10k_htt_tx_ops *tx_ops;
> const struct ath10k_htt_rx_ops *rx_ops;
> + bool disable_tx_comple;
This is a strange variable name. Would disable_tx_comp or
disable_tx_complete/disable_tx_completion be better?
> };
>
> struct ath10k_htt_tx_ops {
> diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
> index 83a7fb6..d808824 100644
> --- a/drivers/net/wireless/ath/ath10k/htt_rx.c
> +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
> @@ -3691,6 +3691,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
> }
> case HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION: {
> struct htt_tx_done tx_done = {};
> + struct ath10k_htt *htt = &ar->htt;
> + struct ath10k_htc *htc = &ar->htc;
> + struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
> int status = __le32_to_cpu(resp->mgmt_tx_completion.status);
> int info = __le32_to_cpu(resp->mgmt_tx_completion.info);
>
> @@ -3716,6 +3719,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
> break;
> }
>
> + if (htt->disable_tx_comple) {
> + spin_lock_bh(&htc->tx_lock);
> + ep->tx_credits++;
> + spin_unlock_bh(&htc->tx_lock);
> + }
> +
> status = ath10k_txrx_tx_unref(htt, &tx_done);
> if (!status) {
> spin_lock_bh(&htt->tx_lock);
> @@ -3790,7 +3799,34 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
> skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
> return false;
> }
> - case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
> + case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:{
nit: space after :
> + struct ath10k_htt *htt = &ar->htt;
> + struct ath10k_htc *htc = &ar->htc;
> + struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
> + u32 *msg_word;
> + u32 htt_credit_delta_abs;
> + int htt_credit_delta;
> + int sign;
> +
> + msg_word = (u32 *)resp;
Just have:
u32 msg_word;
msg_word = *((u32 *)resp);
Instead of de-referencing over and over again.
Also, are you sure that no "__le32_to_cpu" is required here?
> + htt_credit_delta_abs = HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word);
> + sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1;
> + htt_credit_delta = sign * htt_credit_delta_abs;
I'd avoid the multiplication:
htt_credit_delta = HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word);
if (HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word))
htt_credit_delta = -htt_credit_delta;
> +
> + ath10k_dbg(ar, ATH10K_DBG_HTT,
> + "credit update: abs:%d, sign:%d, delta:%d\n",
> + htt_credit_delta_abs, sign, htt_credit_delta);
> +
> + if (htt->disable_tx_comple) {
> + spin_lock_bh(&htc->tx_lock);
> + ep->tx_credits += htt_credit_delta;
> + spin_unlock_bh(&htc->tx_lock);
> + ath10k_dbg(ar, ATH10K_DBG_HTT,
> + "credit total:%d\n",
> + ep->tx_credits);
> + }
> + break;
> + }
> break;
A single break is enough.
> case HTT_T2H_MSG_TYPE_CHAN_CHANGE: {
> u32 phymode = __le32_to_cpu(resp->chan_change.phymode);
> diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
> index 2ef717f1..cda8a59 100644
> --- a/drivers/net/wireless/ath/ath10k/htt_tx.c
> +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
> @@ -543,7 +543,33 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
>
> void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
> {
> + struct ath10k_htt *htt = &ar->htt;
> + struct htt_tx_done tx_done = {0};
> + struct htt_cmd_hdr *htt_hdr;
> + struct htt_data_tx_desc *desc_hdr;
> + u16 flags1;
> +
> dev_kfree_skb_any(skb);
> +
> + if (htt->disable_tx_comple) {
> + htt_hdr = (struct htt_cmd_hdr *)skb->data;
> + if (htt_hdr->msg_type == HTT_H2T_MSG_TYPE_TX_FRM) {
> + desc_hdr = (struct htt_data_tx_desc *)
> + (skb->data + sizeof(*htt_hdr));
> + flags1 = __le16_to_cpu(desc_hdr->flags1);
> +
> + ath10k_dbg(ar, ATH10K_DBG_HTT,
> + "ath10k_htt_htc_tx_complete msdu id:%u ,flags1:%x\n",
> + __le16_to_cpu(desc_hdr->id), flags1);
> +
> + if (flags1 & HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE)
> + return;
> +
> + tx_done.status = HTT_TX_COMPL_STATE_ACK;
> + tx_done.msdu_id = __le16_to_cpu(desc_hdr->id);
> + ath10k_txrx_tx_unref(&ar->htt, &tx_done);
> + }
> + }
> }
>
> void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb)
> @@ -1260,6 +1286,10 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
> case ATH10K_HW_TXRX_MGMT:
> flags0 |= SM(ATH10K_HW_TXRX_MGMT,
> HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
> +
> + if (htt->disable_tx_comple)
> + flags1 |= HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE;
> +
> flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
> break;
> }
> diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
> index 2ae57c1..6349665 100644
> --- a/drivers/net/wireless/ath/ath10k/hw.h
> +++ b/drivers/net/wireless/ath/ath10k/hw.h
> @@ -759,7 +759,7 @@ struct ath10k_hw_ops {
> #define TARGET_TLV_NUM_TDLS_VDEVS 1
> #define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
> #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
> -#define TARGET_TLV_NUM_MSDU_DESC_HL 64
> +#define TARGET_TLV_NUM_MSDU_DESC_HL 1024
> #define TARGET_TLV_NUM_WOW_PATTERNS 22
> #define TARGET_TLV_MGMT_NUM_MSDU_DESC (50)
>
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
> index f42aca6..4d6da04 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.c
> +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> @@ -1790,6 +1790,33 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
> return 0;
> }
>
> +static int ath10k_sdio_get_htt_tx_complete(struct ath10k *ar)
> +{
> + u32 addr, val;
> + int ret = 0;
No need to initialize to 0.
> +
> + addr = host_interest_item_address(HI_ITEM(hi_acs_flags));
> +
> + ret = ath10k_sdio_hif_diag_read32(ar, addr, &val);
> + if (ret) {
> + ath10k_warn(ar,
> + "unable to read hi_acs_flags for htt tx comple : %d\n", ret);
> + return ret;
> + }
> +
> + if (val & HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK) {
> + ath10k_dbg(ar, ATH10K_DBG_SDIO,
> + "sdio reduce tx comple fw ack\n");
> + ret = 1;
> + } else {
> + ath10k_dbg(ar, ATH10K_DBG_SDIO,
> + "sdio reduce tx comple fw not ack\n");
> + ret = 0;
> + }
> +
> + return ret;
> +}
> +
> /* HIF start/stop */
>
> static int ath10k_sdio_hif_start(struct ath10k *ar)
> @@ -2073,6 +2100,7 @@ static void ath10k_sdio_hif_send_complete_check(struct ath10k *ar,
> .start = ath10k_sdio_hif_start,
> .stop = ath10k_sdio_hif_stop,
> .swap_mailbox = ath10k_sdio_hif_swap_mailbox,
> + .get_htt_tx_complete = ath10k_sdio_get_htt_tx_complete,
> .map_service_to_pipe = ath10k_sdio_hif_map_service_to_pipe,
> .get_default_pipe = ath10k_sdio_hif_get_default_pipe,
> .send_complete_check = ath10k_sdio_hif_send_complete_check,
> --
> 1.9.1
>
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Nicolas
> Boichat
> Sent: Tuesday, August 27, 2019 3:43 PM
> To: Wen Gong <[email protected]>
> Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> [email protected]>; [email protected]
> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
> 32 for sdio
>
> > @@ -501,6 +501,7 @@ static int ath10k_sdio_mbox_alloc_bundle(struct
> ath10k *ar,
> > int ret, i;
> >
> > *bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr-
> >flags);
> > + *bndl_cnt += (FIELD_GET(GENMASK(3, 2), htc_hdr->flags) << 4);
>
> GENMASK(3, 2): Please define this macro somewhere.
>
> Also, I'd merge the 2 lines in 1.
Patch v2 has sent, https://patchwork.kernel.org/patch/11116677/
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Nicolas
> Boichat
> Sent: Tuesday, August 27, 2019 4:08 PM
> To: Wen Gong <[email protected]>
> Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> [email protected]>; [email protected]; Wen Gong
> <[email protected]>
> Subject: [EXT] Re: [PATCH 1/7] ath10k: enable RX bundle receive for sdio
>
> On Tue, Aug 27, 2019 at 4:03 PM Wen Gong <[email protected]>
> wrote:
> >
> > > -----Original Message-----
> > > From: ath10k <[email protected]> On Behalf Of Nicolas
> > > Boichat
> > > Sent: Tuesday, August 27, 2019 3:41 PM
> > > To: Wen Gong <[email protected]>
> > > Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> > > [email protected]>; [email protected]
> > > Subject: [EXT] Re: [PATCH 1/7] ath10k: enable RX bundle receive for sdio
> > The bundled buffer len is 256 * 3 = 768, it has 256 bytes for each packet,
> the left size is padding which
> > Is not needed, but the left padding is not same for each packet, before read
> all the buffer from sdio bus,
> > It does not know each packet's act len, it only know the 1st packet's act len.
> > So it need to copy all the alloc_len's buffer to ensure it will not lose data.
>
> Gotcha, thanks.
Patch v2 sent with the changes, https://patchwork.kernel.org/patch/11116681/
>
> > > Actually, just use skb_put_data.
> > >
> > > Also, do you have the same issue as
> > > https://patchwork.kernel.org/patch/11116215/ w.r.t. act_len being
> > > incorrect?
> > >
> > > > + pkt->status = 0;
> > > > + skb_put(skb, pkt->act_len);
>
> So I guess this is incorrect, see patchwork linked above.
>
> > > > + pkt_offset += pkt->alloc_len;
> > > > }
> > > >
> > > > return 0;
> > > >
> > >
> > > _______________________________________________
> > > ath10k mailing list
> > > [email protected]
> > > http://lists.infradead.org/mailman/listinfo/ath10k
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Nicolas
> Boichat
> Sent: Tuesday, August 27, 2019 3:56 PM
> To: Wen Gong <[email protected]>
> Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> [email protected]>; [email protected]
> Subject: [EXT] Re: [PATCH 4/7] ath10k: disable TX complete indication of htt
> for sdio
>
> On Tue, Aug 20, 2019 at 7:55 PM Wen Gong <[email protected]> wrote:
> >
> > Tx complete message from firmware cost bus bandwidth of sdio, and bus
> > bandwidth is the bollteneck of throughput, it will effect the bandwidth
> > occupancy of data packet of TX and RX.
> >
> > This patch disable TX complete indication from firmware for htt data
> > packet, it results in significant performance improvement on TX path.
> >
Patch v2 sent with the changes, https://patchwork.kernel.org/patch/11116685/
> >
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
In terms of deeply grokking what increasing buffering to achieve high
bandwidth on a testbench, vs what it can do to clobber latency in the
real world at low bandwidths, I tend to point folk at:
https://www.youtube.com/watch?v=Rb-UnHDw02o&t=25m40s
where I got a whole bunch of hackers to stand up and act like packets
in an aggregating FIFO wifi queue.
This key section is only 8 minutes long, and I promise, y'all laugh
at least 3 times at the demonstration.
At the time, also, the ath10k was so overbuffered that on one test
I could try to start 100 flows, and only get five.
https://lwn.net/Articles/705884/
and on my slides:
https://blog.linuxplumbersconf.org/2016/ocw//system/presentations/3963/original/linuxplumbers_wifi_latency-3Nov.pdf
Wen Gong <[email protected]> writes:
> The max bundle size support by firmware is 32, change it from 8 to 32
> will help performance. This results in significant performance
> improvement on RX path.
>
> Tested with QCA6174 SDIO with firmware
> WLAN.RMH.4.4.1-00007-QCARMSWP-1.
>
> Signed-off-by: Wen Gong <[email protected]>
> ---
> drivers/net/wireless/ath/ath10k/htc.h | 2 +-
> drivers/net/wireless/ath/ath10k/sdio.c | 5 +++--
> drivers/net/wireless/ath/ath10k/sdio.h | 4 ++--
> 3 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
> index f55d3ca..8c79b9e 100644
> --- a/drivers/net/wireless/ath/ath10k/htc.h
> +++ b/drivers/net/wireless/ath/ath10k/htc.h
> @@ -39,7 +39,7 @@
> * 4-byte aligned.
> */
>
> -#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 8
> +#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
>
> enum ath10k_htc_tx_flags {
> ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
> index d9395f0..baa6051 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.c
> +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> @@ -24,8 +24,8 @@
> #include "trace.h"
> #include "sdio.h"
>
> -#define ATH10K_SDIO_DMA_BUF_SIZE (32 * 1024)
> -#define ATH10K_SDIO_VSG_BUF_SIZE (32 * 1024)
> +#define ATH10K_SDIO_DMA_BUF_SIZE (64 * 1024)
> +#define ATH10K_SDIO_VSG_BUF_SIZE (64 * 1024)
>
> /* inlined helper functions */
>
> @@ -501,6 +501,7 @@ static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
> int ret, i;
>
> *bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr->flags);
> + *bndl_cnt += (FIELD_GET(GENMASK(3, 2), htc_hdr->flags) << 4);
>
> if (*bndl_cnt > HTC_HOST_MAX_MSG_PER_RX_BUNDLE) {
> ath10k_warn(ar,
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
> index 4896eca..3ca76c7 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.h
> +++ b/drivers/net/wireless/ath/ath10k/sdio.h
> @@ -89,10 +89,10 @@
> * to the maximum value (HTC_HOST_MAX_MSG_PER_RX_BUNDLE).
> *
> * in this case the driver must allocate
> - * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE) skb's.
> + * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2) skb's.
> */
> #define ATH10K_SDIO_MAX_RX_MSGS \
> - (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE)
> + (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2)
>
> #define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u
> #define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Wen Gong
> Sent: Tuesday, August 20, 2019 7:55 PM
> To: [email protected]
> Cc: [email protected]
> Subject: [EXT] [PATCH 3/7] ath10k: add workqueue for RX path of sdio
>
Patch v2 sent, https://patchwork.kernel.org/patch/11116671/
> --
> 1.9.1
>
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Wen Gong
> Sent: Tuesday, August 20, 2019 7:55 PM
> To: [email protected]
> Cc: [email protected]
> Subject: [EXT] [PATCH 4/7] ath10k: disable TX complete indication of htt for
> sdio
>
Patch v2 sent, https://patchwork.kernel.org/patch/11116685/
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Wen Gong
> Sent: Tuesday, August 20, 2019 7:55 PM
> To: [email protected]
> Cc: [email protected]
> Subject: [EXT] [PATCH 5/7] ath10k: add htt TX bundle for sdio
>
Patch v2 sent, https://patchwork.kernel.org/patch/11116687/
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Wen Gong
> Sent: Tuesday, August 20, 2019 7:55 PM
> To: [email protected]
> Cc: [email protected]
> Subject: [EXT] [PATCH 6/7] ath10k: enable alt data of TX path for sdio
>
Patch v2 sent, https://patchwork.kernel.org/patch/11116683/
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: ath10k <[email protected]> On Behalf Of Wen Gong
> Sent: Tuesday, August 20, 2019 7:55 PM
> To: [email protected]
> Cc: [email protected]
> Subject: [EXT] [PATCH 7/7] ath10k: enable napi on RX path for sdio
>
Patch v2 sent, https://patchwork.kernel.org/patch/11116669/
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
> -----Original Message-----
> From: Dave Taht <[email protected]>
> Sent: Wednesday, September 4, 2019 12:10 AM
> To: Wen Gong <[email protected]>; [email protected];
> [email protected]
> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
> 32 for sdio
>
>
> In terms of deeply grokking what increasing buffering to achieve high
> bandwidth on a testbench, vs what it can do to clobber latency in the
> real world at low bandwidths, I tend to point folk at:
>
> https://www.youtube.com/watch?v=Rb-UnHDw02o&t=25m40s
>
> where I got a whole bunch of hackers to stand up and act like packets
> in an aggregating FIFO wifi queue.
>
> This key section is only 8 minutes long, and I promise, y'all laugh
> at least 3 times at the demonstration.
>
> At the time, also, the ath10k was so overbuffered that on one test
> I could try to start 100 flows, and only get five.
>
> https://lwn.net/Articles/705884/
>
> and on my slides:
>
> https://blog.linuxplumbersconf.org/2016/ocw//system/presentations/3963/
> original/linuxplumbers_wifi_latency-3Nov.pdf
>
Hi Dave,
So your mean is change 8 to 32 will impact latency? It will increase latency of rx?
>
> 0xFFFEFFFF
Wen Gong <[email protected]> writes:
>> -----Original Message-----
>> From: Dave Taht <[email protected]>
>> Sent: Wednesday, September 4, 2019 12:10 AM
>> To: Wen Gong <[email protected]>; [email protected];
>> [email protected]
>> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
>> 32 for sdio
>>
>>
>> In terms of deeply grokking what increasing buffering to achieve high
>> bandwidth on a testbench, vs what it can do to clobber latency in the
>> real world at low bandwidths, I tend to point folk at:
>>
>> https://www.youtube.com/watch?v=Rb-UnHDw02o&t=25m40s
>>
>> where I got a whole bunch of hackers to stand up and act like packets
>> in an aggregating FIFO wifi queue.
>>
>> This key section is only 8 minutes long, and I promise, y'all laugh
>> at least 3 times at the demonstration.
>>
>> At the time, also, the ath10k was so overbuffered that on one test
>> I could try to start 100 flows, and only get five.
>>
>> https://lwn.net/Articles/705884/
>>
>> and on my slides:
>>
>> https://blog.linuxplumbersconf.org/2016/ocw//system/presentations/3963/
>> original/linuxplumbers_wifi_latency-3Nov.pdf
>>
> Hi Dave,
> So your mean is change 8 to 32 will impact latency? It will increase latency of rx?
Heh. for rx, in this case, probably not!
I just get twitchy every time folk fiddle with buffer sizes. In one
recent case someone had fiddled with the interrupt polling interval on
something, going from 1ms to 10ms - it saved on cpu, but...
... just trying to make sure folk grok the tradoffs with a bit of
laughter.
carry on!
>
>>
>> 0xFFFEFFFF
> -----Original Message-----
> From: Dave Taht <[email protected]>
> Sent: Wednesday, September 4, 2019 9:34 PM
> To: Wen Gong <[email protected]>
> Cc: [email protected]; [email protected]
> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
> 32 for sdio
>
> > Hi Dave,
> > So your mean is change 8 to 32 will impact latency? It will increase latency
> of rx?
>
> Heh. for rx, in this case, probably not!
>
> I just get twitchy every time folk fiddle with buffer sizes. In one
> recent case someone had fiddled with the interrupt polling interval on
> something, going from 1ms to 10ms - it saved on cpu, but...
> ... just trying to make sure folk grok the tradoffs with a bit of
> laughter.
>
> carry on!
Hah, so you do not have any concern about this patch.
Patch 3 sent, https://patchwork.kernel.org/patch/11122175/
>
> >
> >>
> >> 0xFFFEFFFF