ath10k: replace send_head() with tx_sg()
authorMichal Kazior <michal.kazior@tieto.com>
Thu, 27 Feb 2014 16:50:04 +0000 (18:50 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Fri, 28 Feb 2014 09:59:06 +0000 (11:59 +0200)
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: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.h
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/pci.c

index d44d618..a0b1a8c 100644 (file)
@@ -266,12 +266,12 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
  * ath10k_ce_sendlist_send.
  * The caller takes responsibility for any needed locking.
  */
-static 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)
+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)
 {
        struct ath10k *ar = ce_state->ar;
        struct ath10k_ce_ring *src_ring = ce_state->src_ring;
index 67dbde6..322e929 100644 (file)
@@ -152,6 +152,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
                   unsigned int transfer_id,
                   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 (*send_cb)(struct ath10k_ce_pipe *),
                                int disable_interrupts);
index dcdea68..2ac7bea 100644 (file)
 #include <linux/kernel.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 {
        int (*tx_completion)(struct ath10k *ar,
                             struct sk_buff *wbuf,
@@ -31,11 +39,9 @@ struct ath10k_hif_cb {
 };
 
 struct ath10k_hif_ops {
-       /* Send the head of a buffer to HIF for transmission to the target. */
-       int (*send_head)(struct ath10k *ar, u8 pipe_id,
-                        unsigned int transfer_id,
-                        unsigned int nbytes,
-                        struct sk_buff *buf);
+       /* send a scatter-gather list to the target */
+       int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
+                    struct ath10k_hif_sg_item *items, int n_items);
 
        /*
         * API to handle HIF-specific BMI message exchanges, this API is
@@ -86,12 +92,11 @@ struct ath10k_hif_ops {
 };
 
 
-static inline int ath10k_hif_send_head(struct ath10k *ar, u8 pipe_id,
-                                      unsigned int transfer_id,
-                                      unsigned int nbytes,
-                                      struct sk_buff *buf)
+static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+                                  struct ath10k_hif_sg_item *items,
+                                  int n_items)
 {
-       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,
index 69f1f46..64ab8d6 100644 (file)
@@ -125,6 +125,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
 {
        struct ath10k_htc_ep *ep = &htc->endpoint[eid];
        struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
+       struct ath10k_hif_sg_item sg_item;
        struct device *dev = htc->ar->dev;
        int credits = 0;
        int ret;
@@ -166,8 +167,13 @@ int ath10k_htc_send(struct ath10k_htc *htc,
        if (ret)
                goto err_credits;
 
-       ret = ath10k_hif_send_head(htc->ar, ep->ul_pipe_id, ep->eid,
-                                  skb->len, skb);
+       sg_item.transfer_id = ep->eid;
+       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)
                goto err_unmap;
 
index d973975..713c18e 100644 (file)
@@ -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,
                                             &ce_data, &nbytes,
                                             &transfer_id) == 0) {
+               if (transfer_context == NULL)
+                       continue;
+
                compl = get_free_compl(pipe_info);
                if (!compl)
                        break;
@@ -781,39 +784,64 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
        ath10k_pci_process_ce(ar);
 }
 
-/* Send the first nbytes bytes of the buffer */
-static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
-                                   unsigned int transfer_id,
-                                   unsigned int bytes, struct sk_buff *nbuf)
+static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+                               struct ath10k_hif_sg_item *items, int n_items)
 {
-       struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf);
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe_id]);
-       struct ath10k_ce_pipe *ce_hdl = pipe_info->ce_hdl;
-       unsigned int len;
-       u32 flags = 0;
-       int ret;
+       struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
+       struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl;
+       struct ath10k_ce_ring *src_ring = ce_pipe->src_ring;
+       unsigned int nentries_mask = src_ring->nentries_mask;
+       unsigned int sw_index = src_ring->sw_index;
+       unsigned int write_index = src_ring->write_index;
+       int err, i;
 
-       len = min(bytes, nbuf->len);
-       bytes -= len;
+       spin_lock_bh(&ar_pci->ce_lock);
 
-       if (len & 3)
-               ath10k_warn("skb not aligned to 4-byte boundary (%d)\n", len);
+       if (unlikely(CE_RING_DELTA(nentries_mask,
+                                  write_index, sw_index - 1) < n_items)) {
+               err = -ENOBUFS;
+               goto unlock;
+       }
 
-       ath10k_dbg(ATH10K_DBG_PCI,
-                  "pci send data vaddr %p paddr 0x%llx len %d as %d bytes\n",
-                  nbuf->data, (unsigned long long) skb_cb->paddr,
-                  nbuf->len, len);
-       ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL,
-                       "ath10k tx: data: ",
-                       nbuf->data, nbuf->len);
-
-       ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id,
-                            flags);
-       if (ret)
-               ath10k_warn("failed to send sk_buff to CE: %p\n", nbuf);
+       for (i = 0; i < n_items - 1; i++) {
+               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);
 
-       return ret;
+               err = ath10k_ce_send_nolock(ce_pipe,
+                                           items[i].transfer_context,
+                                           items[i].paddr,
+                                           items[i].len,
+                                           items[i].transfer_id,
+                                           CE_SEND_FLAG_GATHER);
+               if (err)
+                       goto unlock;
+       }
+
+       /* `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)
@@ -2249,7 +2277,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 #endif
 
 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,
        .start                  = ath10k_pci_hif_start,
        .stop                   = ath10k_pci_hif_stop,