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