Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH v2 1/7] ath10k: enable RX bundle receive for sdio
From: Wen Gong @ 2019-08-27 11:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless
In-Reply-To: <1566903707-27536-1-git-send-email-wgong@codeaurora.org>

From: Alagu Sankar <alagusankar@silex-india.com>

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 <alagusankar@silex-india.com>
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/sdio.c | 112 +++++++++++++++++++++++----------
 drivers/net/wireless/ath/ath10k/sdio.h |   7 ++-
 2 files changed, 85 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 8ed4fbd..eacb4d5 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,
@@ -381,16 +384,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
 	struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
 	bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
 	enum ath10k_htc_ep_id eid;
-	u16 payload_len;
 	u8 *trailer;
 	int ret;
 
-	payload_len = le16_to_cpu(htc_hdr->len);
-	skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
-
 	if (trailer_present) {
-		trailer = skb->data + sizeof(*htc_hdr) +
-			  payload_len - htc_hdr->trailer_len;
+		trailer = skb->data + skb->len - htc_hdr->trailer_len;
 
 		eid = pipe_id_to_eid(htc_hdr->eid);
 
@@ -489,11 +487,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 +532,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 +576,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 +603,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 +612,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 +629,78 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
 	return ret;
 }
 
-static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
-				      struct ath10k_sdio_rx_data *pkt)
+static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
 {
 	struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+	struct ath10k_sdio_rx_data *pkt = &ar_sdio->rx_pkts[0];
 	struct sk_buff *skb = pkt->skb;
+	struct ath10k_htc_hdr *htc_hdr;
 	int ret;
 
 	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 {
+		htc_hdr = (struct ath10k_htc_hdr *)skb->data;
+		pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
+		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;
+	struct ath10k_htc_hdr *htc_hdr;
 	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];
+		htc_hdr = (struct ath10k_htc_hdr *)(ar_sdio->vsg_buffer + pkt_offset);
+		pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
+
+		memcpy(skb->data, ar_sdio->vsg_buffer + pkt_offset,
+		       pkt->act_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 +743,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 +1154,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 +2049,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


^ permalink raw reply related

* [PATCH v2 6/7] ath10k: enable alt data of TX path for sdio
From: Wen Gong @ 2019-08-27 11:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless
In-Reply-To: <1566903707-27536-1-git-send-email-wgong@codeaurora.org>

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 <wgong@codeaurora.org>
---
 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 e0eb5f0..5cacab6 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);
@@ -1095,6 +1098,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 d805ea5..f0a9e60af 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -139,8 +139,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 {
@@ -377,6 +383,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


^ permalink raw reply related

* [PATCH v2 2/7] ath10k: change max RX bundle size from 8 to 32 for sdio
From: Wen Gong @ 2019-08-27 11:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless
In-Reply-To: <1566903707-27536-1-git-send-email-wgong@codeaurora.org>

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 <wgong@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/htc.h  | 6 +++++-
 drivers/net/wireless/ath/ath10k/sdio.c | 6 +++---
 drivers/net/wireless/ath/ath10k/sdio.h | 4 ++--
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index f55d3ca..8a07da0 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,
@@ -52,6 +52,10 @@ enum ath10k_htc_rx_flags {
 	ATH10K_HTC_FLAG_BUNDLE_MASK     = 0xF0
 };
 
+#define HTC_GET_BUNDLE_COUNT(flags) \
+	    (FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, (flags)) +  \
+	    (FIELD_GET(GENMASK(3, 2), (flags)) << 4))
+
 struct ath10k_htc_hdr {
 	u8 eid; /* @enum ath10k_htc_ep_id */
 	u8 flags; /* @enum ath10k_htc_tx_flags, ath10k_htc_rx_flags */
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index eacb4d5..e5c365e 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 */
 
@@ -495,7 +495,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 = HTC_GET_BUNDLE_COUNT(htc_hdr->flags);
 
 	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


^ permalink raw reply related

* [PATCH v2 3/7] ath10k: add workqueue for RX path of sdio
From: Wen Gong @ 2019-08-27 11:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless
In-Reply-To: <1566903707-27536-1-git-send-email-wgong@codeaurora.org>

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 <wgong@codeaurora.org>
---
 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 e5c365e..5363a37 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -412,6 +412,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)
@@ -465,10 +526,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


^ permalink raw reply related

* [PATCH v2 7/7] ath10k: enable napi on RX path for sdio
From: Wen Gong @ 2019-08-27 11:01 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless
In-Reply-To: <1566903707-27536-1-git-send-email-wgong@codeaurora.org>

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 <wgong@codeaurora.org>
---
 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 127b4e4..f69346f 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 4851a2e..462a25b 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;
@@ -2298,6 +2300,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 e2d8b51..9340ae3 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 = {
@@ -3895,6 +3893,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 a302eda..a1ef31e 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


^ permalink raw reply related

* Re: [PATCH 31/49] ath11k: add mac.c
From: Vasanthakumar Thiagarajan @ 2019-08-27 10:51 UTC (permalink / raw)
  To: Nicolas Cavallari
  Cc: Kalle Valo, linux-wireless, ath11k, devicetree,
	linux-wireless-owner
In-Reply-To: <c37a9fc4-aa74-a333-a67c-cce66ad78ec0@green-communications.fr>

On 2019-08-23 20:32, Nicolas Cavallari wrote:
> On 20/08/2019 17:47, Kalle Valo wrote:
>> +	ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
>> +					 BIT(NL80211_IFTYPE_AP) |
>> +					 BIT(NL80211_IFTYPE_MESH_POINT);
> 
> [...]
> 
>> +	ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
> 
> so IBSS-RSN is supported without IBSS support ?

Sure. IBSS-RSN is not relevant when IBSS is not supported, I guess.
We'll take care of this. Thanks.

Vasanth

^ permalink raw reply

* Re: [PATCH 10/49] ath11k: add debug.c
From: Sven Eckelmann @ 2019-08-27 10:49 UTC (permalink / raw)
  To: Anilkumar Kolli; +Cc: ath11k, devicetree, linux-wireless, Kalle Valo
In-Reply-To: <f93b9c98fcfb9a910c3efc04d11d5aa0@codeaurora.org>

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

On Tuesday, 27 August 2019 12:04:27 CEST Anilkumar Kolli wrote:
> Could you plz try removing below patch?
> https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/072-ath11k-print-stats-on-crash.patch?h=win_ap.1.0

It is not applied. At least I can't find any ath11k_core_dump_bp_stats

Kind regards,
	Sven

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

^ permalink raw reply

* Re: [PATCH 31/49] ath11k: add mac.c
From: Vasanthakumar Thiagarajan @ 2019-08-27 10:43 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen
  Cc: Kalle Valo, linux-wireless, ath11k, devicetree,
	linux-wireless-owner
In-Reply-To: <875zmqsudn.fsf@toke.dk>

On 2019-08-21 15:38, Toke Høiland-Jørgensen wrote:
> Vasanthakumar Thiagarajan <vthiagar@codeaurora.org> writes:
> 
>> On 2019-08-20 22:21, Toke Høiland-Jørgensen wrote:
>>> [... snip ... ]
>>> 
>>>> +static const struct ieee80211_ops ath11k_ops = {
>>>> +	.tx				= ath11k_mac_op_tx,
>>> 
>>> No wake_tx_queue? :(
>> 
>> Yes, packet queueing is handled in firmware. This makes sense
>> especially when we enable 802.11 encap offload support where most of
>> the data path processing in mac80211 will be skipped and packet is
>> given to driver/firmware in 802.3 format itself. Then firmware would
>> take care of all the classification, queueing and encapsulation
>> operations.
> 
> Well, so does ath10k, and yet we still saw a significant improvement by
> moving queueing back into the host where it can be handled by the
> FQ-CoDel-enabled queueing structure.
> 

Sure, we could probably try that with ath11k as well at some point when 
we have a baseline with HE support.

Vasanth

^ permalink raw reply

* Re: [PATCH 10/49] ath11k: add debug.c
From: Anilkumar Kolli @ 2019-08-27 10:04 UTC (permalink / raw)
  To: Sven Eckelmann; +Cc: ath11k, devicetree, linux-wireless, Kalle Valo
In-Reply-To: <18655975.RomJW5s5WE@bentobox>

On 2019-08-27 15:23, Sven Eckelmann wrote:
> On Tuesday, 27 August 2019 11:04:23 CEST Anilkumar Kolli wrote:
> [...]
>> > Yes, but it shouldn't kill the complete system.
>> >
>> This will not kill the whole system, This will crash target and we 
>> have
>> mechanism to recover the system.
>> 
>> Hope u have generated the crash with below patch,
>> https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/019-ath11k-disable-q6-recovery-to-crash-kernel.patch?h=win_ap.1.0
>> 
>> Please remove this patch to see the target recover after the crash.
> 
> John also pointed me to this patch yesterday and I have now removed it.
> 
> But the wifi hardware doesn't recover after issuing an assert. All(?) 
> firmware
> request will just timeout:
> 
>     [ 1093.114530] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1093.114555] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1093.118903] ath11k c000000.wifi1: Failed to set dtim period for
> VDEV 0: -11
>     [ 1096.124532] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1096.124554] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1096.128902] ath11k c000000.wifi1: Failed to set CTS prot for 
> VDEV: 0
>     [ 1099.134527] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1099.134547] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1099.138895] ath11k c000000.wifi1: Failed to set preamble for 
> VDEV: 0
>     [ 1102.144526] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1102.144546] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1102.148894] ath11k c000000.wifi1: failed to set mgmt tx rate -11
>     [ 1105.154526] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1105.154547] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1105.158895] ath11k c000000.wifi1: failed to set beacon tx rate 
> -11
>     [ 1114.164529] ath11k c000000.wifi1: wmi command 16387 timeout
>     [ 1114.164553] ath11k c000000.wifi1: failed to send 
> WMI_PDEV_SET_PARAM cmd
>     [ 1114.168899] ath11k c000000.wifi1: Failed to set beacon mode for 
> VDEV: 0
>     [ 1117.174527] ath11k c000000.wifi1: wmi command 28675 timeout
>     [ 1117.174550] ath11k c000000.wifi1: failed to send 
> WMI_BCN_TMPL_CMDID
>     [ 1117.178899] ath11k c000000.wifi1: failed to submit beacon
> template command: -11
>     [ 1117.185231] ath11k c000000.wifi1: failed to update bcn template: 
> -11
>     [ 1120.184524] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1120.184545] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1120.188893] ath11k c000000.wifi1: Failed to set dtim period for
> VDEV 0: -11
>     [ 1123.194527] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1123.194548] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1123.198895] ath11k c000000.wifi1: Failed to set CTS prot for 
> VDEV: 0
>     [ 1126.204526] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1126.204547] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1126.208894] ath11k c000000.wifi1: Failed to set preamble for 
> VDEV: 0
>     [ 1129.214527] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1129.214548] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1129.218897] ath11k c000000.wifi1: failed to set mgmt tx rate -11
>     [ 1132.224525] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1132.224546] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1132.228894] ath11k c000000.wifi1: failed to set beacon tx rate 
> -11
> 
> ath11k must be unloaded + loaded again to fix this problem.
> 

