lede/package/kernel/mac80211/patches/ath11k/143-ath11k-disabling-credit-flow-for-ath11k.patch

440 lines
13 KiB
Diff

From 929e141221444868ee98f253717479e5dd333102 Mon Sep 17 00:00:00 2001
From: Maharaja Kennadyrajan <mkenna@codeaurora.org>
Date: Fri, 19 Mar 2021 14:45:37 +0530
Subject: [PATCH] ath11k: register copy engine send completion callback
Register send completion callback for copy engine-0 (CE0)
for the function ath11k_htc_tx_completion_handler().
This callback will be used for freeing the skbs allocated
by the ath11k_htc_send() from the below functions:
ath11k_htc_connect_service() & ath11k_htc_start().
Signed-off-by: Maharaja Kennadyrajan <mkenna@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/ce.c | 33 +++++++++++----
drivers/net/wireless/ath/ath11k/ce.h | 3 +-
drivers/net/wireless/ath/ath11k/core.c | 2 +
drivers/net/wireless/ath/ath11k/htc.c | 75 ++++++++++++++++++++++++----------
drivers/net/wireless/ath/ath11k/htc.h | 4 ++
drivers/net/wireless/ath/ath11k/hw.h | 1 +
drivers/net/wireless/ath/ath11k/wmi.c | 54 +++++++++++++++++++++---
drivers/net/wireless/ath/ath11k/wmi.h | 1 +
8 files changed, 138 insertions(+), 35 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/ce.c
+++ b/drivers/net/wireless/ath/ath11k/ce.c
@@ -14,6 +14,7 @@ const struct ce_attr ath11k_host_ce_conf
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
+ .send_cb = ath11k_htc_tx_completion_handler,
},
/* CE1: target->host HTT + HTC control */
@@ -40,6 +41,7 @@ const struct ce_attr ath11k_host_ce_conf
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
+ .send_cb = ath11k_htc_tx_completion_handler,
},
/* CE4: host->target HTT */
@@ -73,6 +75,7 @@ const struct ce_attr ath11k_host_ce_conf
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
+ .send_cb = ath11k_htc_tx_completion_handler,
},
/* CE8: target autonomous hif_memcpy */
@@ -89,6 +92,7 @@ const struct ce_attr ath11k_host_ce_conf
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
+ .send_cb = ath11k_htc_tx_completion_handler,
},
/* CE10: target->host HTT */
@@ -116,6 +120,7 @@ const struct ce_attr ath11k_host_ce_conf
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
+ .send_cb = ath11k_htc_tx_completion_handler,
},
/* CE1: target->host HTT + HTC control */
@@ -142,6 +147,7 @@ const struct ce_attr ath11k_host_ce_conf
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
+ .send_cb = ath11k_htc_tx_completion_handler,
},
/* CE4: host->target HTT */
@@ -436,19 +442,33 @@ err_unlock:
return skb;
}
-static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe)
+static void ath11k_ce_tx_process_cb(struct ath11k_ce_pipe *pipe)
{
struct ath11k_base *ab = pipe->ab;
struct sk_buff *skb;
+ struct sk_buff_head list;
+ __skb_queue_head_init(&list);
while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) {
if (!skb)
continue;
dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len,
DMA_TO_DEVICE);
- dev_kfree_skb_any(skb);
+ if ((!pipe->send_cb) || ab->hw_params.credit_flow) {
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ __skb_queue_tail(&list, skb);
}
+
+ while ((skb = __skb_dequeue(&list))) {
+ ath11k_dbg(ab, ATH11K_DBG_AHB, "tx ce pipe %d len %d\n",
+ pipe->pipe_num, skb->len);
+ pipe->send_cb(ab, skb);
+ }
+
}
static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_id,
@@ -582,7 +602,7 @@ static int ath11k_ce_alloc_pipe(struct a
pipe->attr_flags = attr->flags;
if (attr->src_nentries) {
- pipe->send_cb = ath11k_ce_send_done_cb;
+ pipe->send_cb = attr->send_cb;
nentries = roundup_pow_of_two(attr->src_nentries);
desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC);
ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz);
@@ -613,9 +633,10 @@ static int ath11k_ce_alloc_pipe(struct a
void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id)
{
struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id];
+ const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id];
- if (pipe->send_cb)
- pipe->send_cb(pipe);
+ if (attr->src_nentries)
+ ath11k_ce_tx_process_cb(pipe);
if (pipe->recv_cb)
ath11k_ce_recv_process_cb(pipe);
@@ -624,9 +645,10 @@ void ath11k_ce_per_engine_service(struct
void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id)
{
struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id];
+ const struct ce_attr *attr = &ab->hw_params.host_ce_config[pipe_id];
- if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb)
- pipe->send_cb(pipe);
+ if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && attr->src_nentries)
+ ath11k_ce_tx_process_cb(pipe);
}
EXPORT_SYMBOL(ath11k_ce_per_engine_service);
--- a/drivers/net/wireless/ath/ath11k/ce.h
+++ b/drivers/net/wireless/ath/ath11k/ce.h
@@ -101,6 +101,7 @@ struct ce_attr {
unsigned int dest_nentries;
void (*recv_cb)(struct ath11k_base *, struct sk_buff *);
+ void (*send_cb)(struct ath11k_base *, struct sk_buff *);
};
#define CE_DESC_RING_ALIGN 8
@@ -154,7 +155,7 @@ struct ath11k_ce_pipe {
unsigned int buf_sz;
unsigned int rx_buf_needed;
- void (*send_cb)(struct ath11k_ce_pipe *);
+ void (*send_cb)(struct ath11k_base *, struct sk_buff *);
void (*recv_cb)(struct ath11k_base *, struct sk_buff *);
struct tasklet_struct intr_tq;
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -41,6 +41,7 @@ static const struct ath11k_hw_params ath
.max_radios = 3,
.bdf_addr = 0x4B0C0000,
.hw_ops = &ipq8074_ops,
+ .credit_flow = false,
.ring_mask = &ath11k_hw_ring_mask_ipq8074,
.internal_sleep_clock = false,
.regs = &ipq8074_regs,
@@ -78,6 +79,7 @@ static const struct ath11k_hw_params ath
.max_radios = 2,
.bdf_addr = 0x4ABC0000,
.hw_ops = &ipq6018_ops,
+ .credit_flow = false,
.ring_mask = &ath11k_hw_ring_mask_ipq8074,
.internal_sleep_clock = false,
.regs = &ipq8074_regs,
--- a/drivers/net/wireless/ath/ath11k/htc.c
+++ b/drivers/net/wireless/ath/ath11k/htc.c
@@ -86,8 +86,7 @@ int ath11k_htc_send(struct ath11k_htc *h
}
skb_push(skb, sizeof(struct ath11k_htc_hdr));
-
- if (ep->tx_credit_flow_enabled) {
+ if (ab->hw_params.credit_flow && ep->tx_credit_flow_enabled) {
credits = DIV_ROUND_UP(skb->len, htc->target_credit_size);
spin_lock_bh(&htc->tx_lock);
if (ep->tx_credits < credits) {
@@ -112,7 +111,11 @@ int ath11k_htc_send(struct ath11k_htc *h
ret = dma_mapping_error(dev, skb_cb->paddr);
if (ret) {
ret = -EIO;
- goto err_credits;
+ if (ab->hw_params.credit_flow)
+ goto err_credits;
+
+ else
+ goto err_pull;
}
ret = ath11k_ce_send(htc->ab, skb, ep->ul_pipe_id, ep->eid);
@@ -124,14 +127,13 @@ int ath11k_htc_send(struct ath11k_htc *h
err_unmap:
dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
err_credits:
- if (ep->tx_credit_flow_enabled) {
+ if (ab->hw_params.credit_flow && ep->tx_credit_flow_enabled) {
spin_lock_bh(&htc->tx_lock);
ep->tx_credits += credits;
ath11k_dbg(ab, ATH11K_DBG_HTC,
"htc ep %d reverted %d credits back (total %d)\n",
eid, credits, ep->tx_credits);
spin_unlock_bh(&htc->tx_lock);
-
if (ep->ep_ops.ep_tx_credits)
ep->ep_ops.ep_tx_credits(htc->ab);
}
@@ -200,24 +202,25 @@ static int ath11k_htc_process_trailer(st
status = -EINVAL;
break;
}
-
- switch (record->hdr.id) {
- case ATH11K_HTC_RECORD_CREDITS:
- len = sizeof(struct ath11k_htc_credit_report);
- if (record->hdr.len < len) {
- ath11k_warn(ab, "Credit report too long\n");
- status = -EINVAL;
+ if(ab->hw_params.credit_flow) {
+ switch (record->hdr.id) {
+ case ATH11K_HTC_RECORD_CREDITS:
+ len = sizeof(struct ath11k_htc_credit_report);
+ if (record->hdr.len < len) {
+ ath11k_warn(ab, "Credit report too long\n");
+ status = -EINVAL;
+ break;
+ }
+ ath11k_htc_process_credit_report(htc,
+ record->credit_report,
+ record->hdr.len,
+ src_eid);
+ break;
+ default:
+ ath11k_warn(ab, "Unhandled record: id:%d length:%d\n",
+ record->hdr.id, record->hdr.len);
break;
}
- ath11k_htc_process_credit_report(htc,
- record->credit_report,
- record->hdr.len,
- src_eid);
- break;
- default:
- ath11k_warn(ab, "Unhandled record: id:%d length:%d\n",
- record->hdr.id, record->hdr.len);
- break;
}
if (status)
@@ -231,6 +234,29 @@ static int ath11k_htc_process_trailer(st
return status;
}
+void ath11k_htc_tx_completion_handler(struct ath11k_base *ab,
+ struct sk_buff *skb)
+{
+ struct ath11k_htc *htc = &ab->htc;
+ struct ath11k_htc_ep *ep;
+ u8 eid = ATH11K_HTC_EP_UNUSED;
+
+ eid = ATH11K_SKB_CB(skb)->eid;
+ if (eid >= ATH11K_HTC_EP_COUNT)
+ return;
+
+ spin_lock_bh(&htc->tx_lock);
+ ep = &htc->endpoint[eid];
+ if (!ep->ep_ops.ep_tx_complete) {
+ dev_kfree_skb_any(skb);
+ spin_unlock_bh(&htc->tx_lock);
+ return;
+ }
+ spin_unlock_bh(&htc->tx_lock);
+
+ ep->ep_ops.ep_tx_complete(htc->ab, skb);
+}
+
void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
struct sk_buff *skb)
{
@@ -584,6 +610,11 @@ int ath11k_htc_connect_service(struct at
disable_credit_flow_ctrl = true;
}
+ if (!ab->hw_params.credit_flow) {
+ flags |= ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
+ disable_credit_flow_ctrl = true;
+ }
+
req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags);
req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID,
conn_req->service_id);
@@ -708,6 +739,8 @@ int ath11k_htc_start(struct ath11k_htc *
msg = (struct ath11k_htc_setup_complete_extended *)skb->data;
msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID,
ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID);
+ if (!ab->hw_params.credit_flow)
+ msg->flags |= ATH11K_GLOBAL_DISABLE_CREDIT_FLOW;
ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n");
--- a/drivers/net/wireless/ath/ath11k/htc.h
+++ b/drivers/net/wireless/ath/ath11k/htc.h
@@ -114,6 +114,8 @@ struct ath11k_htc_conn_svc_resp {
u32 svc_meta_pad;
} __packed;
+#define ATH11K_GLOBAL_DISABLE_CREDIT_FLOW BIT(1)
+
struct ath11k_htc_setup_complete_extended {
u32 msg_id;
u32 flags;
@@ -309,5 +311,7 @@ int ath11k_htc_send(struct ath11k_htc *h
struct sk_buff *ath11k_htc_alloc_skb(struct ath11k_base *ar, int size);
void ath11k_htc_rx_completion_handler(struct ath11k_base *ar,
struct sk_buff *skb);
+void ath11k_htc_tx_completion_handler(struct ath11k_base *ab,
+ struct sk_buff *skb);
#endif
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -156,6 +156,7 @@ struct ath11k_hw_params {
bool htt_peer_map_v2;
bool tcl_0_only;
u8 spectral_fft_sz;
+ bool credit_flow;
u16 interface_modes;
bool supports_monitor;
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -261,20 +261,35 @@ int ath11k_wmi_cmd_send(struct ath11k_pd
{
struct ath11k_wmi_base *wmi_sc = wmi->wmi_ab;
int ret = -EOPNOTSUPP;
+ struct ath11k_base *ab = wmi_sc->ab;
might_sleep();
- wait_event_timeout(wmi_sc->tx_credits_wq, ({
- ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id);
+ if (ab->hw_params.credit_flow) {
+ wait_event_timeout(wmi_sc->tx_credits_wq, ({
+ ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id);
+
+ if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags))
+ ret = -ESHUTDOWN;
- if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags))
- ret = -ESHUTDOWN;
+ (ret != -EAGAIN);
+ }), WMI_SEND_TIMEOUT_HZ);
+ } else {
+ wait_event_timeout(wmi->tx_ce_desc_wq, ({
+ ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id);
- (ret != -EAGAIN);
- }), WMI_SEND_TIMEOUT_HZ);
+ if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags))
+ ret = -ESHUTDOWN;
+
+ (ret != -ENOBUFS);
+ }), WMI_SEND_TIMEOUT_HZ);
+ }
if (ret == -EAGAIN)
ath11k_warn(wmi_sc->ab, "wmi command %d timeout\n", cmd_id);
+ if (ret == -ENOBUFS)
+ ath11k_warn(wmi_sc->ab, "ce desc not available for wmi command %d\n",
+ cmd_id);
return ret;
}
@@ -5328,6 +5343,32 @@ static void ath11k_wmi_op_ep_tx_credits(
static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab,
struct sk_buff *skb)
{
+ struct ath11k_pdev_wmi *wmi;
+ u32 i;
+ u8 wmi_ep_count;
+ u8 eid = ATH11K_HTC_EP_UNUSED;
+
+ eid = ATH11K_SKB_CB(skb)->eid;
+ if (eid >= ATH11K_HTC_EP_COUNT)
+ goto out;
+
+ wmi_ep_count = ab->htc.wmi_ep_count;
+ if (wmi_ep_count > ab->hw_params.max_radios)
+ goto out;
+
+ dev_kfree_skb(skb);
+
+ for (i = 0; i < ab->htc.wmi_ep_count; i++) {
+ if (ab->wmi_ab.wmi[i].eid == eid) {
+ wmi = &ab->wmi_ab.wmi[i];
+ break;
+ }
+ }
+
+ wake_up(&wmi->tx_ce_desc_wq);
+
+ return;
+out:
dev_kfree_skb(skb);
}
@@ -6545,6 +6586,7 @@ static int ath11k_connect_pdev_htc_servi
ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid;
ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid;
ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len;
+ init_waitqueue_head(&ab->wmi_ab.wmi[pdev_idx].tx_ce_desc_wq);
return 0;
}
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -2446,6 +2446,7 @@ struct ath11k_pdev_wmi {
enum ath11k_htc_ep_id eid;
const struct wmi_peer_flags_map *peer_flags;
u32 rx_decap_mode;
+ wait_queue_head_t tx_ce_desc_wq;
};
struct vdev_create_params {