ath10k: add hif tx methods for wcn3990
authorGovind Singh <govinds@codeaurora.org>
Tue, 10 Apr 2018 15:01:24 +0000 (18:01 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 19 Apr 2018 15:52:31 +0000 (18:52 +0300)
Add hif tx/tx-complete methods for wcn3990
target.

Signed-off-by: Govind Singh <govinds@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ath/ath10k/snoc.c

index 9d402e4..899f0a3 100644 (file)
@@ -42,6 +42,9 @@ static char *const ce_name[] = {
        "WLAN_CE_11",
 };
 
+static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
+static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
+
 static const struct ath10k_snoc_drv_priv drv_priv = {
        .hw_rev = ATH10K_HW_WCN3990,
        .dma_mask = DMA_BIT_MASK(37),
@@ -54,7 +57,7 @@ static struct ce_attr host_ce_config_wlan[] = {
                .src_nentries = 16,
                .src_sz_max = 2048,
                .dest_nentries = 0,
-               .send_cb = NULL,
+               .send_cb = ath10k_snoc_htc_tx_cb,
        },
 
        /* CE1: target->host HTT + HTC control */
@@ -81,7 +84,7 @@ static struct ce_attr host_ce_config_wlan[] = {
                .src_nentries = 32,
                .src_sz_max = 2048,
                .dest_nentries = 0,
-               .send_cb = NULL,
+               .send_cb = ath10k_snoc_htc_tx_cb,
        },
 
        /* CE4: host->target HTT */
@@ -90,7 +93,7 @@ static struct ce_attr host_ce_config_wlan[] = {
                .src_nentries = 256,
                .src_sz_max = 256,
                .dest_nentries = 0,
-               .send_cb = NULL,
+               .send_cb = ath10k_snoc_htt_tx_cb,
        },
 
        /* CE5: target->host HTT (ipa_uc->target ) */
@@ -359,6 +362,117 @@ static void ath10k_snoc_rx_post(struct ath10k *ar)
                ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]);
 }
 
+static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state)
+{
+       struct ath10k *ar = ce_state->ar;
+       struct sk_buff_head list;
+       struct sk_buff *skb;
+
+       __skb_queue_head_init(&list);
+       while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
+               if (!skb)
+                       continue;
+
+               __skb_queue_tail(&list, skb);
+       }
+
+       while ((skb = __skb_dequeue(&list)))
+               ath10k_htc_tx_completion_handler(ar, skb);
+}
+
+static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
+{
+       struct ath10k *ar = ce_state->ar;
+       struct sk_buff *skb;
+
+       while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
+               if (!skb)
+                       continue;
+
+               dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
+                                skb->len, DMA_TO_DEVICE);
+               ath10k_htt_hif_tx_complete(ar, skb);
+       }
+}
+
+static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+                                struct ath10k_hif_sg_item *items, int n_items)
+{
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+       struct ath10k_ce *ce = ath10k_ce_priv(ar);
+       struct ath10k_snoc_pipe *snoc_pipe;
+       struct ath10k_ce_pipe *ce_pipe;
+       int err, i = 0;
+
+       snoc_pipe = &ar_snoc->pipe_info[pipe_id];
+       ce_pipe = snoc_pipe->ce_hdl;
+       spin_lock_bh(&ce->ce_lock);
+
+       for (i = 0; i < n_items - 1; i++) {
+               ath10k_dbg(ar, ATH10K_DBG_SNOC,
+                          "snoc tx item %d paddr %pad len %d n_items %d\n",
+                          i, &items[i].paddr, items[i].len, n_items);
+
+               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 err;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_SNOC,
+                  "snoc tx item %d paddr %pad len %d n_items %d\n",
+                  i, &items[i].paddr, items[i].len, n_items);
+
+       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 err;
+
+       spin_unlock_bh(&ce->ce_lock);
+
+       return 0;
+
+err:
+       for (; i > 0; i--)
+               __ath10k_ce_send_revert(ce_pipe);
+
+       spin_unlock_bh(&ce->ce_lock);
+       return err;
+}
+
+static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
+{
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+       ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n");
+
+       return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl);
+}
+
+static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,
+                                               int force)
+{
+       int resources;
+
+       ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n");
+
+       if (!force) {
+               resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe);
+
+               if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))
+                       return;
+       }
+       ath10k_ce_per_engine_service(ar, pipe);
+}
+
 static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,
                                               u16 service_id,
                                               u8 *ul_pipe, u8 *dl_pipe)
@@ -587,6 +701,9 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = {
        .get_default_pipe       = ath10k_snoc_hif_get_default_pipe,
        .power_up               = ath10k_snoc_hif_power_up,
        .power_down             = ath10k_snoc_hif_power_down,
+       .tx_sg                  = ath10k_snoc_hif_tx_sg,
+       .send_complete_check    = ath10k_snoc_hif_send_complete_check,
+       .get_free_queue_number  = ath10k_snoc_hif_get_free_queue_number,
 };
 
 static const struct ath10k_bus_ops ath10k_snoc_bus_ops = {