Could you plz try removing below patch?
https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/072-ath11k-print-stats-on-crash.patch?h=win_ap.1.0

-- 
Thanks
Anil.

^ permalink raw reply

* Re: [PATCH 10/49] ath11k: add debug.c
From: Sven Eckelmann @ 2019-08-27  9:53 UTC (permalink / raw)
  To: Anilkumar Kolli; +Cc: ath11k, devicetree, linux-wireless, Kalle Valo
In-Reply-To: <6622b83f754404ec05b9442027757c5e@codeaurora.org>

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

On Tuesday, 27 August 2019 11:04:23 CEST Anilkumar Kolli wrote:
[...]
> > Yes, but it shouldn't kill the complete system.
> > 
> This will not kill the whole system, This will crash target and we have 
> mechanism to recover the system.
> 
> Hope u have generated the crash with below patch,
> https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/019-ath11k-disable-q6-recovery-to-crash-kernel.patch?h=win_ap.1.0
> 
> Please remove this patch to see the target recover after the crash.

John also pointed me to this patch yesterday and I have now removed it.

But the wifi hardware doesn't recover after issuing an assert. All(?) firmware 
request will just timeout:

    [ 1093.114530] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1093.114555] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1093.118903] ath11k c000000.wifi1: Failed to set dtim period for VDEV 0: -11
    [ 1096.124532] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1096.124554] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1096.128902] ath11k c000000.wifi1: Failed to set CTS prot for VDEV: 0
    [ 1099.134527] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1099.134547] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1099.138895] ath11k c000000.wifi1: Failed to set preamble for VDEV: 0
    [ 1102.144526] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1102.144546] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1102.148894] ath11k c000000.wifi1: failed to set mgmt tx rate -11
    [ 1105.154526] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1105.154547] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1105.158895] ath11k c000000.wifi1: failed to set beacon tx rate -11
    [ 1114.164529] ath11k c000000.wifi1: wmi command 16387 timeout
    [ 1114.164553] ath11k c000000.wifi1: failed to send WMI_PDEV_SET_PARAM cmd
    [ 1114.168899] ath11k c000000.wifi1: Failed to set beacon mode for VDEV: 0
    [ 1117.174527] ath11k c000000.wifi1: wmi command 28675 timeout
    [ 1117.174550] ath11k c000000.wifi1: failed to send WMI_BCN_TMPL_CMDID
    [ 1117.178899] ath11k c000000.wifi1: failed to submit beacon template command: -11
    [ 1117.185231] ath11k c000000.wifi1: failed to update bcn template: -11
    [ 1120.184524] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1120.184545] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1120.188893] ath11k c000000.wifi1: Failed to set dtim period for VDEV 0: -11
    [ 1123.194527] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1123.194548] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1123.198895] ath11k c000000.wifi1: Failed to set CTS prot for VDEV: 0
    [ 1126.204526] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1126.204547] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1126.208894] ath11k c000000.wifi1: Failed to set preamble for VDEV: 0
    [ 1129.214527] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1129.214548] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1129.218897] ath11k c000000.wifi1: failed to set mgmt tx rate -11
    [ 1132.224525] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1132.224546] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1132.228894] ath11k c000000.wifi1: failed to set beacon tx rate -11

ath11k must be unloaded + loaded again to fix this problem.

Kind regards,
	Sven

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

^ permalink raw reply

* RE: [PATCH v4] rtw88: pci: Move a mass of jobs in hw IRQ to soft IRQ
From: Tony Chuang @ 2019-08-27  9:20 UTC (permalink / raw)
  To: Jian-Hong Pan, Kalle Valo, David S . Miller
  Cc: linux-wireless@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux@endlessm.com
In-Reply-To: <20190826070827.1436-1-jian-hong@endlessm.com>

