Commit 726346fc authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: replace send_head() with tx_sg()

PCI is capable of handling scatter-gather lists.
This can be used to avoid copying memory.

Change the name of the callback while at to
reflect its purpose.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 7676a888
...@@ -266,7 +266,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, ...@@ -266,7 +266,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
* ath10k_ce_sendlist_send. * ath10k_ce_sendlist_send.
* The caller takes responsibility for any needed locking. * The caller takes responsibility for any needed locking.
*/ */
static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
void *per_transfer_context, void *per_transfer_context,
u32 buffer, u32 buffer,
unsigned int nbytes, unsigned int nbytes,
......
...@@ -152,6 +152,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, ...@@ -152,6 +152,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
unsigned int transfer_id, unsigned int transfer_id,
unsigned int flags); unsigned int flags);
int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
void *per_transfer_context,
u32 buffer,
unsigned int nbytes,
unsigned int transfer_id,
unsigned int flags);
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
void (*send_cb)(struct ath10k_ce_pipe *), void (*send_cb)(struct ath10k_ce_pipe *),
int disable_interrupts); int disable_interrupts);
......
...@@ -21,6 +21,14 @@ ...@@ -21,6 +21,14 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include "core.h" #include "core.h"
struct ath10k_hif_sg_item {
u16 transfer_id;
void *transfer_context; /* NULL = tx completion callback not called */
void *vaddr; /* for debugging mostly */
u32 paddr;
u16 len;
};
struct ath10k_hif_cb { struct ath10k_hif_cb {
int (*tx_completion)(struct ath10k *ar, int (*tx_completion)(struct ath10k *ar,
struct sk_buff *wbuf, struct sk_buff *wbuf,
...@@ -31,11 +39,9 @@ struct ath10k_hif_cb { ...@@ -31,11 +39,9 @@ struct ath10k_hif_cb {
}; };
struct ath10k_hif_ops { struct ath10k_hif_ops {
/* Send the head of a buffer to HIF for transmission to the target. */ /* send a scatter-gather list to the target */
int (*send_head)(struct ath10k *ar, u8 pipe_id, int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
unsigned int transfer_id, struct ath10k_hif_sg_item *items, int n_items);
unsigned int nbytes,
struct sk_buff *buf);
/* /*
* API to handle HIF-specific BMI message exchanges, this API is * API to handle HIF-specific BMI message exchanges, this API is
...@@ -86,12 +92,11 @@ struct ath10k_hif_ops { ...@@ -86,12 +92,11 @@ struct ath10k_hif_ops {
}; };
static inline int ath10k_hif_send_head(struct ath10k *ar, u8 pipe_id, static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
unsigned int transfer_id, struct ath10k_hif_sg_item *items,
unsigned int nbytes, int n_items)
struct sk_buff *buf)
{ {
return ar->hif.ops->send_head(ar, pipe_id, transfer_id, nbytes, buf); return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);
} }
static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
......
...@@ -125,6 +125,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, ...@@ -125,6 +125,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
{ {
struct ath10k_htc_ep *ep = &htc->endpoint[eid]; struct ath10k_htc_ep *ep = &htc->endpoint[eid];
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct ath10k_hif_sg_item sg_item;
struct device *dev = htc->ar->dev; struct device *dev = htc->ar->dev;
int credits = 0; int credits = 0;
int ret; int ret;
...@@ -166,8 +167,13 @@ int ath10k_htc_send(struct ath10k_htc *htc, ...@@ -166,8 +167,13 @@ int ath10k_htc_send(struct ath10k_htc *htc,
if (ret) if (ret)
goto err_credits; goto err_credits;
ret = ath10k_hif_send_head(htc->ar, ep->ul_pipe_id, ep->eid, sg_item.transfer_id = ep->eid;
skb->len, skb); sg_item.transfer_context = skb;
sg_item.vaddr = skb->data;
sg_item.paddr = skb_cb->paddr;
sg_item.len = skb->len;
ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1);
if (ret) if (ret)
goto err_unmap; goto err_unmap;
......
...@@ -714,6 +714,9 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) ...@@ -714,6 +714,9 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
while (ath10k_ce_completed_send_next(ce_state, &transfer_context, while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
&ce_data, &nbytes, &ce_data, &nbytes,
&transfer_id) == 0) { &transfer_id) == 0) {
if (transfer_context == NULL)
continue;
compl = get_free_compl(pipe_info); compl = get_free_compl(pipe_info);
if (!compl) if (!compl)
break; break;
...@@ -781,39 +784,64 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) ...@@ -781,39 +784,64 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
ath10k_pci_process_ce(ar); ath10k_pci_process_ce(ar);
} }
/* Send the first nbytes bytes of the buffer */ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id, struct ath10k_hif_sg_item *items, int n_items)
unsigned int transfer_id,
unsigned int bytes, struct sk_buff *nbuf)
{ {
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf);
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe_id]); struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
struct ath10k_ce_pipe *ce_hdl = pipe_info->ce_hdl; struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl;
unsigned int len; struct ath10k_ce_ring *src_ring = ce_pipe->src_ring;
u32 flags = 0; unsigned int nentries_mask = src_ring->nentries_mask;
int ret; unsigned int sw_index = src_ring->sw_index;
unsigned int write_index = src_ring->write_index;
int err, i;
len = min(bytes, nbuf->len); spin_lock_bh(&ar_pci->ce_lock);
bytes -= len;
if (len & 3) if (unlikely(CE_RING_DELTA(nentries_mask,
ath10k_warn("skb not aligned to 4-byte boundary (%d)\n", len); write_index, sw_index - 1) < n_items)) {
err = -ENOBUFS;
goto unlock;
}
for (i = 0; i < n_items - 1; i++) {
ath10k_dbg(ATH10K_DBG_PCI, ath10k_dbg(ATH10K_DBG_PCI,
"pci send data vaddr %p paddr 0x%llx len %d as %d bytes\n", "pci tx item %d paddr 0x%08x len %d n_items %d\n",
nbuf->data, (unsigned long long) skb_cb->paddr, i, items[i].paddr, items[i].len, n_items);
nbuf->len, len); ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, items[i].vaddr, items[i].len);
"ath10k tx: data: ",
nbuf->data, nbuf->len);
ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id, err = ath10k_ce_send_nolock(ce_pipe,
flags); items[i].transfer_context,
if (ret) items[i].paddr,
ath10k_warn("failed to send sk_buff to CE: %p\n", nbuf); items[i].len,
items[i].transfer_id,
CE_SEND_FLAG_GATHER);
if (err)
goto unlock;
}
return ret; /* `i` is equal to `n_items -1` after for() */
ath10k_dbg(ATH10K_DBG_PCI,
"pci tx item %d paddr 0x%08x len %d n_items %d\n",
i, items[i].paddr, items[i].len, n_items);
ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
items[i].vaddr, items[i].len);
err = ath10k_ce_send_nolock(ce_pipe,
items[i].transfer_context,
items[i].paddr,
items[i].len,
items[i].transfer_id,
0);
if (err)
goto unlock;
err = 0;
unlock:
spin_unlock_bh(&ar_pci->ce_lock);
return err;
} }
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
...@@ -2249,7 +2277,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) ...@@ -2249,7 +2277,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
#endif #endif
static const struct ath10k_hif_ops ath10k_pci_hif_ops = { static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.send_head = ath10k_pci_hif_send_head, .tx_sg = ath10k_pci_hif_tx_sg,
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
.start = ath10k_pci_hif_start, .start = ath10k_pci_hif_start,
.stop = ath10k_pci_hif_stop, .stop = ath10k_pci_hif_stop,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment