ath10k: htc: rx trailer lookahead support
authorErik Stromdahl <erik.stromdahl@gmail.com>
Wed, 26 Apr 2017 09:17:52 +0000 (12:17 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 4 May 2017 12:55:16 +0000 (15:55 +0300)
The RX trailer parsing is now capable of parsing lookahead reports.
A lookahead contains the first 4 bytes of the next HTC message
(that will be read in the next SDIO read operation).
Lookaheads are used by the SDIO/mbox HIF layer to determine if
the next message is part of a bundle, which endpoint it belongs
to and how long it is.

Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/htc.h

index f3dbce6ea0daae60470210915d85390f983dc9ca..0a06562c0d325be09fd6451cbe95679314908d94 100644 (file)
@@ -231,11 +231,78 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
        spin_unlock_bh(&htc->tx_lock);
 }
 
+static int
+ath10k_htc_process_lookahead(struct ath10k_htc *htc,
+                            const struct ath10k_htc_lookahead_report *report,
+                            int len,
+                            enum ath10k_htc_ep_id eid,
+                            void *next_lookaheads,
+                            int *next_lookaheads_len)
+{
+       struct ath10k *ar = htc->ar;
+
+       /* Invalid lookahead flags are actually transmitted by
+        * the target in the HTC control message.
+        * Since this will happen at every boot we silently ignore
+        * the lookahead in this case
+        */
+       if (report->pre_valid != ((~report->post_valid) & 0xFF))
+               return 0;
+
+       if (next_lookaheads && next_lookaheads_len) {
+               ath10k_dbg(ar, ATH10K_DBG_HTC,
+                          "htc rx lookahead found pre_valid 0x%x post_valid 0x%x\n",
+                          report->pre_valid, report->post_valid);
+
+               /* look ahead bytes are valid, copy them over */
+               memcpy((u8 *)next_lookaheads, report->lookahead, 4);
+
+               *next_lookaheads_len = 1;
+       }
+
+       return 0;
+}
+
+static int
+ath10k_htc_process_lookahead_bundle(struct ath10k_htc *htc,
+                                   const struct ath10k_htc_lookahead_bundle *report,
+                                   int len,
+                                   enum ath10k_htc_ep_id eid,
+                                   void *next_lookaheads,
+                                   int *next_lookaheads_len)
+{
+       struct ath10k *ar = htc->ar;
+       int bundle_cnt = len / sizeof(*report);
+
+       if (!bundle_cnt || (bundle_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE)) {
+               ath10k_warn(ar, "Invalid lookahead bundle count: %d\n",
+                           bundle_cnt);
+               return -EINVAL;
+       }
+
+       if (next_lookaheads && next_lookaheads_len) {
+               int i;
+
+               for (i = 0; i < bundle_cnt; i++) {
+                       memcpy(((u8 *)next_lookaheads) + 4 * i,
+                              report->lookahead, 4);
+                       report++;
+               }
+
+               *next_lookaheads_len = bundle_cnt;
+       }
+
+       return 0;
+}
+
 int ath10k_htc_process_trailer(struct ath10k_htc *htc,
                               u8 *buffer,
                               int length,
-                              enum ath10k_htc_ep_id src_eid)
+                              enum ath10k_htc_ep_id src_eid,
+                              void *next_lookaheads,
+                              int *next_lookaheads_len)
 {
+       struct ath10k_htc_lookahead_bundle *bundle;
        struct ath10k *ar = htc->ar;
        int status = 0;
        struct ath10k_htc_record *record;
@@ -275,6 +342,29 @@ int ath10k_htc_process_trailer(struct ath10k_htc *htc,
                                                         record->hdr.len,
                                                         src_eid);
                        break;
+               case ATH10K_HTC_RECORD_LOOKAHEAD:
+                       len = sizeof(struct ath10k_htc_lookahead_report);
+                       if (record->hdr.len < len) {
+                               ath10k_warn(ar, "Lookahead report too long\n");
+                               status = -EINVAL;
+                               break;
+                       }
+                       status = ath10k_htc_process_lookahead(htc,
+                                                             record->lookahead_report,
+                                                             record->hdr.len,
+                                                             src_eid,
+                                                             next_lookaheads,
+                                                             next_lookaheads_len);
+                       break;
+               case ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE:
+                       bundle = record->lookahead_bundle;
+                       status = ath10k_htc_process_lookahead_bundle(htc,
+                                                                    bundle,
+                                                                    record->hdr.len,
+                                                                    src_eid,
+                                                                    next_lookaheads,
+                                                                    next_lookaheads_len);
+                       break;
                default:
                        ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
                                    record->hdr.id, record->hdr.len);
@@ -362,7 +452,8 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
                trailer += payload_len;
                trailer -= trailer_len;
                status = ath10k_htc_process_trailer(htc, trailer,
-                                                   trailer_len, hdr->eid);
+                                                   trailer_len, hdr->eid,
+                                                   NULL, NULL);
                if (status)
                        goto out;
 
index f728ce7124cf5b194fb4d48b8ef7841e611b6bf9..ae6003495649b95e5ddae425fe517a76793d15be 100644 (file)
@@ -50,6 +50,8 @@ struct ath10k;
  * 4-byte aligned.
  */
 
+#define HTC_HOST_MAX_MSG_PER_BUNDLE        8
+
 enum ath10k_htc_tx_flags {
        ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
        ATH10K_HTC_FLAG_SEND_BUNDLE        = 0x02
@@ -174,8 +176,10 @@ struct ath10k_htc_msg {
 } __packed __aligned(4);
 
 enum ath10k_ath10k_htc_record_id {
-       ATH10K_HTC_RECORD_NULL    = 0,
-       ATH10K_HTC_RECORD_CREDITS = 1
+       ATH10K_HTC_RECORD_NULL             = 0,
+       ATH10K_HTC_RECORD_CREDITS          = 1,
+       ATH10K_HTC_RECORD_LOOKAHEAD        = 2,
+       ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE = 3,
 };
 
 struct ath10k_ath10k_htc_record_hdr {
@@ -192,10 +196,28 @@ struct ath10k_htc_credit_report {
        u8 pad1;
 } __packed;
 
+struct ath10k_htc_lookahead_report {
+       u8 pre_valid;
+       u8 pad0;
+       u8 pad1;
+       u8 pad2;
+       u8 lookahead[4];
+       u8 post_valid;
+       u8 pad3;
+       u8 pad4;
+       u8 pad5;
+} __packed;
+
+struct ath10k_htc_lookahead_bundle {
+       u8 lookahead[4];
+} __packed;
+
 struct ath10k_htc_record {
        struct ath10k_ath10k_htc_record_hdr hdr;
        union {
                struct ath10k_htc_credit_report credit_report[0];
+               struct ath10k_htc_lookahead_report lookahead_report[0];
+               struct ath10k_htc_lookahead_bundle lookahead_bundle[0];
                u8 pauload[0];
        };
 } __packed __aligned(4);
@@ -356,6 +378,8 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
 int ath10k_htc_process_trailer(struct ath10k_htc *htc,
                               u8 *buffer,
                               int length,
-                              enum ath10k_htc_ep_id src_eid);
+                              enum ath10k_htc_ep_id src_eid,
+                              void *next_lookaheads,
+                              int *next_lookaheads_len);
 
 #endif