> From: Jian-Hong Pan 
> Subject: [PATCH v4] rtw88: pci: Move a mass of jobs in hw IRQ to soft IRQ
> 
> There is a mass of jobs between spin lock and unlock in the hardware
> IRQ which will occupy much time originally. To make system work more
> efficiently, this patch moves the jobs to the soft IRQ (bottom half) to
> reduce the time in hardware IRQ.
> 
> Signed-off-by: Jian-Hong Pan <jian-hong@endlessm.com>
> ---
> v2:
>  Change the spin_lock_irqsave/unlock_irqrestore to spin_lock/unlock in
>  rtw_pci_interrupt_handler. Because the interrupts are already disabled
>  in the hardware interrupt handler.
> 
> v3:
>  Extend the spin lock protecting area for the TX path in
>  rtw_pci_interrupt_threadfn by Realtek's suggestion
> 
> v4:
>  Remove the WiFi running check in rtw_pci_interrupt_threadfn to avoid AP
>  connection failed by Realtek's suggestion.
> 
>  drivers/net/wireless/realtek/rtw88/pci.c | 32 +++++++++++++++++++-----
>  1 file changed, 26 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/pci.c
> b/drivers/net/wireless/realtek/rtw88/pci.c
> index 00ef229552d5..955dd6c6fb57 100644
> --- a/drivers/net/wireless/realtek/rtw88/pci.c
> +++ b/drivers/net/wireless/realtek/rtw88/pci.c
> @@ -866,12 +866,29 @@ static irqreturn_t rtw_pci_interrupt_handler(int irq,
> void *dev)
>  {
>  	struct rtw_dev *rtwdev = dev;
>  	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
> -	u32 irq_status[4];
> 
>  	spin_lock(&rtwpci->irq_lock);
>  	if (!rtwpci->irq_enabled)
>  		goto out;
> 
> +	/* disable RTW PCI interrupt to avoid more interrupts before the end of
> +	 * thread function
> +	 */
> +	rtw_pci_disable_interrupt(rtwdev, rtwpci);
> +out:
> +	spin_unlock(&rtwpci->irq_lock);
> +
> +	return IRQ_WAKE_THREAD;
> +}
> +
> +static irqreturn_t rtw_pci_interrupt_threadfn(int irq, void *dev)
> +{
> +	struct rtw_dev *rtwdev = dev;
> +	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
> +	unsigned long flags;
> +	u32 irq_status[4];
> +
> +	spin_lock_irqsave(&rtwpci->irq_lock, flags);
>  	rtw_pci_irq_recognized(rtwdev, rtwpci, irq_status);
> 
>  	if (irq_status[0] & IMR_MGNTDOK)
> @@ -891,8 +908,9 @@ static irqreturn_t rtw_pci_interrupt_handler(int irq,
> void *dev)
>  	if (irq_status[0] & IMR_ROK)
>  		rtw_pci_rx_isr(rtwdev, rtwpci, RTW_RX_QUEUE_MPDU);
> 
> -out:
> -	spin_unlock(&rtwpci->irq_lock);
> +	/* all of the jobs for this interrupt have been done */
> +	rtw_pci_enable_interrupt(rtwdev, rtwpci);
> +	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
> 
>  	return IRQ_HANDLED;
>  }
> @@ -1152,8 +1170,10 @@ static int rtw_pci_probe(struct pci_dev *pdev,
>  		goto err_destroy_pci;
>  	}
> 
> -	ret = request_irq(pdev->irq, &rtw_pci_interrupt_handler,
> -			  IRQF_SHARED, KBUILD_MODNAME, rtwdev);
> +	ret = devm_request_threaded_irq(rtwdev->dev, pdev->irq,
> +					rtw_pci_interrupt_handler,
> +					rtw_pci_interrupt_threadfn,
> +					IRQF_SHARED, KBUILD_MODNAME, rtwdev);
>  	if (ret) {
>  		ieee80211_unregister_hw(hw);
>  		goto err_destroy_pci;
> @@ -1192,7 +1212,7 @@ static void rtw_pci_remove(struct pci_dev *pdev)
>  	rtw_pci_disable_interrupt(rtwdev, rtwpci);
>  	rtw_pci_destroy(rtwdev, pdev);
>  	rtw_pci_declaim(rtwdev, pdev);
> -	free_irq(rtwpci->pdev->irq, rtwdev);
> +	devm_free_irq(rtwdev->dev, rtwpci->pdev->irq, rtwdev);
>  	rtw_core_deinit(rtwdev);
>  	ieee80211_free_hw(hw);
>  }
> --
> 2.20.1


Now it works fine with MSI interrupt enabled.

But this patch is conflicting with MSI interrupt patch.
Is there a better way we can make Kalle apply them more smoothly?
I can rebase them and submit both if you're OK.

Yan-Hsuan

^ permalink raw reply

* Re: [PATCH 10/49] ath11k: add debug.c
From: Anilkumar Kolli @ 2019-08-27  9:04 UTC (permalink / raw)
  To: Sven Eckelmann; +Cc: ath11k, devicetree, linux-wireless, Kalle Valo
In-Reply-To: <4441194.D8eDD6Tzdi@bentobox>

On 2019-08-27 13:05, Sven Eckelmann wrote:
> On Tuesday, 27 August 2019 09:33:39 CEST Anilkumar Kolli wrote:
> [...]
>> >     [ 4312.884650] The reading for sensor 4 is 0x002041f7
>> >     [ 4312.891499] The reading for sensor 5 is 0x002051f4
>> >     [ 4312.896415] Couldn't get reading for sensor 6
>> >     [ 4312.901189] Couldn't get reading for sensor 7
>> >     [ 4312.905561] The reading for sensor 8 is 0x002081e0
>> >     [ 4312.909902] The reading for sensor 9 is 0x002091f7
>> >     [ 4312.914645] Couldn't get reading for sensor 10
>> >     [ 4312.919364] The reading for sensor 11 is 0x0020b1fa
>> >     [ 4312.923791] The reading for sensor 12 is 0x0020c1fa
>> >     [ 4312.928621] Couldn't get reading for sensor 13
>> >     [ 4312.933425] The reading for sensor 14 is 0x0020e1f4
>> >     [ 4312.937941] The reading for sensor 15 is 0x0020f1e7
>> >     [ 4313.942700] Rebooting in 3 seconds..
>> >
>> > Maybe can be fixed by a different kernel (for the remoteproc). But I
>> > don't
>> > have this kernel at the moment.
>> >
>> 
>> The write of an "assert", sends 'WMI_FORCE_FW_HANG_CMDID' WMI command 
>> to
>> target firmware.
>> This WMI command forces the target to assert.
> 
> Yes, but it shouldn't kill the complete system.
> 
This will not kill the whole system, This will crash target and we have 
mechanism to recover the system.

Hope u have generated the crash with below patch,
https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/019-ath11k-disable-q6-recovery-to-crash-kernel.patch?h=win_ap.1.0

Please remove this patch to see the target recover after the crash.

Thanks
Anil


^ permalink raw reply

* Re: [PATCH 5.3] rt2x00: clear up IV's on key removal
From: Emil Karlson @ 2019-08-27  8:30 UTC (permalink / raw)
  To: Stanislaw Gruszka
  Cc: linux-wireless, Felix Fietkau, Daniel Golle, Tomislav Požega,
	Mathias Kresin, Fredrik Noring
In-Reply-To: <1566564483-31088-1-git-send-email-sgruszka@redhat.com>

On Fri, 23 Aug 2019 14:48:03 +0200
Stanislaw Gruszka <sgruszka@redhat.com> wrote:

> After looking at code I realized that my previous fix
> 95844124385e ("rt2x00: clear IV's on start to fix AP mode regression")
> was incomplete. We can still have wrong IV's after re-keyring.
> To fix that, clear up IV's also on key removal.
> 
> Fixes: 710e6cc1595e ("rt2800: do not nullify initialization vector
> data") Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
> ---
>  drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 19
> ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
> b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index
> ecbe78b8027b..28e2de04834e 100644 ---
> a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++
> b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1654,13 +1654,18
> @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev
> *rt2x00dev, offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
>  
> -	rt2800_register_multiread(rt2x00dev, offset,
> -				  &iveiv_entry, sizeof(iveiv_entry));
> -	if ((crypto->cipher == CIPHER_TKIP) ||
> -	    (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
> -	    (crypto->cipher == CIPHER_AES))
> -		iveiv_entry.iv[3] |= 0x20;
> -	iveiv_entry.iv[3] |= key->keyidx << 6;
> +	if (crypto->cmd == SET_KEY) {
> +		rt2800_register_multiread(rt2x00dev, offset,
> +					  &iveiv_entry,
> sizeof(iveiv_entry));
> +		if ((crypto->cipher == CIPHER_TKIP) ||
> +		    (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
> +		    (crypto->cipher == CIPHER_AES))
> +			iveiv_entry.iv[3] |= 0x20;
> +		iveiv_entry.iv[3] |= key->keyidx << 6;
> +	} else {
> +		memset(&iveiv_entry, 0, sizeof(iveiv_entry));
> +	}
> +
>  	rt2800_register_multiwrite(rt2x00dev, offset,
>  				   &iveiv_entry,
> sizeof(iveiv_entry)); }

Seems to work when used with the previous patch on top of 5.3-rc6
tested-by: Emil Karlson <jekarl@iki.fi>

^ permalink raw reply

* [PATCH][V2] bcma: fix incorrect update of BCMA_CORE_PCI_MDIO_DATA
From: Colin King @ 2019-08-27  8:16 UTC (permalink / raw)
  To: Hauke Mehrtens, Rafał Miłecki, linux-wireless
  Cc: kernel-janitors, linux-kernel

From: Colin Ian King <colin.king@canonical.com>

An earlier commit re-worked the setting of the bitmask and is now
assigning v with some bit flags rather than bitwise or-ing them
into v, consequently the earlier bit-settings of v are being lost.
Fix this by replacing an assignment with the bitwise or instead.

Addresses-Coverity: ("Unused value")
Fixes: 2be25cac8402 ("bcma: add constants for PCI and use them")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---

V2: fix bcma_pcie_mdio_write as well as bcma_pcie_mdio_read

---
 drivers/bcma/driver_pci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index f499a469e66d..12b2cc9a3fbe 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -78,7 +78,7 @@ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u16 device, u8 address)
 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
 	}
 
