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.
21 /* FW/HTC requires 4-byte aligned streams */ in ath11k_htc_alloc_skb()
22 if (!IS_ALIGNED((unsigned long)skb->data, 4)) in ath11k_htc_alloc_skb()
44 WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4)); in ath11k_htc_build_tx_ctrl_skb()
57 hdr = (struct ath11k_htc_hdr *)skb->data; in ath11k_htc_prepare_tx_skb()
60 hdr->htc_info = FIELD_PREP(HTC_HDR_ENDPOINTID, ep->eid) | in ath11k_htc_prepare_tx_skb()
62 (skb->len - sizeof(*hdr))); in ath11k_htc_prepare_tx_skb()
64 if (ep->tx_credit_flow_enabled) in ath11k_htc_prepare_tx_skb()
65 hdr->htc_info |= FIELD_PREP(HTC_HDR_FLAGS, in ath11k_htc_prepare_tx_skb()
68 spin_lock_bh(&ep->htc->tx_lock); in ath11k_htc_prepare_tx_skb()
69 hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++); in ath11k_htc_prepare_tx_skb()
70 spin_unlock_bh(&ep->htc->tx_lock); in ath11k_htc_prepare_tx_skb()
77 struct ath11k_htc_ep *ep = &htc->endpoint[eid]; in ath11k_htc_send()
79 struct device *dev = htc->ab->dev; in ath11k_htc_send()
80 struct ath11k_base *ab = htc->ab; in ath11k_htc_send()
83 bool credit_flow_enabled = (ab->hw_params.credit_flow && in ath11k_htc_send()
84 ep->tx_credit_flow_enabled); in ath11k_htc_send()
88 return -ENOENT; in ath11k_htc_send()
94 credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); in ath11k_htc_send()
95 spin_lock_bh(&htc->tx_lock); in ath11k_htc_send()
96 if (ep->tx_credits < credits) { in ath11k_htc_send()
99 eid, credits, ep->tx_credits); in ath11k_htc_send()
100 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
101 ret = -EAGAIN; in ath11k_htc_send()
104 ep->tx_credits -= credits; in ath11k_htc_send()
107 eid, credits, ep->tx_credits); in ath11k_htc_send()
108 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
113 skb_cb->eid = eid; in ath11k_htc_send()
114 skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); in ath11k_htc_send()
115 ret = dma_mapping_error(dev, skb_cb->paddr); in ath11k_htc_send()
117 ret = -EIO; in ath11k_htc_send()
122 skb, skb_cb->eid, &skb_cb->paddr); in ath11k_htc_send()
124 ret = ath11k_ce_send(htc->ab, skb, ep->ul_pipe_id, ep->eid); in ath11k_htc_send()
131 dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); in ath11k_htc_send()
134 spin_lock_bh(&htc->tx_lock); in ath11k_htc_send()
135 ep->tx_credits += credits; in ath11k_htc_send()
138 eid, credits, ep->tx_credits); in ath11k_htc_send()
139 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
141 if (ep->ep_ops.ep_tx_credits) in ath11k_htc_send()
142 ep->ep_ops.ep_tx_credits(htc->ab); in ath11k_htc_send()
155 struct ath11k_base *ab = htc->ab; in ath11k_htc_process_credit_report()
164 spin_lock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
166 if (report->eid >= ATH11K_HTC_EP_COUNT) in ath11k_htc_process_credit_report()
169 ep = &htc->endpoint[report->eid]; in ath11k_htc_process_credit_report()
170 ep->tx_credits += report->credits; in ath11k_htc_process_credit_report()
173 report->eid, report->credits, ep->tx_credits); in ath11k_htc_process_credit_report()
175 if (ep->ep_ops.ep_tx_credits) { in ath11k_htc_process_credit_report()
176 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
177 ep->ep_ops.ep_tx_credits(htc->ab); in ath11k_htc_process_credit_report()
178 spin_lock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
181 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
189 struct ath11k_base *ab = htc->ab; in ath11k_htc_process_trailer()
197 if (length < sizeof(record->hdr)) { in ath11k_htc_process_trailer()
198 status = -EINVAL; in ath11k_htc_process_trailer()
202 if (record->hdr.len > length) { in ath11k_htc_process_trailer()
205 record->hdr.len); in ath11k_htc_process_trailer()
206 status = -EINVAL; in ath11k_htc_process_trailer()
210 if (ab->hw_params.credit_flow) { in ath11k_htc_process_trailer()
211 switch (record->hdr.id) { in ath11k_htc_process_trailer()
214 if (record->hdr.len < len) { in ath11k_htc_process_trailer()
216 status = -EINVAL; in ath11k_htc_process_trailer()
220 record->credit_report, in ath11k_htc_process_trailer()
221 record->hdr.len, in ath11k_htc_process_trailer()
226 record->hdr.id, record->hdr.len); in ath11k_htc_process_trailer()
235 buffer += sizeof(record->hdr) + record->hdr.len; in ath11k_htc_process_trailer()
236 length -= sizeof(record->hdr) + record->hdr.len; in ath11k_htc_process_trailer()
247 set_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); in ath11k_htc_suspend_complete()
249 clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); in ath11k_htc_suspend_complete()
251 complete(&ab->htc_suspend); in ath11k_htc_suspend_complete()
257 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_tx_completion_handler()
262 eid = ATH11K_SKB_CB(skb)->eid; in ath11k_htc_tx_completion_handler()
268 ep = &htc->endpoint[eid]; in ath11k_htc_tx_completion_handler()
269 spin_lock_bh(&htc->tx_lock); in ath11k_htc_tx_completion_handler()
270 ep_tx_complete = ep->ep_ops.ep_tx_complete; in ath11k_htc_tx_completion_handler()
271 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_tx_completion_handler()
276 ep_tx_complete(htc->ab, skb); in ath11k_htc_tx_completion_handler()
288 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_rx_completion_handler()
297 hdr = (struct ath11k_htc_hdr *)skb->data; in ath11k_htc_rx_completion_handler()
300 eid = FIELD_GET(HTC_HDR_ENDPOINTID, hdr->htc_info); in ath11k_htc_rx_completion_handler()
307 ep = &htc->endpoint[eid]; in ath11k_htc_rx_completion_handler()
309 payload_len = FIELD_GET(HTC_HDR_PAYLOADLEN, hdr->htc_info); in ath11k_htc_rx_completion_handler()
317 if (skb->len < payload_len) { in ath11k_htc_rx_completion_handler()
319 skb->len, payload_len); in ath11k_htc_rx_completion_handler()
324 trailer_present = (FIELD_GET(HTC_HDR_FLAGS, hdr->htc_info)) & in ath11k_htc_rx_completion_handler()
333 trailer_len = FIELD_GET(HTC_HDR_CONTROLBYTES0, hdr->ctrl_info); in ath11k_htc_rx_completion_handler()
346 trailer -= trailer_len; in ath11k_htc_rx_completion_handler()
352 skb_trim(skb, skb->len - trailer_len); in ath11k_htc_rx_completion_handler()
360 struct ath11k_htc_msg *msg = (struct ath11k_htc_msg *)skb->data; in ath11k_htc_rx_completion_handler()
362 message_id = FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id); in ath11k_htc_rx_completion_handler()
371 if (completion_done(&htc->ctl_resp)) { in ath11k_htc_rx_completion_handler()
376 complete(&htc->ctl_resp); in ath11k_htc_rx_completion_handler()
380 htc->control_resp_len = in ath11k_htc_rx_completion_handler()
381 min_t(int, skb->len, in ath11k_htc_rx_completion_handler()
384 memcpy(htc->control_resp_buffer, skb->data, in ath11k_htc_rx_completion_handler()
385 htc->control_resp_len); in ath11k_htc_rx_completion_handler()
387 complete(&htc->ctl_resp); in ath11k_htc_rx_completion_handler()
400 FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id)); in ath11k_htc_rx_completion_handler()
406 ep->ep_ops.ep_rx_complete(ab, skb); in ath11k_htc_rx_completion_handler()
409 ath11k_ce_poll_send_completed(ab, ep->ul_pipe_id); in ath11k_htc_rx_completion_handler()
457 return "IPA TX"; in htc_service_name()
471 ep = &htc->endpoint[i]; in ath11k_htc_reset_endpoint_states()
472 ep->service_id = ATH11K_HTC_SVC_ID_UNUSED; in ath11k_htc_reset_endpoint_states()
473 ep->max_ep_message_len = 0; in ath11k_htc_reset_endpoint_states()
474 ep->max_tx_queue_depth = 0; in ath11k_htc_reset_endpoint_states()
475 ep->eid = i; in ath11k_htc_reset_endpoint_states()
476 ep->htc = htc; in ath11k_htc_reset_endpoint_states()
477 ep->tx_credit_flow_enabled = true; in ath11k_htc_reset_endpoint_states()
487 if (htc->service_alloc_table[i].service_id == service_id) { in ath11k_htc_get_credit_allocation()
489 htc->service_alloc_table[i].credit_allocation; in ath11k_htc_get_credit_allocation()
506 credits = htc->total_transmit_credits; in ath11k_htc_setup_target_buffer_assignments()
507 serv_entry = htc->service_alloc_table; in ath11k_htc_setup_target_buffer_assignments()
509 if ((htc->wmi_ep_count == 0) || in ath11k_htc_setup_target_buffer_assignments()
510 (htc->wmi_ep_count > ARRAY_SIZE(svc_id))) in ath11k_htc_setup_target_buffer_assignments()
511 return -EINVAL; in ath11k_htc_setup_target_buffer_assignments()
514 credits = credits / htc->wmi_ep_count; in ath11k_htc_setup_target_buffer_assignments()
515 for (i = 0; i < htc->wmi_ep_count; i++) { in ath11k_htc_setup_target_buffer_assignments()
526 struct ath11k_base *ab = htc->ab; in ath11k_htc_wait_target()
528 struct ath11k_htc_ready *ready; in ath11k_htc_wait_target() local
533 time_left = wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_wait_target()
538 for (i = 0; i < ab->hw_params.ce_count; i++) in ath11k_htc_wait_target()
539 ath11k_ce_per_engine_service(htc->ab, i); in ath11k_htc_wait_target()
542 wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_wait_target()
546 status = -ETIMEDOUT; in ath11k_htc_wait_target()
554 if (htc->control_resp_len < sizeof(*ready)) { in ath11k_htc_wait_target()
555 ath11k_warn(ab, "Invalid HTC ready msg len:%d\n", in ath11k_htc_wait_target()
556 htc->control_resp_len); in ath11k_htc_wait_target()
557 return -ECOMM; in ath11k_htc_wait_target()
560 ready = (struct ath11k_htc_ready *)htc->control_resp_buffer; in ath11k_htc_wait_target()
561 message_id = FIELD_GET(HTC_MSG_MESSAGEID, ready->id_credit_count); in ath11k_htc_wait_target()
563 ready->id_credit_count); in ath11k_htc_wait_target()
564 credit_size = FIELD_GET(HTC_READY_MSG_CREDITSIZE, ready->size_ep); in ath11k_htc_wait_target()
567 ath11k_warn(ab, "Invalid HTC ready msg: 0x%x\n", message_id); in ath11k_htc_wait_target()
568 return -ECOMM; in ath11k_htc_wait_target()
571 htc->total_transmit_credits = credit_count; in ath11k_htc_wait_target()
572 htc->target_credit_size = credit_size; in ath11k_htc_wait_target()
575 "target ready total_transmit_credits %d target_credit_size %d\n", in ath11k_htc_wait_target()
576 htc->total_transmit_credits, htc->target_credit_size); in ath11k_htc_wait_target()
578 if ((htc->total_transmit_credits == 0) || in ath11k_htc_wait_target()
579 (htc->target_credit_size == 0)) { in ath11k_htc_wait_target()
581 return -ECOMM; in ath11k_htc_wait_target()
585 * back-to-back write. in ath11k_htc_wait_target()
587 if (ab->hw_params.supports_shadow_regs) in ath11k_htc_wait_target()
588 htc->total_transmit_credits = 1; in ath11k_htc_wait_target()
599 struct ath11k_base *ab = htc->ab; in ath11k_htc_connect_service()
614 if (conn_req->service_id == ATH11K_HTC_SVC_ID_RSVD_CTRL) { in ath11k_htc_connect_service()
619 goto setup; in ath11k_htc_connect_service()
623 conn_req->service_id); in ath11k_htc_connect_service()
627 htc_service_name(conn_req->service_id)); in ath11k_htc_connect_service()
629 skb = ath11k_htc_build_tx_ctrl_skb(htc->ab); in ath11k_htc_connect_service()
632 return -ENOMEM; in ath11k_htc_connect_service()
637 memset(skb->data, 0, length); in ath11k_htc_connect_service()
639 req_msg = (struct ath11k_htc_conn_svc *)skb->data; in ath11k_htc_connect_service()
640 req_msg->msg_svc_id = FIELD_PREP(HTC_MSG_MESSAGEID, in ath11k_htc_connect_service()
646 if (!(conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL || in ath11k_htc_connect_service()
647 conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1 || in ath11k_htc_connect_service()
648 conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2)) { in ath11k_htc_connect_service()
653 if (!ab->hw_params.credit_flow) { in ath11k_htc_connect_service()
658 req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags); in ath11k_htc_connect_service()
659 req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID, in ath11k_htc_connect_service()
660 conn_req->service_id); in ath11k_htc_connect_service()
662 reinit_completion(&htc->ctl_resp); in ath11k_htc_connect_service()
671 time_left = wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_connect_service()
675 return -ETIMEDOUT; in ath11k_htc_connect_service()
679 resp_msg = (struct ath11k_htc_conn_svc_resp *)htc->control_resp_buffer; in ath11k_htc_connect_service()
680 message_id = FIELD_GET(HTC_MSG_MESSAGEID, resp_msg->msg_svc_id); in ath11k_htc_connect_service()
682 resp_msg->msg_svc_id); in ath11k_htc_connect_service()
685 (htc->control_resp_len < sizeof(*resp_msg))) { in ath11k_htc_connect_service()
687 return -EPROTO; in ath11k_htc_connect_service()
693 FIELD_GET(HTC_SVC_RESP_MSG_STATUS, resp_msg->flags_len), in ath11k_htc_connect_service()
694 FIELD_GET(HTC_SVC_RESP_MSG_ENDPOINTID, resp_msg->flags_len)); in ath11k_htc_connect_service()
696 conn_resp->connect_resp_code = FIELD_GET(HTC_SVC_RESP_MSG_STATUS, in ath11k_htc_connect_service()
697 resp_msg->flags_len); in ath11k_htc_connect_service()
700 if (conn_resp->connect_resp_code != ATH11K_HTC_CONN_SVC_STATUS_SUCCESS) { in ath11k_htc_connect_service()
703 conn_resp->connect_resp_code); in ath11k_htc_connect_service()
704 return -EPROTO; in ath11k_htc_connect_service()
709 resp_msg->flags_len); in ath11k_htc_connect_service()
712 resp_msg->flags_len); in ath11k_htc_connect_service()
714 setup: in ath11k_htc_connect_service()
717 return -EPROTO; in ath11k_htc_connect_service()
720 return -EPROTO; in ath11k_htc_connect_service()
722 ep = &htc->endpoint[assigned_eid]; in ath11k_htc_connect_service()
723 ep->eid = assigned_eid; in ath11k_htc_connect_service()
725 if (ep->service_id != ATH11K_HTC_SVC_ID_UNUSED) in ath11k_htc_connect_service()
726 return -EPROTO; in ath11k_htc_connect_service()
729 conn_resp->eid = assigned_eid; in ath11k_htc_connect_service()
730 conn_resp->max_msg_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE, in ath11k_htc_connect_service()
731 resp_msg->flags_len); in ath11k_htc_connect_service()
733 /* setup the endpoint */ in ath11k_htc_connect_service()
734 ep->service_id = conn_req->service_id; in ath11k_htc_connect_service()
735 ep->max_tx_queue_depth = conn_req->max_send_queue_depth; in ath11k_htc_connect_service()
736 ep->max_ep_message_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE, in ath11k_htc_connect_service()
737 resp_msg->flags_len); in ath11k_htc_connect_service()
738 ep->tx_credits = tx_alloc; in ath11k_htc_connect_service()
741 ep->ep_ops = conn_req->ep_ops; in ath11k_htc_connect_service()
743 status = ath11k_hif_map_service_to_pipe(htc->ab, in ath11k_htc_connect_service()
744 ep->service_id, in ath11k_htc_connect_service()
745 &ep->ul_pipe_id, in ath11k_htc_connect_service()
746 &ep->dl_pipe_id); in ath11k_htc_connect_service()
751 "htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", in ath11k_htc_connect_service()
752 htc_service_name(ep->service_id), ep->ul_pipe_id, in ath11k_htc_connect_service()
753 ep->dl_pipe_id, ep->eid); in ath11k_htc_connect_service()
755 if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { in ath11k_htc_connect_service()
756 ep->tx_credit_flow_enabled = false; in ath11k_htc_connect_service()
759 htc_service_name(ep->service_id), assigned_eid); in ath11k_htc_connect_service()
769 struct ath11k_base *ab = htc->ab; in ath11k_htc_start()
772 skb = ath11k_htc_build_tx_ctrl_skb(htc->ab); in ath11k_htc_start()
774 return -ENOMEM; in ath11k_htc_start()
777 memset(skb->data, 0, skb->len); in ath11k_htc_start()
779 msg = (struct ath11k_htc_setup_complete_extended *)skb->data; in ath11k_htc_start()
780 msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID, in ath11k_htc_start()
783 if (ab->hw_params.credit_flow) in ath11k_htc_start()
786 msg->flags |= ATH11K_GLOBAL_DISABLE_CREDIT_FLOW; in ath11k_htc_start()
799 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_init()
804 spin_lock_init(&htc->tx_lock); in ath11k_htc_init()
808 htc->ab = ab; in ath11k_htc_init()
810 switch (ab->wmi_ab.preferred_hw_mode) { in ath11k_htc_init()
812 htc->wmi_ep_count = 1; in ath11k_htc_init()
816 htc->wmi_ep_count = 2; in ath11k_htc_init()
819 htc->wmi_ep_count = 3; in ath11k_htc_init()
822 htc->wmi_ep_count = ab->hw_params.max_radios; in ath11k_htc_init()
826 /* setup our pseudo HTC control endpoint connection */ in ath11k_htc_init()
841 init_completion(&htc->ctl_resp); in ath11k_htc_init()