mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 04:13:31 +00:00
440 lines
13 KiB
Diff
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 {
|