-	v = BCMA_CORE_PCI_MDIODATA_START;
+	v |= BCMA_CORE_PCI_MDIODATA_START;
 	v |= BCMA_CORE_PCI_MDIODATA_READ;
 	v |= BCMA_CORE_PCI_MDIODATA_TA;
 
@@ -121,7 +121,7 @@ static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u16 device,
 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
 	}
 
-	v = BCMA_CORE_PCI_MDIODATA_START;
+	v |= BCMA_CORE_PCI_MDIODATA_START;
 	v |= BCMA_CORE_PCI_MDIODATA_WRITE;
 	v |= BCMA_CORE_PCI_MDIODATA_TA;
 	v |= data;
-- 
2.20.1


^ permalink raw reply related

* Re: [PATCH] bcma: fix incorrect update of BCMA_CORE_PCI_MDIO_DATA
From: Colin Ian King @ 2019-08-27  7:58 UTC (permalink / raw)
  To: Larry Finger, Hauke Mehrtens, Rafał Miłecki,
	linux-wireless
  Cc: kernel-janitors, linux-kernel
In-Reply-To: <f1aa1f6f-d293-c2cd-d1fc-a6b10d49a1bb@lwfinger.net>

On 22/08/2019 17:38, Larry Finger wrote:
> On 8/22/19 11:11 AM, Colin Ian King wrote:
>> On 22/08/2019 17:03, Larry Finger wrote:
>>> On 8/22/19 8:35 AM, Colin King wrote:
>>>> From: Colin Ian King <colin.king@canonical.com>
>>>>
>>>> An earlier commit re-worked the setting of the bitmask and is now
>>>> assigning v with some bit flags rather than bitwise or-ing them
>>>> into v, consequently the earlier bit-settings of v are being lost.
>>>> Fix this by replacing an assignment with the bitwise or instead.
>>>>
>>>> Addresses-Coverity: ("Unused value")
>>>> Fixes: 2be25cac8402 ("bcma: add constants for PCI and use them")
>>>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>>>> ---
>>>>    drivers/bcma/driver_pci.c | 2 +-
>>>>    1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
>>>> index f499a469e66d..d219ee947c07 100644
>>>> --- a/drivers/bcma/driver_pci.c
>>>> +++ b/drivers/bcma/driver_pci.c
>>>> @@ -78,7 +78,7 @@ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci
>>>> *pc, u16 device, u8 address)
>>>>            v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
>>>>        }
>>>>    -    v = BCMA_CORE_PCI_MDIODATA_START;
>>>> +    v |= BCMA_CORE_PCI_MDIODATA_START;
>>>>        v |= BCMA_CORE_PCI_MDIODATA_READ;
>>>>        v |= BCMA_CORE_PCI_MDIODATA_TA;
>>>
>>> I'm not sure the "Fixes" attribute is correct.
>>>
>>> The changes for this section in commit 2be25cac8402 are
>>>
>>> -       v = (1 << 30); /* Start of Transaction */
>>> -       v |= (1 << 28); /* Write Transaction */
>>> -       v |= (1 << 17); /* Turnaround */
>>> -       v |= (0x1F << 18);
>>> +       v = BCMA_CORE_PCI_MDIODATA_START;
>>> +       v |= BCMA_CORE_PCI_MDIODATA_WRITE;
>>> +       v |= (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
>>> +             BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
>>> +       v |= (BCMA_CORE_PCI_MDIODATA_BLK_ADDR <<
>>> +             BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
>>> +       v |= BCMA_CORE_PCI_MDIODATA_TA;
>>>
>>> Because the code has done quite a bit of work on v just above this
>>> section, I agree that this is likely an error, but that error happened
>>> in an earlier commit. Thus 2be25cac8402 did not introduce the error,
>>> merely copied it.

I did a second look at Larry's comments above and realized the code he
is referring to is in bcma_pcie_mdio_set_phy which is OK

Instead, the code I'm fixing is in bcma_pcie_mdio_read, which was broken
by commit 2be25cac8402fab56bb51166f464d1b420bcf744

        if (pc->core->id.rev >= 10) {
                max_retries = 200;
                bcma_pcie_mdio_set_phy(pc, device);
+               v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
+                    BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
+               v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
+       } else {
+               v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
+               v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
        }

-       v = (1 << 30); /* Start of Transaction */
-       v |= (1 << 29); /* Read Transaction */
-       v |= (1 << 17); /* Turnaround */
-       if (pc->core->id.rev < 10)
-               v |= (u32)device << 22;
-       v |= (u32)address << 18;
-       pcicore_write32(pc, mdio_data, v);
+       v = BCMA_CORE_PCI_MDIODATA_START;
+       v |= BCMA_CORE_PCI_MDIODATA_READ;
+       v |= BCMA_CORE_PCI_MDIODATA_TA;
+
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);


>>
>> Ugh, this goes back further. I didn't spot that. I'm less confident of
>> what the correct settings should be now.
>>
>>>
>>> Has this change been tested?
>>
>> Afraid not, I don't have the H/W.
> 
> I admit that I looked at this only because I found it hard to believe
> that the collective wisdom of the list would have missed the usage of
> "=" instead of "|=". At least that test was passed. :)

Maybe not after all :-)

> 
> Larry
> 

I'll send a V2 with the write fix, and the same fixes commit sha

^ permalink raw reply

* RE: [PATCH 1/7] ath10k: enable RX bundle receive for sdio
From: Wen Gong @ 2019-08-27  8:02 UTC (permalink / raw)
  To: Nicolas Boichat, Wen Gong
  Cc: open list:NETWORKING DRIVERS (WIRELESS),
	ath10k@lists.infradead.org
In-Reply-To: <CANMq1KBR0nd+XOJWpgWyoJdsFgZByQyjD-0dpttygiN0OfiD5Q@mail.gmail.com>

> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Nicolas
> Boichat
> Sent: Tuesday, August 27, 2019 3:41 PM
> To: Wen Gong <wgong@codeaurora.org>
> Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> wireless@vger.kernel.org>; ath10k@lists.infradead.org
> 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
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply

* Re: [PATCH 1/7] ath10k: enable RX bundle receive for sdio
From: Nicolas Boichat @ 2019-08-27  8:08 UTC (permalink / raw)
  To: Wen Gong
  Cc: Wen Gong, open list:NETWORKING DRIVERS (WIRELESS),
	ath10k@lists.infradead.org
In-Reply-To: <2ec213d88ebb4b89812826866b39886d@aptaiexm02f.ap.qualcomm.com>

On Tue, Aug 27, 2019 at 4:03 PM Wen Gong <wgong@qti.qualcomm.com> wrote:
>
> > -----Original Message-----
> > From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Nicolas
> > Boichat
> > Sent: Tuesday, August 27, 2019 3:41 PM
> > To: Wen Gong <wgong@codeaurora.org>
> > Cc: open list:NETWORKING DRIVERS (WIRELESS) <linux-
> > wireless@vger.kernel.org>; ath10k@lists.infradead.org
> > 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
> > ath10k@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply

