Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2007-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "core.h"
0018 #include "debug.h"
0019 #include "hif-ops.h"
0020 
0021 #define HTC_PACKET_CONTAINER_ALLOCATION 32
0022 #define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH)
0023 
0024 static int ath6kl_htc_pipe_tx(struct htc_target *handle,
0025                   struct htc_packet *packet);
0026 static void ath6kl_htc_pipe_cleanup(struct htc_target *handle);
0027 
0028 /* htc pipe tx path */
0029 static inline void restore_tx_packet(struct htc_packet *packet)
0030 {
0031     if (packet->info.tx.flags & HTC_FLAGS_TX_FIXUP_NETBUF) {
0032         skb_pull(packet->skb, sizeof(struct htc_frame_hdr));
0033         packet->info.tx.flags &= ~HTC_FLAGS_TX_FIXUP_NETBUF;
0034     }
0035 }
0036 
0037 static void do_send_completion(struct htc_endpoint *ep,
0038                    struct list_head *queue_to_indicate)
0039 {
0040     struct htc_packet *packet;
0041 
0042     if (list_empty(queue_to_indicate)) {
0043         /* nothing to indicate */
0044         return;
0045     }
0046 
0047     if (ep->ep_cb.tx_comp_multi != NULL) {
0048         ath6kl_dbg(ATH6KL_DBG_HTC,
0049                "%s: calling ep %d, send complete multiple callback (%d pkts)\n",
0050                __func__, ep->eid,
0051                get_queue_depth(queue_to_indicate));
0052         /*
0053          * a multiple send complete handler is being used,
0054          * pass the queue to the handler
0055          */
0056         ep->ep_cb.tx_comp_multi(ep->target, queue_to_indicate);
0057         /*
0058          * all packets are now owned by the callback,
0059          * reset queue to be safe
0060          */
0061         INIT_LIST_HEAD(queue_to_indicate);
0062     } else {
0063         /* using legacy EpTxComplete */
0064         do {
0065             packet = list_first_entry(queue_to_indicate,
0066                           struct htc_packet, list);
0067 
0068             list_del(&packet->list);
0069             ath6kl_dbg(ATH6KL_DBG_HTC,
0070                    "%s: calling ep %d send complete callback on packet 0x%p\n",
0071                    __func__, ep->eid, packet);
0072             ep->ep_cb.tx_complete(ep->target, packet);
0073         } while (!list_empty(queue_to_indicate));
0074     }
0075 }
0076 
0077 static void send_packet_completion(struct htc_target *target,
0078                    struct htc_packet *packet)
0079 {
0080     struct htc_endpoint *ep = &target->endpoint[packet->endpoint];
0081     struct list_head container;
0082 
0083     restore_tx_packet(packet);
0084     INIT_LIST_HEAD(&container);
0085     list_add_tail(&packet->list, &container);
0086 
0087     /* do completion */
0088     do_send_completion(ep, &container);
0089 }
0090 
0091 static void get_htc_packet_credit_based(struct htc_target *target,
0092                     struct htc_endpoint *ep,
0093                     struct list_head *queue)
0094 {
0095     int credits_required;
0096     int remainder;
0097     u8 send_flags;
0098     struct htc_packet *packet;
0099     unsigned int transfer_len;
0100 
0101     /* NOTE : the TX lock is held when this function is called */
0102 
0103     /* loop until we can grab as many packets out of the queue as we can */
0104     while (true) {
0105         send_flags = 0;
0106         if (list_empty(&ep->txq))
0107             break;
0108 
0109         /* get packet at head, but don't remove it */
0110         packet = list_first_entry(&ep->txq, struct htc_packet, list);
0111 
0112         ath6kl_dbg(ATH6KL_DBG_HTC,
0113                "%s: got head packet:0x%p , queue depth: %d\n",
0114                __func__, packet, get_queue_depth(&ep->txq));
0115 
0116         transfer_len = packet->act_len + HTC_HDR_LENGTH;
0117 
0118         if (transfer_len <= target->tgt_cred_sz) {
0119             credits_required = 1;
0120         } else {
0121             /* figure out how many credits this message requires */
0122             credits_required = transfer_len / target->tgt_cred_sz;
0123             remainder = transfer_len % target->tgt_cred_sz;
0124 
0125             if (remainder)
0126                 credits_required++;
0127         }
0128 
0129         ath6kl_dbg(ATH6KL_DBG_HTC, "%s: creds required:%d got:%d\n",
0130                __func__, credits_required, ep->cred_dist.credits);
0131 
0132         if (ep->eid == ENDPOINT_0) {
0133             /*
0134              * endpoint 0 is special, it always has a credit and
0135              * does not require credit based flow control
0136              */
0137             credits_required = 0;
0138 
0139         } else {
0140             if (ep->cred_dist.credits < credits_required)
0141                 break;
0142 
0143             ep->cred_dist.credits -= credits_required;
0144             ep->ep_st.cred_cosumd += credits_required;
0145 
0146             /* check if we need credits back from the target */
0147             if (ep->cred_dist.credits <
0148                     ep->cred_dist.cred_per_msg) {
0149                 /* tell the target we need credits ASAP! */
0150                 send_flags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
0151                 ep->ep_st.cred_low_indicate += 1;
0152                 ath6kl_dbg(ATH6KL_DBG_HTC,
0153                        "%s: host needs credits\n",
0154                        __func__);
0155             }
0156         }
0157 
0158         /* now we can fully dequeue */
0159         packet = list_first_entry(&ep->txq, struct htc_packet, list);
0160 
0161         list_del(&packet->list);
0162         /* save the number of credits this packet consumed */
0163         packet->info.tx.cred_used = credits_required;
0164         /* save send flags */
0165         packet->info.tx.flags = send_flags;
0166         packet->info.tx.seqno = ep->seqno;
0167         ep->seqno++;
0168         /* queue this packet into the caller's queue */
0169         list_add_tail(&packet->list, queue);
0170     }
0171 }
0172 
0173 static void get_htc_packet(struct htc_target *target,
0174                struct htc_endpoint *ep,
0175                struct list_head *queue, int resources)
0176 {
0177     struct htc_packet *packet;
0178 
0179     /* NOTE : the TX lock is held when this function is called */
0180 
0181     /* loop until we can grab as many packets out of the queue as we can */
0182     while (resources) {
0183         if (list_empty(&ep->txq))
0184             break;
0185 
0186         packet = list_first_entry(&ep->txq, struct htc_packet, list);
0187         list_del(&packet->list);
0188 
0189         ath6kl_dbg(ATH6KL_DBG_HTC,
0190                "%s: got packet:0x%p , new queue depth: %d\n",
0191                __func__, packet, get_queue_depth(&ep->txq));
0192         packet->info.tx.seqno = ep->seqno;
0193         packet->info.tx.flags = 0;
0194         packet->info.tx.cred_used = 0;
0195         ep->seqno++;
0196 
0197         /* queue this packet into the caller's queue */
0198         list_add_tail(&packet->list, queue);
0199         resources--;
0200     }
0201 }
0202 
0203 static int htc_issue_packets(struct htc_target *target,
0204                  struct htc_endpoint *ep,
0205                  struct list_head *pkt_queue)
0206 {
0207     int status = 0;
0208     u16 payload_len;
0209     struct sk_buff *skb;
0210     struct htc_frame_hdr *htc_hdr;
0211     struct htc_packet *packet;
0212 
0213     ath6kl_dbg(ATH6KL_DBG_HTC,
0214            "%s: queue: 0x%p, pkts %d\n", __func__,
0215            pkt_queue, get_queue_depth(pkt_queue));
0216 
0217     while (!list_empty(pkt_queue)) {
0218         packet = list_first_entry(pkt_queue, struct htc_packet, list);
0219         list_del(&packet->list);
0220 
0221         skb = packet->skb;
0222         if (!skb) {
0223             WARN_ON_ONCE(1);
0224             status = -EINVAL;
0225             break;
0226         }
0227 
0228         payload_len = packet->act_len;
0229 
0230         /* setup HTC frame header */
0231         htc_hdr = skb_push(skb, sizeof(*htc_hdr));
0232         if (!htc_hdr) {
0233             WARN_ON_ONCE(1);
0234             status = -EINVAL;
0235             break;
0236         }
0237 
0238         packet->info.tx.flags |= HTC_FLAGS_TX_FIXUP_NETBUF;
0239 
0240         /* Endianess? */
0241         put_unaligned((u16) payload_len, &htc_hdr->payld_len);
0242         htc_hdr->flags = packet->info.tx.flags;
0243         htc_hdr->eid = (u8) packet->endpoint;
0244         htc_hdr->ctrl[0] = 0;
0245         htc_hdr->ctrl[1] = (u8) packet->info.tx.seqno;
0246 
0247         spin_lock_bh(&target->tx_lock);
0248 
0249         /* store in look up queue to match completions */
0250         list_add_tail(&packet->list, &ep->pipe.tx_lookup_queue);
0251         ep->ep_st.tx_issued += 1;
0252         spin_unlock_bh(&target->tx_lock);
0253 
0254         status = ath6kl_hif_pipe_send(target->dev->ar,
0255                           ep->pipe.pipeid_ul, NULL, skb);
0256 
0257         if (status != 0) {
0258             if (status != -ENOMEM) {
0259                 /* TODO: if more than 1 endpoint maps to the
0260                  * same PipeID, it is possible to run out of
0261                  * resources in the HIF layer.
0262                  * Don't emit the error
0263                  */
0264                 ath6kl_dbg(ATH6KL_DBG_HTC,
0265                        "%s: failed status:%d\n",
0266                        __func__, status);
0267             }
0268             spin_lock_bh(&target->tx_lock);
0269             list_del(&packet->list);
0270 
0271             /* reclaim credits */
0272             ep->cred_dist.credits += packet->info.tx.cred_used;
0273             spin_unlock_bh(&target->tx_lock);
0274 
0275             /* put it back into the callers queue */
0276             list_add(&packet->list, pkt_queue);
0277             break;
0278         }
0279     }
0280 
0281     if (status != 0) {
0282         while (!list_empty(pkt_queue)) {
0283             if (status != -ENOMEM) {
0284                 ath6kl_dbg(ATH6KL_DBG_HTC,
0285                        "%s: failed pkt:0x%p status:%d\n",
0286                        __func__, packet, status);
0287             }
0288 
0289             packet = list_first_entry(pkt_queue,
0290                           struct htc_packet, list);
0291             list_del(&packet->list);
0292             packet->status = status;
0293             send_packet_completion(target, packet);
0294         }
0295     }
0296 
0297     return status;
0298 }
0299 
0300 static enum htc_send_queue_result htc_try_send(struct htc_target *target,
0301                            struct htc_endpoint *ep,
0302                            struct list_head *txq)
0303 {
0304     struct list_head send_queue;    /* temp queue to hold packets */
0305     struct htc_packet *packet, *tmp_pkt;
0306     struct ath6kl *ar = target->dev->ar;
0307     enum htc_send_full_action action;
0308     int tx_resources, overflow, txqueue_depth, i, good_pkts;
0309     u8 pipeid;
0310 
0311     ath6kl_dbg(ATH6KL_DBG_HTC, "%s: (queue:0x%p depth:%d)\n",
0312            __func__, txq,
0313            (txq == NULL) ? 0 : get_queue_depth(txq));
0314 
0315     /* init the local send queue */
0316     INIT_LIST_HEAD(&send_queue);
0317 
0318     /*
0319      * txq equals to NULL means
0320      * caller didn't provide a queue, just wants us to
0321      * check queues and send
0322      */
0323     if (txq != NULL) {
0324         if (list_empty(txq)) {
0325             /* empty queue */
0326             return HTC_SEND_QUEUE_DROP;
0327         }
0328 
0329         spin_lock_bh(&target->tx_lock);
0330         txqueue_depth = get_queue_depth(&ep->txq);
0331         spin_unlock_bh(&target->tx_lock);
0332 
0333         if (txqueue_depth >= ep->max_txq_depth) {
0334             /* we've already overflowed */
0335             overflow = get_queue_depth(txq);
0336         } else {
0337             /* get how much we will overflow by */
0338             overflow = txqueue_depth;
0339             overflow += get_queue_depth(txq);
0340             /* get how much we will overflow the TX queue by */
0341             overflow -= ep->max_txq_depth;
0342         }
0343 
0344         /* if overflow is negative or zero, we are okay */
0345         if (overflow > 0) {
0346             ath6kl_dbg(ATH6KL_DBG_HTC,
0347                    "%s: Endpoint %d, TX queue will overflow :%d, Tx Depth:%d, Max:%d\n",
0348                    __func__, ep->eid, overflow, txqueue_depth,
0349                    ep->max_txq_depth);
0350         }
0351         if ((overflow <= 0) ||
0352             (ep->ep_cb.tx_full == NULL)) {
0353             /*
0354              * all packets will fit or caller did not provide send
0355              * full indication handler -- just move all of them
0356              * to the local send_queue object
0357              */
0358             list_splice_tail_init(txq, &send_queue);
0359         } else {
0360             good_pkts = get_queue_depth(txq) - overflow;
0361             if (good_pkts < 0) {
0362                 WARN_ON_ONCE(1);
0363                 return HTC_SEND_QUEUE_DROP;
0364             }
0365 
0366             /* we have overflowed, and a callback is provided */
0367             /* dequeue all non-overflow packets to the sendqueue */
0368             for (i = 0; i < good_pkts; i++) {
0369                 /* pop off caller's queue */
0370                 packet = list_first_entry(txq,
0371                               struct htc_packet,
0372                               list);
0373                 /* move to local queue */
0374                 list_move_tail(&packet->list, &send_queue);
0375             }
0376 
0377             /*
0378              * the caller's queue has all the packets that won't fit
0379              * walk through the caller's queue and indicate each to
0380              * the send full handler
0381              */
0382             list_for_each_entry_safe(packet, tmp_pkt,
0383                          txq, list) {
0384                 ath6kl_dbg(ATH6KL_DBG_HTC,
0385                        "%s: Indicate overflowed TX pkts: %p\n",
0386                        __func__, packet);
0387                 action = ep->ep_cb.tx_full(ep->target, packet);
0388                 if (action == HTC_SEND_FULL_DROP) {
0389                     /* callback wants the packet dropped */
0390                     ep->ep_st.tx_dropped += 1;
0391 
0392                     /* leave this one in the caller's queue
0393                      * for cleanup */
0394                 } else {
0395                     /* callback wants to keep this packet,
0396                      * move from caller's queue to the send
0397                      * queue */
0398                     list_move_tail(&packet->list,
0399                                &send_queue);
0400                 }
0401             }
0402 
0403             if (list_empty(&send_queue)) {
0404                 /* no packets made it in, caller will cleanup */
0405                 return HTC_SEND_QUEUE_DROP;
0406             }
0407         }
0408     }
0409 
0410     if (!ep->pipe.tx_credit_flow_enabled) {
0411         tx_resources =
0412             ath6kl_hif_pipe_get_free_queue_number(ar,
0413                               ep->pipe.pipeid_ul);
0414     } else {
0415         tx_resources = 0;
0416     }
0417 
0418     spin_lock_bh(&target->tx_lock);
0419     if (!list_empty(&send_queue)) {
0420         /* transfer packets to tail */
0421         list_splice_tail_init(&send_queue, &ep->txq);
0422         if (!list_empty(&send_queue)) {
0423             WARN_ON_ONCE(1);
0424             spin_unlock_bh(&target->tx_lock);
0425             return HTC_SEND_QUEUE_DROP;
0426         }
0427         INIT_LIST_HEAD(&send_queue);
0428     }
0429 
0430     /* increment tx processing count on entry */
0431     ep->tx_proc_cnt++;
0432 
0433     if (ep->tx_proc_cnt > 1) {
0434         /*
0435          * Another thread or task is draining the TX queues on this
0436          * endpoint that thread will reset the tx processing count
0437          * when the queue is drained.
0438          */
0439         ep->tx_proc_cnt--;
0440         spin_unlock_bh(&target->tx_lock);
0441         return HTC_SEND_QUEUE_OK;
0442     }
0443 
0444     /***** beyond this point only 1 thread may enter ******/
0445 
0446     /*
0447      * Now drain the endpoint TX queue for transmission as long as we have
0448      * enough transmit resources.
0449      */
0450     while (true) {
0451         if (get_queue_depth(&ep->txq) == 0)
0452             break;
0453 
0454         if (ep->pipe.tx_credit_flow_enabled) {
0455             /*
0456              * Credit based mechanism provides flow control
0457              * based on target transmit resource availability,
0458              * we assume that the HIF layer will always have
0459              * bus resources greater than target transmit
0460              * resources.
0461              */
0462             get_htc_packet_credit_based(target, ep, &send_queue);
0463         } else {
0464             /*
0465              * Get all packets for this endpoint that we can
0466              * for this pass.
0467              */
0468             get_htc_packet(target, ep, &send_queue, tx_resources);
0469         }
0470 
0471         if (get_queue_depth(&send_queue) == 0) {
0472             /*
0473              * Didn't get packets due to out of resources or TX
0474              * queue was drained.
0475              */
0476             break;
0477         }
0478 
0479         spin_unlock_bh(&target->tx_lock);
0480 
0481         /* send what we can */
0482         htc_issue_packets(target, ep, &send_queue);
0483 
0484         if (!ep->pipe.tx_credit_flow_enabled) {
0485             pipeid = ep->pipe.pipeid_ul;
0486             tx_resources =
0487                 ath6kl_hif_pipe_get_free_queue_number(ar, pipeid);
0488         }
0489 
0490         spin_lock_bh(&target->tx_lock);
0491     }
0492 
0493     /* done with this endpoint, we can clear the count */
0494     ep->tx_proc_cnt = 0;
0495     spin_unlock_bh(&target->tx_lock);
0496 
0497     return HTC_SEND_QUEUE_OK;
0498 }
0499 
0500 /* htc control packet manipulation */
0501 static void destroy_htc_txctrl_packet(struct htc_packet *packet)
0502 {
0503     struct sk_buff *skb;
0504     skb = packet->skb;
0505     dev_kfree_skb(skb);
0506     kfree(packet);
0507 }
0508 
0509 static struct htc_packet *build_htc_txctrl_packet(void)
0510 {
0511     struct htc_packet *packet = NULL;
0512     struct sk_buff *skb;
0513 
0514     packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL);
0515     if (packet == NULL)
0516         return NULL;
0517 
0518     skb = __dev_alloc_skb(HTC_CONTROL_BUFFER_SIZE, GFP_KERNEL);
0519 
0520     if (skb == NULL) {
0521         kfree(packet);
0522         return NULL;
0523     }
0524     packet->skb = skb;
0525 
0526     return packet;
0527 }
0528 
0529 static void htc_free_txctrl_packet(struct htc_target *target,
0530                    struct htc_packet *packet)
0531 {
0532     destroy_htc_txctrl_packet(packet);
0533 }
0534 
0535 static struct htc_packet *htc_alloc_txctrl_packet(struct htc_target *target)
0536 {
0537     return build_htc_txctrl_packet();
0538 }
0539 
0540 static void htc_txctrl_complete(struct htc_target *target,
0541                 struct htc_packet *packet)
0542 {
0543     htc_free_txctrl_packet(target, packet);
0544 }
0545 
0546 #define MAX_MESSAGE_SIZE 1536
0547 
0548 static int htc_setup_target_buffer_assignments(struct htc_target *target)
0549 {
0550     int status, credits, credit_per_maxmsg, i;
0551     struct htc_pipe_txcredit_alloc *entry;
0552     unsigned int hif_usbaudioclass = 0;
0553 
0554     credit_per_maxmsg = MAX_MESSAGE_SIZE / target->tgt_cred_sz;
0555     if (MAX_MESSAGE_SIZE % target->tgt_cred_sz)
0556         credit_per_maxmsg++;
0557 
0558     /* TODO, this should be configured by the caller! */
0559 
0560     credits = target->tgt_creds;
0561     entry = &target->pipe.txcredit_alloc[0];
0562 
0563     status = -ENOMEM;
0564 
0565     /* FIXME: hif_usbaudioclass is always zero */
0566     if (hif_usbaudioclass) {
0567         ath6kl_dbg(ATH6KL_DBG_HTC,
0568                "%s: For USB Audio Class- Total:%d\n",
0569                __func__, credits);
0570         entry++;
0571         entry++;
0572         /* Setup VO Service To have Max Credits */
0573         entry->service_id = WMI_DATA_VO_SVC;
0574         entry->credit_alloc = (credits - 6);
0575         if (entry->credit_alloc == 0)
0576             entry->credit_alloc++;
0577 
0578         credits -= (int) entry->credit_alloc;
0579         if (credits <= 0)
0580             return status;
0581 
0582         entry++;
0583         entry->service_id = WMI_CONTROL_SVC;
0584         entry->credit_alloc = credit_per_maxmsg;
0585         credits -= (int) entry->credit_alloc;
0586         if (credits <= 0)
0587             return status;
0588 
0589         /* leftovers go to best effort */
0590         entry++;
0591         entry++;
0592         entry->service_id = WMI_DATA_BE_SVC;
0593         entry->credit_alloc = (u8) credits;
0594         status = 0;
0595     } else {
0596         entry++;
0597         entry->service_id = WMI_DATA_VI_SVC;
0598         entry->credit_alloc = credits / 4;
0599         if (entry->credit_alloc == 0)
0600             entry->credit_alloc++;
0601 
0602         credits -= (int) entry->credit_alloc;
0603         if (credits <= 0)
0604             return status;
0605 
0606         entry++;
0607         entry->service_id = WMI_DATA_VO_SVC;
0608         entry->credit_alloc = credits / 4;
0609         if (entry->credit_alloc == 0)
0610             entry->credit_alloc++;
0611 
0612         credits -= (int) entry->credit_alloc;
0613         if (credits <= 0)
0614             return status;
0615 
0616         entry++;
0617         entry->service_id = WMI_CONTROL_SVC;
0618         entry->credit_alloc = credit_per_maxmsg;
0619         credits -= (int) entry->credit_alloc;
0620         if (credits <= 0)
0621             return status;
0622 
0623         entry++;
0624         entry->service_id = WMI_DATA_BK_SVC;
0625         entry->credit_alloc = credit_per_maxmsg;
0626         credits -= (int) entry->credit_alloc;
0627         if (credits <= 0)
0628             return status;
0629 
0630         /* leftovers go to best effort */
0631         entry++;
0632         entry->service_id = WMI_DATA_BE_SVC;
0633         entry->credit_alloc = (u8) credits;
0634         status = 0;
0635     }
0636 
0637     if (status == 0) {
0638         for (i = 0; i < ENDPOINT_MAX; i++) {
0639             if (target->pipe.txcredit_alloc[i].service_id != 0) {
0640                 ath6kl_dbg(ATH6KL_DBG_HTC,
0641                        "HTC Service Index : %d TX : 0x%2.2X : alloc:%d\n",
0642                        i,
0643                        target->pipe.txcredit_alloc[i].
0644                        service_id,
0645                        target->pipe.txcredit_alloc[i].
0646                        credit_alloc);
0647             }
0648         }
0649     }
0650     return status;
0651 }
0652 
0653 /* process credit reports and call distribution function */
0654 static void htc_process_credit_report(struct htc_target *target,
0655                       struct htc_credit_report *rpt,
0656                       int num_entries,
0657                       enum htc_endpoint_id from_ep)
0658 {
0659     int total_credits = 0, i;
0660     struct htc_endpoint *ep;
0661 
0662     /* lock out TX while we update credits */
0663     spin_lock_bh(&target->tx_lock);
0664 
0665     for (i = 0; i < num_entries; i++, rpt++) {
0666         if (rpt->eid >= ENDPOINT_MAX) {
0667             WARN_ON_ONCE(1);
0668             spin_unlock_bh(&target->tx_lock);
0669             return;
0670         }
0671 
0672         ep = &target->endpoint[rpt->eid];
0673         ep->cred_dist.credits += rpt->credits;
0674 
0675         if (ep->cred_dist.credits && get_queue_depth(&ep->txq)) {
0676             spin_unlock_bh(&target->tx_lock);
0677             htc_try_send(target, ep, NULL);
0678             spin_lock_bh(&target->tx_lock);
0679         }
0680 
0681         total_credits += rpt->credits;
0682     }
0683     ath6kl_dbg(ATH6KL_DBG_HTC,
0684            "Report indicated %d credits to distribute\n",
0685            total_credits);
0686 
0687     spin_unlock_bh(&target->tx_lock);
0688 }
0689 
0690 /* flush endpoint TX queue */
0691 static void htc_flush_tx_endpoint(struct htc_target *target,
0692                   struct htc_endpoint *ep, u16 tag)
0693 {
0694     struct htc_packet *packet;
0695 
0696     spin_lock_bh(&target->tx_lock);
0697     while (get_queue_depth(&ep->txq)) {
0698         packet = list_first_entry(&ep->txq, struct htc_packet, list);
0699         list_del(&packet->list);
0700         packet->status = 0;
0701         send_packet_completion(target, packet);
0702     }
0703     spin_unlock_bh(&target->tx_lock);
0704 }
0705 
0706 /*
0707  * In the adapted HIF layer, struct sk_buff * are passed between HIF and HTC,
0708  * since upper layers expects struct htc_packet containers we use the completed
0709  * skb and lookup it's corresponding HTC packet buffer from a lookup list.
0710  * This is extra overhead that can be fixed by re-aligning HIF interfaces with
0711  * HTC.
0712  */
0713 static struct htc_packet *htc_lookup_tx_packet(struct htc_target *target,
0714                            struct htc_endpoint *ep,
0715                            struct sk_buff *skb)
0716 {
0717     struct htc_packet *packet, *tmp_pkt, *found_packet = NULL;
0718 
0719     spin_lock_bh(&target->tx_lock);
0720 
0721     /*
0722      * interate from the front of tx lookup queue
0723      * this lookup should be fast since lower layers completes in-order and
0724      * so the completed packet should be at the head of the list generally
0725      */
0726     list_for_each_entry_safe(packet, tmp_pkt, &ep->pipe.tx_lookup_queue,
0727                  list) {
0728         /* check for removal */
0729         if (skb == packet->skb) {
0730             /* found it */
0731             list_del(&packet->list);
0732             found_packet = packet;
0733             break;
0734         }
0735     }
0736 
0737     spin_unlock_bh(&target->tx_lock);
0738 
0739     return found_packet;
0740 }
0741 
0742 static int ath6kl_htc_pipe_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
0743 {
0744     struct htc_target *target = ar->htc_target;
0745     struct htc_frame_hdr *htc_hdr;
0746     struct htc_endpoint *ep;
0747     struct htc_packet *packet;
0748     u8 ep_id, *netdata;
0749 
0750     netdata = skb->data;
0751 
0752     htc_hdr = (struct htc_frame_hdr *) netdata;
0753 
0754     ep_id = htc_hdr->eid;
0755     ep = &target->endpoint[ep_id];
0756 
0757     packet = htc_lookup_tx_packet(target, ep, skb);
0758     if (packet == NULL) {
0759         /* may have already been flushed and freed */
0760         ath6kl_err("HTC TX lookup failed!\n");
0761     } else {
0762         /* will be giving this buffer back to upper layers */
0763         packet->status = 0;
0764         send_packet_completion(target, packet);
0765     }
0766     skb = NULL;
0767 
0768     if (!ep->pipe.tx_credit_flow_enabled) {
0769         /*
0770          * note: when using TX credit flow, the re-checking of queues
0771          * happens when credits flow back from the target. in the
0772          * non-TX credit case, we recheck after the packet completes
0773          */
0774         htc_try_send(target, ep, NULL);
0775     }
0776 
0777     return 0;
0778 }
0779 
0780 static int htc_send_packets_multiple(struct htc_target *target,
0781                      struct list_head *pkt_queue)
0782 {
0783     struct htc_endpoint *ep;
0784     struct htc_packet *packet, *tmp_pkt;
0785 
0786     if (list_empty(pkt_queue))
0787         return -EINVAL;
0788 
0789     /* get first packet to find out which ep the packets will go into */
0790     packet = list_first_entry(pkt_queue, struct htc_packet, list);
0791 
0792     if (packet->endpoint >= ENDPOINT_MAX) {
0793         WARN_ON_ONCE(1);
0794         return -EINVAL;
0795     }
0796     ep = &target->endpoint[packet->endpoint];
0797 
0798     htc_try_send(target, ep, pkt_queue);
0799 
0800     /* do completion on any packets that couldn't get in */
0801     if (!list_empty(pkt_queue)) {
0802         list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
0803             packet->status = -ENOMEM;
0804         }
0805 
0806         do_send_completion(ep, pkt_queue);
0807     }
0808 
0809     return 0;
0810 }
0811 
0812 /* htc pipe rx path */
0813 static struct htc_packet *alloc_htc_packet_container(struct htc_target *target)
0814 {
0815     struct htc_packet *packet;
0816     spin_lock_bh(&target->rx_lock);
0817 
0818     if (target->pipe.htc_packet_pool == NULL) {
0819         spin_unlock_bh(&target->rx_lock);
0820         return NULL;
0821     }
0822 
0823     packet = target->pipe.htc_packet_pool;
0824     target->pipe.htc_packet_pool = (struct htc_packet *) packet->list.next;
0825 
0826     spin_unlock_bh(&target->rx_lock);
0827 
0828     packet->list.next = NULL;
0829     return packet;
0830 }
0831 
0832 static void free_htc_packet_container(struct htc_target *target,
0833                       struct htc_packet *packet)
0834 {
0835     struct list_head *lh;
0836 
0837     spin_lock_bh(&target->rx_lock);
0838 
0839     if (target->pipe.htc_packet_pool == NULL) {
0840         target->pipe.htc_packet_pool = packet;
0841         packet->list.next = NULL;
0842     } else {
0843         lh = (struct list_head *) target->pipe.htc_packet_pool;
0844         packet->list.next = lh;
0845         target->pipe.htc_packet_pool = packet;
0846     }
0847 
0848     spin_unlock_bh(&target->rx_lock);
0849 }
0850 
0851 static int htc_process_trailer(struct htc_target *target, u8 *buffer,
0852                    int len, enum htc_endpoint_id from_ep)
0853 {
0854     struct htc_credit_report *report;
0855     struct htc_record_hdr *record;
0856     u8 *record_buf;
0857     int status = 0;
0858 
0859     while (len > 0) {
0860         if (len < sizeof(struct htc_record_hdr)) {
0861             status = -EINVAL;
0862             break;
0863         }
0864 
0865         /* these are byte aligned structs */
0866         record = (struct htc_record_hdr *) buffer;
0867         len -= sizeof(struct htc_record_hdr);
0868         buffer += sizeof(struct htc_record_hdr);
0869 
0870         if (record->len > len) {
0871             /* no room left in buffer for record */
0872             ath6kl_dbg(ATH6KL_DBG_HTC,
0873                    "invalid length: %d (id:%d) buffer has: %d bytes left\n",
0874                    record->len, record->rec_id, len);
0875             status = -EINVAL;
0876             break;
0877         }
0878 
0879         /* start of record follows the header */
0880         record_buf = buffer;
0881 
0882         switch (record->rec_id) {
0883         case HTC_RECORD_CREDITS:
0884             if (record->len < sizeof(struct htc_credit_report)) {
0885                 WARN_ON_ONCE(1);
0886                 return -EINVAL;
0887             }
0888 
0889             report = (struct htc_credit_report *) record_buf;
0890             htc_process_credit_report(target, report,
0891                           record->len / sizeof(*report),
0892                           from_ep);
0893             break;
0894         default:
0895             ath6kl_dbg(ATH6KL_DBG_HTC,
0896                    "unhandled record: id:%d length:%d\n",
0897                    record->rec_id, record->len);
0898             break;
0899         }
0900 
0901         /* advance buffer past this record for next time around */
0902         buffer += record->len;
0903         len -= record->len;
0904     }
0905 
0906     return status;
0907 }
0908 
0909 static void do_recv_completion(struct htc_endpoint *ep,
0910                    struct list_head *queue_to_indicate)
0911 {
0912     struct htc_packet *packet;
0913 
0914     if (list_empty(queue_to_indicate)) {
0915         /* nothing to indicate */
0916         return;
0917     }
0918 
0919     /* using legacy EpRecv */
0920     while (!list_empty(queue_to_indicate)) {
0921         packet = list_first_entry(queue_to_indicate,
0922                       struct htc_packet, list);
0923         list_del(&packet->list);
0924         ep->ep_cb.rx(ep->target, packet);
0925     }
0926 
0927     return;
0928 }
0929 
0930 static void recv_packet_completion(struct htc_target *target,
0931                    struct htc_endpoint *ep,
0932                    struct htc_packet *packet)
0933 {
0934     struct list_head container;
0935     INIT_LIST_HEAD(&container);
0936     list_add_tail(&packet->list, &container);
0937 
0938     /* do completion */
0939     do_recv_completion(ep, &container);
0940 }
0941 
0942 static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
0943                        u8 pipeid)
0944 {
0945     struct htc_target *target = ar->htc_target;
0946     u8 *netdata, *trailer, hdr_info;
0947     struct htc_frame_hdr *htc_hdr;
0948     u32 netlen, trailerlen = 0;
0949     struct htc_packet *packet;
0950     struct htc_endpoint *ep;
0951     u16 payload_len;
0952     int status = 0;
0953 
0954     /*
0955      * ar->htc_target can be NULL due to a race condition that can occur
0956      * during driver initialization(we do 'ath6kl_hif_power_on' before
0957      * initializing 'ar->htc_target' via 'ath6kl_htc_create').
0958      * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as
0959      * usb_complete_t/callback function for 'usb_fill_bulk_urb'.
0960      * Thus the possibility of ar->htc_target being NULL
0961      * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
0962      */
0963     if (WARN_ON_ONCE(!target)) {
0964         ath6kl_err("Target not yet initialized\n");
0965         status = -EINVAL;
0966         goto free_skb;
0967     }
0968 
0969 
0970     netdata = skb->data;
0971     netlen = skb->len;
0972 
0973     htc_hdr = (struct htc_frame_hdr *) netdata;
0974 
0975     if (htc_hdr->eid >= ENDPOINT_MAX) {
0976         ath6kl_dbg(ATH6KL_DBG_HTC,
0977                "HTC Rx: invalid EndpointID=%d\n",
0978                htc_hdr->eid);
0979         status = -EINVAL;
0980         goto free_skb;
0981     }
0982     ep = &target->endpoint[htc_hdr->eid];
0983 
0984     payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
0985 
0986     if (netlen < (payload_len + HTC_HDR_LENGTH)) {
0987         ath6kl_dbg(ATH6KL_DBG_HTC,
0988                "HTC Rx: insufficient length, got:%d expected =%zu\n",
0989                netlen, payload_len + HTC_HDR_LENGTH);
0990         status = -EINVAL;
0991         goto free_skb;
0992     }
0993 
0994     /* get flags to check for trailer */
0995     hdr_info = htc_hdr->flags;
0996     if (hdr_info & HTC_FLG_RX_TRAILER) {
0997         /* extract the trailer length */
0998         hdr_info = htc_hdr->ctrl[0];
0999         if ((hdr_info < sizeof(struct htc_record_hdr)) ||
1000             (hdr_info > payload_len)) {
1001             ath6kl_dbg(ATH6KL_DBG_HTC,
1002                    "invalid header: payloadlen should be %d, CB[0]: %d\n",
1003                    payload_len, hdr_info);
1004             status = -EINVAL;
1005             goto free_skb;
1006         }
1007 
1008         trailerlen = hdr_info;
1009         /* process trailer after hdr/apps payload */
1010         trailer = (u8 *) htc_hdr + HTC_HDR_LENGTH +
1011             payload_len - hdr_info;
1012         status = htc_process_trailer(target, trailer, hdr_info,
1013                          htc_hdr->eid);
1014         if (status != 0)
1015             goto free_skb;
1016     }
1017 
1018     if (((int) payload_len - (int) trailerlen) <= 0) {
1019         /* zero length packet with trailer, just drop these */
1020         goto free_skb;
1021     }
1022 
1023     if (htc_hdr->eid == ENDPOINT_0) {
1024         /* handle HTC control message */
1025         if (target->htc_flags & HTC_OP_STATE_SETUP_COMPLETE) {
1026             /*
1027              * fatal: target should not send unsolicited
1028              * messageson the endpoint 0
1029              */
1030             ath6kl_dbg(ATH6KL_DBG_HTC,
1031                    "HTC ignores Rx Ctrl after setup complete\n");
1032             status = -EINVAL;
1033             goto free_skb;
1034         }
1035 
1036         /* remove HTC header */
1037         skb_pull(skb, HTC_HDR_LENGTH);
1038 
1039         netdata = skb->data;
1040         netlen = skb->len;
1041 
1042         spin_lock_bh(&target->rx_lock);
1043 
1044         target->pipe.ctrl_response_valid = true;
1045         target->pipe.ctrl_response_len = min_t(int, netlen,
1046                                HTC_MAX_CTRL_MSG_LEN);
1047         memcpy(target->pipe.ctrl_response_buf, netdata,
1048                target->pipe.ctrl_response_len);
1049 
1050         spin_unlock_bh(&target->rx_lock);
1051 
1052         dev_kfree_skb(skb);
1053         skb = NULL;
1054 
1055         goto free_skb;
1056     }
1057 
1058     /*
1059      * TODO: the message based HIF architecture allocates net bufs
1060      * for recv packets since it bridges that HIF to upper layers,
1061      * which expects HTC packets, we form the packets here
1062      */
1063     packet = alloc_htc_packet_container(target);
1064     if (packet == NULL) {
1065         status = -ENOMEM;
1066         goto free_skb;
1067     }
1068 
1069     packet->status = 0;
1070     packet->endpoint = htc_hdr->eid;
1071     packet->pkt_cntxt = skb;
1072 
1073     /* TODO: for backwards compatibility */
1074     packet->buf = skb_push(skb, 0) + HTC_HDR_LENGTH;
1075     packet->act_len = netlen - HTC_HDR_LENGTH - trailerlen;
1076 
1077     /*
1078      * TODO: this is a hack because the driver layer will set the
1079      * actual len of the skb again which will just double the len
1080      */
1081     skb_trim(skb, 0);
1082 
1083     recv_packet_completion(target, ep, packet);
1084 
1085     /* recover the packet container */
1086     free_htc_packet_container(target, packet);
1087     skb = NULL;
1088 
1089 free_skb:
1090     dev_kfree_skb(skb);
1091 
1092     return status;
1093 }
1094 
1095 static void htc_flush_rx_queue(struct htc_target *target,
1096                    struct htc_endpoint *ep)
1097 {
1098     struct list_head container;
1099     struct htc_packet *packet;
1100 
1101     spin_lock_bh(&target->rx_lock);
1102 
1103     while (1) {
1104         if (list_empty(&ep->rx_bufq))
1105             break;
1106 
1107         packet = list_first_entry(&ep->rx_bufq,
1108                       struct htc_packet, list);
1109         list_del(&packet->list);
1110 
1111         spin_unlock_bh(&target->rx_lock);
1112         packet->status = -ECANCELED;
1113         packet->act_len = 0;
1114 
1115         ath6kl_dbg(ATH6KL_DBG_HTC,
1116                "Flushing RX packet:0x%p, length:%d, ep:%d\n",
1117                packet, packet->buf_len,
1118                packet->endpoint);
1119 
1120         INIT_LIST_HEAD(&container);
1121         list_add_tail(&packet->list, &container);
1122 
1123         /* give the packet back */
1124         do_recv_completion(ep, &container);
1125         spin_lock_bh(&target->rx_lock);
1126     }
1127 
1128     spin_unlock_bh(&target->rx_lock);
1129 }
1130 
1131 /* polling routine to wait for a control packet to be received */
1132 static int htc_wait_recv_ctrl_message(struct htc_target *target)
1133 {
1134     int count = HTC_TARGET_RESPONSE_POLL_COUNT;
1135 
1136     while (count > 0) {
1137         spin_lock_bh(&target->rx_lock);
1138 
1139         if (target->pipe.ctrl_response_valid) {
1140             target->pipe.ctrl_response_valid = false;
1141             spin_unlock_bh(&target->rx_lock);
1142             break;
1143         }
1144 
1145         spin_unlock_bh(&target->rx_lock);
1146 
1147         count--;
1148 
1149         msleep_interruptible(HTC_TARGET_RESPONSE_POLL_WAIT);
1150     }
1151 
1152     if (count <= 0) {
1153         ath6kl_warn("htc pipe control receive timeout!\n");
1154         return -ETIMEDOUT;
1155     }
1156 
1157     return 0;
1158 }
1159 
1160 static void htc_rxctrl_complete(struct htc_target *context,
1161                 struct htc_packet *packet)
1162 {
1163     struct sk_buff *skb = packet->skb;
1164 
1165     if (packet->endpoint == ENDPOINT_0 &&
1166         packet->status == -ECANCELED &&
1167         skb != NULL)
1168         dev_kfree_skb(skb);
1169 }
1170 
1171 /* htc pipe initialization */
1172 static void reset_endpoint_states(struct htc_target *target)
1173 {
1174     struct htc_endpoint *ep;
1175     int i;
1176 
1177     for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1178         ep = &target->endpoint[i];
1179         ep->svc_id = 0;
1180         ep->len_max = 0;
1181         ep->max_txq_depth = 0;
1182         ep->eid = i;
1183         INIT_LIST_HEAD(&ep->txq);
1184         INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue);
1185         INIT_LIST_HEAD(&ep->rx_bufq);
1186         ep->target = target;
1187         ep->pipe.tx_credit_flow_enabled = true;
1188     }
1189 }
1190 
1191 /* start HTC, this is called after all services are connected */
1192 static int htc_config_target_hif_pipe(struct htc_target *target)
1193 {
1194     return 0;
1195 }
1196 
1197 /* htc service functions */
1198 static u8 htc_get_credit_alloc(struct htc_target *target, u16 service_id)
1199 {
1200     u8 allocation = 0;
1201     int i;
1202 
1203     for (i = 0; i < ENDPOINT_MAX; i++) {
1204         if (target->pipe.txcredit_alloc[i].service_id == service_id)
1205             allocation =
1206                 target->pipe.txcredit_alloc[i].credit_alloc;
1207     }
1208 
1209     if (allocation == 0) {
1210         ath6kl_dbg(ATH6KL_DBG_HTC,
1211                "HTC Service TX : 0x%2.2X : allocation is zero!\n",
1212                service_id);
1213     }
1214 
1215     return allocation;
1216 }
1217 
1218 static int ath6kl_htc_pipe_conn_service(struct htc_target *target,
1219              struct htc_service_connect_req *conn_req,
1220              struct htc_service_connect_resp *conn_resp)
1221 {
1222     struct ath6kl *ar = target->dev->ar;
1223     struct htc_packet *packet = NULL;
1224     struct htc_conn_service_resp *resp_msg;
1225     struct htc_conn_service_msg *conn_msg;
1226     enum htc_endpoint_id assigned_epid = ENDPOINT_MAX;
1227     bool disable_credit_flowctrl = false;
1228     unsigned int max_msg_size = 0;
1229     struct htc_endpoint *ep;
1230     int length, status = 0;
1231     struct sk_buff *skb;
1232     u8 tx_alloc;
1233     u16 flags;
1234 
1235     if (conn_req->svc_id == 0) {
1236         WARN_ON_ONCE(1);
1237         status = -EINVAL;
1238         goto free_packet;
1239     }
1240 
1241     if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) {
1242         /* special case for pseudo control service */
1243         assigned_epid = ENDPOINT_0;
1244         max_msg_size = HTC_MAX_CTRL_MSG_LEN;
1245         tx_alloc = 0;
1246 
1247     } else {
1248         tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id);
1249         if (tx_alloc == 0) {
1250             status = -ENOMEM;
1251             goto free_packet;
1252         }
1253 
1254         /* allocate a packet to send to the target */
1255         packet = htc_alloc_txctrl_packet(target);
1256 
1257         if (packet == NULL) {
1258             WARN_ON_ONCE(1);
1259             status = -ENOMEM;
1260             goto free_packet;
1261         }
1262 
1263         skb = packet->skb;
1264         length = sizeof(struct htc_conn_service_msg);
1265 
1266         /* assemble connect service message */
1267         conn_msg = skb_put(skb, length);
1268         if (conn_msg == NULL) {
1269             WARN_ON_ONCE(1);
1270             status = -EINVAL;
1271             goto free_packet;
1272         }
1273 
1274         memset(conn_msg, 0,
1275                sizeof(struct htc_conn_service_msg));
1276         conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID);
1277         conn_msg->svc_id = cpu_to_le16(conn_req->svc_id);
1278         conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags &
1279                     ~HTC_CONN_FLGS_SET_RECV_ALLOC_MASK);
1280 
1281         /* tell target desired recv alloc for this ep */
1282         flags = tx_alloc << HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT;
1283         conn_msg->conn_flags |= cpu_to_le16(flags);
1284 
1285         if (conn_req->conn_flags &
1286             HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL) {
1287             disable_credit_flowctrl = true;
1288         }
1289 
1290         set_htc_pkt_info(packet, NULL, (u8 *) conn_msg,
1291                  length,
1292                  ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
1293 
1294         status = ath6kl_htc_pipe_tx(target, packet);
1295 
1296         /* we don't own it anymore */
1297         packet = NULL;
1298         if (status != 0)
1299             goto free_packet;
1300 
1301         /* wait for response */
1302         status = htc_wait_recv_ctrl_message(target);
1303         if (status != 0)
1304             goto free_packet;
1305 
1306         /* we controlled the buffer creation so it has to be
1307          * properly aligned
1308          */
1309         resp_msg = (struct htc_conn_service_resp *)
1310             target->pipe.ctrl_response_buf;
1311 
1312         if (resp_msg->msg_id != cpu_to_le16(HTC_MSG_CONN_SVC_RESP_ID) ||
1313             (target->pipe.ctrl_response_len < sizeof(*resp_msg))) {
1314             /* this message is not valid */
1315             WARN_ON_ONCE(1);
1316             status = -EINVAL;
1317             goto free_packet;
1318         }
1319 
1320         ath6kl_dbg(ATH6KL_DBG_TRC,
1321                "%s: service 0x%X conn resp: status: %d ep: %d\n",
1322                __func__, resp_msg->svc_id, resp_msg->status,
1323                resp_msg->eid);
1324 
1325         conn_resp->resp_code = resp_msg->status;
1326         /* check response status */
1327         if (resp_msg->status != HTC_SERVICE_SUCCESS) {
1328             ath6kl_dbg(ATH6KL_DBG_HTC,
1329                    "Target failed service 0x%X connect request (status:%d)\n",
1330                    resp_msg->svc_id, resp_msg->status);
1331             status = -EINVAL;
1332             goto free_packet;
1333         }
1334 
1335         assigned_epid = (enum htc_endpoint_id) resp_msg->eid;
1336         max_msg_size = le16_to_cpu(resp_msg->max_msg_sz);
1337     }
1338 
1339     /* the rest are parameter checks so set the error status */
1340     status = -EINVAL;
1341 
1342     if (assigned_epid >= ENDPOINT_MAX) {
1343         WARN_ON_ONCE(1);
1344         goto free_packet;
1345     }
1346 
1347     if (max_msg_size == 0) {
1348         WARN_ON_ONCE(1);
1349         goto free_packet;
1350     }
1351 
1352     ep = &target->endpoint[assigned_epid];
1353     ep->eid = assigned_epid;
1354     if (ep->svc_id != 0) {
1355         /* endpoint already in use! */
1356         WARN_ON_ONCE(1);
1357         goto free_packet;
1358     }
1359 
1360     /* return assigned endpoint to caller */
1361     conn_resp->endpoint = assigned_epid;
1362     conn_resp->len_max = max_msg_size;
1363 
1364     /* setup the endpoint */
1365     ep->svc_id = conn_req->svc_id; /* this marks ep in use */
1366     ep->max_txq_depth = conn_req->max_txq_depth;
1367     ep->len_max = max_msg_size;
1368     ep->cred_dist.credits = tx_alloc;
1369     ep->cred_dist.cred_sz = target->tgt_cred_sz;
1370     ep->cred_dist.cred_per_msg = max_msg_size / target->tgt_cred_sz;
1371     if (max_msg_size % target->tgt_cred_sz)
1372         ep->cred_dist.cred_per_msg++;
1373 
1374     /* copy all the callbacks */
1375     ep->ep_cb = conn_req->ep_cb;
1376 
1377     /* initialize tx_drop_packet_threshold */
1378     ep->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM;
1379 
1380     status = ath6kl_hif_pipe_map_service(ar, ep->svc_id,
1381                          &ep->pipe.pipeid_ul,
1382                          &ep->pipe.pipeid_dl);
1383     if (status != 0)
1384         goto free_packet;
1385 
1386     ath6kl_dbg(ATH6KL_DBG_HTC,
1387            "SVC Ready: 0x%4.4X: ULpipe:%d DLpipe:%d id:%d\n",
1388            ep->svc_id, ep->pipe.pipeid_ul,
1389            ep->pipe.pipeid_dl, ep->eid);
1390 
1391     if (disable_credit_flowctrl && ep->pipe.tx_credit_flow_enabled) {
1392         ep->pipe.tx_credit_flow_enabled = false;
1393         ath6kl_dbg(ATH6KL_DBG_HTC,
1394                "SVC: 0x%4.4X ep:%d TX flow control off\n",
1395                ep->svc_id, assigned_epid);
1396     }
1397 
1398 free_packet:
1399     if (packet != NULL)
1400         htc_free_txctrl_packet(target, packet);
1401     return status;
1402 }
1403 
1404 /* htc export functions */
1405 static void *ath6kl_htc_pipe_create(struct ath6kl *ar)
1406 {
1407     int status = 0;
1408     struct htc_endpoint *ep = NULL;
1409     struct htc_target *target = NULL;
1410     struct htc_packet *packet;
1411     int i;
1412 
1413     target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
1414     if (target == NULL) {
1415         ath6kl_err("htc create unable to allocate memory\n");
1416         status = -ENOMEM;
1417         goto fail_htc_create;
1418     }
1419 
1420     spin_lock_init(&target->htc_lock);
1421     spin_lock_init(&target->rx_lock);
1422     spin_lock_init(&target->tx_lock);
1423 
1424     reset_endpoint_states(target);
1425 
1426     for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) {
1427         packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL);
1428 
1429         if (packet != NULL)
1430             free_htc_packet_container(target, packet);
1431     }
1432 
1433     target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL);
1434     if (!target->dev) {
1435         ath6kl_err("unable to allocate memory\n");
1436         status = -ENOMEM;
1437         goto fail_htc_create;
1438     }
1439     target->dev->ar = ar;
1440     target->dev->htc_cnxt = target;
1441 
1442     /* Get HIF default pipe for HTC message exchange */
1443     ep = &target->endpoint[ENDPOINT_0];
1444 
1445     ath6kl_hif_pipe_get_default(ar, &ep->pipe.pipeid_ul,
1446                     &ep->pipe.pipeid_dl);
1447 
1448     return target;
1449 
1450 fail_htc_create:
1451     if (status != 0) {
1452         if (target != NULL)
1453             ath6kl_htc_pipe_cleanup(target);
1454 
1455         target = NULL;
1456     }
1457     return target;
1458 }
1459 
1460 /* cleanup the HTC instance */
1461 static void ath6kl_htc_pipe_cleanup(struct htc_target *target)
1462 {
1463     struct htc_packet *packet;
1464 
1465     while (true) {
1466         packet = alloc_htc_packet_container(target);
1467         if (packet == NULL)
1468             break;
1469         kfree(packet);
1470     }
1471 
1472     kfree(target->dev);
1473 
1474     /* kfree our instance */
1475     kfree(target);
1476 }
1477 
1478 static int ath6kl_htc_pipe_start(struct htc_target *target)
1479 {
1480     struct sk_buff *skb;
1481     struct htc_setup_comp_ext_msg *setup;
1482     struct htc_packet *packet;
1483 
1484     htc_config_target_hif_pipe(target);
1485 
1486     /* allocate a buffer to send */
1487     packet = htc_alloc_txctrl_packet(target);
1488     if (packet == NULL) {
1489         WARN_ON_ONCE(1);
1490         return -ENOMEM;
1491     }
1492 
1493     skb = packet->skb;
1494 
1495     /* assemble setup complete message */
1496     setup = skb_put(skb, sizeof(*setup));
1497     memset(setup, 0, sizeof(struct htc_setup_comp_ext_msg));
1498     setup->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID);
1499 
1500     ath6kl_dbg(ATH6KL_DBG_HTC, "HTC using TX credit flow control\n");
1501 
1502     set_htc_pkt_info(packet, NULL, (u8 *) setup,
1503              sizeof(struct htc_setup_comp_ext_msg),
1504              ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
1505 
1506     target->htc_flags |= HTC_OP_STATE_SETUP_COMPLETE;
1507 
1508     return ath6kl_htc_pipe_tx(target, packet);
1509 }
1510 
1511 static void ath6kl_htc_pipe_stop(struct htc_target *target)
1512 {
1513     int i;
1514     struct htc_endpoint *ep;
1515 
1516     /* cleanup endpoints */
1517     for (i = 0; i < ENDPOINT_MAX; i++) {
1518         ep = &target->endpoint[i];
1519         htc_flush_rx_queue(target, ep);
1520         htc_flush_tx_endpoint(target, ep, HTC_TX_PACKET_TAG_ALL);
1521     }
1522 
1523     reset_endpoint_states(target);
1524     target->htc_flags &= ~HTC_OP_STATE_SETUP_COMPLETE;
1525 }
1526 
1527 static int ath6kl_htc_pipe_get_rxbuf_num(struct htc_target *target,
1528                      enum htc_endpoint_id endpoint)
1529 {
1530     int num;
1531 
1532     spin_lock_bh(&target->rx_lock);
1533     num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq));
1534     spin_unlock_bh(&target->rx_lock);
1535 
1536     return num;
1537 }
1538 
1539 static int ath6kl_htc_pipe_tx(struct htc_target *target,
1540                   struct htc_packet *packet)
1541 {
1542     struct list_head queue;
1543 
1544     ath6kl_dbg(ATH6KL_DBG_HTC,
1545            "%s: endPointId: %d, buffer: 0x%p, length: %d\n",
1546            __func__, packet->endpoint, packet->buf,
1547            packet->act_len);
1548 
1549     INIT_LIST_HEAD(&queue);
1550     list_add_tail(&packet->list, &queue);
1551 
1552     return htc_send_packets_multiple(target, &queue);
1553 }
1554 
1555 static int ath6kl_htc_pipe_wait_target(struct htc_target *target)
1556 {
1557     struct htc_ready_ext_msg *ready_msg;
1558     struct htc_service_connect_req connect;
1559     struct htc_service_connect_resp resp;
1560     int status = 0;
1561 
1562     status = htc_wait_recv_ctrl_message(target);
1563 
1564     if (status != 0)
1565         return status;
1566 
1567     if (target->pipe.ctrl_response_len < sizeof(*ready_msg)) {
1568         ath6kl_warn("invalid htc pipe ready msg len: %d\n",
1569                 target->pipe.ctrl_response_len);
1570         return -ECOMM;
1571     }
1572 
1573     ready_msg = (struct htc_ready_ext_msg *) target->pipe.ctrl_response_buf;
1574 
1575     if (ready_msg->ver2_0_info.msg_id != cpu_to_le16(HTC_MSG_READY_ID)) {
1576         ath6kl_warn("invalid htc pipe ready msg: 0x%x\n",
1577                 ready_msg->ver2_0_info.msg_id);
1578         return -ECOMM;
1579     }
1580 
1581     ath6kl_dbg(ATH6KL_DBG_HTC,
1582            "Target Ready! : transmit resources : %d size:%d\n",
1583            ready_msg->ver2_0_info.cred_cnt,
1584            ready_msg->ver2_0_info.cred_sz);
1585 
1586     target->tgt_creds = le16_to_cpu(ready_msg->ver2_0_info.cred_cnt);
1587     target->tgt_cred_sz = le16_to_cpu(ready_msg->ver2_0_info.cred_sz);
1588 
1589     if ((target->tgt_creds == 0) || (target->tgt_cred_sz == 0))
1590         return -ECOMM;
1591 
1592     htc_setup_target_buffer_assignments(target);
1593 
1594     /* setup our pseudo HTC control endpoint connection */
1595     memset(&connect, 0, sizeof(connect));
1596     memset(&resp, 0, sizeof(resp));
1597     connect.ep_cb.tx_complete = htc_txctrl_complete;
1598     connect.ep_cb.rx = htc_rxctrl_complete;
1599     connect.max_txq_depth = NUM_CONTROL_TX_BUFFERS;
1600     connect.svc_id = HTC_CTRL_RSVD_SVC;
1601 
1602     /* connect fake service */
1603     status = ath6kl_htc_pipe_conn_service(target, &connect, &resp);
1604 
1605     return status;
1606 }
1607 
1608 static void ath6kl_htc_pipe_flush_txep(struct htc_target *target,
1609                        enum htc_endpoint_id endpoint, u16 tag)
1610 {
1611     struct htc_endpoint *ep = &target->endpoint[endpoint];
1612 
1613     if (ep->svc_id == 0) {
1614         WARN_ON_ONCE(1);
1615         /* not in use.. */
1616         return;
1617     }
1618 
1619     htc_flush_tx_endpoint(target, ep, tag);
1620 }
1621 
1622 static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target,
1623                           struct list_head *pkt_queue)
1624 {
1625     struct htc_packet *packet, *tmp_pkt, *first;
1626     struct htc_endpoint *ep;
1627     int status = 0;
1628 
1629     if (list_empty(pkt_queue))
1630         return -EINVAL;
1631 
1632     first = list_first_entry(pkt_queue, struct htc_packet, list);
1633 
1634     if (first->endpoint >= ENDPOINT_MAX) {
1635         WARN_ON_ONCE(1);
1636         return -EINVAL;
1637     }
1638 
1639     ath6kl_dbg(ATH6KL_DBG_HTC, "%s: epid: %d, cnt:%d, len: %d\n",
1640            __func__, first->endpoint, get_queue_depth(pkt_queue),
1641            first->buf_len);
1642 
1643     ep = &target->endpoint[first->endpoint];
1644 
1645     spin_lock_bh(&target->rx_lock);
1646 
1647     /* store receive packets */
1648     list_splice_tail_init(pkt_queue, &ep->rx_bufq);
1649 
1650     spin_unlock_bh(&target->rx_lock);
1651 
1652     if (status != 0) {
1653         /* walk through queue and mark each one canceled */
1654         list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
1655             packet->status = -ECANCELED;
1656         }
1657 
1658         do_recv_completion(ep, pkt_queue);
1659     }
1660 
1661     return status;
1662 }
1663 
1664 static void ath6kl_htc_pipe_activity_changed(struct htc_target *target,
1665                          enum htc_endpoint_id ep,
1666                          bool active)
1667 {
1668     /* TODO */
1669 }
1670 
1671 static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target)
1672 {
1673     struct htc_endpoint *endpoint;
1674     struct htc_packet *packet, *tmp_pkt;
1675     int i;
1676 
1677     for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1678         endpoint = &target->endpoint[i];
1679 
1680         spin_lock_bh(&target->rx_lock);
1681 
1682         list_for_each_entry_safe(packet, tmp_pkt,
1683                      &endpoint->rx_bufq, list) {
1684             list_del(&packet->list);
1685             spin_unlock_bh(&target->rx_lock);
1686             ath6kl_dbg(ATH6KL_DBG_HTC,
1687                    "htc rx flush pkt 0x%p len %d ep %d\n",
1688                    packet, packet->buf_len,
1689                    packet->endpoint);
1690             dev_kfree_skb(packet->pkt_cntxt);
1691             spin_lock_bh(&target->rx_lock);
1692         }
1693 
1694         spin_unlock_bh(&target->rx_lock);
1695     }
1696 }
1697 
1698 static int ath6kl_htc_pipe_credit_setup(struct htc_target *target,
1699                     struct ath6kl_htc_credit_info *info)
1700 {
1701     return 0;
1702 }
1703 
1704 static const struct ath6kl_htc_ops ath6kl_htc_pipe_ops = {
1705     .create = ath6kl_htc_pipe_create,
1706     .wait_target = ath6kl_htc_pipe_wait_target,
1707     .start = ath6kl_htc_pipe_start,
1708     .conn_service = ath6kl_htc_pipe_conn_service,
1709     .tx = ath6kl_htc_pipe_tx,
1710     .stop = ath6kl_htc_pipe_stop,
1711     .cleanup = ath6kl_htc_pipe_cleanup,
1712     .flush_txep = ath6kl_htc_pipe_flush_txep,
1713     .flush_rx_buf = ath6kl_htc_pipe_flush_rx_buf,
1714     .activity_changed = ath6kl_htc_pipe_activity_changed,
1715     .get_rxbuf_num = ath6kl_htc_pipe_get_rxbuf_num,
1716     .add_rxbuf_multiple = ath6kl_htc_pipe_add_rxbuf_multiple,
1717     .credit_setup = ath6kl_htc_pipe_credit_setup,
1718     .tx_complete = ath6kl_htc_pipe_tx_complete,
1719     .rx_complete = ath6kl_htc_pipe_rx_complete,
1720 };
1721 
1722 void ath6kl_htc_pipe_attach(struct ath6kl *ar)
1723 {
1724     ar->htc_ops = &ath6kl_htc_pipe_ops;
1725 }