xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/htc.c (revision ab589bac)
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4  */
5 #include <linux/skbuff.h>
6 #include <linux/ctype.h>
7 
8 #include "debug.h"
9 #include "hif.h"
10 
11 struct sk_buff *ath11k_htc_alloc_skb(struct ath11k_base *ab, int size)
12 {
13 	struct sk_buff *skb;
14 
15 	skb = dev_alloc_skb(size + sizeof(struct ath11k_htc_hdr));
16 	if (!skb)
17 		return NULL;
18 
19 	skb_reserve(skb, sizeof(struct ath11k_htc_hdr));
20 
21 	/* FW/HTC requires 4-byte aligned streams */
22 	if (!IS_ALIGNED((unsigned long)skb->data, 4))
23 		ath11k_warn(ab, "Unaligned HTC tx skb\n");
24 
25 	return skb;
26 }
27 
28 static void ath11k_htc_control_tx_complete(struct ath11k_base *ab,
29 					   struct sk_buff *skb)
30 {
31 	kfree_skb(skb);
32 }
33 
34 static struct sk_buff *ath11k_htc_build_tx_ctrl_skb(void *ab)
35 {
36 	struct sk_buff *skb;
37 	struct ath11k_skb_cb *skb_cb;
38 
39 	skb = dev_alloc_skb(ATH11K_HTC_CONTROL_BUFFER_SIZE);
40 	if (!skb)
41 		return NULL;
42 
43 	skb_reserve(skb, sizeof(struct ath11k_htc_hdr));
44 	WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4));
45 
46 	skb_cb = ATH11K_SKB_CB(skb);
47 	memset(skb_cb, 0, sizeof(*skb_cb));
48 
49 	ath11k_dbg(ab, ATH11K_DBG_HTC, "%s: skb %pK\n", __func__, skb);
50 	return skb;
51 }
52 
53 static void ath11k_htc_prepare_tx_skb(struct ath11k_htc_ep *ep,
54 				      struct sk_buff *skb)
55 {
56 	struct ath11k_htc_hdr *hdr;
57 
58 	hdr = (struct ath11k_htc_hdr *)skb->data;
59 
60 	memset(hdr, 0, sizeof(*hdr));
61 	hdr->htc_info = FIELD_PREP(HTC_HDR_ENDPOINTID, ep->eid) |
62 			FIELD_PREP(HTC_HDR_PAYLOADLEN,
63 				   (skb->len - sizeof(*hdr))) |
64 			FIELD_PREP(HTC_HDR_FLAGS,
65 				   ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE);
66 
67 	spin_lock_bh(&ep->htc->tx_lock);
68 	hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++);
69 	spin_unlock_bh(&ep->htc->tx_lock);
70 }
71 
72 int ath11k_htc_send(struct ath11k_htc *htc,
73 		    enum ath11k_htc_ep_id eid,
74 		    struct sk_buff *skb)
75 {
76 	struct ath11k_htc_ep *ep = &htc->endpoint[eid];
77 	struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
78 	struct device *dev = htc->ab->dev;
79 	struct ath11k_base *ab = htc->ab;
80 	int credits = 0;
81 	int ret;
82 
83 	if (eid >= ATH11K_HTC_EP_COUNT) {
84 		ath11k_warn(ab, "Invalid endpoint id: %d\n", eid);
85 		return -ENOENT;
86 	}
87 
88 	skb_push(skb, sizeof(struct ath11k_htc_hdr));
89 
90 	if (ep->tx_credit_flow_enabled) {
91 		credits = DIV_ROUND_UP(skb->len, htc->target_credit_size);
92 		spin_lock_bh(&htc->tx_lock);
93 		if (ep->tx_credits < credits) {
94 			ath11k_dbg(ab, ATH11K_DBG_HTC,
95 				   "htc insufficient credits ep %d required %d available %d\n",
96 				   eid, credits, ep->tx_credits);
97 			spin_unlock_bh(&htc->tx_lock);
98 			ret = -EAGAIN;
99 			goto err_pull;
100 		}
101 		ep->tx_credits -= credits;
102 		ath11k_dbg(ab, ATH11K_DBG_HTC,
103 			   "htc ep %d consumed %d credits (total %d)\n",
104 			   eid, credits, ep->tx_credits);
105 		spin_unlock_bh(&htc->tx_lock);
106 	}
107 
108 	ath11k_htc_prepare_tx_skb(ep, skb);
109 
110 	skb_cb->eid = eid;
111 	skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
112 	ret = dma_mapping_error(dev, skb_cb->paddr);
113 	if (ret) {
114 		ret = -EIO;
115 		goto err_credits;
116 	}
117 
118 	ret = ath11k_ce_send(htc->ab, skb, ep->ul_pipe_id, ep->eid);
119 	if (ret)
120 		goto err_unmap;
121 
122 	return 0;
123 
124 err_unmap:
125 	dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
126 err_credits:
127 	if (ep->tx_credit_flow_enabled) {
128 		spin_lock_bh(&htc->tx_lock);
129 		ep->tx_credits += credits;
130 		ath11k_dbg(ab, ATH11K_DBG_HTC,
131 			   "htc ep %d reverted %d credits back (total %d)\n",
132 			   eid, credits, ep->tx_credits);
133 		spin_unlock_bh(&htc->tx_lock);
134 
135 		if (ep->ep_ops.ep_tx_credits)
136 			ep->ep_ops.ep_tx_credits(htc->ab);
137 	}
138 err_pull:
139 	skb_pull(skb, sizeof(struct ath11k_htc_hdr));
140 	return ret;
141 }
142 
143 static void
144 ath11k_htc_process_credit_report(struct ath11k_htc *htc,
145 				 const struct ath11k_htc_credit_report *report,
146 				 int len,
147 				 enum ath11k_htc_ep_id eid)
148 {
149 	struct ath11k_base *ab = htc->ab;
150 	struct ath11k_htc_ep *ep;
151 	int i, n_reports;
152 
153 	if (len % sizeof(*report))
154 		ath11k_warn(ab, "Uneven credit report len %d", len);
155 
156 	n_reports = len / sizeof(*report);
157 
158 	spin_lock_bh(&htc->tx_lock);
159 	for (i = 0; i < n_reports; i++, report++) {
160 		if (report->eid >= ATH11K_HTC_EP_COUNT)
161 			break;
162 
163 		ep = &htc->endpoint[report->eid];
164 		ep->tx_credits += report->credits;
165 
166 		ath11k_dbg(ab, ATH11K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
167 			   report->eid, report->credits, ep->tx_credits);
168 
169 		if (ep->ep_ops.ep_tx_credits) {
170 			spin_unlock_bh(&htc->tx_lock);
171 			ep->ep_ops.ep_tx_credits(htc->ab);
172 			spin_lock_bh(&htc->tx_lock);
173 		}
174 	}
175 	spin_unlock_bh(&htc->tx_lock);
176 }
177 
178 static int ath11k_htc_process_trailer(struct ath11k_htc *htc,
179 				      u8 *buffer,
180 				      int length,
181 				      enum ath11k_htc_ep_id src_eid)
182 {
183 	struct ath11k_base *ab = htc->ab;
184 	int status = 0;
185 	struct ath11k_htc_record *record;
186 	size_t len;
187 
188 	while (length > 0) {
189 		record = (struct ath11k_htc_record *)buffer;
190 
191 		if (length < sizeof(record->hdr)) {
192 			status = -EINVAL;
193 			break;
194 		}
195 
196 		if (record->hdr.len > length) {
197 			/* no room left in buffer for record */
198 			ath11k_warn(ab, "Invalid record length: %d\n",
199 				    record->hdr.len);
200 			status = -EINVAL;
201 			break;
202 		}
203 
204 		switch (record->hdr.id) {
205 		case ATH11K_HTC_RECORD_CREDITS:
206 			len = sizeof(struct ath11k_htc_credit_report);
207 			if (record->hdr.len < len) {
208 				ath11k_warn(ab, "Credit report too long\n");
209 				status = -EINVAL;
210 				break;
211 			}
212 			ath11k_htc_process_credit_report(htc,
213 							 record->credit_report,
214 							 record->hdr.len,
215 							 src_eid);
216 			break;
217 		default:
218 			ath11k_warn(ab, "Unhandled record: id:%d length:%d\n",
219 				    record->hdr.id, record->hdr.len);
220 			break;
221 		}
222 
223 		if (status)
224 			break;
225 
226 		/* multiple records may be present in a trailer */
227 		buffer += sizeof(record->hdr) + record->hdr.len;
228 		length -= sizeof(record->hdr) + record->hdr.len;
229 	}
230 
231 	return status;
232 }
233 
234 void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
235 				      struct sk_buff *skb)
236 {
237 	int status = 0;
238 	struct ath11k_htc *htc = &ab->htc;
239 	struct ath11k_htc_hdr *hdr;
240 	struct ath11k_htc_ep *ep;
241 	u16 payload_len;
242 	u32 trailer_len = 0;
243 	size_t min_len;
244 	u8 eid;
245 	bool trailer_present;
246 
247 	hdr = (struct ath11k_htc_hdr *)skb->data;
248 	skb_pull(skb, sizeof(*hdr));
249 
250 	eid = FIELD_GET(HTC_HDR_ENDPOINTID, hdr->htc_info);
251 
252 	if (eid >= ATH11K_HTC_EP_COUNT) {
253 		ath11k_warn(ab, "HTC Rx: invalid eid %d\n", eid);
254 		goto out;
255 	}
256 
257 	ep = &htc->endpoint[eid];
258 
259 	payload_len = FIELD_GET(HTC_HDR_PAYLOADLEN, hdr->htc_info);
260 
261 	if (payload_len + sizeof(*hdr) > ATH11K_HTC_MAX_LEN) {
262 		ath11k_warn(ab, "HTC rx frame too long, len: %zu\n",
263 			    payload_len + sizeof(*hdr));
264 		goto out;
265 	}
266 
267 	if (skb->len < payload_len) {
268 		ath11k_warn(ab, "HTC Rx: insufficient length, got %d, expected %d\n",
269 			    skb->len, payload_len);
270 		goto out;
271 	}
272 
273 	/* get flags to check for trailer */
274 	trailer_present = (FIELD_GET(HTC_HDR_FLAGS, hdr->htc_info)) &
275 			  ATH11K_HTC_FLAG_TRAILER_PRESENT;
276 
277 	if (trailer_present) {
278 		u8 *trailer;
279 
280 		trailer_len = FIELD_GET(HTC_HDR_CONTROLBYTES0, hdr->ctrl_info);
281 		min_len = sizeof(struct ath11k_htc_record_hdr);
282 
283 		if ((trailer_len < min_len) ||
284 		    (trailer_len > payload_len)) {
285 			ath11k_warn(ab, "Invalid trailer length: %d\n",
286 				    trailer_len);
287 			goto out;
288 		}
289 
290 		trailer = (u8 *)hdr;
291 		trailer += sizeof(*hdr);
292 		trailer += payload_len;
293 		trailer -= trailer_len;
294 		status = ath11k_htc_process_trailer(htc, trailer,
295 						    trailer_len, eid);
296 		if (status)
297 			goto out;
298 
299 		skb_trim(skb, skb->len - trailer_len);
300 	}
301 
302 	if (trailer_len >= payload_len)
303 		/* zero length packet with trailer data, just drop these */
304 		goto out;
305 
306 	if (eid == ATH11K_HTC_EP_0) {
307 		struct ath11k_htc_msg *msg = (struct ath11k_htc_msg *)skb->data;
308 
309 		switch (FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id)) {
310 		case ATH11K_HTC_MSG_READY_ID:
311 		case ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID:
312 			/* handle HTC control message */
313 			if (completion_done(&htc->ctl_resp)) {
314 				/* this is a fatal error, target should not be
315 				 * sending unsolicited messages on the ep 0
316 				 */
317 				ath11k_warn(ab, "HTC rx ctrl still processing\n");
318 				complete(&htc->ctl_resp);
319 				goto out;
320 			}
321 
322 			htc->control_resp_len =
323 				min_t(int, skb->len,
324 				      ATH11K_HTC_MAX_CTRL_MSG_LEN);
325 
326 			memcpy(htc->control_resp_buffer, skb->data,
327 			       htc->control_resp_len);
328 
329 			complete(&htc->ctl_resp);
330 			break;
331 		default:
332 			ath11k_warn(ab, "ignoring unsolicited htc ep0 event\n");
333 			break;
334 		}
335 		goto out;
336 	}
337 
338 	ath11k_dbg(ab, ATH11K_DBG_HTC, "htc rx completion ep %d skb %pK\n",
339 		   eid, skb);
340 	ep->ep_ops.ep_rx_complete(ab, skb);
341 
342 	/* poll tx completion for interrupt disabled CE's */
343 	ath11k_ce_poll_send_completed(ab, ep->ul_pipe_id);
344 
345 	/* skb is now owned by the rx completion handler */
346 	skb = NULL;
347 out:
348 	kfree_skb(skb);
349 }
350 
351 static void ath11k_htc_control_rx_complete(struct ath11k_base *ab,
352 					   struct sk_buff *skb)
353 {
354 	/* This is unexpected. FW is not supposed to send regular rx on this
355 	 * endpoint.
356 	 */
357 	ath11k_warn(ab, "unexpected htc rx\n");
358 	kfree_skb(skb);
359 }
360 
361 static const char *htc_service_name(enum ath11k_htc_svc_id id)
362 {
363 	switch (id) {
364 	case ATH11K_HTC_SVC_ID_RESERVED:
365 		return "Reserved";
366 	case ATH11K_HTC_SVC_ID_RSVD_CTRL:
367 		return "Control";
368 	case ATH11K_HTC_SVC_ID_WMI_CONTROL:
369 		return "WMI";
370 	case ATH11K_HTC_SVC_ID_WMI_DATA_BE:
371 		return "DATA BE";
372 	case ATH11K_HTC_SVC_ID_WMI_DATA_BK:
373 		return "DATA BK";
374 	case ATH11K_HTC_SVC_ID_WMI_DATA_VI:
375 		return "DATA VI";
376 	case ATH11K_HTC_SVC_ID_WMI_DATA_VO:
377 		return "DATA VO";
378 	case ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1:
379 		return "WMI MAC1";
380 	case ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2:
381 		return "WMI MAC2";
382 	case ATH11K_HTC_SVC_ID_NMI_CONTROL:
383 		return "NMI Control";
384 	case ATH11K_HTC_SVC_ID_NMI_DATA:
385 		return "NMI Data";
386 	case ATH11K_HTC_SVC_ID_HTT_DATA_MSG:
387 		return "HTT Data";
388 	case ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS:
389 		return "RAW";
390 	case ATH11K_HTC_SVC_ID_IPA_TX:
391 		return "IPA TX";
392 	case ATH11K_HTC_SVC_ID_PKT_LOG:
393 		return "PKT LOG";
394 	}
395 
396 	return "Unknown";
397 }
398 
399 static void ath11k_htc_reset_endpoint_states(struct ath11k_htc *htc)
400 {
401 	struct ath11k_htc_ep *ep;
402 	int i;
403 
404 	for (i = ATH11K_HTC_EP_0; i < ATH11K_HTC_EP_COUNT; i++) {
405 		ep = &htc->endpoint[i];
406 		ep->service_id = ATH11K_HTC_SVC_ID_UNUSED;
407 		ep->max_ep_message_len = 0;
408 		ep->max_tx_queue_depth = 0;
409 		ep->eid = i;
410 		ep->htc = htc;
411 		ep->tx_credit_flow_enabled = true;
412 	}
413 }
414 
415 static u8 ath11k_htc_get_credit_allocation(struct ath11k_htc *htc,
416 					   u16 service_id)
417 {
418 	u8 i, allocation = 0;
419 
420 	for (i = 0; i < ATH11K_HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) {
421 		if (htc->service_alloc_table[i].service_id == service_id) {
422 			allocation =
423 				htc->service_alloc_table[i].credit_allocation;
424 		}
425 	}
426 
427 	return allocation;
428 }
429 
430 static int ath11k_htc_setup_target_buffer_assignments(struct ath11k_htc *htc)
431 {
432 	struct ath11k_htc_svc_tx_credits *serv_entry;
433 	u32 svc_id[] = {
434 		ATH11K_HTC_SVC_ID_WMI_CONTROL,
435 		ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1,
436 		ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2,
437 	};
438 	int i, credits;
439 
440 	credits =  htc->total_transmit_credits;
441 	serv_entry = htc->service_alloc_table;
442 
443 	if ((htc->wmi_ep_count == 0) ||
444 	    (htc->wmi_ep_count > ARRAY_SIZE(svc_id)))
445 		return -EINVAL;
446 
447 	/* Divide credits among number of endpoints for WMI */
448 	credits = credits / htc->wmi_ep_count;
449 	for (i = 0; i < htc->wmi_ep_count; i++) {
450 		serv_entry[i].service_id = svc_id[i];
451 		serv_entry[i].credit_allocation = credits;
452 	}
453 
454 	return 0;
455 }
456 
457 int ath11k_htc_wait_target(struct ath11k_htc *htc)
458 {
459 	int i, status = 0;
460 	struct ath11k_base *ab = htc->ab;
461 	unsigned long time_left;
462 	struct ath11k_htc_ready *ready;
463 	u16 message_id;
464 	u16 credit_count;
465 	u16 credit_size;
466 
467 	time_left = wait_for_completion_timeout(&htc->ctl_resp,
468 						ATH11K_HTC_WAIT_TIMEOUT_HZ);
469 	if (!time_left) {
470 		ath11k_warn(ab, "failed to receive control response completion, polling..\n");
471 
472 		for (i = 0; i < ab->hw_params.ce_count; i++)
473 			ath11k_ce_per_engine_service(htc->ab, i);
474 
475 		time_left =
476 			wait_for_completion_timeout(&htc->ctl_resp,
477 						    ATH11K_HTC_WAIT_TIMEOUT_HZ);
478 
479 		if (!time_left)
480 			status = -ETIMEDOUT;
481 	}
482 
483 	if (status < 0) {
484 		ath11k_warn(ab, "ctl_resp never came in (%d)\n", status);
485 		return status;
486 	}
487 
488 	if (htc->control_resp_len < sizeof(*ready)) {
489 		ath11k_warn(ab, "Invalid HTC ready msg len:%d\n",
490 			    htc->control_resp_len);
491 		return -ECOMM;
492 	}
493 
494 	ready = (struct ath11k_htc_ready *)htc->control_resp_buffer;
495 	message_id   = FIELD_GET(HTC_MSG_MESSAGEID, ready->id_credit_count);
496 	credit_count = FIELD_GET(HTC_READY_MSG_CREDITCOUNT,
497 				 ready->id_credit_count);
498 	credit_size  = FIELD_GET(HTC_READY_MSG_CREDITSIZE, ready->size_ep);
499 
500 	if (message_id != ATH11K_HTC_MSG_READY_ID) {
501 		ath11k_warn(ab, "Invalid HTC ready msg: 0x%x\n", message_id);
502 		return -ECOMM;
503 	}
504 
505 	htc->total_transmit_credits = credit_count;
506 	htc->target_credit_size = credit_size;
507 
508 	ath11k_dbg(ab, ATH11K_DBG_HTC,
509 		   "Target ready! transmit resources: %d size:%d\n",
510 		   htc->total_transmit_credits, htc->target_credit_size);
511 
512 	if ((htc->total_transmit_credits == 0) ||
513 	    (htc->target_credit_size == 0)) {
514 		ath11k_warn(ab, "Invalid credit size received\n");
515 		return -ECOMM;
516 	}
517 
518 	/* For QCA6390, wmi endpoint uses 1 credit to avoid
519 	 * back-to-back write.
520 	 */
521 	if (ab->hw_params.supports_shadow_regs)
522 		htc->total_transmit_credits = 1;
523 
524 	ath11k_htc_setup_target_buffer_assignments(htc);
525 
526 	return 0;
527 }
528 
529 int ath11k_htc_connect_service(struct ath11k_htc *htc,
530 			       struct ath11k_htc_svc_conn_req *conn_req,
531 			       struct ath11k_htc_svc_conn_resp *conn_resp)
532 {
533 	struct ath11k_base *ab = htc->ab;
534 	struct ath11k_htc_conn_svc *req_msg;
535 	struct ath11k_htc_conn_svc_resp resp_msg_dummy;
536 	struct ath11k_htc_conn_svc_resp *resp_msg = &resp_msg_dummy;
537 	enum ath11k_htc_ep_id assigned_eid = ATH11K_HTC_EP_COUNT;
538 	struct ath11k_htc_ep *ep;
539 	struct sk_buff *skb;
540 	unsigned int max_msg_size = 0;
541 	int length, status;
542 	unsigned long time_left;
543 	bool disable_credit_flow_ctrl = false;
544 	u16 message_id, service_id, flags = 0;
545 	u8 tx_alloc = 0;
546 
547 	/* special case for HTC pseudo control service */
548 	if (conn_req->service_id == ATH11K_HTC_SVC_ID_RSVD_CTRL) {
549 		disable_credit_flow_ctrl = true;
550 		assigned_eid = ATH11K_HTC_EP_0;
551 		max_msg_size = ATH11K_HTC_MAX_CTRL_MSG_LEN;
552 		memset(&resp_msg_dummy, 0, sizeof(resp_msg_dummy));
553 		goto setup;
554 	}
555 
556 	tx_alloc = ath11k_htc_get_credit_allocation(htc,
557 						    conn_req->service_id);
558 	if (!tx_alloc)
559 		ath11k_dbg(ab, ATH11K_DBG_BOOT,
560 			   "boot htc service %s does not allocate target credits\n",
561 			   htc_service_name(conn_req->service_id));
562 
563 	skb = ath11k_htc_build_tx_ctrl_skb(htc->ab);
564 	if (!skb) {
565 		ath11k_warn(ab, "Failed to allocate HTC packet\n");
566 		return -ENOMEM;
567 	}
568 
569 	length = sizeof(*req_msg);
570 	skb_put(skb, length);
571 	memset(skb->data, 0, length);
572 
573 	req_msg = (struct ath11k_htc_conn_svc *)skb->data;
574 	req_msg->msg_svc_id = FIELD_PREP(HTC_MSG_MESSAGEID,
575 					 ATH11K_HTC_MSG_CONNECT_SERVICE_ID);
576 
577 	flags |= FIELD_PREP(ATH11K_HTC_CONN_FLAGS_RECV_ALLOC, tx_alloc);
578 
579 	/* Only enable credit flow control for WMI ctrl service */
580 	if (!(conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL ||
581 	      conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1 ||
582 	      conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2)) {
583 		flags |= ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
584 		disable_credit_flow_ctrl = true;
585 	}
586 
587 	req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags);
588 	req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID,
589 					  conn_req->service_id);
590 
591 	reinit_completion(&htc->ctl_resp);
592 
593 	status = ath11k_htc_send(htc, ATH11K_HTC_EP_0, skb);
594 	if (status) {
595 		kfree_skb(skb);
596 		return status;
597 	}
598 
599 	/* wait for response */
600 	time_left = wait_for_completion_timeout(&htc->ctl_resp,
601 						ATH11K_HTC_CONN_SVC_TIMEOUT_HZ);
602 	if (!time_left) {
603 		ath11k_err(ab, "Service connect timeout\n");
604 		return -ETIMEDOUT;
605 	}
606 
607 	/* we controlled the buffer creation, it's aligned */
608 	resp_msg = (struct ath11k_htc_conn_svc_resp *)htc->control_resp_buffer;
609 	message_id = FIELD_GET(HTC_MSG_MESSAGEID, resp_msg->msg_svc_id);
610 	service_id = FIELD_GET(HTC_SVC_RESP_MSG_SERVICEID,
611 			       resp_msg->msg_svc_id);
612 
613 	if ((message_id != ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
614 	    (htc->control_resp_len < sizeof(*resp_msg))) {
615 		ath11k_err(ab, "Invalid resp message ID 0x%x", message_id);
616 		return -EPROTO;
617 	}
618 
619 	ath11k_dbg(ab, ATH11K_DBG_HTC,
620 		   "HTC Service %s connect response: status: 0x%lx, assigned ep: 0x%lx\n",
621 		   htc_service_name(service_id),
622 		   FIELD_GET(HTC_SVC_RESP_MSG_STATUS, resp_msg->flags_len),
623 		   FIELD_GET(HTC_SVC_RESP_MSG_ENDPOINTID, resp_msg->flags_len));
624 
625 	conn_resp->connect_resp_code = FIELD_GET(HTC_SVC_RESP_MSG_STATUS,
626 						 resp_msg->flags_len);
627 
628 	/* check response status */
629 	if (conn_resp->connect_resp_code != ATH11K_HTC_CONN_SVC_STATUS_SUCCESS) {
630 		ath11k_err(ab, "HTC Service %s connect request failed: 0x%x)\n",
631 			   htc_service_name(service_id),
632 		       conn_resp->connect_resp_code);
633 		return -EPROTO;
634 	}
635 
636 	assigned_eid = (enum ath11k_htc_ep_id)FIELD_GET(
637 						HTC_SVC_RESP_MSG_ENDPOINTID,
638 						resp_msg->flags_len);
639 
640 	max_msg_size = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE,
641 				 resp_msg->flags_len);
642 
643 setup:
644 
645 	if (assigned_eid >= ATH11K_HTC_EP_COUNT)
646 		return -EPROTO;
647 
648 	if (max_msg_size == 0)
649 		return -EPROTO;
650 
651 	ep = &htc->endpoint[assigned_eid];
652 	ep->eid = assigned_eid;
653 
654 	if (ep->service_id != ATH11K_HTC_SVC_ID_UNUSED)
655 		return -EPROTO;
656 
657 	/* return assigned endpoint to caller */
658 	conn_resp->eid = assigned_eid;
659 	conn_resp->max_msg_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE,
660 					   resp_msg->flags_len);
661 
662 	/* setup the endpoint */
663 	ep->service_id = conn_req->service_id;
664 	ep->max_tx_queue_depth = conn_req->max_send_queue_depth;
665 	ep->max_ep_message_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE,
666 					   resp_msg->flags_len);
667 	ep->tx_credits = tx_alloc;
668 
669 	/* copy all the callbacks */
670 	ep->ep_ops = conn_req->ep_ops;
671 
672 	status = ath11k_hif_map_service_to_pipe(htc->ab,
673 						ep->service_id,
674 						&ep->ul_pipe_id,
675 						&ep->dl_pipe_id);
676 	if (status)
677 		return status;
678 
679 	ath11k_dbg(ab, ATH11K_DBG_BOOT,
680 		   "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
681 		   htc_service_name(ep->service_id), ep->ul_pipe_id,
682 		   ep->dl_pipe_id, ep->eid);
683 
684 	if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
685 		ep->tx_credit_flow_enabled = false;
686 		ath11k_dbg(ab, ATH11K_DBG_BOOT,
687 			   "boot htc service '%s' eid %d TX flow control disabled\n",
688 			   htc_service_name(ep->service_id), assigned_eid);
689 	}
690 
691 	return status;
692 }
693 
694 int ath11k_htc_start(struct ath11k_htc *htc)
695 {
696 	struct sk_buff *skb;
697 	int status = 0;
698 	struct ath11k_base *ab = htc->ab;
699 	struct ath11k_htc_setup_complete_extended *msg;
700 
701 	skb = ath11k_htc_build_tx_ctrl_skb(htc->ab);
702 	if (!skb)
703 		return -ENOMEM;
704 
705 	skb_put(skb, sizeof(*msg));
706 	memset(skb->data, 0, skb->len);
707 
708 	msg = (struct ath11k_htc_setup_complete_extended *)skb->data;
709 	msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID,
710 				 ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID);
711 
712 	ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n");
713 
714 	status = ath11k_htc_send(htc, ATH11K_HTC_EP_0, skb);
715 	if (status) {
716 		kfree_skb(skb);
717 		return status;
718 	}
719 
720 	return 0;
721 }
722 
723 int ath11k_htc_init(struct ath11k_base *ab)
724 {
725 	struct ath11k_htc *htc = &ab->htc;
726 	struct ath11k_htc_svc_conn_req conn_req;
727 	struct ath11k_htc_svc_conn_resp conn_resp;
728 	int ret;
729 
730 	spin_lock_init(&htc->tx_lock);
731 
732 	ath11k_htc_reset_endpoint_states(htc);
733 
734 	htc->ab = ab;
735 
736 	switch (ab->wmi_ab.preferred_hw_mode) {
737 	case WMI_HOST_HW_MODE_SINGLE:
738 		htc->wmi_ep_count = 1;
739 		break;
740 	case WMI_HOST_HW_MODE_DBS:
741 	case WMI_HOST_HW_MODE_DBS_OR_SBS:
742 		htc->wmi_ep_count = 2;
743 		break;
744 	case WMI_HOST_HW_MODE_DBS_SBS:
745 		htc->wmi_ep_count = 3;
746 		break;
747 	default:
748 		htc->wmi_ep_count = ab->hw_params.max_radios;
749 		break;
750 	}
751 
752 	/* setup our pseudo HTC control endpoint connection */
753 	memset(&conn_req, 0, sizeof(conn_req));
754 	memset(&conn_resp, 0, sizeof(conn_resp));
755 	conn_req.ep_ops.ep_tx_complete = ath11k_htc_control_tx_complete;
756 	conn_req.ep_ops.ep_rx_complete = ath11k_htc_control_rx_complete;
757 	conn_req.max_send_queue_depth = ATH11K_NUM_CONTROL_TX_BUFFERS;
758 	conn_req.service_id = ATH11K_HTC_SVC_ID_RSVD_CTRL;
759 
760 	/* connect fake service */
761 	ret = ath11k_htc_connect_service(htc, &conn_req, &conn_resp);
762 	if (ret) {
763 		ath11k_err(ab, "could not connect to htc service (%d)\n", ret);
764 		return ret;
765 	}
766 
767 	init_completion(&htc->ctl_resp);
768 
769 	return 0;
770 }
771