* Re: [PATCH 4/7] ath10k: disable TX complete indication of htt for sdio
From: Nicolas Boichat @ 2019-08-27  7:56 UTC (permalink / raw)
  To: Wen Gong; +Cc: ath10k, open list:NETWORKING DRIVERS (WIRELESS)
In-Reply-To: <1566302108-18219-5-git-send-email-wgong@codeaurora.org>

On Tue, Aug 20, 2019 at 7:55 PM Wen Gong <wgong@codeaurora.org> 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 <wgong@codeaurora.org>
> ---
>  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
>

^ permalink raw reply

* Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to 32 for sdio
From: Nicolas Boichat @ 2019-08-27  7:42 UTC (permalink / raw)
  To: Wen Gong; +Cc: ath10k, open list:NETWORKING DRIVERS (WIRELESS)
In-Reply-To: <1566302108-18219-3-git-send-email-wgong@codeaurora.org>

On Tue, Aug 20, 2019 at 7:55 PM Wen Gong <wgong@codeaurora.org> 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 <wgong@codeaurora.org>
> ---
>  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
>

^ permalink raw reply

* Re: [PATCH 1/7] ath10k: enable RX bundle receive for sdio
From: Nicolas Boichat @ 2019-08-27  7:40 UTC (permalink / raw)
  To: Wen Gong; +Cc: ath10k, open list:NETWORKING DRIVERS (WIRELESS)
In-Reply-To: <1566302108-18219-2-git-send-email-wgong@codeaurora.org>

On Tue, Aug 20, 2019 at 7:55 PM Wen Gong <wgong@codeaurora.org> wrote:
>
> From: Alagu Sankar <alagusankar@silex-india.com>
>
> 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 <alagusankar@silex-india.com>
> Signed-off-by: Wen Gong <wgong@codeaurora.org>
> ---
>  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
>

^ permalink raw reply

* Re: [PATCH 10/49] ath11k: add debug.c
From: Sven Eckelmann @ 2019-08-27  7:35 UTC (permalink / raw)
  To: Anilkumar Kolli; +Cc: ath11k, devicetree, linux-wireless, Kalle Valo
In-Reply-To: <80bdedf3740960e0ce05b02a77d1b457@codeaurora.org>

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

On Tuesday, 27 August 2019 09:33:39 CEST Anilkumar Kolli wrote:
[...]
> >     [ 4312.884650] The reading for sensor 4 is 0x002041f7
> >     [ 4312.891499] The reading for sensor 5 is 0x002051f4
> >     [ 4312.896415] Couldn't get reading for sensor 6
> >     [ 4312.901189] Couldn't get reading for sensor 7
> >     [ 4312.905561] The reading for sensor 8 is 0x002081e0
> >     [ 4312.909902] The reading for sensor 9 is 0x002091f7
> >     [ 4312.914645] Couldn't get reading for sensor 10
> >     [ 4312.919364] The reading for sensor 11 is 0x0020b1fa
> >     [ 4312.923791] The reading for sensor 12 is 0x0020c1fa
> >     [ 4312.928621] Couldn't get reading for sensor 13
> >     [ 4312.933425] The reading for sensor 14 is 0x0020e1f4
> >     [ 4312.937941] The reading for sensor 15 is 0x0020f1e7
> >     [ 4313.942700] Rebooting in 3 seconds..
> > 
> > Maybe can be fixed by a different kernel (for the remoteproc). But I 
> > don't
> > have this kernel at the moment.
> > 
> 
> The write of an "assert", sends 'WMI_FORCE_FW_HANG_CMDID' WMI command to 
> target firmware.
> This WMI command forces the target to assert.

Yes, but it shouldn't kill the complete system.

Kind regards,
	Sven

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

^ permalink raw reply

* Re: [PATCH 10/49] ath11k: add debug.c
From: Anilkumar Kolli @ 2019-08-27  7:33 UTC (permalink / raw)
  To: Sven Eckelmann; +Cc: ath11k, devicetree, linux-wireless, Kalle Valo
In-Reply-To: <2708501.D2hezO5Rnt@bentobox>

On 2019-08-26 19:17, Sven Eckelmann wrote:
> On Tuesday, 20 August 2019 17:47:36 CEST Kalle Valo wrote:
>> +static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
>> +                                            char __user *user_buf,
>> +                                            size_t count, loff_t 
>> *ppos)
>> +{
>> +       const char buf[] =
>> +               "To simulate firmware crash write one of the keywords 
>> to this file:\n"
>> +               "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to 
>> firmware to cause assert.\n"
>> +               "`hw-restart` - this will simply queue hw restart 
>> without fw/hw actually crashing.\n";
>> +
>> +       return simple_read_from_buffer(user_buf, count, ppos, buf, 
>> strlen(buf));
>> +}
> 
> There is nothing in the write handler which handles "hw-restart". It 
> just
> causes an -EINVAL.
> 

Yes. I will add "hw-restart".

