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()
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()
67 spin_lock_bh(&ep->htc->tx_lock); in ath11k_htc_prepare_tx_skb()
68 hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++); in ath11k_htc_prepare_tx_skb()
69 spin_unlock_bh(&ep->htc->tx_lock); in ath11k_htc_prepare_tx_skb()
76 struct ath11k_htc_ep *ep = &htc->endpoint[eid]; in ath11k_htc_send()
78 struct device *dev = htc->ab->dev; in ath11k_htc_send()
79 struct ath11k_base *ab = htc->ab; in ath11k_htc_send()
85 return -ENOENT; in ath11k_htc_send()
90 if (ep->tx_credit_flow_enabled) { in ath11k_htc_send()
91 credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); in ath11k_htc_send()
92 spin_lock_bh(&htc->tx_lock); in ath11k_htc_send()
93 if (ep->tx_credits < credits) { in ath11k_htc_send()
96 eid, credits, ep->tx_credits); in ath11k_htc_send()
97 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
98 ret = -EAGAIN; in ath11k_htc_send()
101 ep->tx_credits -= credits; in ath11k_htc_send()
104 eid, credits, ep->tx_credits); in ath11k_htc_send()
105 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
110 skb_cb->eid = eid; in ath11k_htc_send()
111 skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); in ath11k_htc_send()
112 ret = dma_mapping_error(dev, skb_cb->paddr); in ath11k_htc_send()
114 ret = -EIO; in ath11k_htc_send()
118 ret = ath11k_ce_send(htc->ab, skb, ep->ul_pipe_id, ep->eid); in ath11k_htc_send()
125 dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); in ath11k_htc_send()
127 if (ep->tx_credit_flow_enabled) { in ath11k_htc_send()
128 spin_lock_bh(&htc->tx_lock); in ath11k_htc_send()
129 ep->tx_credits += credits; in ath11k_htc_send()
132 eid, credits, ep->tx_credits); in ath11k_htc_send()
133 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_send()
135 if (ep->ep_ops.ep_tx_credits) in ath11k_htc_send()
136 ep->ep_ops.ep_tx_credits(htc->ab); in ath11k_htc_send()
149 struct ath11k_base *ab = htc->ab; in ath11k_htc_process_credit_report()
158 spin_lock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
160 if (report->eid >= ATH11K_HTC_EP_COUNT) in ath11k_htc_process_credit_report()
163 ep = &htc->endpoint[report->eid]; in ath11k_htc_process_credit_report()
164 ep->tx_credits += report->credits; in ath11k_htc_process_credit_report()
167 report->eid, report->credits, ep->tx_credits); in ath11k_htc_process_credit_report()
169 if (ep->ep_ops.ep_tx_credits) { in ath11k_htc_process_credit_report()
170 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
171 ep->ep_ops.ep_tx_credits(htc->ab); in ath11k_htc_process_credit_report()
172 spin_lock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
175 spin_unlock_bh(&htc->tx_lock); in ath11k_htc_process_credit_report()
183 struct ath11k_base *ab = htc->ab; in ath11k_htc_process_trailer()
191 if (length < sizeof(record->hdr)) { in ath11k_htc_process_trailer()
192 status = -EINVAL; in ath11k_htc_process_trailer()
196 if (record->hdr.len > length) { in ath11k_htc_process_trailer()
199 record->hdr.len); in ath11k_htc_process_trailer()
200 status = -EINVAL; in ath11k_htc_process_trailer()
204 switch (record->hdr.id) { in ath11k_htc_process_trailer()
207 if (record->hdr.len < len) { in ath11k_htc_process_trailer()
209 status = -EINVAL; in ath11k_htc_process_trailer()
213 record->credit_report, in ath11k_htc_process_trailer()
214 record->hdr.len, in ath11k_htc_process_trailer()
219 record->hdr.id, record->hdr.len); in ath11k_htc_process_trailer()
227 buffer += sizeof(record->hdr) + record->hdr.len; in ath11k_htc_process_trailer()
228 length -= sizeof(record->hdr) + record->hdr.len; in ath11k_htc_process_trailer()
238 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_rx_completion_handler()
247 hdr = (struct ath11k_htc_hdr *)skb->data; in ath11k_htc_rx_completion_handler()
250 eid = FIELD_GET(HTC_HDR_ENDPOINTID, hdr->htc_info); in ath11k_htc_rx_completion_handler()
257 ep = &htc->endpoint[eid]; in ath11k_htc_rx_completion_handler()
259 payload_len = FIELD_GET(HTC_HDR_PAYLOADLEN, hdr->htc_info); in ath11k_htc_rx_completion_handler()
267 if (skb->len < payload_len) { in ath11k_htc_rx_completion_handler()
269 skb->len, payload_len); in ath11k_htc_rx_completion_handler()
274 trailer_present = (FIELD_GET(HTC_HDR_FLAGS, hdr->htc_info)) & in ath11k_htc_rx_completion_handler()
280 trailer_len = FIELD_GET(HTC_HDR_CONTROLBYTES0, hdr->ctrl_info); in ath11k_htc_rx_completion_handler()
293 trailer -= trailer_len; in ath11k_htc_rx_completion_handler()
299 skb_trim(skb, skb->len - trailer_len); in ath11k_htc_rx_completion_handler()
307 struct ath11k_htc_msg *msg = (struct ath11k_htc_msg *)skb->data; in ath11k_htc_rx_completion_handler()
309 switch (FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id)) { in ath11k_htc_rx_completion_handler()
313 if (completion_done(&htc->ctl_resp)) { in ath11k_htc_rx_completion_handler()
318 complete(&htc->ctl_resp); in ath11k_htc_rx_completion_handler()
322 htc->control_resp_len = in ath11k_htc_rx_completion_handler()
323 min_t(int, skb->len, in ath11k_htc_rx_completion_handler()
326 memcpy(htc->control_resp_buffer, skb->data, in ath11k_htc_rx_completion_handler()
327 htc->control_resp_len); in ath11k_htc_rx_completion_handler()
329 complete(&htc->ctl_resp); in ath11k_htc_rx_completion_handler()
340 ep->ep_ops.ep_rx_complete(ab, skb); in ath11k_htc_rx_completion_handler()
343 ath11k_ce_poll_send_completed(ab, ep->ul_pipe_id); in ath11k_htc_rx_completion_handler()
391 return "IPA TX"; in htc_service_name()
405 ep = &htc->endpoint[i]; in ath11k_htc_reset_endpoint_states()
406 ep->service_id = ATH11K_HTC_SVC_ID_UNUSED; in ath11k_htc_reset_endpoint_states()
407 ep->max_ep_message_len = 0; in ath11k_htc_reset_endpoint_states()
408 ep->max_tx_queue_depth = 0; in ath11k_htc_reset_endpoint_states()
409 ep->eid = i; in ath11k_htc_reset_endpoint_states()
410 ep->htc = htc; in ath11k_htc_reset_endpoint_states()
411 ep->tx_credit_flow_enabled = true; in ath11k_htc_reset_endpoint_states()
421 if (htc->service_alloc_table[i].service_id == service_id) { in ath11k_htc_get_credit_allocation()
423 htc->service_alloc_table[i].credit_allocation; in ath11k_htc_get_credit_allocation()
440 credits = htc->total_transmit_credits; in ath11k_htc_setup_target_buffer_assignments()
441 serv_entry = htc->service_alloc_table; in ath11k_htc_setup_target_buffer_assignments()
443 if ((htc->wmi_ep_count == 0) || in ath11k_htc_setup_target_buffer_assignments()
444 (htc->wmi_ep_count > ARRAY_SIZE(svc_id))) in ath11k_htc_setup_target_buffer_assignments()
445 return -EINVAL; in ath11k_htc_setup_target_buffer_assignments()
448 credits = credits / htc->wmi_ep_count; in ath11k_htc_setup_target_buffer_assignments()
449 for (i = 0; i < htc->wmi_ep_count; i++) { in ath11k_htc_setup_target_buffer_assignments()
460 struct ath11k_base *ab = htc->ab; in ath11k_htc_wait_target()
462 struct ath11k_htc_ready *ready; in ath11k_htc_wait_target() local
467 time_left = wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_wait_target()
472 for (i = 0; i < ab->hw_params.ce_count; i++) in ath11k_htc_wait_target()
473 ath11k_ce_per_engine_service(htc->ab, i); in ath11k_htc_wait_target()
476 wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_wait_target()
480 status = -ETIMEDOUT; in ath11k_htc_wait_target()
488 if (htc->control_resp_len < sizeof(*ready)) { in ath11k_htc_wait_target()
489 ath11k_warn(ab, "Invalid HTC ready msg len:%d\n", in ath11k_htc_wait_target()
490 htc->control_resp_len); in ath11k_htc_wait_target()
491 return -ECOMM; in ath11k_htc_wait_target()
494 ready = (struct ath11k_htc_ready *)htc->control_resp_buffer; in ath11k_htc_wait_target()
495 message_id = FIELD_GET(HTC_MSG_MESSAGEID, ready->id_credit_count); in ath11k_htc_wait_target()
497 ready->id_credit_count); in ath11k_htc_wait_target()
498 credit_size = FIELD_GET(HTC_READY_MSG_CREDITSIZE, ready->size_ep); in ath11k_htc_wait_target()
501 ath11k_warn(ab, "Invalid HTC ready msg: 0x%x\n", message_id); in ath11k_htc_wait_target()
502 return -ECOMM; in ath11k_htc_wait_target()
505 htc->total_transmit_credits = credit_count; in ath11k_htc_wait_target()
506 htc->target_credit_size = credit_size; in ath11k_htc_wait_target()
509 "Target ready! transmit resources: %d size:%d\n", in ath11k_htc_wait_target()
510 htc->total_transmit_credits, htc->target_credit_size); in ath11k_htc_wait_target()
512 if ((htc->total_transmit_credits == 0) || in ath11k_htc_wait_target()
513 (htc->target_credit_size == 0)) { in ath11k_htc_wait_target()
515 return -ECOMM; in ath11k_htc_wait_target()
519 * back-to-back write. in ath11k_htc_wait_target()
521 if (ab->hw_params.supports_shadow_regs) in ath11k_htc_wait_target()
522 htc->total_transmit_credits = 1; in ath11k_htc_wait_target()
533 struct ath11k_base *ab = htc->ab; in ath11k_htc_connect_service()
548 if (conn_req->service_id == ATH11K_HTC_SVC_ID_RSVD_CTRL) { in ath11k_htc_connect_service()
553 goto setup; in ath11k_htc_connect_service()
557 conn_req->service_id); in ath11k_htc_connect_service()
561 htc_service_name(conn_req->service_id)); in ath11k_htc_connect_service()
563 skb = ath11k_htc_build_tx_ctrl_skb(htc->ab); in ath11k_htc_connect_service()
566 return -ENOMEM; in ath11k_htc_connect_service()
571 memset(skb->data, 0, length); in ath11k_htc_connect_service()
573 req_msg = (struct ath11k_htc_conn_svc *)skb->data; in ath11k_htc_connect_service()
574 req_msg->msg_svc_id = FIELD_PREP(HTC_MSG_MESSAGEID, in ath11k_htc_connect_service()
580 if (!(conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL || in ath11k_htc_connect_service()
581 conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1 || in ath11k_htc_connect_service()
582 conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2)) { in ath11k_htc_connect_service()
587 req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags); in ath11k_htc_connect_service()
588 req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID, in ath11k_htc_connect_service()
589 conn_req->service_id); in ath11k_htc_connect_service()
591 reinit_completion(&htc->ctl_resp); in ath11k_htc_connect_service()
600 time_left = wait_for_completion_timeout(&htc->ctl_resp, in ath11k_htc_connect_service()
604 return -ETIMEDOUT; in ath11k_htc_connect_service()
608 resp_msg = (struct ath11k_htc_conn_svc_resp *)htc->control_resp_buffer; in ath11k_htc_connect_service()
609 message_id = FIELD_GET(HTC_MSG_MESSAGEID, resp_msg->msg_svc_id); in ath11k_htc_connect_service()
611 resp_msg->msg_svc_id); in ath11k_htc_connect_service()
614 (htc->control_resp_len < sizeof(*resp_msg))) { in ath11k_htc_connect_service()
616 return -EPROTO; in ath11k_htc_connect_service()
622 FIELD_GET(HTC_SVC_RESP_MSG_STATUS, resp_msg->flags_len), in ath11k_htc_connect_service()
623 FIELD_GET(HTC_SVC_RESP_MSG_ENDPOINTID, resp_msg->flags_len)); in ath11k_htc_connect_service()
625 conn_resp->connect_resp_code = FIELD_GET(HTC_SVC_RESP_MSG_STATUS, in ath11k_htc_connect_service()
626 resp_msg->flags_len); in ath11k_htc_connect_service()
629 if (conn_resp->connect_resp_code != ATH11K_HTC_CONN_SVC_STATUS_SUCCESS) { in ath11k_htc_connect_service()
632 conn_resp->connect_resp_code); in ath11k_htc_connect_service()
633 return -EPROTO; in ath11k_htc_connect_service()
638 resp_msg->flags_len); in ath11k_htc_connect_service()
641 resp_msg->flags_len); in ath11k_htc_connect_service()
643 setup: in ath11k_htc_connect_service()
646 return -EPROTO; in ath11k_htc_connect_service()
649 return -EPROTO; in ath11k_htc_connect_service()
651 ep = &htc->endpoint[assigned_eid]; in ath11k_htc_connect_service()
652 ep->eid = assigned_eid; in ath11k_htc_connect_service()
654 if (ep->service_id != ATH11K_HTC_SVC_ID_UNUSED) in ath11k_htc_connect_service()
655 return -EPROTO; in ath11k_htc_connect_service()
658 conn_resp->eid = assigned_eid; in ath11k_htc_connect_service()
659 conn_resp->max_msg_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE, in ath11k_htc_connect_service()
660 resp_msg->flags_len); in ath11k_htc_connect_service()
662 /* setup the endpoint */ in ath11k_htc_connect_service()
663 ep->service_id = conn_req->service_id; in ath11k_htc_connect_service()
664 ep->max_tx_queue_depth = conn_req->max_send_queue_depth; in ath11k_htc_connect_service()
665 ep->max_ep_message_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE, in ath11k_htc_connect_service()
666 resp_msg->flags_len); in ath11k_htc_connect_service()
667 ep->tx_credits = tx_alloc; in ath11k_htc_connect_service()
670 ep->ep_ops = conn_req->ep_ops; in ath11k_htc_connect_service()
672 status = ath11k_hif_map_service_to_pipe(htc->ab, in ath11k_htc_connect_service()
673 ep->service_id, in ath11k_htc_connect_service()
674 &ep->ul_pipe_id, in ath11k_htc_connect_service()
675 &ep->dl_pipe_id); in ath11k_htc_connect_service()
680 "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", in ath11k_htc_connect_service()
681 htc_service_name(ep->service_id), ep->ul_pipe_id, in ath11k_htc_connect_service()
682 ep->dl_pipe_id, ep->eid); in ath11k_htc_connect_service()
684 if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { in ath11k_htc_connect_service()
685 ep->tx_credit_flow_enabled = false; in ath11k_htc_connect_service()
688 htc_service_name(ep->service_id), assigned_eid); in ath11k_htc_connect_service()
698 struct ath11k_base *ab = htc->ab; in ath11k_htc_start()
701 skb = ath11k_htc_build_tx_ctrl_skb(htc->ab); in ath11k_htc_start()
703 return -ENOMEM; in ath11k_htc_start()
706 memset(skb->data, 0, skb->len); in ath11k_htc_start()
708 msg = (struct ath11k_htc_setup_complete_extended *)skb->data; in ath11k_htc_start()
709 msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID, in ath11k_htc_start()
725 struct ath11k_htc *htc = &ab->htc; in ath11k_htc_init()
730 spin_lock_init(&htc->tx_lock); in ath11k_htc_init()
734 htc->ab = ab; in ath11k_htc_init()
736 switch (ab->wmi_ab.preferred_hw_mode) { in ath11k_htc_init()
738 htc->wmi_ep_count = 1; in ath11k_htc_init()
742 htc->wmi_ep_count = 2; in ath11k_htc_init()
745 htc->wmi_ep_count = 3; in ath11k_htc_init()
748 htc->wmi_ep_count = ab->hw_params.max_radios; in ath11k_htc_init()
752 /* setup our pseudo HTC control endpoint connection */ in ath11k_htc_init()
767 init_completion(&htc->ctl_resp); in ath11k_htc_init()