brintos

brintos / linux-shallow public Read only

0
0
Text · 43.0 KiB · 2f2edfe Raw
1725 lines · c
1/*2 * Copyright (c) 2007-2011 Atheros Communications Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * 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 3222#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH)23 24static int ath6kl_htc_pipe_tx(struct htc_target *handle,25			      struct htc_packet *packet);26static void ath6kl_htc_pipe_cleanup(struct htc_target *handle);27 28/* htc pipe tx path */29static 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 37static 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 handler55		 */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 safe60		 */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 77static 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 91static 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 and135			 * does not require credit based flow control136			 */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 173static 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 203static 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 the259				 * same PipeID, it is possible to run out of260				 * resources in the HIF layer.261				 * Don't emit the error262				 */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 299static 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 means319	 * caller didn't provide a queue, just wants us to320	 * check queues and send321	 */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 send354			 * full indication handler -- just move all of them355			 * to the local send_queue object356			 */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 fit378			 * walk through the caller's queue and indicate each to379			 * the send full handler380			 */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 queue392					 * for cleanup */393				} else {394					/* callback wants to keep this packet,395					 * move from caller's queue to the send396					 * 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 this435		 * endpoint that thread will reset the tx processing count436		 * 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 have447	 * 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 control456			 * based on target transmit resource availability,457			 * we assume that the HIF layer will always have458			 * bus resources greater than target transmit459			 * resources.460			 */461			get_htc_packet_credit_based(target, ep, &send_queue);462		} else {463			/*464			 * Get all packets for this endpoint that we can465			 * 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 TX473			 * 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 */500static 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 508static 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 528static void htc_free_txctrl_packet(struct htc_target *target,529				   struct htc_packet *packet)530{531	destroy_htc_txctrl_packet(packet);532}533 534static struct htc_packet *htc_alloc_txctrl_packet(struct htc_target *target)535{536	return build_htc_txctrl_packet();537}538 539static 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 1536546 547static 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 */653static 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 */690static 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 completed708 * 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 with710 * HTC.711 */712static 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 queue722	 * this lookup should be fast since lower layers completes in-order and723	 * so the completed packet should be at the head of the list generally724	 */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 741static 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 queues770		 * happens when credits flow back from the target. in the771		 * non-TX credit case, we recheck after the packet completes772		 */773		htc_try_send(target, ep, NULL);774	}775 776	return 0;777}778 779static 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 */812static 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 831static 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 850static 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 908static 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 929static 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 941static 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 occur955	 * during driver initialization(we do 'ath6kl_hif_power_on' before956	 * initializing 'ar->htc_target' via 'ath6kl_htc_create').957	 * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as958	 * usb_complete_t/callback function for 'usb_fill_bulk_urb'.959	 * Thus the possibility of ar->htc_target being NULL960	 * 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 unsolicited1027			 * messageson the endpoint 01028			 */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 bufs1059	 * for recv packets since it bridges that HIF to upper layers,1060	 * which expects HTC packets, we form the packets here1061	 */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 the1078	 * actual len of the skb again which will just double the len1079	 */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 1088free_skb:1089	dev_kfree_skb(skb);1090 1091	return status;1092}1093 1094static 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 */1131static 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 1159static 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 */1171static 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 */1191static int htc_config_target_hif_pipe(struct htc_target *target)1192{1193	return 0;1194}1195 1196/* htc service functions */1197static 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 1217static 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 be1306		 * properly aligned1307		 */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 1397free_packet:1398	if (packet != NULL)1399		htc_free_txctrl_packet(target, packet);1400	return status;1401}1402 1403/* htc export functions */1404static 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 1449fail_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 */1460static 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 1477static 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 1510static 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 1526static 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 1538static 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 1554static 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 1607static 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 1621static 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 1663static void ath6kl_htc_pipe_activity_changed(struct htc_target *target,1664					     enum htc_endpoint_id ep,1665					     bool active)1666{1667	/* TODO */1668}1669 1670static 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 1697static int ath6kl_htc_pipe_credit_setup(struct htc_target *target,1698					struct ath6kl_htc_credit_info *info)1699{1700	return 0;1701}1702 1703static 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 1721void ath6kl_htc_pipe_attach(struct ath6kl *ar)1722{1723	ar->htc_ops = &ath6kl_htc_pipe_ops;1724}1725