>> +
>> +/* Simulate firmware crash:
>> + * 'soft': Call wmi command causing firmware hang. This firmware hang 
>> is
>> + * recoverable by warm firmware reset.
>> + * 'hard': Force firmware crash by setting any vdev parameter for not 
>> allowed
>> + * vdev id. This is hard firmware crash because it is recoverable 
>> only by cold
>> + * firmware reset.
>> + */
>> +static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
>> +                                             const char __user 
>> *user_buf,
>> +                                             size_t count, loff_t 
>> *ppos)
>> +{
>> +       struct ath11k_base *ab = file->private_data;
>> +       struct ath11k_pdev *pdev;
>> +       struct ath11k *ar = ab->pdevs[0].ar;
>> +       char buf[32] = {0};
>> +       ssize_t rc;
>> +       int i, ret, radioup;
>> +
>> +       for (i = 0; i < ab->num_radios; i++) {
>> +               pdev = &ab->pdevs[i];
>> +               ar = pdev->ar;
>> +               if (ar && ar->state == ATH11K_STATE_ON) {
>> +                       radioup = 1;
>> +                       break;
>> +               }
>> +       }
>> +       /* filter partial writes and invalid commands */
>> +       if (*ppos != 0 || count >= sizeof(buf) || count == 0)
>> +               return -EINVAL;
>> +
>> +       rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 
>> user_buf, count);
>> +       if (rc < 0)
>> +               return rc;
>> +
>> +       /* drop the possible '\n' from the end */
>> +       if (buf[*ppos - 1] == '\n')
>> +               buf[*ppos - 1] = '\0';
>> +
>> +       if (radioup == 0) {
>> +               ret = -ENETDOWN;
>> +               goto exit;
>> +       }
>> +
>> +       if (!strcmp(buf, "assert")) {
>> +               ath11k_info(ab, "simulating firmware assert crash\n");
>> +               ret = ath11k_wmi_force_fw_hang_cmd(ar,
>> +                                                  
>> ATH11K_WMI_FW_HANG_ASSERT_TYPE,
>> +                                                  
>> ATH11K_WMI_FW_HANG_DELAY);
>> +       } else {
>> +               ret = -EINVAL;
>> +               goto exit;
>> +       }
>> +
>> +       if (ret) {
>> +               ath11k_warn(ab, "failed to simulate firmware crash: 
>> %d\n", ret);
>> +               goto exit;
>> +       }
>> +
>> +       ret = count;
>> +
>> +exit:
>> +       return ret;
>> +}
> 
> And right now, the write of an "assert" to this file just causes an
> fatal error for the system:
> 
>     [ 4312.409255] qcom-q6v5-wcss-pil cd00000.qcom_q6v5_wcss: fatal
> error received:
>     [ 4312.409255] QC Image Version:
> QC_IMAGE_VERSION_STRING=WLAN.HK.2.1.0.1-00410-QCAHKSWPL_SILICONZ-2
>     [ 4312.409255] Image Variant : 
> IMAGE_VARIANT_STRING=8074.wlanfw.eval_v2Q
>     [ 4312.409255]
>     [ 4312.409255] wlan_wmi.c:234 Assertion 0 failedparam0 :zero,
> param1 :zero, param2 :zero.
>     [ 4312.409255] Thread ID      : 0x00000069  Thread name    : WLAN
> RT0  Process ID     : 0
>     [ 4312.409255] Register:
>     [ 4312.409255] SP : 0x4c168d58
>     [ 4312.409255] FP : 0x4c168d60
>     [ 4312.409255] PC : 0x4b1c8850
>     [ 4312.409255] SSR : 0x00000008
>     [ 4312.409255] BADVA : 0x00020000
>     [ 4312.409255] LR : 0x4b1c7c68
>     [ 4312.409255]
>     [ 4312.409255] Stack Dump
>     [ 4312.409255] from : 0x4c168d58
>     [ 4312.409255] to   : 0x4c168f00
>     [ 4312.409255]
>     [ 4312.455997] remoteproc remoteproc0: crash detected in
> cd00000.qcom_q6v5_wcss: type fatal error
>     [ 4312.478259] remoteproc remoteproc0: handling crash #1 in
> cd00000.qcom_q6v5_wcss
>     [ 4312.486826] Kernel panic - not syncing: remoteproc remoteproc0:
> Resetting the SoC - cd00000.qcom_q6v5_wcss crashed
>     [ 4312.494028] CPU: 2 PID: 5590 Comm: kworker/2:0 Tainted: G
>  W       4.4.60 #0
>     [ 4312.504436] Hardware name: Generic DT based system
>     [ 4312.511991] Workqueue: events rproc_crash_handler_work
>     [ 4312.521880] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.521979] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.529789] [<803dd818>] (dump_stack) from [<80225d80>]
> (panic+0x84/0x1f8)
>     [ 4312.536818] [<80225d80>] (panic) from [<80555278>]
> (rproc_crash_handler_work+0x90/0x98)
>     [ 4312.543678] [<80555278>] (rproc_crash_handler_work) from
> [<802380e8>] (process_one_work+0x1c0/0x2f8)
>     [ 4312.551578] [<802380e8>] (process_one_work) from [<80238d24>]
> (worker_thread+0x2b0/0x3ec)
>     [ 4312.560952] [<80238d24>] (worker_thread) from [<8023cf84>]
> (kthread+0xd8/0xec)
>     [ 4312.569023] [<8023cf84>] (kthread) from [<80209be8>]
> (ret_from_fork+0x14/0x2c)
>     [ 4312.576141] CPU0: stopping
>     [ 4312.583335] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G        W
>     4.4.60 #0
>     [ 4312.586032] Hardware name: Generic DT based system
>     [ 4312.593237] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.597930] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.605827] [<803dd818>] (dump_stack) from [<8021dc3c>]
> (handle_IPI+0xe8/0x180)
>     [ 4312.612858] [<8021dc3c>] (handle_IPI) from [<802093a4>]
> (gic_handle_irq+0x78/0x94)
>     [ 4312.620063] [<802093a4>] (gic_handle_irq) from [<8020a480>]
> (__irq_svc+0x40/0x74)
>     [ 4312.627701] Exception stack(0x80c67f60 to 0x80c67fa8)
>     [ 4312.635249] 7f60: 00000001 00000000 00000000 8020b320 00000000
> 80c66000 00000000 80c612cc
>     [ 4312.640291] 7f80: 80c67fb8 808f3a30 80cae010 00000000 00000000
> 80c67fb0 80218edc 80218ee0
>     [ 4312.648448] 7fa0: 60000013 ffffffff
>     [ 4312.656601] [<8020a480>] (__irq_svc) from [<80218ee0>]
> (arch_cpu_idle+0x2c/0x50)
>     [ 4312.659909] [<80218ee0>] (arch_cpu_idle) from [<80254b38>]
> (cpu_startup_entry+0x134/0x214)
>     [ 4312.667553] [<80254b38>] (cpu_startup_entry) from [<808cac48>]
> (start_kernel+0x380/0x404)
>     [ 4312.675620] CPU1: stopping
>     [ 4312.683855] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G        W
>     4.4.60 #0
>     [ 4312.686466] Hardware name: Generic DT based system
>     [ 4312.693671] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.698363] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.706263] [<803dd818>] (dump_stack) from [<8021dc3c>]
> (handle_IPI+0xe8/0x180)
>     [ 4312.713293] [<8021dc3c>] (handle_IPI) from [<802093a4>]
> (gic_handle_irq+0x78/0x94)
>     [ 4312.720497] [<802093a4>] (gic_handle_irq) from [<8020a480>]
> (__irq_svc+0x40/0x74)
>     [ 4312.728135] Exception stack(0xbe083f98 to 0xbe083fe0)
>     [ 4312.735683] 3f80:
>         00000001 00000000
>     [ 4312.740725] 3fa0: 00000000 8020b320 00000000 be082000 00000000
> 80c612cc be083ff0 410fd034
>     [ 4312.748884] 3fc0: 00000000 00000000 00000000 be083fe8 80218edc
> 80218ee0 60000013 ffffffff
>     [ 4312.757045] [<8020a480>] (__irq_svc) from [<80218ee0>]
> (arch_cpu_idle+0x2c/0x50)
>     [ 4312.765203] [<80218ee0>] (arch_cpu_idle) from [<80254b38>]
> (cpu_startup_entry+0x134/0x214)
>     [ 4312.772669] [<80254b38>] (cpu_startup_entry) from [<4120944c>]
> (0x4120944c)
>     [ 4312.780737] CPU3: stopping
>     [ 4312.787589] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G        W
>     4.4.60 #0
>     [ 4312.790372] Hardware name: Generic DT based system
>     [ 4312.797577] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.802270] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.810167] [<803dd818>] (dump_stack) from [<8021dc3c>]
> (handle_IPI+0xe8/0x180)
>     [ 4312.817199] [<8021dc3c>] (handle_IPI) from [<802093a4>]
> (gic_handle_irq+0x78/0x94)
>     [ 4312.824403] [<802093a4>] (gic_handle_irq) from [<8020a480>]
> (__irq_svc+0x40/0x74)
>     [ 4312.832041] Exception stack(0xbe087f98 to 0xbe087fe0)
>     [ 4312.839588] 7f80:
>         00000001 00000000
>     [ 4312.844630] 7fa0: 00000000 8020b320 00000000 be086000 00000000
> 80c612cc be087ff0 410fd034
>     [ 4312.852791] 7fc0: 00000000 00000000 00000000 be087fe8 80218edc
> 80218ee0 60000013 ffffffff
>     [ 4312.860951] [<8020a480>] (__irq_svc) from [<80218ee0>]
> (arch_cpu_idle+0x2c/0x50)
>     [ 4312.869109] [<80218ee0>] (arch_cpu_idle) from [<80254b38>]
> (cpu_startup_entry+0x134/0x214)
>     [ 4312.876576] [<80254b38>] (cpu_startup_entry) from [<4120944c>]
> (0x4120944c)
>     [ 4312.884650] The reading for sensor 4 is 0x002041f7
>     [ 4312.891499] The reading for sensor 5 is 0x002051f4
>     [ 4312.896415] Couldn't get reading for sensor 6
>     [ 4312.901189] Couldn't get reading for sensor 7
>     [ 4312.905561] The reading for sensor 8 is 0x002081e0
>     [ 4312.909902] The reading for sensor 9 is 0x002091f7
>     [ 4312.914645] Couldn't get reading for sensor 10
>     [ 4312.919364] The reading for sensor 11 is 0x0020b1fa
>     [ 4312.923791] The reading for sensor 12 is 0x0020c1fa
>     [ 4312.928621] Couldn't get reading for sensor 13
>     [ 4312.933425] The reading for sensor 14 is 0x0020e1f4
>     [ 4312.937941] The reading for sensor 15 is 0x0020f1e7
>     [ 4313.942700] Rebooting in 3 seconds..
> 
> Maybe can be fixed by a different kernel (for the remoteproc). But I 
> don't
> have this kernel at the moment.
> 

The write of an "assert", sends 'WMI_FORCE_FW_HANG_CMDID' WMI command to 
target firmware.
This WMI command forces the target to assert.

Anil

> 
> Kind regards,
> 	Sven
> _______________________________________________
> ath11k mailing list
> ath11k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath11k

-- 
Thanks
Anil.

^ permalink raw reply

