Lines Matching +full:ipa +full:- +full:setup +full:- +full:ready
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
22 /* FW/HTC requires 4-byte aligned streams */ in ath11k_htc_alloc_skb()
23 if (!IS_ALIGNED((unsigned long)skb->data, 4)) in ath11k_htc_alloc_skb()
45 WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4)); in ath11k_htc_build_tx_ctrl_skb()
58 hdr = (struct ath11k_htc_hdr *)skb->data; in ath11k_htc_prepare_tx_skb()
61 hdr->htc_info = FIELD_PREP(HTC_HDR_ENDPOINTID, ep->eid) | in ath11k_htc_prepare_tx_skb()
63 (skb->len - sizeof(*hdr))); in ath11k_htc_prepare_tx_skb()
65 if (ep->tx_credit_flow_enabled) in ath11k_htc_prepare_tx_skb()
66 hdr->htc_info |= FIELD_PREP(HTC_HDR_FLAGS, in ath11k_htc_prepare_tx_skb()
69 spin_lock_bh(&ep->htc->tx_lock); in ath11k_htc_prepare_tx_skb()
70 hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++); in ath11k_htc_prepare_tx_skb()
71 spin_unlock_bh(&ep->htc->tx_lock); in ath11k_htc_prepare_tx_skb()
78 struct ath11k_htc_ep *ep = &htc->endpoint[eid]; in ath11k_htc_send()
80 struct device *dev = htc->ab->dev; in ath11k_htc_send()
81 struct ath11k_base *ab = htc->ab; in ath11k_htc_send()
84 bool credit_flow_enabled = (ab->hw_params.credit_flow && in ath11k_htc_send()
85 ep->tx_credit_flow_enabled); in ath11k_htc_send()
89 return -ENOENT; in ath11k_htc_send()
95 credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); in ath11k_htc_send()
96 spin_lock_bh(&htc->tx_lock); in ath11k_htc_send()
97 if (ep->tx_credits < credits) { in ath11k_htc_send()
100 eid, credits, ep->tx_credits); in ath11k_htc_send()
101 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
102 ret = -EAGAIN; in ath11k_htc_send()
105 ep->tx_credits -= credits; in ath11k_htc_send()
108 eid, credits, ep->tx_credits); in ath11k_htc_send()
109 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
114 skb_cb->eid = eid; in ath11k_htc_send()
115 skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); in ath11k_htc_send()
116 ret = dma_mapping_error(dev, skb_cb->paddr); in ath11k_htc_send()
118 ret = -EIO; in ath11k_htc_send()
123 skb, skb_cb->eid, &skb_cb->paddr); in ath11k_htc_send()
125 ret = ath11k_ce_send(htc->ab, skb, ep->ul_pipe_id, ep->eid); in ath11k_htc_send()
132 dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); in ath11k_htc_send()
135 spin_lock_bh(&htc->tx_lock); in ath11k_htc_send()
136 ep->tx_credits += credits; in ath11k_htc_send()
139 eid, credits, ep->tx_credits); in ath11k_htc_send()
140 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
142 if (ep->ep_ops.ep_tx_credits) in ath11k_htc_send()
143 ep->ep_ops.ep_tx_credits(htc->ab); in ath11k_htc_send()
156 struct ath11k_base *ab = htc->ab; in ath11k_htc_process_credit_report()
165 spin_lock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
167 if (report->eid >= ATH11K_HTC_EP_COUNT) in ath11k_htc_process_credit_report()
170 ep = &htc->endpoint[report->eid]; in ath11k_htc_process_credit_report()
171 ep->tx_credits += report->credits; in ath11k_htc_process_credit_report()
174 report->eid, report->credits, ep->tx_credits); in ath11k_htc_process_credit_report()
176 if (ep->ep_ops.ep_tx_credits) { in ath11k_htc_process_credit_report()
177 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
178 ep->ep_ops.ep_tx_credits(htc->ab); in ath11k_htc_process_credit_report()
179 spin_lock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
182 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
190 struct ath11k_base *ab = htc->ab; in ath11k_htc_process_trailer()
198 if (length < sizeof(record->hdr)) { in ath11k_htc_process_trailer()
199 status = -EINVAL; in ath11k_htc_process_trailer()
203 if (record->hdr.len > length) { in ath11k_htc_process_trailer()
206 record->hdr.len); in ath11k_htc_process_trailer()
207 status = -EINVAL; in ath11k_htc_process_trailer()
211 if (ab->hw_params.credit_flow) { in ath11k_htc_process_trailer()
212 switch (record->hdr.id) { in ath11k_htc_process_trailer()
215 if (record->hdr.len < len) { in ath11k_htc_process_trailer()
217 status = -EINVAL; in ath11k_htc_process_trailer()
221 record->credit_report, in ath11k_htc_process_trailer()
222 record->hdr.len, in ath11k_htc_process_trailer()
227 record->hdr.id, record->hdr.len); in ath11k_htc_process_trailer()
236 buffer += sizeof(record->hdr) + record->hdr.len; in ath11k_htc_process_trailer()
237 length -= sizeof(record->hdr) + record->hdr.len; in ath11k_htc_process_trailer()
248 set_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); in ath11k_htc_suspend_complete()
250 clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); in ath11k_htc_suspend_complete()
252 complete(&ab->htc_suspend); in ath11k_htc_suspend_complete()
258 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_tx_completion_handler()
263 eid = ATH11K_SKB_CB(skb)->eid; in ath11k_htc_tx_completion_handler()
269 ep = &htc->endpoint[eid]; in ath11k_htc_tx_completion_handler()
270 spin_lock_bh(&htc->tx_lock); in ath11k_htc_tx_completion_handler()
271 ep_tx_complete = ep->ep_ops.ep_tx_complete; in ath11k_htc_tx_completion_handler()
272 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_tx_completion_handler()
277 ep_tx_complete(htc->ab, skb); in ath11k_htc_tx_completion_handler()
289 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_rx_completion_handler()
298 hdr = (struct ath11k_htc_hdr *)skb->data; in ath11k_htc_rx_completion_handler()
301 eid = FIELD_GET(HTC_HDR_ENDPOINTID, hdr->htc_info); in ath11k_htc_rx_completion_handler()
308 ep = &htc->endpoint[eid]; in ath11k_htc_rx_completion_handler()
310 payload_len = FIELD_GET(HTC_HDR_PAYLOADLEN, hdr->htc_info); in ath11k_htc_rx_completion_handler()
318 if (skb->len < payload_len) { in ath11k_htc_rx_completion_handler()
320 skb->len, payload_len); in ath11k_htc_rx_completion_handler()
325 trailer_present = (FIELD_GET(HTC_HDR_FLAGS, hdr->htc_info)) & in ath11k_htc_rx_completion_handler()
334 trailer_len = FIELD_GET(HTC_HDR_CONTROLBYTES0, hdr->ctrl_info); in ath11k_htc_rx_completion_handler()
347 trailer -= trailer_len; in ath11k_htc_rx_completion_handler()
353 skb_trim(skb, skb->len - trailer_len); in ath11k_htc_rx_completion_handler()
361 struct ath11k_htc_msg *msg = (struct ath11k_htc_msg *)skb->data; in ath11k_htc_rx_completion_handler()
363 message_id = FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id); in ath11k_htc_rx_completion_handler()
372 if (completion_done(&htc->ctl_resp)) { in ath11k_htc_rx_completion_handler()
377 complete(&htc->ctl_resp); in ath11k_htc_rx_completion_handler()
381 htc->control_resp_len = in ath11k_htc_rx_completion_handler()
382 min_t(int, skb->len, in ath11k_htc_rx_completion_handler()
385 memcpy(htc->control_resp_buffer, skb->data, in ath11k_htc_rx_completion_handler()
386 htc->control_resp_len); in ath11k_htc_rx_completion_handler()
388 complete(&htc->ctl_resp); in ath11k_htc_rx_completion_handler()
401 FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id)); in ath11k_htc_rx_completion_handler()
407 ep->ep_ops.ep_rx_complete(ab, skb); in ath11k_htc_rx_completion_handler()
410 ath11k_ce_poll_send_completed(ab, ep->ul_pipe_id); in ath11k_htc_rx_completion_handler()
458 return "IPA TX"; in htc_service_name()
472 ep = &htc->endpoint[i]; in ath11k_htc_reset_endpoint_states()
473 ep->service_id = ATH11K_HTC_SVC_ID_UNUSED; in ath11k_htc_reset_endpoint_states()
474 ep->max_ep_message_len = 0; in ath11k_htc_reset_endpoint_states()
475 ep->max_tx_queue_depth = 0; in ath11k_htc_reset_endpoint_states()
476 ep->eid = i; in ath11k_htc_reset_endpoint_states()
477 ep->htc = htc; in ath11k_htc_reset_endpoint_states()
478 ep->tx_credit_flow_enabled = true; in ath11k_htc_reset_endpoint_states()
488 if (htc->service_alloc_table[i].service_id == service_id) { in ath11k_htc_get_credit_allocation()
490 htc->service_alloc_table[i].credit_allocation; in ath11k_htc_get_credit_allocation()
507 credits = htc->total_transmit_credits; in ath11k_htc_setup_target_buffer_assignments()
508 serv_entry = htc->service_alloc_table; in ath11k_htc_setup_target_buffer_assignments()
510 if ((htc->wmi_ep_count == 0) || in ath11k_htc_setup_target_buffer_assignments()
511 (htc->wmi_ep_count > ARRAY_SIZE(svc_id))) in ath11k_htc_setup_target_buffer_assignments()
512 return -EINVAL; in ath11k_htc_setup_target_buffer_assignments()
515 credits = credits / htc->wmi_ep_count; in ath11k_htc_setup_target_buffer_assignments()
516 for (i = 0; i < htc->wmi_ep_count; i++) { in ath11k_htc_setup_target_buffer_assignments()
527 struct ath11k_base *ab = htc->ab; in ath11k_htc_wait_target()
529 struct ath11k_htc_ready *ready; in ath11k_htc_wait_target() local
534 time_left = wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_wait_target()
539 for (i = 0; i < ab->hw_params.ce_count; i++) in ath11k_htc_wait_target()
540 ath11k_ce_per_engine_service(htc->ab, i); in ath11k_htc_wait_target()
543 wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_wait_target()
547 status = -ETIMEDOUT; in ath11k_htc_wait_target()
555 if (htc->control_resp_len < sizeof(*ready)) { in ath11k_htc_wait_target()
556 ath11k_warn(ab, "Invalid HTC ready msg len:%d\n", in ath11k_htc_wait_target()
557 htc->control_resp_len); in ath11k_htc_wait_target()
558 return -ECOMM; in ath11k_htc_wait_target()
561 ready = (struct ath11k_htc_ready *)htc->control_resp_buffer; in ath11k_htc_wait_target()
562 message_id = FIELD_GET(HTC_MSG_MESSAGEID, ready->id_credit_count); in ath11k_htc_wait_target()
564 ready->id_credit_count); in ath11k_htc_wait_target()
565 credit_size = FIELD_GET(HTC_READY_MSG_CREDITSIZE, ready->size_ep); in ath11k_htc_wait_target()
568 ath11k_warn(ab, "Invalid HTC ready msg: 0x%x\n", message_id); in ath11k_htc_wait_target()
569 return -ECOMM; in ath11k_htc_wait_target()
572 htc->total_transmit_credits = credit_count; in ath11k_htc_wait_target()
573 htc->target_credit_size = credit_size; in ath11k_htc_wait_target()
576 "target ready total_transmit_credits %d target_credit_size %d\n", in ath11k_htc_wait_target()
577 htc->total_transmit_credits, htc->target_credit_size); in ath11k_htc_wait_target()
579 if ((htc->total_transmit_credits == 0) || in ath11k_htc_wait_target()
580 (htc->target_credit_size == 0)) { in ath11k_htc_wait_target()
582 return -ECOMM; in ath11k_htc_wait_target()
586 * back-to-back write. in ath11k_htc_wait_target()
588 if (ab->hw_params.supports_shadow_regs) in ath11k_htc_wait_target()
589 htc->total_transmit_credits = 1; in ath11k_htc_wait_target()
600 struct ath11k_base *ab = htc->ab; in ath11k_htc_connect_service()
615 if (conn_req->service_id == ATH11K_HTC_SVC_ID_RSVD_CTRL) { in ath11k_htc_connect_service()
620 goto setup; in ath11k_htc_connect_service()
624 conn_req->service_id); in ath11k_htc_connect_service()
628 htc_service_name(conn_req->service_id)); in ath11k_htc_connect_service()
630 skb = ath11k_htc_build_tx_ctrl_skb(htc->ab); in ath11k_htc_connect_service()
633 return -ENOMEM; in ath11k_htc_connect_service()
638 memset(skb->data, 0, length); in ath11k_htc_connect_service()
640 req_msg = (struct ath11k_htc_conn_svc *)skb->data; in ath11k_htc_connect_service()
641 req_msg->msg_svc_id = FIELD_PREP(HTC_MSG_MESSAGEID, in ath11k_htc_connect_service()
647 if (!(conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL || in ath11k_htc_connect_service()
648 conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1 || in ath11k_htc_connect_service()
649 conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2)) { in ath11k_htc_connect_service()
654 if (!ab->hw_params.credit_flow) { in ath11k_htc_connect_service()
659 req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags); in ath11k_htc_connect_service()
660 req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID, in ath11k_htc_connect_service()
661 conn_req->service_id); in ath11k_htc_connect_service()
663 reinit_completion(&htc->ctl_resp); in ath11k_htc_connect_service()
672 time_left = wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_connect_service()
676 return -ETIMEDOUT; in ath11k_htc_connect_service()
680 resp_msg = (struct ath11k_htc_conn_svc_resp *)htc->control_resp_buffer; in ath11k_htc_connect_service()
681 message_id = FIELD_GET(HTC_MSG_MESSAGEID, resp_msg->msg_svc_id); in ath11k_htc_connect_service()
683 resp_msg->msg_svc_id); in ath11k_htc_connect_service()
686 (htc->control_resp_len < sizeof(*resp_msg))) { in ath11k_htc_connect_service()
688 return -EPROTO; in ath11k_htc_connect_service()
694 FIELD_GET(HTC_SVC_RESP_MSG_STATUS, resp_msg->flags_len), in ath11k_htc_connect_service()
695 FIELD_GET(HTC_SVC_RESP_MSG_ENDPOINTID, resp_msg->flags_len)); in ath11k_htc_connect_service()
697 conn_resp->connect_resp_code = FIELD_GET(HTC_SVC_RESP_MSG_STATUS, in ath11k_htc_connect_service()
698 resp_msg->flags_len); in ath11k_htc_connect_service()
701 if (conn_resp->connect_resp_code != ATH11K_HTC_CONN_SVC_STATUS_SUCCESS) { in ath11k_htc_connect_service()
704 conn_resp->connect_resp_code); in ath11k_htc_connect_service()
705 return -EPROTO; in ath11k_htc_connect_service()
710 resp_msg->flags_len); in ath11k_htc_connect_service()
713 resp_msg->flags_len); in ath11k_htc_connect_service()
715 setup: in ath11k_htc_connect_service()
718 return -EPROTO; in ath11k_htc_connect_service()
721 return -EPROTO; in ath11k_htc_connect_service()
723 ep = &htc->endpoint[assigned_eid]; in ath11k_htc_connect_service()
724 ep->eid = assigned_eid; in ath11k_htc_connect_service()
726 if (ep->service_id != ATH11K_HTC_SVC_ID_UNUSED) in ath11k_htc_connect_service()
727 return -EPROTO; in ath11k_htc_connect_service()
730 conn_resp->eid = assigned_eid; in ath11k_htc_connect_service()
731 conn_resp->max_msg_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE, in ath11k_htc_connect_service()
732 resp_msg->flags_len); in ath11k_htc_connect_service()
734 /* setup the endpoint */ in ath11k_htc_connect_service()
735 ep->service_id = conn_req->service_id; in ath11k_htc_connect_service()
736 ep->max_tx_queue_depth = conn_req->max_send_queue_depth; in ath11k_htc_connect_service()
737 ep->max_ep_message_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE, in ath11k_htc_connect_service()
738 resp_msg->flags_len); in ath11k_htc_connect_service()
739 ep->tx_credits = tx_alloc; in ath11k_htc_connect_service()
742 ep->ep_ops = conn_req->ep_ops; in ath11k_htc_connect_service()
744 status = ath11k_hif_map_service_to_pipe(htc->ab, in ath11k_htc_connect_service()
745 ep->service_id, in ath11k_htc_connect_service()
746 &ep->ul_pipe_id, in ath11k_htc_connect_service()
747 &ep->dl_pipe_id); in ath11k_htc_connect_service()
752 "htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", in ath11k_htc_connect_service()
753 htc_service_name(ep->service_id), ep->ul_pipe_id, in ath11k_htc_connect_service()
754 ep->dl_pipe_id, ep->eid); in ath11k_htc_connect_service()
756 if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { in ath11k_htc_connect_service()
757 ep->tx_credit_flow_enabled = false; in ath11k_htc_connect_service()
760 htc_service_name(ep->service_id), assigned_eid); in ath11k_htc_connect_service()
770 struct ath11k_base *ab = htc->ab; in ath11k_htc_start()
773 skb = ath11k_htc_build_tx_ctrl_skb(htc->ab); in ath11k_htc_start()
775 return -ENOMEM; in ath11k_htc_start()
778 memset(skb->data, 0, skb->len); in ath11k_htc_start()
780 msg = (struct ath11k_htc_setup_complete_extended *)skb->data; in ath11k_htc_start()
781 msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID, in ath11k_htc_start()
784 if (ab->hw_params.credit_flow) in ath11k_htc_start()
787 msg->flags |= ATH11K_GLOBAL_DISABLE_CREDIT_FLOW; in ath11k_htc_start()
800 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_init()
805 spin_lock_init(&htc->tx_lock); in ath11k_htc_init()
809 htc->ab = ab; in ath11k_htc_init()
811 switch (ab->wmi_ab.preferred_hw_mode) { in ath11k_htc_init()
813 htc->wmi_ep_count = 1; in ath11k_htc_init()
817 htc->wmi_ep_count = 2; in ath11k_htc_init()
820 htc->wmi_ep_count = 3; in ath11k_htc_init()
823 htc->wmi_ep_count = ab->hw_params.max_radios; in ath11k_htc_init()
827 /* setup our pseudo HTC control endpoint connection */ in ath11k_htc_init()
842 init_completion(&htc->ctl_resp); in ath11k_htc_init()