]> Git Repo - J-linux.git/blob - drivers/net/wireless/ath/ath6kl/htc_pipe.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / net / wireless / ath / ath6kl / htc_pipe.c
1 /*
2  * Copyright (c) 2007-2011 Atheros Communications Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include "core.h"
18 #include "debug.h"
19 #include "hif-ops.h"
20
21 #define HTC_PACKET_CONTAINER_ALLOCATION 32
22 #define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH)
23
24 static int ath6kl_htc_pipe_tx(struct htc_target *handle,
25                               struct htc_packet *packet);
26 static void ath6kl_htc_pipe_cleanup(struct htc_target *handle);
27
28 /* htc pipe tx path */
29 static inline void restore_tx_packet(struct htc_packet *packet)
30 {
31         if (packet->info.tx.flags & HTC_FLAGS_TX_FIXUP_NETBUF) {
32                 skb_pull(packet->skb, sizeof(struct htc_frame_hdr));
33                 packet->info.tx.flags &= ~HTC_FLAGS_TX_FIXUP_NETBUF;
34         }
35 }
36
37 static void do_send_completion(struct htc_endpoint *ep,
38                                struct list_head *queue_to_indicate)
39 {
40         struct htc_packet *packet;
41
42         if (list_empty(queue_to_indicate)) {
43                 /* nothing to indicate */
44                 return;
45         }
46
47         if (ep->ep_cb.tx_comp_multi != NULL) {
48                 ath6kl_dbg(ATH6KL_DBG_HTC,
49                            "%s: calling ep %d, send complete multiple callback (%d pkts)\n",
50                            __func__, ep->eid,
51                            get_queue_depth(queue_to_indicate));
52                 /*
53                  * a multiple send complete handler is being used,
54                  * pass the queue to the handler
55                  */
56                 ep->ep_cb.tx_comp_multi(ep->target, queue_to_indicate);
57                 /*
58                  * all packets are now owned by the callback,
59                  * reset queue to be safe
60                  */
61                 INIT_LIST_HEAD(queue_to_indicate);
62         } else {
63                 /* using legacy EpTxComplete */
64                 do {
65                         packet = list_first_entry(queue_to_indicate,
66                                                   struct htc_packet, list);
67
68                         list_del(&packet->list);
69                         ath6kl_dbg(ATH6KL_DBG_HTC,
70                                    "%s: calling ep %d send complete callback on packet 0x%p\n",
71                                    __func__, ep->eid, packet);
72                         ep->ep_cb.tx_complete(ep->target, packet);
73                 } while (!list_empty(queue_to_indicate));
74         }
75 }
76
77 static void send_packet_completion(struct htc_target *target,
78                                    struct htc_packet *packet)
79 {
80         struct htc_endpoint *ep = &target->endpoint[packet->endpoint];
81         struct list_head container;
82
83         restore_tx_packet(packet);
84         INIT_LIST_HEAD(&container);
85         list_add_tail(&packet->list, &container);
86
87         /* do completion */
88         do_send_completion(ep, &container);
89 }
90
91 static void get_htc_packet_credit_based(struct htc_target *target,
92                                         struct htc_endpoint *ep,
93                                         struct list_head *queue)
94 {
95         int credits_required;
96         int remainder;
97         u8 send_flags;
98         struct htc_packet *packet;
99         unsigned int transfer_len;
100
101         /* NOTE : the TX lock is held when this function is called */
102
103         /* loop until we can grab as many packets out of the queue as we can */
104         while (true) {
105                 send_flags = 0;
106                 if (list_empty(&ep->txq))
107                         break;
108
109                 /* get packet at head, but don't remove it */
110                 packet = list_first_entry(&ep->txq, struct htc_packet, list);
111
112                 ath6kl_dbg(ATH6KL_DBG_HTC,
113                            "%s: got head packet:0x%p , queue depth: %d\n",
114                            __func__, packet, get_queue_depth(&ep->txq));
115
116                 transfer_len = packet->act_len + HTC_HDR_LENGTH;
117
118                 if (transfer_len <= target->tgt_cred_sz) {
119                         credits_required = 1;
120                 } else {
121                         /* figure out how many credits this message requires */
122                         credits_required = transfer_len / target->tgt_cred_sz;
123                         remainder = transfer_len % target->tgt_cred_sz;
124
125                         if (remainder)
126                                 credits_required++;
127                 }
128
129                 ath6kl_dbg(ATH6KL_DBG_HTC, "%s: creds required:%d got:%d\n",
130                            __func__, credits_required, ep->cred_dist.credits);
131
132                 if (ep->eid == ENDPOINT_0) {
133                         /*
134                          * endpoint 0 is special, it always has a credit and
135                          * does not require credit based flow control
136                          */
137                         credits_required = 0;
138
139                 } else {
140                         if (ep->cred_dist.credits < credits_required)
141                                 break;
142
143                         ep->cred_dist.credits -= credits_required;
144                         ep->ep_st.cred_cosumd += credits_required;
145
146                         /* check if we need credits back from the target */
147                         if (ep->cred_dist.credits <
148                                         ep->cred_dist.cred_per_msg) {
149                                 /* tell the target we need credits ASAP! */
150                                 send_flags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
151                                 ep->ep_st.cred_low_indicate += 1;
152                                 ath6kl_dbg(ATH6KL_DBG_HTC,
153                                            "%s: host needs credits\n",
154                                            __func__);
155                         }
156                 }
157
158                 /* now we can fully dequeue */
159                 packet = list_first_entry(&ep->txq, struct htc_packet, list);
160
161                 list_del(&packet->list);
162                 /* save the number of credits this packet consumed */
163                 packet->info.tx.cred_used = credits_required;
164                 /* save send flags */
165                 packet->info.tx.flags = send_flags;
166                 packet->info.tx.seqno = ep->seqno;
167                 ep->seqno++;
168                 /* queue this packet into the caller's queue */
169                 list_add_tail(&packet->list, queue);
170         }
171 }
172
173 static void get_htc_packet(struct htc_target *target,
174                            struct htc_endpoint *ep,
175                            struct list_head *queue, int resources)
176 {
177         struct htc_packet *packet;
178
179         /* NOTE : the TX lock is held when this function is called */
180
181         /* loop until we can grab as many packets out of the queue as we can */
182         while (resources) {
183                 if (list_empty(&ep->txq))
184                         break;
185
186                 packet = list_first_entry(&ep->txq, struct htc_packet, list);
187                 list_del(&packet->list);
188
189                 ath6kl_dbg(ATH6KL_DBG_HTC,
190                            "%s: got packet:0x%p , new queue depth: %d\n",
191                            __func__, packet, get_queue_depth(&ep->txq));
192                 packet->info.tx.seqno = ep->seqno;
193                 packet->info.tx.flags = 0;
194                 packet->info.tx.cred_used = 0;
195                 ep->seqno++;
196
197                 /* queue this packet into the caller's queue */
198                 list_add_tail(&packet->list, queue);
199                 resources--;
200         }
201 }
202
203 static int htc_issue_packets(struct htc_target *target,
204                              struct htc_endpoint *ep,
205                              struct list_head *pkt_queue)
206 {
207         int status = 0;
208         u16 payload_len;
209         struct sk_buff *skb;
210         struct htc_frame_hdr *htc_hdr;
211         struct htc_packet *packet;
212
213         ath6kl_dbg(ATH6KL_DBG_HTC,
214                    "%s: queue: 0x%p, pkts %d\n", __func__,
215                    pkt_queue, get_queue_depth(pkt_queue));
216
217         while (!list_empty(pkt_queue)) {
218                 packet = list_first_entry(pkt_queue, struct htc_packet, list);
219                 list_del(&packet->list);
220
221                 skb = packet->skb;
222                 if (!skb) {
223                         WARN_ON_ONCE(1);
224                         status = -EINVAL;
225                         break;
226                 }
227
228                 payload_len = packet->act_len;
229
230                 /* setup HTC frame header */
231                 htc_hdr = skb_push(skb, sizeof(*htc_hdr));
232                 if (!htc_hdr) {
233                         WARN_ON_ONCE(1);
234                         status = -EINVAL;
235                         break;
236                 }
237
238                 packet->info.tx.flags |= HTC_FLAGS_TX_FIXUP_NETBUF;
239
240                 put_unaligned_le16(payload_len, &htc_hdr->payld_len);
241                 htc_hdr->flags = packet->info.tx.flags;
242                 htc_hdr->eid = (u8) packet->endpoint;
243                 htc_hdr->ctrl[0] = 0;
244                 htc_hdr->ctrl[1] = (u8) packet->info.tx.seqno;
245
246                 spin_lock_bh(&target->tx_lock);
247
248                 /* store in look up queue to match completions */
249                 list_add_tail(&packet->list, &ep->pipe.tx_lookup_queue);
250                 ep->ep_st.tx_issued += 1;
251                 spin_unlock_bh(&target->tx_lock);
252
253                 status = ath6kl_hif_pipe_send(target->dev->ar,
254                                               ep->pipe.pipeid_ul, NULL, skb);
255
256                 if (status != 0) {
257                         if (status != -ENOMEM) {
258                                 /* TODO: if more than 1 endpoint maps to the
259                                  * same PipeID, it is possible to run out of
260                                  * resources in the HIF layer.
261                                  * Don't emit the error
262                                  */
263                                 ath6kl_dbg(ATH6KL_DBG_HTC,
264                                            "%s: failed status:%d\n",
265                                            __func__, status);
266                         }
267                         spin_lock_bh(&target->tx_lock);
268                         list_del(&packet->list);
269
270                         /* reclaim credits */
271                         ep->cred_dist.credits += packet->info.tx.cred_used;
272                         spin_unlock_bh(&target->tx_lock);
273
274                         /* put it back into the callers queue */
275                         list_add(&packet->list, pkt_queue);
276                         break;
277                 }
278         }
279
280         if (status != 0) {
281                 while (!list_empty(pkt_queue)) {
282                         if (status != -ENOMEM) {
283                                 ath6kl_dbg(ATH6KL_DBG_HTC,
284                                            "%s: failed pkt:0x%p status:%d\n",
285                                            __func__, packet, status);
286                         }
287
288                         packet = list_first_entry(pkt_queue,
289                                                   struct htc_packet, list);
290                         list_del(&packet->list);
291                         packet->status = status;
292                         send_packet_completion(target, packet);
293                 }
294         }
295
296         return status;
297 }
298
299 static enum htc_send_queue_result htc_try_send(struct htc_target *target,
300                                                struct htc_endpoint *ep,
301                                                struct list_head *txq)
302 {
303         struct list_head send_queue;    /* temp queue to hold packets */
304         struct htc_packet *packet, *tmp_pkt;
305         struct ath6kl *ar = target->dev->ar;
306         enum htc_send_full_action action;
307         int tx_resources, overflow, txqueue_depth, i, good_pkts;
308         u8 pipeid;
309
310         ath6kl_dbg(ATH6KL_DBG_HTC, "%s: (queue:0x%p depth:%d)\n",
311                    __func__, txq,
312                    (txq == NULL) ? 0 : get_queue_depth(txq));
313
314         /* init the local send queue */
315         INIT_LIST_HEAD(&send_queue);
316
317         /*
318          * txq equals to NULL means
319          * caller didn't provide a queue, just wants us to
320          * check queues and send
321          */
322         if (txq != NULL) {
323                 if (list_empty(txq)) {
324                         /* empty queue */
325                         return HTC_SEND_QUEUE_DROP;
326                 }
327
328                 spin_lock_bh(&target->tx_lock);
329                 txqueue_depth = get_queue_depth(&ep->txq);
330                 spin_unlock_bh(&target->tx_lock);
331
332                 if (txqueue_depth >= ep->max_txq_depth) {
333                         /* we've already overflowed */
334                         overflow = get_queue_depth(txq);
335                 } else {
336                         /* get how much we will overflow by */
337                         overflow = txqueue_depth;
338                         overflow += get_queue_depth(txq);
339                         /* get how much we will overflow the TX queue by */
340                         overflow -= ep->max_txq_depth;
341                 }
342
343                 /* if overflow is negative or zero, we are okay */
344                 if (overflow > 0) {
345                         ath6kl_dbg(ATH6KL_DBG_HTC,
346                                    "%s: Endpoint %d, TX queue will overflow :%d, Tx Depth:%d, Max:%d\n",
347                                    __func__, ep->eid, overflow, txqueue_depth,
348                                    ep->max_txq_depth);
349                 }
350                 if ((overflow <= 0) ||
351                     (ep->ep_cb.tx_full == NULL)) {
352                         /*
353                          * all packets will fit or caller did not provide send
354                          * full indication handler -- just move all of them
355                          * to the local send_queue object
356                          */
357                         list_splice_tail_init(txq, &send_queue);
358                 } else {
359                         good_pkts = get_queue_depth(txq) - overflow;
360                         if (good_pkts < 0) {
361                                 WARN_ON_ONCE(1);
362                                 return HTC_SEND_QUEUE_DROP;
363                         }
364
365                         /* we have overflowed, and a callback is provided */
366                         /* dequeue all non-overflow packets to the sendqueue */
367                         for (i = 0; i < good_pkts; i++) {
368                                 /* pop off caller's queue */
369                                 packet = list_first_entry(txq,
370                                                           struct htc_packet,
371                                                           list);
372                                 /* move to local queue */
373                                 list_move_tail(&packet->list, &send_queue);
374                         }
375
376                         /*
377                          * the caller's queue has all the packets that won't fit
378                          * walk through the caller's queue and indicate each to
379                          * the send full handler
380                          */
381                         list_for_each_entry_safe(packet, tmp_pkt,
382                                                  txq, list) {
383                                 ath6kl_dbg(ATH6KL_DBG_HTC,
384                                            "%s: Indicate overflowed TX pkts: %p\n",
385                                            __func__, packet);
386                                 action = ep->ep_cb.tx_full(ep->target, packet);
387                                 if (action == HTC_SEND_FULL_DROP) {
388                                         /* callback wants the packet dropped */
389                                         ep->ep_st.tx_dropped += 1;
390
391                                         /* leave this one in the caller's queue
392                                          * for cleanup */
393                                 } else {
394                                         /* callback wants to keep this packet,
395                                          * move from caller's queue to the send
396                                          * queue */
397                                         list_move_tail(&packet->list,
398                                                        &send_queue);
399                                 }
400                         }
401
402                         if (list_empty(&send_queue)) {
403                                 /* no packets made it in, caller will cleanup */
404                                 return HTC_SEND_QUEUE_DROP;
405                         }
406                 }
407         }
408
409         if (!ep->pipe.tx_credit_flow_enabled) {
410                 tx_resources =
411                     ath6kl_hif_pipe_get_free_queue_number(ar,
412                                                           ep->pipe.pipeid_ul);
413         } else {
414                 tx_resources = 0;
415         }
416
417         spin_lock_bh(&target->tx_lock);
418         if (!list_empty(&send_queue)) {
419                 /* transfer packets to tail */
420                 list_splice_tail_init(&send_queue, &ep->txq);
421                 if (!list_empty(&send_queue)) {
422                         WARN_ON_ONCE(1);
423                         spin_unlock_bh(&target->tx_lock);
424                         return HTC_SEND_QUEUE_DROP;
425                 }
426                 INIT_LIST_HEAD(&send_queue);
427         }
428
429         /* increment tx processing count on entry */
430         ep->tx_proc_cnt++;
431
432         if (ep->tx_proc_cnt > 1) {
433                 /*
434                  * Another thread or task is draining the TX queues on this
435                  * endpoint that thread will reset the tx processing count
436                  * when the queue is drained.
437                  */
438                 ep->tx_proc_cnt--;
439                 spin_unlock_bh(&target->tx_lock);
440                 return HTC_SEND_QUEUE_OK;
441         }
442
443         /***** beyond this point only 1 thread may enter ******/
444
445         /*
446          * Now drain the endpoint TX queue for transmission as long as we have
447          * enough transmit resources.
448          */
449         while (true) {
450                 if (get_queue_depth(&ep->txq) == 0)
451                         break;
452
453                 if (ep->pipe.tx_credit_flow_enabled) {
454                         /*
455                          * Credit based mechanism provides flow control
456                          * based on target transmit resource availability,
457                          * we assume that the HIF layer will always have
458                          * bus resources greater than target transmit
459                          * resources.
460                          */
461                         get_htc_packet_credit_based(target, ep, &send_queue);
462                 } else {
463                         /*
464                          * Get all packets for this endpoint that we can
465                          * for this pass.
466                          */
467                         get_htc_packet(target, ep, &send_queue, tx_resources);
468                 }
469
470                 if (get_queue_depth(&send_queue) == 0) {
471                         /*
472                          * Didn't get packets due to out of resources or TX
473                          * queue was drained.
474                          */
475                         break;
476                 }
477
478                 spin_unlock_bh(&target->tx_lock);
479
480                 /* send what we can */
481                 htc_issue_packets(target, ep, &send_queue);
482
483                 if (!ep->pipe.tx_credit_flow_enabled) {
484                         pipeid = ep->pipe.pipeid_ul;
485                         tx_resources =
486                             ath6kl_hif_pipe_get_free_queue_number(ar, pipeid);
487                 }
488
489                 spin_lock_bh(&target->tx_lock);
490         }
491
492         /* done with this endpoint, we can clear the count */
493         ep->tx_proc_cnt = 0;
494         spin_unlock_bh(&target->tx_lock);
495
496         return HTC_SEND_QUEUE_OK;
497 }
498
499 /* htc control packet manipulation */
500 static void destroy_htc_txctrl_packet(struct htc_packet *packet)
501 {
502         struct sk_buff *skb;
503         skb = packet->skb;
504         dev_kfree_skb(skb);
505         kfree(packet);
506 }
507
508 static struct htc_packet *build_htc_txctrl_packet(void)
509 {
510         struct htc_packet *packet = NULL;
511         struct sk_buff *skb;
512
513         packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL);
514         if (packet == NULL)
515                 return NULL;
516
517         skb = __dev_alloc_skb(HTC_CONTROL_BUFFER_SIZE, GFP_KERNEL);
518
519         if (skb == NULL) {
520                 kfree(packet);
521                 return NULL;
522         }
523         packet->skb = skb;
524
525         return packet;
526 }
527
528 static void htc_free_txctrl_packet(struct htc_target *target,
529                                    struct htc_packet *packet)
530 {
531         destroy_htc_txctrl_packet(packet);
532 }
533
534 static struct htc_packet *htc_alloc_txctrl_packet(struct htc_target *target)
535 {
536         return build_htc_txctrl_packet();
537 }
538
539 static void htc_txctrl_complete(struct htc_target *target,
540                                 struct htc_packet *packet)
541 {
542         htc_free_txctrl_packet(target, packet);
543 }
544
545 #define MAX_MESSAGE_SIZE 1536
546
547 static int htc_setup_target_buffer_assignments(struct htc_target *target)
548 {
549         int status, credits, credit_per_maxmsg, i;
550         struct htc_pipe_txcredit_alloc *entry;
551         unsigned int hif_usbaudioclass = 0;
552
553         credit_per_maxmsg = MAX_MESSAGE_SIZE / target->tgt_cred_sz;
554         if (MAX_MESSAGE_SIZE % target->tgt_cred_sz)
555                 credit_per_maxmsg++;
556
557         /* TODO, this should be configured by the caller! */
558
559         credits = target->tgt_creds;
560         entry = &target->pipe.txcredit_alloc[0];
561
562         status = -ENOMEM;
563
564         /* FIXME: hif_usbaudioclass is always zero */
565         if (hif_usbaudioclass) {
566                 ath6kl_dbg(ATH6KL_DBG_HTC,
567                            "%s: For USB Audio Class- Total:%d\n",
568                            __func__, credits);
569                 entry++;
570                 entry++;
571                 /* Setup VO Service To have Max Credits */
572                 entry->service_id = WMI_DATA_VO_SVC;
573                 entry->credit_alloc = (credits - 6);
574                 if (entry->credit_alloc == 0)
575                         entry->credit_alloc++;
576
577                 credits -= (int) entry->credit_alloc;
578                 if (credits <= 0)
579                         return status;
580
581                 entry++;
582                 entry->service_id = WMI_CONTROL_SVC;
583                 entry->credit_alloc = credit_per_maxmsg;
584                 credits -= (int) entry->credit_alloc;
585                 if (credits <= 0)
586                         return status;
587
588                 /* leftovers go to best effort */
589                 entry++;
590                 entry++;
591                 entry->service_id = WMI_DATA_BE_SVC;
592                 entry->credit_alloc = (u8) credits;
593                 status = 0;
594         } else {
595                 entry++;
596                 entry->service_id = WMI_DATA_VI_SVC;
597                 entry->credit_alloc = credits / 4;
598                 if (entry->credit_alloc == 0)
599                         entry->credit_alloc++;
600
601                 credits -= (int) entry->credit_alloc;
602                 if (credits <= 0)
603                         return status;
604
605                 entry++;
606                 entry->service_id = WMI_DATA_VO_SVC;
607                 entry->credit_alloc = credits / 4;
608                 if (entry->credit_alloc == 0)
609                         entry->credit_alloc++;
610
611                 credits -= (int) entry->credit_alloc;
612                 if (credits <= 0)
613                         return status;
614
615                 entry++;
616                 entry->service_id = WMI_CONTROL_SVC;
617                 entry->credit_alloc = credit_per_maxmsg;
618                 credits -= (int) entry->credit_alloc;
619                 if (credits <= 0)
620                         return status;
621
622                 entry++;
623                 entry->service_id = WMI_DATA_BK_SVC;
624                 entry->credit_alloc = credit_per_maxmsg;
625                 credits -= (int) entry->credit_alloc;
626                 if (credits <= 0)
627                         return status;
628
629                 /* leftovers go to best effort */
630                 entry++;
631                 entry->service_id = WMI_DATA_BE_SVC;
632                 entry->credit_alloc = (u8) credits;
633                 status = 0;
634         }
635
636         if (status == 0) {
637                 for (i = 0; i < ENDPOINT_MAX; i++) {
638                         if (target->pipe.txcredit_alloc[i].service_id != 0) {
639                                 ath6kl_dbg(ATH6KL_DBG_HTC,
640                                            "HTC Service Index : %d TX : 0x%2.2X : alloc:%d\n",
641                                            i,
642                                            target->pipe.txcredit_alloc[i].
643                                            service_id,
644                                            target->pipe.txcredit_alloc[i].
645                                            credit_alloc);
646                         }
647                 }
648         }
649         return status;
650 }
651
652 /* process credit reports and call distribution function */
653 static void htc_process_credit_report(struct htc_target *target,
654                                       struct htc_credit_report *rpt,
655                                       int num_entries,
656                                       enum htc_endpoint_id from_ep)
657 {
658         int total_credits = 0, i;
659         struct htc_endpoint *ep;
660
661         /* lock out TX while we update credits */
662         spin_lock_bh(&target->tx_lock);
663
664         for (i = 0; i < num_entries; i++, rpt++) {
665                 if (rpt->eid >= ENDPOINT_MAX) {
666                         WARN_ON_ONCE(1);
667                         spin_unlock_bh(&target->tx_lock);
668                         return;
669                 }
670
671                 ep = &target->endpoint[rpt->eid];
672                 ep->cred_dist.credits += rpt->credits;
673
674                 if (ep->cred_dist.credits && get_queue_depth(&ep->txq)) {
675                         spin_unlock_bh(&target->tx_lock);
676                         htc_try_send(target, ep, NULL);
677                         spin_lock_bh(&target->tx_lock);
678                 }
679
680                 total_credits += rpt->credits;
681         }
682         ath6kl_dbg(ATH6KL_DBG_HTC,
683                    "Report indicated %d credits to distribute\n",
684                    total_credits);
685
686         spin_unlock_bh(&target->tx_lock);
687 }
688
689 /* flush endpoint TX queue */
690 static void htc_flush_tx_endpoint(struct htc_target *target,
691                                   struct htc_endpoint *ep, u16 tag)
692 {
693         struct htc_packet *packet;
694
695         spin_lock_bh(&target->tx_lock);
696         while (get_queue_depth(&ep->txq)) {
697                 packet = list_first_entry(&ep->txq, struct htc_packet, list);
698                 list_del(&packet->list);
699                 packet->status = 0;
700                 send_packet_completion(target, packet);
701         }
702         spin_unlock_bh(&target->tx_lock);
703 }
704
705 /*
706  * In the adapted HIF layer, struct sk_buff * are passed between HIF and HTC,
707  * since upper layers expects struct htc_packet containers we use the completed
708  * skb and lookup it's corresponding HTC packet buffer from a lookup list.
709  * This is extra overhead that can be fixed by re-aligning HIF interfaces with
710  * HTC.
711  */
712 static struct htc_packet *htc_lookup_tx_packet(struct htc_target *target,
713                                                struct htc_endpoint *ep,
714                                                struct sk_buff *skb)
715 {
716         struct htc_packet *packet, *tmp_pkt, *found_packet = NULL;
717
718         spin_lock_bh(&target->tx_lock);
719
720         /*
721          * interate from the front of tx lookup queue
722          * this lookup should be fast since lower layers completes in-order and
723          * so the completed packet should be at the head of the list generally
724          */
725         list_for_each_entry_safe(packet, tmp_pkt, &ep->pipe.tx_lookup_queue,
726                                  list) {
727                 /* check for removal */
728                 if (skb == packet->skb) {
729                         /* found it */
730                         list_del(&packet->list);
731                         found_packet = packet;
732                         break;
733                 }
734         }
735
736         spin_unlock_bh(&target->tx_lock);
737
738         return found_packet;
739 }
740
741 static int ath6kl_htc_pipe_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
742 {
743         struct htc_target *target = ar->htc_target;
744         struct htc_frame_hdr *htc_hdr;
745         struct htc_endpoint *ep;
746         struct htc_packet *packet;
747         u8 ep_id, *netdata;
748
749         netdata = skb->data;
750
751         htc_hdr = (struct htc_frame_hdr *) netdata;
752
753         ep_id = htc_hdr->eid;
754         ep = &target->endpoint[ep_id];
755
756         packet = htc_lookup_tx_packet(target, ep, skb);
757         if (packet == NULL) {
758                 /* may have already been flushed and freed */
759                 ath6kl_err("HTC TX lookup failed!\n");
760         } else {
761                 /* will be giving this buffer back to upper layers */
762                 packet->status = 0;
763                 send_packet_completion(target, packet);
764         }
765         skb = NULL;
766
767         if (!ep->pipe.tx_credit_flow_enabled) {
768                 /*
769                  * note: when using TX credit flow, the re-checking of queues
770                  * happens when credits flow back from the target. in the
771                  * non-TX credit case, we recheck after the packet completes
772                  */
773                 htc_try_send(target, ep, NULL);
774         }
775
776         return 0;
777 }
778
779 static int htc_send_packets_multiple(struct htc_target *target,
780                                      struct list_head *pkt_queue)
781 {
782         struct htc_endpoint *ep;
783         struct htc_packet *packet, *tmp_pkt;
784
785         if (list_empty(pkt_queue))
786                 return -EINVAL;
787
788         /* get first packet to find out which ep the packets will go into */
789         packet = list_first_entry(pkt_queue, struct htc_packet, list);
790
791         if (packet->endpoint >= ENDPOINT_MAX) {
792                 WARN_ON_ONCE(1);
793                 return -EINVAL;
794         }
795         ep = &target->endpoint[packet->endpoint];
796
797         htc_try_send(target, ep, pkt_queue);
798
799         /* do completion on any packets that couldn't get in */
800         if (!list_empty(pkt_queue)) {
801                 list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
802                         packet->status = -ENOMEM;
803                 }
804
805                 do_send_completion(ep, pkt_queue);
806         }
807
808         return 0;
809 }
810
811 /* htc pipe rx path */
812 static struct htc_packet *alloc_htc_packet_container(struct htc_target *target)
813 {
814         struct htc_packet *packet;
815         spin_lock_bh(&target->rx_lock);
816
817         if (target->pipe.htc_packet_pool == NULL) {
818                 spin_unlock_bh(&target->rx_lock);
819                 return NULL;
820         }
821
822         packet = target->pipe.htc_packet_pool;
823         target->pipe.htc_packet_pool = (struct htc_packet *) packet->list.next;
824
825         spin_unlock_bh(&target->rx_lock);
826
827         packet->list.next = NULL;
828         return packet;
829 }
830
831 static void free_htc_packet_container(struct htc_target *target,
832                                       struct htc_packet *packet)
833 {
834         struct list_head *lh;
835
836         spin_lock_bh(&target->rx_lock);
837
838         if (target->pipe.htc_packet_pool == NULL) {
839                 target->pipe.htc_packet_pool = packet;
840                 packet->list.next = NULL;
841         } else {
842                 lh = (struct list_head *) target->pipe.htc_packet_pool;
843                 packet->list.next = lh;
844                 target->pipe.htc_packet_pool = packet;
845         }
846
847         spin_unlock_bh(&target->rx_lock);
848 }
849
850 static int htc_process_trailer(struct htc_target *target, u8 *buffer,
851                                int len, enum htc_endpoint_id from_ep)
852 {
853         struct htc_credit_report *report;
854         struct htc_record_hdr *record;
855         u8 *record_buf;
856         int status = 0;
857
858         while (len > 0) {
859                 if (len < sizeof(struct htc_record_hdr)) {
860                         status = -EINVAL;
861                         break;
862                 }
863
864                 /* these are byte aligned structs */
865                 record = (struct htc_record_hdr *) buffer;
866                 len -= sizeof(struct htc_record_hdr);
867                 buffer += sizeof(struct htc_record_hdr);
868
869                 if (record->len > len) {
870                         /* no room left in buffer for record */
871                         ath6kl_dbg(ATH6KL_DBG_HTC,
872                                    "invalid length: %d (id:%d) buffer has: %d bytes left\n",
873                                    record->len, record->rec_id, len);
874                         status = -EINVAL;
875                         break;
876                 }
877
878                 /* start of record follows the header */
879                 record_buf = buffer;
880
881                 switch (record->rec_id) {
882                 case HTC_RECORD_CREDITS:
883                         if (record->len < sizeof(struct htc_credit_report)) {
884                                 WARN_ON_ONCE(1);
885                                 return -EINVAL;
886                         }
887
888                         report = (struct htc_credit_report *) record_buf;
889                         htc_process_credit_report(target, report,
890                                                   record->len / sizeof(*report),
891                                                   from_ep);
892                         break;
893                 default:
894                         ath6kl_dbg(ATH6KL_DBG_HTC,
895                                    "unhandled record: id:%d length:%d\n",
896                                    record->rec_id, record->len);
897                         break;
898                 }
899
900                 /* advance buffer past this record for next time around */
901                 buffer += record->len;
902                 len -= record->len;
903         }
904
905         return status;
906 }
907
908 static void do_recv_completion(struct htc_endpoint *ep,
909                                struct list_head *queue_to_indicate)
910 {
911         struct htc_packet *packet;
912
913         if (list_empty(queue_to_indicate)) {
914                 /* nothing to indicate */
915                 return;
916         }
917
918         /* using legacy EpRecv */
919         while (!list_empty(queue_to_indicate)) {
920                 packet = list_first_entry(queue_to_indicate,
921                                           struct htc_packet, list);
922                 list_del(&packet->list);
923                 ep->ep_cb.rx(ep->target, packet);
924         }
925
926         return;
927 }
928
929 static void recv_packet_completion(struct htc_target *target,
930                                    struct htc_endpoint *ep,
931                                    struct htc_packet *packet)
932 {
933         struct list_head container;
934         INIT_LIST_HEAD(&container);
935         list_add_tail(&packet->list, &container);
936
937         /* do completion */
938         do_recv_completion(ep, &container);
939 }
940
941 static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
942                                        u8 pipeid)
943 {
944         struct htc_target *target = ar->htc_target;
945         u8 *netdata, *trailer, hdr_info;
946         struct htc_frame_hdr *htc_hdr;
947         u32 netlen, trailerlen = 0;
948         struct htc_packet *packet;
949         struct htc_endpoint *ep;
950         u16 payload_len;
951         int status = 0;
952
953         /*
954          * ar->htc_target can be NULL due to a race condition that can occur
955          * during driver initialization(we do 'ath6kl_hif_power_on' before
956          * initializing 'ar->htc_target' via 'ath6kl_htc_create').
957          * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as
958          * usb_complete_t/callback function for 'usb_fill_bulk_urb'.
959          * Thus the possibility of ar->htc_target being NULL
960          * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
961          */
962         if (!target) {
963                 ath6kl_dbg(ATH6KL_DBG_HTC, "Target not yet initialized\n");
964                 status = -EINVAL;
965                 goto free_skb;
966         }
967
968
969         netdata = skb->data;
970         netlen = skb->len;
971
972         htc_hdr = (struct htc_frame_hdr *) netdata;
973
974         if (htc_hdr->eid >= ENDPOINT_MAX) {
975                 ath6kl_dbg(ATH6KL_DBG_HTC,
976                            "HTC Rx: invalid EndpointID=%d\n",
977                            htc_hdr->eid);
978                 status = -EINVAL;
979                 goto free_skb;
980         }
981         ep = &target->endpoint[htc_hdr->eid];
982
983         payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
984
985         if (netlen < (payload_len + HTC_HDR_LENGTH)) {
986                 ath6kl_dbg(ATH6KL_DBG_HTC,
987                            "HTC Rx: insufficient length, got:%d expected =%zu\n",
988                            netlen, payload_len + HTC_HDR_LENGTH);
989                 status = -EINVAL;
990                 goto free_skb;
991         }
992
993         /* get flags to check for trailer */
994         hdr_info = htc_hdr->flags;
995         if (hdr_info & HTC_FLG_RX_TRAILER) {
996                 /* extract the trailer length */
997                 hdr_info = htc_hdr->ctrl[0];
998                 if ((hdr_info < sizeof(struct htc_record_hdr)) ||
999                     (hdr_info > payload_len)) {
1000                         ath6kl_dbg(ATH6KL_DBG_HTC,
1001                                    "invalid header: payloadlen should be %d, CB[0]: %d\n",
1002                                    payload_len, hdr_info);
1003                         status = -EINVAL;
1004                         goto free_skb;
1005                 }
1006
1007                 trailerlen = hdr_info;
1008                 /* process trailer after hdr/apps payload */
1009                 trailer = (u8 *) htc_hdr + HTC_HDR_LENGTH +
1010                         payload_len - hdr_info;
1011                 status = htc_process_trailer(target, trailer, hdr_info,
1012                                              htc_hdr->eid);
1013                 if (status != 0)
1014                         goto free_skb;
1015         }
1016
1017         if (((int) payload_len - (int) trailerlen) <= 0) {
1018                 /* zero length packet with trailer, just drop these */
1019                 goto free_skb;
1020         }
1021
1022         if (htc_hdr->eid == ENDPOINT_0) {
1023                 /* handle HTC control message */
1024                 if (target->htc_flags & HTC_OP_STATE_SETUP_COMPLETE) {
1025                         /*
1026                          * fatal: target should not send unsolicited
1027                          * messageson the endpoint 0
1028                          */
1029                         ath6kl_dbg(ATH6KL_DBG_HTC,
1030                                    "HTC ignores Rx Ctrl after setup complete\n");
1031                         status = -EINVAL;
1032                         goto free_skb;
1033                 }
1034
1035                 /* remove HTC header */
1036                 skb_pull(skb, HTC_HDR_LENGTH);
1037
1038                 netdata = skb->data;
1039                 netlen = skb->len;
1040
1041                 spin_lock_bh(&target->rx_lock);
1042
1043                 target->pipe.ctrl_response_valid = true;
1044                 target->pipe.ctrl_response_len = min_t(int, netlen,
1045                                                        HTC_MAX_CTRL_MSG_LEN);
1046                 memcpy(target->pipe.ctrl_response_buf, netdata,
1047                        target->pipe.ctrl_response_len);
1048
1049                 spin_unlock_bh(&target->rx_lock);
1050
1051                 dev_kfree_skb(skb);
1052                 skb = NULL;
1053
1054                 goto free_skb;
1055         }
1056
1057         /*
1058          * TODO: the message based HIF architecture allocates net bufs
1059          * for recv packets since it bridges that HIF to upper layers,
1060          * which expects HTC packets, we form the packets here
1061          */
1062         packet = alloc_htc_packet_container(target);
1063         if (packet == NULL) {
1064                 status = -ENOMEM;
1065                 goto free_skb;
1066         }
1067
1068         packet->status = 0;
1069         packet->endpoint = htc_hdr->eid;
1070         packet->pkt_cntxt = skb;
1071
1072         /* TODO: for backwards compatibility */
1073         packet->buf = skb_push(skb, 0) + HTC_HDR_LENGTH;
1074         packet->act_len = netlen - HTC_HDR_LENGTH - trailerlen;
1075
1076         /*
1077          * TODO: this is a hack because the driver layer will set the
1078          * actual len of the skb again which will just double the len
1079          */
1080         skb_trim(skb, 0);
1081
1082         recv_packet_completion(target, ep, packet);
1083
1084         /* recover the packet container */
1085         free_htc_packet_container(target, packet);
1086         skb = NULL;
1087
1088 free_skb:
1089         dev_kfree_skb(skb);
1090
1091         return status;
1092 }
1093
1094 static void htc_flush_rx_queue(struct htc_target *target,
1095                                struct htc_endpoint *ep)
1096 {
1097         struct list_head container;
1098         struct htc_packet *packet;
1099
1100         spin_lock_bh(&target->rx_lock);
1101
1102         while (1) {
1103                 if (list_empty(&ep->rx_bufq))
1104                         break;
1105
1106                 packet = list_first_entry(&ep->rx_bufq,
1107                                           struct htc_packet, list);
1108                 list_del(&packet->list);
1109
1110                 spin_unlock_bh(&target->rx_lock);
1111                 packet->status = -ECANCELED;
1112                 packet->act_len = 0;
1113
1114                 ath6kl_dbg(ATH6KL_DBG_HTC,
1115                            "Flushing RX packet:0x%p, length:%d, ep:%d\n",
1116                            packet, packet->buf_len,
1117                            packet->endpoint);
1118
1119                 INIT_LIST_HEAD(&container);
1120                 list_add_tail(&packet->list, &container);
1121
1122                 /* give the packet back */
1123                 do_recv_completion(ep, &container);
1124                 spin_lock_bh(&target->rx_lock);
1125         }
1126
1127         spin_unlock_bh(&target->rx_lock);
1128 }
1129
1130 /* polling routine to wait for a control packet to be received */
1131 static int htc_wait_recv_ctrl_message(struct htc_target *target)
1132 {
1133         int count = HTC_TARGET_RESPONSE_POLL_COUNT;
1134
1135         while (count > 0) {
1136                 spin_lock_bh(&target->rx_lock);
1137
1138                 if (target->pipe.ctrl_response_valid) {
1139                         target->pipe.ctrl_response_valid = false;
1140                         spin_unlock_bh(&target->rx_lock);
1141                         break;
1142                 }
1143
1144                 spin_unlock_bh(&target->rx_lock);
1145
1146                 count--;
1147
1148                 msleep_interruptible(HTC_TARGET_RESPONSE_POLL_WAIT);
1149         }
1150
1151         if (count <= 0) {
1152                 ath6kl_warn("htc pipe control receive timeout!\n");
1153                 return -ETIMEDOUT;
1154         }
1155
1156         return 0;
1157 }
1158
1159 static void htc_rxctrl_complete(struct htc_target *context,
1160                                 struct htc_packet *packet)
1161 {
1162         struct sk_buff *skb = packet->skb;
1163
1164         if (packet->endpoint == ENDPOINT_0 &&
1165             packet->status == -ECANCELED &&
1166             skb != NULL)
1167                 dev_kfree_skb(skb);
1168 }
1169
1170 /* htc pipe initialization */
1171 static void reset_endpoint_states(struct htc_target *target)
1172 {
1173         struct htc_endpoint *ep;
1174         int i;
1175
1176         for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1177                 ep = &target->endpoint[i];
1178                 ep->svc_id = 0;
1179                 ep->len_max = 0;
1180                 ep->max_txq_depth = 0;
1181                 ep->eid = i;
1182                 INIT_LIST_HEAD(&ep->txq);
1183                 INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue);
1184                 INIT_LIST_HEAD(&ep->rx_bufq);
1185                 ep->target = target;
1186                 ep->pipe.tx_credit_flow_enabled = true;
1187         }
1188 }
1189
1190 /* start HTC, this is called after all services are connected */
1191 static int htc_config_target_hif_pipe(struct htc_target *target)
1192 {
1193         return 0;
1194 }
1195
1196 /* htc service functions */
1197 static u8 htc_get_credit_alloc(struct htc_target *target, u16 service_id)
1198 {
1199         u8 allocation = 0;
1200         int i;
1201
1202         for (i = 0; i < ENDPOINT_MAX; i++) {
1203                 if (target->pipe.txcredit_alloc[i].service_id == service_id)
1204                         allocation =
1205                                 target->pipe.txcredit_alloc[i].credit_alloc;
1206         }
1207
1208         if (allocation == 0) {
1209                 ath6kl_dbg(ATH6KL_DBG_HTC,
1210                            "HTC Service TX : 0x%2.2X : allocation is zero!\n",
1211                            service_id);
1212         }
1213
1214         return allocation;
1215 }
1216
1217 static int ath6kl_htc_pipe_conn_service(struct htc_target *target,
1218                      struct htc_service_connect_req *conn_req,
1219                      struct htc_service_connect_resp *conn_resp)
1220 {
1221         struct ath6kl *ar = target->dev->ar;
1222         struct htc_packet *packet = NULL;
1223         struct htc_conn_service_resp *resp_msg;
1224         struct htc_conn_service_msg *conn_msg;
1225         enum htc_endpoint_id assigned_epid = ENDPOINT_MAX;
1226         bool disable_credit_flowctrl = false;
1227         unsigned int max_msg_size = 0;
1228         struct htc_endpoint *ep;
1229         int length, status = 0;
1230         struct sk_buff *skb;
1231         u8 tx_alloc;
1232         u16 flags;
1233
1234         if (conn_req->svc_id == 0) {
1235                 WARN_ON_ONCE(1);
1236                 status = -EINVAL;
1237                 goto free_packet;
1238         }
1239
1240         if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) {
1241                 /* special case for pseudo control service */
1242                 assigned_epid = ENDPOINT_0;
1243                 max_msg_size = HTC_MAX_CTRL_MSG_LEN;
1244                 tx_alloc = 0;
1245
1246         } else {
1247                 tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id);
1248                 if (tx_alloc == 0) {
1249                         status = -ENOMEM;
1250                         goto free_packet;
1251                 }
1252
1253                 /* allocate a packet to send to the target */
1254                 packet = htc_alloc_txctrl_packet(target);
1255
1256                 if (packet == NULL) {
1257                         WARN_ON_ONCE(1);
1258                         status = -ENOMEM;
1259                         goto free_packet;
1260                 }
1261
1262                 skb = packet->skb;
1263                 length = sizeof(struct htc_conn_service_msg);
1264
1265                 /* assemble connect service message */
1266                 conn_msg = skb_put(skb, length);
1267                 if (conn_msg == NULL) {
1268                         WARN_ON_ONCE(1);
1269                         status = -EINVAL;
1270                         goto free_packet;
1271                 }
1272
1273                 memset(conn_msg, 0,
1274                        sizeof(struct htc_conn_service_msg));
1275                 conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID);
1276                 conn_msg->svc_id = cpu_to_le16(conn_req->svc_id);
1277                 conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags &
1278                                         ~HTC_CONN_FLGS_SET_RECV_ALLOC_MASK);
1279
1280                 /* tell target desired recv alloc for this ep */
1281                 flags = tx_alloc << HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT;
1282                 conn_msg->conn_flags |= cpu_to_le16(flags);
1283
1284                 if (conn_req->conn_flags &
1285                     HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL) {
1286                         disable_credit_flowctrl = true;
1287                 }
1288
1289                 set_htc_pkt_info(packet, NULL, (u8 *) conn_msg,
1290                                  length,
1291                                  ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
1292
1293                 status = ath6kl_htc_pipe_tx(target, packet);
1294
1295                 /* we don't own it anymore */
1296                 packet = NULL;
1297                 if (status != 0)
1298                         goto free_packet;
1299
1300                 /* wait for response */
1301                 status = htc_wait_recv_ctrl_message(target);
1302                 if (status != 0)
1303                         goto free_packet;
1304
1305                 /* we controlled the buffer creation so it has to be
1306                  * properly aligned
1307                  */
1308                 resp_msg = (struct htc_conn_service_resp *)
1309                     target->pipe.ctrl_response_buf;
1310
1311                 if (resp_msg->msg_id != cpu_to_le16(HTC_MSG_CONN_SVC_RESP_ID) ||
1312                     (target->pipe.ctrl_response_len < sizeof(*resp_msg))) {
1313                         /* this message is not valid */
1314                         WARN_ON_ONCE(1);
1315                         status = -EINVAL;
1316                         goto free_packet;
1317                 }
1318
1319                 ath6kl_dbg(ATH6KL_DBG_TRC,
1320                            "%s: service 0x%X conn resp: status: %d ep: %d\n",
1321                            __func__, resp_msg->svc_id, resp_msg->status,
1322                            resp_msg->eid);
1323
1324                 conn_resp->resp_code = resp_msg->status;
1325                 /* check response status */
1326                 if (resp_msg->status != HTC_SERVICE_SUCCESS) {
1327                         ath6kl_dbg(ATH6KL_DBG_HTC,
1328                                    "Target failed service 0x%X connect request (status:%d)\n",
1329                                    resp_msg->svc_id, resp_msg->status);
1330                         status = -EINVAL;
1331                         goto free_packet;
1332                 }
1333
1334                 assigned_epid = (enum htc_endpoint_id) resp_msg->eid;
1335                 max_msg_size = le16_to_cpu(resp_msg->max_msg_sz);
1336         }
1337
1338         /* the rest are parameter checks so set the error status */
1339         status = -EINVAL;
1340
1341         if (assigned_epid >= ENDPOINT_MAX) {
1342                 WARN_ON_ONCE(1);
1343                 goto free_packet;
1344         }
1345
1346         if (max_msg_size == 0) {
1347                 WARN_ON_ONCE(1);
1348                 goto free_packet;
1349         }
1350
1351         ep = &target->endpoint[assigned_epid];
1352         ep->eid = assigned_epid;
1353         if (ep->svc_id != 0) {
1354                 /* endpoint already in use! */
1355                 WARN_ON_ONCE(1);
1356                 goto free_packet;
1357         }
1358
1359         /* return assigned endpoint to caller */
1360         conn_resp->endpoint = assigned_epid;
1361         conn_resp->len_max = max_msg_size;
1362
1363         /* setup the endpoint */
1364         ep->svc_id = conn_req->svc_id; /* this marks ep in use */
1365         ep->max_txq_depth = conn_req->max_txq_depth;
1366         ep->len_max = max_msg_size;
1367         ep->cred_dist.credits = tx_alloc;
1368         ep->cred_dist.cred_sz = target->tgt_cred_sz;
1369         ep->cred_dist.cred_per_msg = max_msg_size / target->tgt_cred_sz;
1370         if (max_msg_size % target->tgt_cred_sz)
1371                 ep->cred_dist.cred_per_msg++;
1372
1373         /* copy all the callbacks */
1374         ep->ep_cb = conn_req->ep_cb;
1375
1376         /* initialize tx_drop_packet_threshold */
1377         ep->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM;
1378
1379         status = ath6kl_hif_pipe_map_service(ar, ep->svc_id,
1380                                              &ep->pipe.pipeid_ul,
1381                                              &ep->pipe.pipeid_dl);
1382         if (status != 0)
1383                 goto free_packet;
1384
1385         ath6kl_dbg(ATH6KL_DBG_HTC,
1386                    "SVC Ready: 0x%4.4X: ULpipe:%d DLpipe:%d id:%d\n",
1387                    ep->svc_id, ep->pipe.pipeid_ul,
1388                    ep->pipe.pipeid_dl, ep->eid);
1389
1390         if (disable_credit_flowctrl && ep->pipe.tx_credit_flow_enabled) {
1391                 ep->pipe.tx_credit_flow_enabled = false;
1392                 ath6kl_dbg(ATH6KL_DBG_HTC,
1393                            "SVC: 0x%4.4X ep:%d TX flow control off\n",
1394                            ep->svc_id, assigned_epid);
1395         }
1396
1397 free_packet:
1398         if (packet != NULL)
1399                 htc_free_txctrl_packet(target, packet);
1400         return status;
1401 }
1402
1403 /* htc export functions */
1404 static void *ath6kl_htc_pipe_create(struct ath6kl *ar)
1405 {
1406         int status = 0;
1407         struct htc_endpoint *ep = NULL;
1408         struct htc_target *target = NULL;
1409         struct htc_packet *packet;
1410         int i;
1411
1412         target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
1413         if (target == NULL) {
1414                 ath6kl_err("htc create unable to allocate memory\n");
1415                 status = -ENOMEM;
1416                 goto fail_htc_create;
1417         }
1418
1419         spin_lock_init(&target->htc_lock);
1420         spin_lock_init(&target->rx_lock);
1421         spin_lock_init(&target->tx_lock);
1422
1423         reset_endpoint_states(target);
1424
1425         for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) {
1426                 packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL);
1427
1428                 if (packet != NULL)
1429                         free_htc_packet_container(target, packet);
1430         }
1431
1432         target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL);
1433         if (!target->dev) {
1434                 ath6kl_err("unable to allocate memory\n");
1435                 status = -ENOMEM;
1436                 goto fail_htc_create;
1437         }
1438         target->dev->ar = ar;
1439         target->dev->htc_cnxt = target;
1440
1441         /* Get HIF default pipe for HTC message exchange */
1442         ep = &target->endpoint[ENDPOINT_0];
1443
1444         ath6kl_hif_pipe_get_default(ar, &ep->pipe.pipeid_ul,
1445                                     &ep->pipe.pipeid_dl);
1446
1447         return target;
1448
1449 fail_htc_create:
1450         if (status != 0) {
1451                 if (target != NULL)
1452                         ath6kl_htc_pipe_cleanup(target);
1453
1454                 target = NULL;
1455         }
1456         return target;
1457 }
1458
1459 /* cleanup the HTC instance */
1460 static void ath6kl_htc_pipe_cleanup(struct htc_target *target)
1461 {
1462         struct htc_packet *packet;
1463
1464         while (true) {
1465                 packet = alloc_htc_packet_container(target);
1466                 if (packet == NULL)
1467                         break;
1468                 kfree(packet);
1469         }
1470
1471         kfree(target->dev);
1472
1473         /* kfree our instance */
1474         kfree(target);
1475 }
1476
1477 static int ath6kl_htc_pipe_start(struct htc_target *target)
1478 {
1479         struct sk_buff *skb;
1480         struct htc_setup_comp_ext_msg *setup;
1481         struct htc_packet *packet;
1482
1483         htc_config_target_hif_pipe(target);
1484
1485         /* allocate a buffer to send */
1486         packet = htc_alloc_txctrl_packet(target);
1487         if (packet == NULL) {
1488                 WARN_ON_ONCE(1);
1489                 return -ENOMEM;
1490         }
1491
1492         skb = packet->skb;
1493
1494         /* assemble setup complete message */
1495         setup = skb_put(skb, sizeof(*setup));
1496         memset(setup, 0, sizeof(struct htc_setup_comp_ext_msg));
1497         setup->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID);
1498
1499         ath6kl_dbg(ATH6KL_DBG_HTC, "HTC using TX credit flow control\n");
1500
1501         set_htc_pkt_info(packet, NULL, (u8 *) setup,
1502                          sizeof(struct htc_setup_comp_ext_msg),
1503                          ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
1504
1505         target->htc_flags |= HTC_OP_STATE_SETUP_COMPLETE;
1506
1507         return ath6kl_htc_pipe_tx(target, packet);
1508 }
1509
1510 static void ath6kl_htc_pipe_stop(struct htc_target *target)
1511 {
1512         int i;
1513         struct htc_endpoint *ep;
1514
1515         /* cleanup endpoints */
1516         for (i = 0; i < ENDPOINT_MAX; i++) {
1517                 ep = &target->endpoint[i];
1518                 htc_flush_rx_queue(target, ep);
1519                 htc_flush_tx_endpoint(target, ep, HTC_TX_PACKET_TAG_ALL);
1520         }
1521
1522         reset_endpoint_states(target);
1523         target->htc_flags &= ~HTC_OP_STATE_SETUP_COMPLETE;
1524 }
1525
1526 static int ath6kl_htc_pipe_get_rxbuf_num(struct htc_target *target,
1527                                          enum htc_endpoint_id endpoint)
1528 {
1529         int num;
1530
1531         spin_lock_bh(&target->rx_lock);
1532         num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq));
1533         spin_unlock_bh(&target->rx_lock);
1534
1535         return num;
1536 }
1537
1538 static int ath6kl_htc_pipe_tx(struct htc_target *target,
1539                               struct htc_packet *packet)
1540 {
1541         struct list_head queue;
1542
1543         ath6kl_dbg(ATH6KL_DBG_HTC,
1544                    "%s: endPointId: %d, buffer: 0x%p, length: %d\n",
1545                    __func__, packet->endpoint, packet->buf,
1546                    packet->act_len);
1547
1548         INIT_LIST_HEAD(&queue);
1549         list_add_tail(&packet->list, &queue);
1550
1551         return htc_send_packets_multiple(target, &queue);
1552 }
1553
1554 static int ath6kl_htc_pipe_wait_target(struct htc_target *target)
1555 {
1556         struct htc_ready_ext_msg *ready_msg;
1557         struct htc_service_connect_req connect;
1558         struct htc_service_connect_resp resp;
1559         int status = 0;
1560
1561         status = htc_wait_recv_ctrl_message(target);
1562
1563         if (status != 0)
1564                 return status;
1565
1566         if (target->pipe.ctrl_response_len < sizeof(*ready_msg)) {
1567                 ath6kl_warn("invalid htc pipe ready msg len: %d\n",
1568                             target->pipe.ctrl_response_len);
1569                 return -ECOMM;
1570         }
1571
1572         ready_msg = (struct htc_ready_ext_msg *) target->pipe.ctrl_response_buf;
1573
1574         if (ready_msg->ver2_0_info.msg_id != cpu_to_le16(HTC_MSG_READY_ID)) {
1575                 ath6kl_warn("invalid htc pipe ready msg: 0x%x\n",
1576                             ready_msg->ver2_0_info.msg_id);
1577                 return -ECOMM;
1578         }
1579
1580         ath6kl_dbg(ATH6KL_DBG_HTC,
1581                    "Target Ready! : transmit resources : %d size:%d\n",
1582                    ready_msg->ver2_0_info.cred_cnt,
1583                    ready_msg->ver2_0_info.cred_sz);
1584
1585         target->tgt_creds = le16_to_cpu(ready_msg->ver2_0_info.cred_cnt);
1586         target->tgt_cred_sz = le16_to_cpu(ready_msg->ver2_0_info.cred_sz);
1587
1588         if ((target->tgt_creds == 0) || (target->tgt_cred_sz == 0))
1589                 return -ECOMM;
1590
1591         htc_setup_target_buffer_assignments(target);
1592
1593         /* setup our pseudo HTC control endpoint connection */
1594         memset(&connect, 0, sizeof(connect));
1595         memset(&resp, 0, sizeof(resp));
1596         connect.ep_cb.tx_complete = htc_txctrl_complete;
1597         connect.ep_cb.rx = htc_rxctrl_complete;
1598         connect.max_txq_depth = NUM_CONTROL_TX_BUFFERS;
1599         connect.svc_id = HTC_CTRL_RSVD_SVC;
1600
1601         /* connect fake service */
1602         status = ath6kl_htc_pipe_conn_service(target, &connect, &resp);
1603
1604         return status;
1605 }
1606
1607 static void ath6kl_htc_pipe_flush_txep(struct htc_target *target,
1608                                        enum htc_endpoint_id endpoint, u16 tag)
1609 {
1610         struct htc_endpoint *ep = &target->endpoint[endpoint];
1611
1612         if (ep->svc_id == 0) {
1613                 WARN_ON_ONCE(1);
1614                 /* not in use.. */
1615                 return;
1616         }
1617
1618         htc_flush_tx_endpoint(target, ep, tag);
1619 }
1620
1621 static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target,
1622                                               struct list_head *pkt_queue)
1623 {
1624         struct htc_packet *packet, *tmp_pkt, *first;
1625         struct htc_endpoint *ep;
1626         int status = 0;
1627
1628         if (list_empty(pkt_queue))
1629                 return -EINVAL;
1630
1631         first = list_first_entry(pkt_queue, struct htc_packet, list);
1632
1633         if (first->endpoint >= ENDPOINT_MAX) {
1634                 WARN_ON_ONCE(1);
1635                 return -EINVAL;
1636         }
1637
1638         ath6kl_dbg(ATH6KL_DBG_HTC, "%s: epid: %d, cnt:%d, len: %d\n",
1639                    __func__, first->endpoint, get_queue_depth(pkt_queue),
1640                    first->buf_len);
1641
1642         ep = &target->endpoint[first->endpoint];
1643
1644         spin_lock_bh(&target->rx_lock);
1645
1646         /* store receive packets */
1647         list_splice_tail_init(pkt_queue, &ep->rx_bufq);
1648
1649         spin_unlock_bh(&target->rx_lock);
1650
1651         if (status != 0) {
1652                 /* walk through queue and mark each one canceled */
1653                 list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
1654                         packet->status = -ECANCELED;
1655                 }
1656
1657                 do_recv_completion(ep, pkt_queue);
1658         }
1659
1660         return status;
1661 }
1662
1663 static void ath6kl_htc_pipe_activity_changed(struct htc_target *target,
1664                                              enum htc_endpoint_id ep,
1665                                              bool active)
1666 {
1667         /* TODO */
1668 }
1669
1670 static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target)
1671 {
1672         struct htc_endpoint *endpoint;
1673         struct htc_packet *packet, *tmp_pkt;
1674         int i;
1675
1676         for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1677                 endpoint = &target->endpoint[i];
1678
1679                 spin_lock_bh(&target->rx_lock);
1680
1681                 list_for_each_entry_safe(packet, tmp_pkt,
1682                                          &endpoint->rx_bufq, list) {
1683                         list_del(&packet->list);
1684                         spin_unlock_bh(&target->rx_lock);
1685                         ath6kl_dbg(ATH6KL_DBG_HTC,
1686                                    "htc rx flush pkt 0x%p len %d ep %d\n",
1687                                    packet, packet->buf_len,
1688                                    packet->endpoint);
1689                         dev_kfree_skb(packet->pkt_cntxt);
1690                         spin_lock_bh(&target->rx_lock);
1691                 }
1692
1693                 spin_unlock_bh(&target->rx_lock);
1694         }
1695 }
1696
1697 static int ath6kl_htc_pipe_credit_setup(struct htc_target *target,
1698                                         struct ath6kl_htc_credit_info *info)
1699 {
1700         return 0;
1701 }
1702
1703 static const struct ath6kl_htc_ops ath6kl_htc_pipe_ops = {
1704         .create = ath6kl_htc_pipe_create,
1705         .wait_target = ath6kl_htc_pipe_wait_target,
1706         .start = ath6kl_htc_pipe_start,
1707         .conn_service = ath6kl_htc_pipe_conn_service,
1708         .tx = ath6kl_htc_pipe_tx,
1709         .stop = ath6kl_htc_pipe_stop,
1710         .cleanup = ath6kl_htc_pipe_cleanup,
1711         .flush_txep = ath6kl_htc_pipe_flush_txep,
1712         .flush_rx_buf = ath6kl_htc_pipe_flush_rx_buf,
1713         .activity_changed = ath6kl_htc_pipe_activity_changed,
1714         .get_rxbuf_num = ath6kl_htc_pipe_get_rxbuf_num,
1715         .add_rxbuf_multiple = ath6kl_htc_pipe_add_rxbuf_multiple,
1716         .credit_setup = ath6kl_htc_pipe_credit_setup,
1717         .tx_complete = ath6kl_htc_pipe_tx_complete,
1718         .rx_complete = ath6kl_htc_pipe_rx_complete,
1719 };
1720
1721 void ath6kl_htc_pipe_attach(struct ath6kl *ar)
1722 {
1723         ar->htc_ops = &ath6kl_htc_pipe_ops;
1724 }
This page took 0.126387 seconds and 4 git commands to generate.