* [PATCH v2] ath10k: Adjust skb length in ath10k_sdio_mbox_rx_packet
From: Nicolas Boichat @ 2019-08-27  6:58 UTC (permalink / raw)
  To: Kalle Valo
  Cc: David S . Miller, ath10k, linux-wireless, netdev, linux-kernel,
	wgong, Niklas Cassel, Alagu Sankar, briannorris, tientzu

When the FW bundles multiple packets, pkt->act_len may be incorrect
as it refers to the first packet only (however, the FW will only
bundle packets that fit into the same pkt->alloc_len).

Before this patch, the skb length would be set (incorrectly) to
pkt->act_len in ath10k_sdio_mbox_rx_packet, and then later manually
adjusted in ath10k_sdio_mbox_rx_process_packet.

The first problem is that ath10k_sdio_mbox_rx_process_packet does not
use proper skb_put commands to adjust the length (it directly changes
skb->len), so we end up with a mismatch between skb->head + skb->tail
and skb->data + skb->len. This is quite serious, and causes corruptions
in the TCP stack, as the stack tries to coalesce packets, and relies
on skb->tail being correct (that is, skb_tail_pointer must point to
the first byte_after_ the data).

Instead of re-adjusting the size in ath10k_sdio_mbox_rx_process_packet,
this moves the code to ath10k_sdio_mbox_rx_packet, and also add a
bounds check, as skb_put would crash the kernel if not enough space is
available.

Fixes: 8530b4e7b22bc3b ("ath10k: sdio: set skb len for all rx packets")
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>

---

One simple way to reproduce this issue is this scriplet, that sends a
lot of small packets over SSH (it usually fails before reaching 300):
(for i in `seq 1 300`; do echo $i; sleep 0.1; done) | ssh $IP cat

I was not able to check the original use case why the code was added
(packets > 1500 bytes), as the FW on my board crashes when sending
such large packets.

 drivers/net/wireless/ath/ath10k/sdio.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 8ed4fbd8d6c3888..0a3ac44a13698c1 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -381,16 +381,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
 	struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
 	bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
 	enum ath10k_htc_ep_id eid;
-	u16 payload_len;
 	u8 *trailer;
 	int ret;
 
-	payload_len = le16_to_cpu(htc_hdr->len);
-	skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
-
 	if (trailer_present) {
-		trailer = skb->data + sizeof(*htc_hdr) +
-			  payload_len - htc_hdr->trailer_len;
+		trailer = skb->data + skb->len - htc_hdr->trailer_len;
 
 		eid = pipe_id_to_eid(htc_hdr->eid);
 
@@ -636,9 +631,23 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
 
 	ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
 				 skb->data, pkt->alloc_len);
+	if (!ret) {
+		/* Update actual length. The original length may be incorrect,
+		 * as the FW will bundle multiple packets as long as their sizes
+		 * fit within the same aligned length (pkt->alloc_len).
+		 */
+		struct ath10k_htc_hdr *htc_hdr =
+			(struct ath10k_htc_hdr *)skb->data;
+		pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
+		if (pkt->act_len <= pkt->alloc_len) {
+			skb_put(skb, pkt->act_len);
+		} else {
+			ath10k_warn(ar, "rx_packet too large (%d > %d)\n",
+				    pkt->act_len, pkt->alloc_len);
+			ret = -EMSGSIZE;
+		}
+	}
 	pkt->status = ret;
-	if (!ret)
-		skb_put(skb, pkt->act_len);
 
 	return ret;
 }
-- 
2.23.0.187.g17f5b7556c-goog


^ permalink raw reply related

* Re: [PATCH, RFC] ath10k: Fix skb->len (properly) in ath10k_sdio_mbox_rx_packet
From: Nicolas Boichat @ 2019-08-27  5:23 UTC (permalink / raw)
  To: Wen Gong
  Cc: kvalo@codeaurora.org, Alagu Sankar, netdev@vger.kernel.org,
	briannorris@chromium.org, linux-wireless@vger.kernel.org,
	linux-kernel@vger.kernel.org, ath10k@lists.infradead.org,
	wgong@codeaurora.org, niklas.cassel@linaro.org,
	tientzu@chromium.org, David S . Miller
In-Reply-To: <36878f3488f047978038c844daedd02f@aptaiexm02f.ap.qualcomm.com>

On Tue, Aug 27, 2019 at 11:34 AM Wen Gong <wgong@qti.qualcomm.com> wrote:
>
> > -----Original Message-----
> > From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Nicolas
> > Boichat
> > Sent: Tuesday, August 27, 2019 8:33 AM
> > To: kvalo@codeaurora.org
> > Cc: Alagu Sankar <alagusankar@silex-india.com>; netdev@vger.kernel.org;
> > briannorris@chromium.org; linux-wireless@vger.kernel.org; linux-
> > kernel@vger.kernel.org; ath10k@lists.infradead.org;
> > wgong@codeaurora.org; niklas.cassel@linaro.org; tientzu@chromium.org;
> > David S . Miller <davem@davemloft.net>
> > Subject: [EXT] [PATCH, RFC] ath10k: Fix skb->len (properly) in
> > ath10k_sdio_mbox_rx_packet
> >
> > (not a formal patch, take this as a bug report for now, I can clean
> > up depending on the feedback I get here)
> >
> > There's at least 3 issues here, and the patch fixes 2/3 only, I'm not sure
> > how/if 1 should be handled.
> >  1. ath10k_sdio_mbox_rx_alloc allocating skb of a incorrect size (too
> >     small)
> >  2. ath10k_sdio_mbox_rx_packet calling skb_put with that incorrect size.
> >  3. ath10k_sdio_mbox_rx_process_packet attempts to fixup the size, but
> >     does not use proper skb_put commands to do so, so we end up with
> >     a mismatch between skb->head + skb->tail and skb->data + skb->len.
> >
> > Let's start with 3, this is quite serious as this and causes corruptions
> > in the TCP stack, as the stack tries to coalesce packets, and relies on
> > skb->tail being correct (that is, skb_tail_pointer must point to the
> > first byte _after_ the data): one must never manipulate skb->len
> > directly.
> >
> > Instead, we need to use skb_put to allocate more space (which updates
> > skb->len and skb->tail). But it seems odd to do that in
> > ath10k_sdio_mbox_rx_process_packet, so I move the code to
> > ath10k_sdio_mbox_rx_packet (point 2 above).
> >
> > However, there is still something strange (point 1 above), why is
> > ath10k_sdio_mbox_rx_alloc allocating packets of the incorrect
> > (too small?) size? What happens if the packet is bigger than alloc_len?
> > Does this lead to corruption/lost data?
> >
> > Fixes: 8530b4e7b22bc3b ("ath10k: sdio: set skb len for all rx packets")
> > Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> >
> > ---
> >
> > One simple way to test this is this scriplet, that sends a lot of
> > small packets over SSH:
> > (for i in `seq 1 300`; do echo $i; sleep 0.1; done) | ssh $IP cat
> >
> > In my testing it rarely ever reach 300 without failure.
> >
> >  drivers/net/wireless/ath/ath10k/sdio.c | 18 ++++++++++++------
> >  1 file changed, 12 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/net/wireless/ath/ath10k/sdio.c
> > b/drivers/net/wireless/ath/ath10k/sdio.c
> > index 8ed4fbd8d6c3888..a9f5002863ee7bb 100644
> > --- a/drivers/net/wireless/ath/ath10k/sdio.c
> > +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> > @@ -381,16 +381,14 @@ static int
> > ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
> >       struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
> >       bool trailer_present = htc_hdr->flags &
> > ATH10K_HTC_FLAG_TRAILER_PRESENT;
> >       enum ath10k_htc_ep_id eid;
> > -     u16 payload_len;
> >       u8 *trailer;
> >       int ret;
> >
> > -     payload_len = le16_to_cpu(htc_hdr->len);
> > -     skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
> > +     /* TODO: Remove this? */
> If the pkt->act_len has set again in ath10k_sdio_mbox_rx_packet, seems not needed.

Sure, will drop.

