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