1 // SPDX-License-Identifier: BSD-3-Clause-Clear
3 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4 * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
6 #include <linux/skbuff.h>
7 #include <linux/ctype.h>
12 struct sk_buff
*ath12k_htc_alloc_skb(struct ath12k_base
*ab
, int size
)
16 skb
= dev_alloc_skb(size
+ sizeof(struct ath12k_htc_hdr
));
20 skb_reserve(skb
, sizeof(struct ath12k_htc_hdr
));
22 /* FW/HTC requires 4-byte aligned streams */
23 if (!IS_ALIGNED((unsigned long)skb
->data
, 4))
24 ath12k_warn(ab
, "Unaligned HTC tx skb\n");
29 static void ath12k_htc_control_tx_complete(struct ath12k_base
*ab
,
35 static struct sk_buff
*ath12k_htc_build_tx_ctrl_skb(void)
38 struct ath12k_skb_cb
*skb_cb
;
40 skb
= dev_alloc_skb(ATH12K_HTC_CONTROL_BUFFER_SIZE
);
44 skb_reserve(skb
, sizeof(struct ath12k_htc_hdr
));
45 WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb
->data
, 4));
47 skb_cb
= ATH12K_SKB_CB(skb
);
48 memset(skb_cb
, 0, sizeof(*skb_cb
));
53 static void ath12k_htc_prepare_tx_skb(struct ath12k_htc_ep
*ep
,
56 struct ath12k_htc_hdr
*hdr
;
58 hdr
= (struct ath12k_htc_hdr
*)skb
->data
;
60 memset(hdr
, 0, sizeof(*hdr
));
61 hdr
->htc_info
= le32_encode_bits(ep
->eid
, HTC_HDR_ENDPOINTID
) |
62 le32_encode_bits((skb
->len
- sizeof(*hdr
)),
65 if (ep
->tx_credit_flow_enabled
)
66 hdr
->htc_info
|= le32_encode_bits(ATH12K_HTC_FLAG_NEED_CREDIT_UPDATE
,
69 spin_lock_bh(&ep
->htc
->tx_lock
);
70 hdr
->ctrl_info
= le32_encode_bits(ep
->seq_no
++, HTC_HDR_CONTROLBYTES1
);
71 spin_unlock_bh(&ep
->htc
->tx_lock
);
74 int ath12k_htc_send(struct ath12k_htc
*htc
,
75 enum ath12k_htc_ep_id eid
,
78 struct ath12k_htc_ep
*ep
= &htc
->endpoint
[eid
];
79 struct ath12k_skb_cb
*skb_cb
= ATH12K_SKB_CB(skb
);
80 struct device
*dev
= htc
->ab
->dev
;
81 struct ath12k_base
*ab
= htc
->ab
;
85 if (eid
>= ATH12K_HTC_EP_COUNT
) {
86 ath12k_warn(ab
, "Invalid endpoint id: %d\n", eid
);
90 skb_push(skb
, sizeof(struct ath12k_htc_hdr
));
92 if (ep
->tx_credit_flow_enabled
) {
93 credits
= DIV_ROUND_UP(skb
->len
, htc
->target_credit_size
);
94 spin_lock_bh(&htc
->tx_lock
);
95 if (ep
->tx_credits
< credits
) {
96 ath12k_dbg(ab
, ATH12K_DBG_HTC
,
97 "htc insufficient credits ep %d required %d available %d\n",
98 eid
, credits
, ep
->tx_credits
);
99 spin_unlock_bh(&htc
->tx_lock
);
103 ep
->tx_credits
-= credits
;
104 ath12k_dbg(ab
, ATH12K_DBG_HTC
,
105 "htc ep %d consumed %d credits (total %d)\n",
106 eid
, credits
, ep
->tx_credits
);
107 spin_unlock_bh(&htc
->tx_lock
);
110 ath12k_htc_prepare_tx_skb(ep
, skb
);
112 skb_cb
->paddr
= dma_map_single(dev
, skb
->data
, skb
->len
, DMA_TO_DEVICE
);
113 ret
= dma_mapping_error(dev
, skb_cb
->paddr
);
119 ret
= ath12k_ce_send(htc
->ab
, skb
, ep
->ul_pipe_id
, ep
->eid
);
126 dma_unmap_single(dev
, skb_cb
->paddr
, skb
->len
, DMA_TO_DEVICE
);
128 if (ep
->tx_credit_flow_enabled
) {
129 spin_lock_bh(&htc
->tx_lock
);
130 ep
->tx_credits
+= credits
;
131 ath12k_dbg(ab
, ATH12K_DBG_HTC
,
132 "htc ep %d reverted %d credits back (total %d)\n",
133 eid
, credits
, ep
->tx_credits
);
134 spin_unlock_bh(&htc
->tx_lock
);
136 if (ep
->ep_ops
.ep_tx_credits
)
137 ep
->ep_ops
.ep_tx_credits(htc
->ab
);
140 skb_pull(skb
, sizeof(struct ath12k_htc_hdr
));
145 ath12k_htc_process_credit_report(struct ath12k_htc
*htc
,
146 const struct ath12k_htc_credit_report
*report
,
148 enum ath12k_htc_ep_id eid
)
150 struct ath12k_base
*ab
= htc
->ab
;
151 struct ath12k_htc_ep
*ep
;
154 if (len
% sizeof(*report
))
155 ath12k_warn(ab
, "Uneven credit report len %d", len
);
157 n_reports
= len
/ sizeof(*report
);
159 spin_lock_bh(&htc
->tx_lock
);
160 for (i
= 0; i
< n_reports
; i
++, report
++) {
161 if (report
->eid
>= ATH12K_HTC_EP_COUNT
)
164 ep
= &htc
->endpoint
[report
->eid
];
165 ep
->tx_credits
+= report
->credits
;
167 ath12k_dbg(ab
, ATH12K_DBG_HTC
, "htc ep %d got %d credits (total %d)\n",
168 report
->eid
, report
->credits
, ep
->tx_credits
);
170 if (ep
->ep_ops
.ep_tx_credits
) {
171 spin_unlock_bh(&htc
->tx_lock
);
172 ep
->ep_ops
.ep_tx_credits(htc
->ab
);
173 spin_lock_bh(&htc
->tx_lock
);
176 spin_unlock_bh(&htc
->tx_lock
);
179 static int ath12k_htc_process_trailer(struct ath12k_htc
*htc
,
182 enum ath12k_htc_ep_id src_eid
)
184 struct ath12k_base
*ab
= htc
->ab
;
186 struct ath12k_htc_record
*record
;
190 record
= (struct ath12k_htc_record
*)buffer
;
192 if (length
< sizeof(record
->hdr
)) {
197 if (record
->hdr
.len
> length
) {
198 /* no room left in buffer for record */
199 ath12k_warn(ab
, "Invalid record length: %d\n",
205 switch (record
->hdr
.id
) {
206 case ATH12K_HTC_RECORD_CREDITS
:
207 len
= sizeof(struct ath12k_htc_credit_report
);
208 if (record
->hdr
.len
< len
) {
209 ath12k_warn(ab
, "Credit report too long\n");
213 ath12k_htc_process_credit_report(htc
,
214 record
->credit_report
,
219 ath12k_warn(ab
, "Unhandled record: id:%d length:%d\n",
220 record
->hdr
.id
, record
->hdr
.len
);
227 /* multiple records may be present in a trailer */
228 buffer
+= sizeof(record
->hdr
) + record
->hdr
.len
;
229 length
-= sizeof(record
->hdr
) + record
->hdr
.len
;
235 static void ath12k_htc_suspend_complete(struct ath12k_base
*ab
, bool ack
)
237 ath12k_dbg(ab
, ATH12K_DBG_BOOT
, "boot suspend complete %d\n", ack
);
240 set_bit(ATH12K_FLAG_HTC_SUSPEND_COMPLETE
, &ab
->dev_flags
);
242 clear_bit(ATH12K_FLAG_HTC_SUSPEND_COMPLETE
, &ab
->dev_flags
);
244 complete(&ab
->htc_suspend
);
247 static void ath12k_htc_wakeup_from_suspend(struct ath12k_base
*ab
)
249 ath12k_dbg(ab
, ATH12K_DBG_BOOT
, "boot wakeup from suspend is received\n");
252 void ath12k_htc_rx_completion_handler(struct ath12k_base
*ab
,
256 struct ath12k_htc
*htc
= &ab
->htc
;
257 struct ath12k_htc_hdr
*hdr
;
258 struct ath12k_htc_ep
*ep
;
263 bool trailer_present
;
265 hdr
= (struct ath12k_htc_hdr
*)skb
->data
;
266 skb_pull(skb
, sizeof(*hdr
));
268 eid
= le32_get_bits(hdr
->htc_info
, HTC_HDR_ENDPOINTID
);
270 if (eid
>= ATH12K_HTC_EP_COUNT
) {
271 ath12k_warn(ab
, "HTC Rx: invalid eid %d\n", eid
);
275 ep
= &htc
->endpoint
[eid
];
277 payload_len
= le32_get_bits(hdr
->htc_info
, HTC_HDR_PAYLOADLEN
);
279 if (payload_len
+ sizeof(*hdr
) > ATH12K_HTC_MAX_LEN
) {
280 ath12k_warn(ab
, "HTC rx frame too long, len: %zu\n",
281 payload_len
+ sizeof(*hdr
));
285 if (skb
->len
< payload_len
) {
286 ath12k_warn(ab
, "HTC Rx: insufficient length, got %d, expected %d\n",
287 skb
->len
, payload_len
);
291 /* get flags to check for trailer */
292 trailer_present
= le32_get_bits(hdr
->htc_info
, HTC_HDR_FLAGS
) &
293 ATH12K_HTC_FLAG_TRAILER_PRESENT
;
295 if (trailer_present
) {
298 trailer_len
= le32_get_bits(hdr
->ctrl_info
,
299 HTC_HDR_CONTROLBYTES0
);
300 min_len
= sizeof(struct ath12k_htc_record_hdr
);
302 if ((trailer_len
< min_len
) ||
303 (trailer_len
> payload_len
)) {
304 ath12k_warn(ab
, "Invalid trailer length: %d\n",
310 trailer
+= sizeof(*hdr
);
311 trailer
+= payload_len
;
312 trailer
-= trailer_len
;
313 status
= ath12k_htc_process_trailer(htc
, trailer
,
318 skb_trim(skb
, skb
->len
- trailer_len
);
321 if (trailer_len
>= payload_len
)
322 /* zero length packet with trailer data, just drop these */
325 if (eid
== ATH12K_HTC_EP_0
) {
326 struct ath12k_htc_msg
*msg
= (struct ath12k_htc_msg
*)skb
->data
;
328 switch (le32_get_bits(msg
->msg_svc_id
, HTC_MSG_MESSAGEID
)) {
329 case ATH12K_HTC_MSG_READY_ID
:
330 case ATH12K_HTC_MSG_CONNECT_SERVICE_RESP_ID
:
331 /* handle HTC control message */
332 if (completion_done(&htc
->ctl_resp
)) {
333 /* this is a fatal error, target should not be
334 * sending unsolicited messages on the ep 0
336 ath12k_warn(ab
, "HTC rx ctrl still processing\n");
337 complete(&htc
->ctl_resp
);
341 htc
->control_resp_len
=
343 ATH12K_HTC_MAX_CTRL_MSG_LEN
);
345 memcpy(htc
->control_resp_buffer
, skb
->data
,
346 htc
->control_resp_len
);
348 complete(&htc
->ctl_resp
);
350 case ATH12K_HTC_MSG_SEND_SUSPEND_COMPLETE
:
351 ath12k_htc_suspend_complete(ab
, true);
353 case ATH12K_HTC_MSG_NACK_SUSPEND
:
354 ath12k_htc_suspend_complete(ab
, false);
356 case ATH12K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID
:
357 ath12k_htc_wakeup_from_suspend(ab
);
360 ath12k_warn(ab
, "ignoring unsolicited htc ep0 event %u\n",
361 le32_get_bits(msg
->msg_svc_id
, HTC_MSG_MESSAGEID
));
367 ath12k_dbg(ab
, ATH12K_DBG_HTC
, "htc rx completion ep %d skb %p\n",
369 ep
->ep_ops
.ep_rx_complete(ab
, skb
);
371 /* poll tx completion for interrupt disabled CE's */
372 ath12k_ce_poll_send_completed(ab
, ep
->ul_pipe_id
);
374 /* skb is now owned by the rx completion handler */
380 static void ath12k_htc_control_rx_complete(struct ath12k_base
*ab
,
383 /* This is unexpected. FW is not supposed to send regular rx on this
386 ath12k_warn(ab
, "unexpected htc rx\n");
390 static const char *htc_service_name(enum ath12k_htc_svc_id id
)
393 case ATH12K_HTC_SVC_ID_RESERVED
:
395 case ATH12K_HTC_SVC_ID_RSVD_CTRL
:
397 case ATH12K_HTC_SVC_ID_WMI_CONTROL
:
399 case ATH12K_HTC_SVC_ID_WMI_DATA_BE
:
401 case ATH12K_HTC_SVC_ID_WMI_DATA_BK
:
403 case ATH12K_HTC_SVC_ID_WMI_DATA_VI
:
405 case ATH12K_HTC_SVC_ID_WMI_DATA_VO
:
407 case ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1
:
409 case ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2
:
411 case ATH12K_HTC_SVC_ID_NMI_CONTROL
:
412 return "NMI Control";
413 case ATH12K_HTC_SVC_ID_NMI_DATA
:
415 case ATH12K_HTC_SVC_ID_HTT_DATA_MSG
:
417 case ATH12K_HTC_SVC_ID_TEST_RAW_STREAMS
:
419 case ATH12K_HTC_SVC_ID_IPA_TX
:
421 case ATH12K_HTC_SVC_ID_PKT_LOG
:
423 case ATH12K_HTC_SVC_ID_WMI_CONTROL_DIAG
:
430 static void ath12k_htc_reset_endpoint_states(struct ath12k_htc
*htc
)
432 struct ath12k_htc_ep
*ep
;
435 for (i
= ATH12K_HTC_EP_0
; i
< ATH12K_HTC_EP_COUNT
; i
++) {
436 ep
= &htc
->endpoint
[i
];
437 ep
->service_id
= ATH12K_HTC_SVC_ID_UNUSED
;
438 ep
->max_ep_message_len
= 0;
439 ep
->max_tx_queue_depth
= 0;
442 ep
->tx_credit_flow_enabled
= true;
446 static u8
ath12k_htc_get_credit_allocation(struct ath12k_htc
*htc
,
449 struct ath12k_htc_svc_tx_credits
*serv_entry
;
450 u8 i
, allocation
= 0;
452 serv_entry
= htc
->service_alloc_table
;
454 for (i
= 0; i
< ATH12K_HTC_MAX_SERVICE_ALLOC_ENTRIES
; i
++) {
455 if (serv_entry
[i
].service_id
== service_id
) {
456 allocation
= serv_entry
[i
].credit_allocation
;
464 static int ath12k_htc_setup_target_buffer_assignments(struct ath12k_htc
*htc
)
466 struct ath12k_htc_svc_tx_credits
*serv_entry
;
467 static const u32 svc_id
[] = {
468 ATH12K_HTC_SVC_ID_WMI_CONTROL
,
469 ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1
,
470 ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2
,
474 credits
= htc
->total_transmit_credits
;
475 serv_entry
= htc
->service_alloc_table
;
477 if ((htc
->wmi_ep_count
== 0) ||
478 (htc
->wmi_ep_count
> ARRAY_SIZE(svc_id
)))
481 /* Divide credits among number of endpoints for WMI */
482 credits
= credits
/ htc
->wmi_ep_count
;
483 for (i
= 0; i
< htc
->wmi_ep_count
; i
++) {
484 serv_entry
[i
].service_id
= svc_id
[i
];
485 serv_entry
[i
].credit_allocation
= credits
;
491 int ath12k_htc_wait_target(struct ath12k_htc
*htc
)
494 struct ath12k_base
*ab
= htc
->ab
;
495 unsigned long time_left
;
496 struct ath12k_htc_ready
*ready
;
501 time_left
= wait_for_completion_timeout(&htc
->ctl_resp
,
502 ATH12K_HTC_WAIT_TIMEOUT_HZ
);
504 ath12k_warn(ab
, "failed to receive control response completion, polling..\n");
506 for (i
= 0; i
< ab
->hw_params
->ce_count
; i
++)
507 ath12k_ce_per_engine_service(htc
->ab
, i
);
510 wait_for_completion_timeout(&htc
->ctl_resp
,
511 ATH12K_HTC_WAIT_TIMEOUT_HZ
);
518 ath12k_warn(ab
, "ctl_resp never came in (%d)\n", status
);
522 if (htc
->control_resp_len
< sizeof(*ready
)) {
523 ath12k_warn(ab
, "Invalid HTC ready msg len:%d\n",
524 htc
->control_resp_len
);
528 ready
= (struct ath12k_htc_ready
*)htc
->control_resp_buffer
;
529 message_id
= le32_get_bits(ready
->id_credit_count
, HTC_MSG_MESSAGEID
);
530 credit_count
= le32_get_bits(ready
->id_credit_count
,
531 HTC_READY_MSG_CREDITCOUNT
);
532 credit_size
= le32_get_bits(ready
->size_ep
, HTC_READY_MSG_CREDITSIZE
);
534 if (message_id
!= ATH12K_HTC_MSG_READY_ID
) {
535 ath12k_warn(ab
, "Invalid HTC ready msg: 0x%x\n", message_id
);
539 htc
->total_transmit_credits
= credit_count
;
540 htc
->target_credit_size
= credit_size
;
542 ath12k_dbg(ab
, ATH12K_DBG_HTC
,
543 "Target ready! transmit resources: %d size:%d\n",
544 htc
->total_transmit_credits
, htc
->target_credit_size
);
546 if ((htc
->total_transmit_credits
== 0) ||
547 (htc
->target_credit_size
== 0)) {
548 ath12k_warn(ab
, "Invalid credit size received\n");
552 ath12k_htc_setup_target_buffer_assignments(htc
);
557 int ath12k_htc_connect_service(struct ath12k_htc
*htc
,
558 struct ath12k_htc_svc_conn_req
*conn_req
,
559 struct ath12k_htc_svc_conn_resp
*conn_resp
)
561 struct ath12k_base
*ab
= htc
->ab
;
562 struct ath12k_htc_conn_svc
*req_msg
;
563 struct ath12k_htc_conn_svc_resp resp_msg_dummy
;
564 struct ath12k_htc_conn_svc_resp
*resp_msg
= &resp_msg_dummy
;
565 enum ath12k_htc_ep_id assigned_eid
= ATH12K_HTC_EP_COUNT
;
566 struct ath12k_htc_ep
*ep
;
568 unsigned int max_msg_size
= 0;
570 unsigned long time_left
;
571 bool disable_credit_flow_ctrl
= false;
572 u16 message_id
, service_id
, flags
= 0;
575 /* special case for HTC pseudo control service */
576 if (conn_req
->service_id
== ATH12K_HTC_SVC_ID_RSVD_CTRL
) {
577 disable_credit_flow_ctrl
= true;
578 assigned_eid
= ATH12K_HTC_EP_0
;
579 max_msg_size
= ATH12K_HTC_MAX_CTRL_MSG_LEN
;
580 memset(&resp_msg_dummy
, 0, sizeof(resp_msg_dummy
));
584 tx_alloc
= ath12k_htc_get_credit_allocation(htc
,
585 conn_req
->service_id
);
587 ath12k_dbg(ab
, ATH12K_DBG_BOOT
,
588 "boot htc service %s does not allocate target credits\n",
589 htc_service_name(conn_req
->service_id
));
591 skb
= ath12k_htc_build_tx_ctrl_skb();
593 ath12k_warn(ab
, "Failed to allocate HTC packet\n");
597 length
= sizeof(*req_msg
);
598 skb_put(skb
, length
);
599 memset(skb
->data
, 0, length
);
601 req_msg
= (struct ath12k_htc_conn_svc
*)skb
->data
;
602 req_msg
->msg_svc_id
= le32_encode_bits(ATH12K_HTC_MSG_CONNECT_SERVICE_ID
,
605 flags
|= u32_encode_bits(tx_alloc
, ATH12K_HTC_CONN_FLAGS_RECV_ALLOC
);
607 /* Only enable credit flow control for WMI ctrl service */
608 if (!(conn_req
->service_id
== ATH12K_HTC_SVC_ID_WMI_CONTROL
||
609 conn_req
->service_id
== ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1
||
610 conn_req
->service_id
== ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2
)) {
611 flags
|= ATH12K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL
;
612 disable_credit_flow_ctrl
= true;
615 req_msg
->flags_len
= le32_encode_bits(flags
, HTC_SVC_MSG_CONNECTIONFLAGS
);
616 req_msg
->msg_svc_id
|= le32_encode_bits(conn_req
->service_id
,
617 HTC_SVC_MSG_SERVICE_ID
);
619 reinit_completion(&htc
->ctl_resp
);
621 status
= ath12k_htc_send(htc
, ATH12K_HTC_EP_0
, skb
);
627 /* wait for response */
628 time_left
= wait_for_completion_timeout(&htc
->ctl_resp
,
629 ATH12K_HTC_CONN_SVC_TIMEOUT_HZ
);
631 ath12k_err(ab
, "Service connect timeout\n");
635 /* we controlled the buffer creation, it's aligned */
636 resp_msg
= (struct ath12k_htc_conn_svc_resp
*)htc
->control_resp_buffer
;
637 message_id
= le32_get_bits(resp_msg
->msg_svc_id
, HTC_MSG_MESSAGEID
);
638 service_id
= le32_get_bits(resp_msg
->msg_svc_id
,
639 HTC_SVC_RESP_MSG_SERVICEID
);
641 if ((message_id
!= ATH12K_HTC_MSG_CONNECT_SERVICE_RESP_ID
) ||
642 (htc
->control_resp_len
< sizeof(*resp_msg
))) {
643 ath12k_err(ab
, "Invalid resp message ID 0x%x", message_id
);
647 ath12k_dbg(ab
, ATH12K_DBG_HTC
,
648 "HTC Service %s connect response: status: %u, assigned ep: %u\n",
649 htc_service_name(service_id
),
650 le32_get_bits(resp_msg
->flags_len
, HTC_SVC_RESP_MSG_STATUS
),
651 le32_get_bits(resp_msg
->flags_len
, HTC_SVC_RESP_MSG_ENDPOINTID
));
653 conn_resp
->connect_resp_code
= le32_get_bits(resp_msg
->flags_len
,
654 HTC_SVC_RESP_MSG_STATUS
);
656 /* check response status */
657 if (conn_resp
->connect_resp_code
!= ATH12K_HTC_CONN_SVC_STATUS_SUCCESS
) {
658 ath12k_err(ab
, "HTC Service %s connect request failed: 0x%x)\n",
659 htc_service_name(service_id
),
660 conn_resp
->connect_resp_code
);
664 assigned_eid
= le32_get_bits(resp_msg
->flags_len
,
665 HTC_SVC_RESP_MSG_ENDPOINTID
);
667 max_msg_size
= le32_get_bits(resp_msg
->flags_len
,
668 HTC_SVC_RESP_MSG_MAXMSGSIZE
);
672 if (assigned_eid
>= ATH12K_HTC_EP_COUNT
)
675 if (max_msg_size
== 0)
678 ep
= &htc
->endpoint
[assigned_eid
];
679 ep
->eid
= assigned_eid
;
681 if (ep
->service_id
!= ATH12K_HTC_SVC_ID_UNUSED
)
684 /* return assigned endpoint to caller */
685 conn_resp
->eid
= assigned_eid
;
686 conn_resp
->max_msg_len
= le32_get_bits(resp_msg
->flags_len
,
687 HTC_SVC_RESP_MSG_MAXMSGSIZE
);
689 /* setup the endpoint */
690 ep
->service_id
= conn_req
->service_id
;
691 ep
->max_tx_queue_depth
= conn_req
->max_send_queue_depth
;
692 ep
->max_ep_message_len
= le32_get_bits(resp_msg
->flags_len
,
693 HTC_SVC_RESP_MSG_MAXMSGSIZE
);
694 ep
->tx_credits
= tx_alloc
;
696 /* copy all the callbacks */
697 ep
->ep_ops
= conn_req
->ep_ops
;
699 status
= ath12k_hif_map_service_to_pipe(htc
->ab
,
706 ath12k_dbg(ab
, ATH12K_DBG_BOOT
,
707 "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
708 htc_service_name(ep
->service_id
), ep
->ul_pipe_id
,
709 ep
->dl_pipe_id
, ep
->eid
);
711 if (disable_credit_flow_ctrl
&& ep
->tx_credit_flow_enabled
) {
712 ep
->tx_credit_flow_enabled
= false;
713 ath12k_dbg(ab
, ATH12K_DBG_BOOT
,
714 "boot htc service '%s' eid %d TX flow control disabled\n",
715 htc_service_name(ep
->service_id
), assigned_eid
);
721 int ath12k_htc_start(struct ath12k_htc
*htc
)
725 struct ath12k_base
*ab
= htc
->ab
;
726 struct ath12k_htc_setup_complete_extended
*msg
;
728 skb
= ath12k_htc_build_tx_ctrl_skb();
732 skb_put(skb
, sizeof(*msg
));
733 memset(skb
->data
, 0, skb
->len
);
735 msg
= (struct ath12k_htc_setup_complete_extended
*)skb
->data
;
736 msg
->msg_id
= le32_encode_bits(ATH12K_HTC_MSG_SETUP_COMPLETE_EX_ID
,
739 ath12k_dbg(ab
, ATH12K_DBG_HTC
, "HTC is using TX credit flow control\n");
741 status
= ath12k_htc_send(htc
, ATH12K_HTC_EP_0
, skb
);
750 int ath12k_htc_init(struct ath12k_base
*ab
)
752 struct ath12k_htc
*htc
= &ab
->htc
;
753 struct ath12k_htc_svc_conn_req conn_req
= { };
754 struct ath12k_htc_svc_conn_resp conn_resp
= { };
757 spin_lock_init(&htc
->tx_lock
);
759 ath12k_htc_reset_endpoint_states(htc
);
763 switch (ab
->wmi_ab
.preferred_hw_mode
) {
764 case WMI_HOST_HW_MODE_SINGLE
:
765 htc
->wmi_ep_count
= 1;
767 case WMI_HOST_HW_MODE_DBS
:
768 case WMI_HOST_HW_MODE_DBS_OR_SBS
:
769 htc
->wmi_ep_count
= 2;
771 case WMI_HOST_HW_MODE_DBS_SBS
:
772 htc
->wmi_ep_count
= 3;
775 htc
->wmi_ep_count
= ab
->hw_params
->max_radios
;
779 /* setup our pseudo HTC control endpoint connection */
780 conn_req
.ep_ops
.ep_tx_complete
= ath12k_htc_control_tx_complete
;
781 conn_req
.ep_ops
.ep_rx_complete
= ath12k_htc_control_rx_complete
;
782 conn_req
.max_send_queue_depth
= ATH12K_NUM_CONTROL_TX_BUFFERS
;
783 conn_req
.service_id
= ATH12K_HTC_SVC_ID_RSVD_CTRL
;
785 /* connect fake service */
786 ret
= ath12k_htc_connect_service(htc
, &conn_req
, &conn_resp
);
788 ath12k_err(ab
, "could not connect to htc service (%d)\n", ret
);
792 init_completion(&htc
->ctl_resp
);