> > +     WARN_ON(skb->len != le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr));
> >
> >       if (trailer_present) {
> > -             trailer = skb->data + sizeof(*htc_hdr) +
> > -                       payload_len - htc_hdr->trailer_len;
> > +             trailer = skb->data + skb->len - htc_hdr->trailer_len;
> >
> >               eid = pipe_id_to_eid(htc_hdr->eid);
> >
> > @@ -637,8 +635,16 @@ static int ath10k_sdio_mbox_rx_packet(struct
> > ath10k *ar,
> >       ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
> >                                skb->data, pkt->alloc_len);
> >       pkt->status = ret;
> > -     if (!ret)
> > +     if (!ret) {
> > +             /* Update actual length. */
> > +             /* FIXME: This looks quite wrong, why is pkt->act_len not
> > +              * correct in the first place?
> > +              */
> Firmware will do bundle for rx packet, and the aligned length by block size(256) of each packet's len is same
> in a bundle.
>
> Eg.
> packet 1 len: 300, aligned length:512
> packet 2 len: 400, aligned length:512
> packet 3 len: 200, aligned length:256
> packet 4 len: 100, aligned length:256
> packet 5 len: 700, aligned length:768
> packet 6 len: 600, aligned length:768
>
> then packet 1,2 will in bundle 1, packet 3,4 in a bundle 2, packet 5,6 in a bundle 3.
>
> For bundle 1, packet 1,2 will both allocate with len 512, and act_len is 300 first,
> then packet 2's len will be overwrite to 400.
>
> For bundle 2, packet 3,4 will both allocate with len 256, and act_len is 200 first,
> then packet 4's len will be overwrite to 100.
>
> For bundle 3, packet 5,6 will both allocate with len 768, and act_len is 700 first,
> then packet 6's len will be overwrite to 600.

Ok thanks, I'll send a v2 with an improved description.

> > +             struct ath10k_htc_hdr *htc_hdr =
> > +                     (struct ath10k_htc_hdr *)skb->data;
> > +             pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
> >               skb_put(skb, pkt->act_len);
> > +     }
> >
> >       return ret;
> >  }
> > --
> > 2.23.0.187.g17f5b7556c-goog
> >
> >
> > _______________________________________________
> > ath10k mailing list
> > ath10k@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply

* RE: [PATCH, RFC] ath10k: Fix skb->len (properly) in ath10k_sdio_mbox_rx_packet
From: Wen Gong @ 2019-08-27  3:33 UTC (permalink / raw)
  To: Nicolas Boichat, kvalo@codeaurora.org
  Cc: Alagu Sankar, netdev@vger.kernel.org, briannorris@chromium.org,
	linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org,
	ath10k@lists.infradead.org, wgong@codeaurora.org,
	niklas.cassel@linaro.org, tientzu@chromium.org, David S . Miller
In-Reply-To: <20190827003326.147452-1-drinkcat@chromium.org>

> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Nicolas
> Boichat
> Sent: Tuesday, August 27, 2019 8:33 AM
> To: kvalo@codeaurora.org
> Cc: Alagu Sankar <alagusankar@silex-india.com>; netdev@vger.kernel.org;
> briannorris@chromium.org; linux-wireless@vger.kernel.org; linux-
> kernel@vger.kernel.org; ath10k@lists.infradead.org;
> wgong@codeaurora.org; niklas.cassel@linaro.org; tientzu@chromium.org;
> David S . Miller <davem@davemloft.net>
> Subject: [EXT] [PATCH, RFC] ath10k: Fix skb->len (properly) in
> ath10k_sdio_mbox_rx_packet
> 
> (not a formal patch, take this as a bug report for now, I can clean
> up depending on the feedback I get here)
> 
> There's at least 3 issues here, and the patch fixes 2/3 only, I'm not sure
> how/if 1 should be handled.
>  1. ath10k_sdio_mbox_rx_alloc allocating skb of a incorrect size (too
>     small)
>  2. ath10k_sdio_mbox_rx_packet calling skb_put with that incorrect size.
>  3. ath10k_sdio_mbox_rx_process_packet attempts to fixup the size, but
>     does not use proper skb_put commands to do so, so we end up with
>     a mismatch between skb->head + skb->tail and skb->data + skb->len.
> 
> Let's start with 3, this is quite serious as this and causes corruptions
> in the TCP stack, as the stack tries to coalesce packets, and relies on
> skb->tail being correct (that is, skb_tail_pointer must point to the
> first byte _after_ the data): one must never manipulate skb->len
> directly.
> 
> Instead, we need to use skb_put to allocate more space (which updates
> skb->len and skb->tail). But it seems odd to do that in
> ath10k_sdio_mbox_rx_process_packet, so I move the code to
> ath10k_sdio_mbox_rx_packet (point 2 above).
> 
> However, there is still something strange (point 1 above), why is
> ath10k_sdio_mbox_rx_alloc allocating packets of the incorrect
> (too small?) size? What happens if the packet is bigger than alloc_len?
> Does this lead to corruption/lost data?
> 
> Fixes: 8530b4e7b22bc3b ("ath10k: sdio: set skb len for all rx packets")
> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> 
> ---
> 
> One simple way to test this is this scriplet, that sends a lot of
> small packets over SSH:
> (for i in `seq 1 300`; do echo $i; sleep 0.1; done) | ssh $IP cat
> 
> In my testing it rarely ever reach 300 without failure.
> 
>  drivers/net/wireless/ath/ath10k/sdio.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath10k/sdio.c
> b/drivers/net/wireless/ath/ath10k/sdio.c
> index 8ed4fbd8d6c3888..a9f5002863ee7bb 100644
> --- a/drivers/net/wireless/ath/ath10k/sdio.c
> +++ b/drivers/net/wireless/ath/ath10k/sdio.c
> @@ -381,16 +381,14 @@ static int
> ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
>  	struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
>  	bool trailer_present = htc_hdr->flags &
> ATH10K_HTC_FLAG_TRAILER_PRESENT;
>  	enum ath10k_htc_ep_id eid;
> -	u16 payload_len;
>  	u8 *trailer;
>  	int ret;
> 
> -	payload_len = le16_to_cpu(htc_hdr->len);
> -	skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
> +	/* TODO: Remove this? */
If the pkt->act_len has set again in ath10k_sdio_mbox_rx_packet, seems not needed.
> +	WARN_ON(skb->len != le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr));
> 
>  	if (trailer_present) {
> -		trailer = skb->data + sizeof(*htc_hdr) +
> -			  payload_len - htc_hdr->trailer_len;
> +		trailer = skb->data + skb->len - htc_hdr->trailer_len;
> 
>  		eid = pipe_id_to_eid(htc_hdr->eid);
> 
> @@ -637,8 +635,16 @@ static int ath10k_sdio_mbox_rx_packet(struct
> ath10k *ar,
>  	ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
>  				 skb->data, pkt->alloc_len);
>  	pkt->status = ret;
> -	if (!ret)
> +	if (!ret) {
> +		/* Update actual length. */
> +		/* FIXME: This looks quite wrong, why is pkt->act_len not
> +		 * correct in the first place?
> +		 */
Firmware will do bundle for rx packet, and the aligned length by block size(256) of each packet's len is same 
in a bundle.

Eg. 
packet 1 len: 300, aligned length:512
packet 2 len: 400, aligned length:512
packet 3 len: 200, aligned length:256
packet 4 len: 100, aligned length:256
packet 5 len: 700, aligned length:768
packet 6 len: 600, aligned length:768

then packet 1,2 will in bundle 1, packet 3,4 in a bundle 2, packet 5,6 in a bundle 3.

For bundle 1, packet 1,2 will both allocate with len 512, and act_len is 300 first,
then packet 2's len will be overwrite to 400.

For bundle 2, packet 3,4 will both allocate with len 256, and act_len is 200 first,
then packet 4's len will be overwrite to 100.

For bundle 3, packet 5,6 will both allocate with len 768, and act_len is 700 first,
then packet 6's len will be overwrite to 600.

> +		struct ath10k_htc_hdr *htc_hdr =
> +			(struct ath10k_htc_hdr *)skb->data;
> +		pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
>  		skb_put(skb, pkt->act_len);
> +	}
> 
>  	return ret;
>  }
> --
> 2.23.0.187.g17f5b7556c-goog
> 
> 
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply


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